From c90304f59b9f1eb697881a3372b97620d5747c41 Mon Sep 17 00:00:00 2001 From: cottongin Date: Tue, 27 Jan 2026 07:50:37 -0500 Subject: [PATCH] fix: #348 fit cover artifacts - merge crop parameter (#465) Cherry-picked from upstream PR #465 Resolved conflicts: merged crop parameter with existing progressCallback, kept local dimension calculation and edge luminance caching logic --- lib/Epub/Epub.cpp | 2 +- lib/JpegToBmpConverter/JpegToBmpConverter.cpp | 19 ++++++++++++------- lib/JpegToBmpConverter/JpegToBmpConverter.h | 5 +++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 7165c90..8515004 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -447,7 +447,7 @@ bool Epub::generateCoverBmp(bool cropped) const { if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" || coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") { - Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image\n", millis()); + Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image (%s mode)\n", millis(), cropped ? "cropped" : "fit"); const auto coverJpgTempPath = getCachePath() + "/.cover.jpg"; FsFile coverJpg; diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp index fea0eaf..41167d8 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp @@ -200,7 +200,8 @@ unsigned char JpegToBmpConverter::jpegReadCallback(unsigned char* pBuf, const un // Internal implementation with configurable target size and bit depth bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, - bool oneBit, const std::function& progressCallback) { + bool oneBit, bool crop, + const std::function& progressCallback) { Serial.printf("[%lu] [JPG] Converting JPEG to %s BMP (target: %dx%d)\n", millis(), oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight); @@ -242,8 +243,12 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm const float scaleToFitWidth = static_cast(targetWidth) / imageInfo.m_width; const float scaleToFitHeight = static_cast(targetHeight) / imageInfo.m_height; // We scale to the smaller dimension, so we can potentially crop later. - // TODO: ideally, we already crop here. - const float scale = (scaleToFitWidth > scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; + float scale = 1.0; + if (crop) { // if we will crop, scale to the smaller dimension + scale = (scaleToFitWidth > scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; + } else { // else, scale to the larger dimension to fit + scale = (scaleToFitWidth < scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; + } outWidth = static_cast(imageInfo.m_width * scale); outHeight = static_cast(imageInfo.m_height * scale); @@ -556,22 +561,22 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm } // Core function: Convert JPEG file to 2-bit BMP (uses default target size) -bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut) { - return jpegFileToBmpStreamInternal(jpegFile, bmpOut, TARGET_MAX_WIDTH, TARGET_MAX_HEIGHT, false, nullptr); +bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop) { + return jpegFileToBmpStreamInternal(jpegFile, bmpOut, TARGET_MAX_WIDTH, TARGET_MAX_HEIGHT, false, crop, nullptr); } // Convert with custom target size (for thumbnails, 2-bit) bool JpegToBmpConverter::jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight, const std::function& progressCallback) { - return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, false, progressCallback); + return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, false, true, progressCallback); } // Convert to 1-bit BMP (black and white only, no grays) for fast home screen rendering bool JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight, const std::function& progressCallback) { - return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, true, progressCallback); + return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true, progressCallback); } // Get JPEG dimensions without full conversion diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.h b/lib/JpegToBmpConverter/JpegToBmpConverter.h index eb72dae..de6565b 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.h +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.h @@ -10,10 +10,11 @@ class JpegToBmpConverter { static unsigned char jpegReadCallback(unsigned char* pBuf, unsigned char buf_size, unsigned char* pBytes_actually_read, void* pCallback_data); static bool jpegFileToBmpStreamInternal(class FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, - bool oneBit, const std::function& progressCallback = nullptr); + bool oneBit, bool crop, + const std::function& progressCallback = nullptr); public: - static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut); + static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop = true); // Convert with custom target size (for thumbnails) static bool jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight, const std::function& progressCallback = nullptr);