feat: restore book cover/thumbnail prerender on first open

- Add isValidThumbnailBmp(), generateInvalidFormatCoverBmp(), and
  generateInvalidFormatThumbBmp() methods to Epub class for validating
  BMP files and generating X-pattern marker images when cover extraction
  fails (e.g., progressive JPG).
- Restore prerender block in EpubReaderActivity::onEnter() that checks
  for missing cover BMPs (fit + cropped) and thumbnail BMPs at each
  PRERENDER_THUMB_HEIGHTS size, showing a "Preparing book..." popup
  with progress. Falls back to PlaceholderCoverGenerator, then to
  invalid-format marker BMPs as last resort.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-07 21:22:19 -05:00
parent 22c189281c
commit a5ca15df4f
3 changed files with 225 additions and 0 deletions

View File

@@ -3,6 +3,7 @@
#include <Epub/Page.h>
#include <Epub/blocks/TextBlock.h>
#include <FsHelpers.h>
#include <PlaceholderCoverGenerator.h>
#include <GfxRenderer.h>
#include <HalStorage.h>
#include <I18n.h>
@@ -115,6 +116,61 @@ void EpubReaderActivity::onEnter() {
}
}
// Prerender covers and thumbnails on first open so Home and Sleep screens are instant.
{
int totalSteps = 0;
if (!Storage.exists(epub->getCoverBmpPath(false).c_str())) totalSteps++;
if (!Storage.exists(epub->getCoverBmpPath(true).c_str())) totalSteps++;
for (int i = 0; i < PRERENDER_THUMB_HEIGHTS_COUNT; i++) {
if (!Storage.exists(epub->getThumbBmpPath(PRERENDER_THUMB_HEIGHTS[i]).c_str())) totalSteps++;
}
if (totalSteps > 0) {
Rect popupRect = GUI.drawPopup(renderer, "Preparing book...");
int completedSteps = 0;
auto updateProgress = [&]() {
completedSteps++;
GUI.fillPopupProgress(renderer, popupRect, completedSteps * 100 / totalSteps);
};
if (!Epub::isValidThumbnailBmp(epub->getCoverBmpPath(false))) {
epub->generateCoverBmp(false);
if (!Epub::isValidThumbnailBmp(epub->getCoverBmpPath(false))) {
if (!PlaceholderCoverGenerator::generate(epub->getCoverBmpPath(false), epub->getTitle(), epub->getAuthor(),
480, 800)) {
epub->generateInvalidFormatCoverBmp(false);
}
}
updateProgress();
}
if (!Epub::isValidThumbnailBmp(epub->getCoverBmpPath(true))) {
epub->generateCoverBmp(true);
if (!Epub::isValidThumbnailBmp(epub->getCoverBmpPath(true))) {
if (!PlaceholderCoverGenerator::generate(epub->getCoverBmpPath(true), epub->getTitle(), epub->getAuthor(),
480, 800)) {
epub->generateInvalidFormatCoverBmp(true);
}
}
updateProgress();
}
for (int i = 0; i < PRERENDER_THUMB_HEIGHTS_COUNT; i++) {
if (!Epub::isValidThumbnailBmp(epub->getThumbBmpPath(PRERENDER_THUMB_HEIGHTS[i]))) {
epub->generateThumbBmp(PRERENDER_THUMB_HEIGHTS[i]);
if (!Epub::isValidThumbnailBmp(epub->getThumbBmpPath(PRERENDER_THUMB_HEIGHTS[i]))) {
const int thumbHeight = PRERENDER_THUMB_HEIGHTS[i];
const int thumbWidth = static_cast<int>(thumbHeight * 0.6);
if (!PlaceholderCoverGenerator::generate(epub->getThumbBmpPath(thumbHeight), epub->getTitle(),
epub->getAuthor(), thumbWidth, thumbHeight)) {
epub->generateInvalidFormatThumbBmp(thumbHeight);
}
}
updateProgress();
}
}
}
}
// Save current epub as last opened epub and add to recent books
APP_STATE.openEpubPath = epub->getPath();
APP_STATE.saveToFile();