image tweaks
This commit is contained in:
parent
5f4fa3bebe
commit
1a38fd96af
@ -3,11 +3,40 @@
|
|||||||
This document show most common issues and possible solutions while using the device features.
|
This document show most common issues and possible solutions while using the device features.
|
||||||
|
|
||||||
- [Troubleshooting](#troubleshooting)
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [Images Not Displaying in EPUBs](#images-not-displaying-in-epubs)
|
||||||
- [Cannot See the Device on the Network](#cannot-see-the-device-on-the-network)
|
- [Cannot See the Device on the Network](#cannot-see-the-device-on-the-network)
|
||||||
- [Connection Drops or Times Out](#connection-drops-or-times-out)
|
- [Connection Drops or Times Out](#connection-drops-or-times-out)
|
||||||
- [Upload Fails](#upload-fails)
|
- [Upload Fails](#upload-fails)
|
||||||
- [Saved Password Not Working](#saved-password-not-working)
|
- [Saved Password Not Working](#saved-password-not-working)
|
||||||
|
|
||||||
|
### Images Not Displaying in EPUBs
|
||||||
|
|
||||||
|
**Problem:** Some images in EPUB books show as placeholders like "[Image: filename.jpg]" instead of the actual image
|
||||||
|
|
||||||
|
**Possible Causes:**
|
||||||
|
|
||||||
|
1. **Progressive JPEGs are not supported**
|
||||||
|
- The device uses a minimal JPEG decoder optimized for embedded systems
|
||||||
|
- Progressive/multi-scan JPEGs cannot be decoded due to memory constraints
|
||||||
|
- This affects some professionally published EPUBs, especially maps and high-quality photos
|
||||||
|
- **Workaround:** Use Calibre or another EPUB editor to convert progressive JPEGs to baseline JPEGs
|
||||||
|
|
||||||
|
2. **Unsupported image format**
|
||||||
|
- Only JPEG and PNG images are supported
|
||||||
|
- Other formats (GIF, WebP, SVG graphics) will show placeholders
|
||||||
|
|
||||||
|
3. **Image extraction failed**
|
||||||
|
- The image file may be corrupted or the EPUB structure malformed
|
||||||
|
- Try re-downloading the EPUB or converting it with Calibre
|
||||||
|
|
||||||
|
**How to check if an image is progressive JPEG:**
|
||||||
|
|
||||||
|
```python
|
||||||
|
from PIL import Image
|
||||||
|
print(Image.open("image.jpg").info.get('progressive', 0))
|
||||||
|
# Output: 1 = progressive (not supported), 0 = baseline (supported)
|
||||||
|
```
|
||||||
|
|
||||||
### Cannot See the Device on the Network
|
### Cannot See the Device on the Network
|
||||||
|
|
||||||
**Problem:** Browser shows "Cannot connect" or "Site can't be reached"
|
**Problem:** Browser shows "Cannot connect" or "Site can't be reached"
|
||||||
|
|||||||
@ -33,8 +33,10 @@ class ImageToFramebufferDecoder {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Size validation helpers
|
// Size validation helpers
|
||||||
static constexpr int MAX_SOURCE_WIDTH = 2048;
|
// These limits are generous since picojpeg decodes MCU-by-MCU (no full image buffer needed)
|
||||||
static constexpr int MAX_SOURCE_HEIGHT = 1536;
|
// 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);
|
bool validateImageDimensions(int width, int height, const std::string& format);
|
||||||
void warnUnsupportedFeature(const std::string& feature, const std::string& imagePath);
|
void warnUnsupportedFeature(const std::string& feature, const std::string& imagePath);
|
||||||
|
|||||||
@ -99,7 +99,16 @@ bool JpegToFramebufferConverter::getDimensionsStatic(const std::string& imagePat
|
|||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
if (status != 0) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +169,12 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
|||||||
|
|
||||||
int status = pjpeg_decode_init(&imageInfo, jpegReadCallback, &context, 0);
|
int status = pjpeg_decode_init(&imageInfo, jpegReadCallback, &context, 0);
|
||||||
if (status != 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();
|
file.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,8 @@ constexpr int NUM_ITALIC_TAGS = sizeof(ITALIC_TAGS) / sizeof(ITALIC_TAGS[0]);
|
|||||||
const char* UNDERLINE_TAGS[] = {"u", "ins"};
|
const char* UNDERLINE_TAGS[] = {"u", "ins"};
|
||||||
constexpr int NUM_UNDERLINE_TAGS = sizeof(UNDERLINE_TAGS) / sizeof(UNDERLINE_TAGS[0]);
|
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]);
|
constexpr int NUM_IMAGE_TAGS = sizeof(IMAGE_TAGS) / sizeof(IMAGE_TAGS[0]);
|
||||||
|
|
||||||
const char* SKIP_TAGS[] = {"head"};
|
const char* SKIP_TAGS[] = {"head"};
|
||||||
@ -137,7 +138,8 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
std::string alt;
|
std::string alt;
|
||||||
if (atts != nullptr) {
|
if (atts != nullptr) {
|
||||||
for (int i = 0; atts[i]; i += 2) {
|
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];
|
src = atts[i + 1];
|
||||||
} else if (strcmp(atts[i], "alt") == 0) {
|
} else if (strcmp(atts[i], "alt") == 0) {
|
||||||
alt = atts[i + 1];
|
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()) {
|
if (!alt.empty()) {
|
||||||
alt = "[Image: " + alt + "]";
|
placeholder = "[Image: " + alt + "]";
|
||||||
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
|
} else if (!src.empty()) {
|
||||||
self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth);
|
// Extract filename from path for a more informative placeholder
|
||||||
self->depth += 1;
|
size_t lastSlash = src.find_last_of('/');
|
||||||
self->characterData(userData, alt.c_str(), alt.length());
|
std::string filename = (lastSlash != std::string::npos) ? src.substr(lastSlash + 1) : src;
|
||||||
return;
|
placeholder = "[Image: " + filename + "]";
|
||||||
|
} else {
|
||||||
|
placeholder = "[Image unavailable]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// No alt text, skip
|
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
|
||||||
self->skipUntilDepth = self->depth;
|
self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth);
|
||||||
self->depth += 1;
|
self->depth += 1;
|
||||||
|
self->characterData(userData, placeholder.c_str(), placeholder.length());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user