fix: Port upstream cover extraction fallback and outline improvements

Port PR #838 (epub cover fallback logic) and PR #907 (cover outlines):

- Add fallback cover filename probing when EPUB metadata lacks cover info
- Case-insensitive extension checking for cover images
- Detect and re-generate corrupt/empty thumbnail BMPs
- Always draw outline rect on cover tiles for legibility (PR #907)
- Upgrade Storage.exists() checks to Epub::isValidThumbnailBmp()
- Fallback chain: Real Cover → PlaceholderCoverGenerator → X-pattern marker
- Add epub.load retry logic (cache-only first, then full build)
- Adapt upstream Serial.printf calls to LOG_DBG/LOG_ERR macros

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
cottongin
2026-02-16 01:20:27 -05:00
parent 744d6160e8
commit b965ce9fb7
6 changed files with 400 additions and 77 deletions

View File

@@ -52,10 +52,23 @@ class Epub {
const std::string& getAuthor() const;
const std::string& getLanguage() const;
std::string getCoverBmpPath(bool cropped = false) const;
// Generate a 1-bit BMP cover image from the EPUB cover image.
// Returns true on success. On conversion failure, callers may use
// `generateInvalidFormatCoverBmp` to create a valid marker BMP.
bool generateCoverBmp(bool cropped = false) const;
// Create a valid 1-bit BMP that visually indicates an invalid/unsupported
// cover format (an X pattern). This prevents repeated generation attempts
// by providing a valid BMP file that `isValidThumbnailBmp` accepts.
bool generateInvalidFormatCoverBmp(bool cropped = false) const;
std::string getThumbBmpPath() const;
std::string getThumbBmpPath(int height) const;
// Generate a thumbnail BMP at the requested `height`. Returns true on
// successful conversion. If conversion fails, `generateInvalidFormatThumbBmp`
// can be used to write a valid marker image that prevents retries.
bool generateThumbBmp(int height) const;
// Create a valid 1-bit thumbnail BMP with an X marker indicating an
// invalid/unsupported cover image instead of leaving an empty marker file.
bool generateInvalidFormatThumbBmp(int height) const;
uint8_t* readItemContentsToBytes(const std::string& itemHref, size_t* size = nullptr,
bool trailingNullByte = false) const;
bool readItemContentsToStream(const std::string& itemHref, Print& out, size_t chunkSize) const;
@@ -72,4 +85,9 @@ class Epub {
size_t getBookSize() const;
float calculateProgress(int currentSpineIndex, float currentSpineRead) const;
CssParser* getCssParser() const { return cssParser.get(); }
static bool isValidThumbnailBmp(const std::string& bmpPath);
private:
std::vector<std::string> getCoverCandidates() const;
};