image tweaks
This commit is contained in:
@@ -33,8 +33,10 @@ class ImageToFramebufferDecoder {
|
||||
|
||||
protected:
|
||||
// Size validation helpers
|
||||
static constexpr int MAX_SOURCE_WIDTH = 2048;
|
||||
static constexpr int MAX_SOURCE_HEIGHT = 1536;
|
||||
// These limits are generous since picojpeg decodes MCU-by-MCU (no full image buffer needed)
|
||||
// Memory usage depends on OUTPUT size, not source size
|
||||
static constexpr int MAX_SOURCE_WIDTH = 3072;
|
||||
static constexpr int MAX_SOURCE_HEIGHT = 3072;
|
||||
|
||||
bool validateImageDimensions(int width, int height, const std::string& format);
|
||||
void warnUnsupportedFeature(const std::string& feature, const std::string& imagePath);
|
||||
|
||||
@@ -99,7 +99,16 @@ bool JpegToFramebufferConverter::getDimensionsStatic(const std::string& imagePat
|
||||
file.close();
|
||||
|
||||
if (status != 0) {
|
||||
Serial.printf("[%lu] [JPG] Failed to init JPEG for dimensions: %d\n", millis(), status);
|
||||
// Provide more informative error messages for common JPEG issues
|
||||
// Error codes from picojpeg.h:
|
||||
// 37 = PJPG_NOT_SINGLE_SCAN (multi-scan/progressive JPEG)
|
||||
// 49 = PJPG_UNSUPPORTED_MODE (progressive JPEG)
|
||||
if (status == 37 || status == 49) {
|
||||
Serial.printf("[%lu] [JPG] Progressive/multi-scan JPEG not supported (error %d): %s\n", millis(), status,
|
||||
imagePath.c_str());
|
||||
} else {
|
||||
Serial.printf("[%lu] [JPG] Failed to init JPEG (error %d): %s\n", millis(), status, imagePath.c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -160,7 +169,12 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
||||
|
||||
int status = pjpeg_decode_init(&imageInfo, jpegReadCallback, &context, 0);
|
||||
if (status != 0) {
|
||||
Serial.printf("[%lu] [JPG] picojpeg init failed: %d\n", millis(), status);
|
||||
// Error 37 = PJPG_NOT_SINGLE_SCAN, 49 = PJPG_UNSUPPORTED_MODE (progressive JPEG)
|
||||
if (status == 37 || status == 49) {
|
||||
Serial.printf("[%lu] [JPG] Progressive/multi-scan JPEG not supported (error %d)\n", millis(), status);
|
||||
} else {
|
||||
Serial.printf("[%lu] [JPG] picojpeg init failed (error %d)\n", millis(), status);
|
||||
}
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ constexpr int NUM_ITALIC_TAGS = sizeof(ITALIC_TAGS) / sizeof(ITALIC_TAGS[0]);
|
||||
const char* UNDERLINE_TAGS[] = {"u", "ins"};
|
||||
constexpr int NUM_UNDERLINE_TAGS = sizeof(UNDERLINE_TAGS) / sizeof(UNDERLINE_TAGS[0]);
|
||||
|
||||
const char* IMAGE_TAGS[] = {"img"};
|
||||
// Include "image" for SVG <image> elements (common in Calibre-generated covers)
|
||||
const char* IMAGE_TAGS[] = {"img", "image"};
|
||||
constexpr int NUM_IMAGE_TAGS = sizeof(IMAGE_TAGS) / sizeof(IMAGE_TAGS[0]);
|
||||
|
||||
const char* SKIP_TAGS[] = {"head"};
|
||||
@@ -137,7 +138,8 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
std::string alt;
|
||||
if (atts != nullptr) {
|
||||
for (int i = 0; atts[i]; i += 2) {
|
||||
if (strcmp(atts[i], "src") == 0) {
|
||||
// Standard HTML img uses "src", SVG image uses "xlink:href" or "href"
|
||||
if (strcmp(atts[i], "src") == 0 || strcmp(atts[i], "xlink:href") == 0 || strcmp(atts[i], "href") == 0) {
|
||||
src = atts[i + 1];
|
||||
} else if (strcmp(atts[i], "alt") == 0) {
|
||||
alt = atts[i + 1];
|
||||
@@ -255,19 +257,24 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to alt text if image processing fails
|
||||
// Fallback: show placeholder text when image processing fails
|
||||
// This handles progressive JPEGs, unsupported formats, memory issues, etc.
|
||||
std::string placeholder;
|
||||
if (!alt.empty()) {
|
||||
alt = "[Image: " + alt + "]";
|
||||
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
|
||||
self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth);
|
||||
self->depth += 1;
|
||||
self->characterData(userData, alt.c_str(), alt.length());
|
||||
return;
|
||||
placeholder = "[Image: " + alt + "]";
|
||||
} else if (!src.empty()) {
|
||||
// Extract filename from path for a more informative placeholder
|
||||
size_t lastSlash = src.find_last_of('/');
|
||||
std::string filename = (lastSlash != std::string::npos) ? src.substr(lastSlash + 1) : src;
|
||||
placeholder = "[Image: " + filename + "]";
|
||||
} else {
|
||||
placeholder = "[Image unavailable]";
|
||||
}
|
||||
|
||||
// No alt text, skip
|
||||
self->skipUntilDepth = self->depth;
|
||||
|
||||
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
|
||||
self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth);
|
||||
self->depth += 1;
|
||||
self->characterData(userData, placeholder.c_str(), placeholder.length());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user