A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: User setting for image display (#1291)

## Summary

**What is the goal of this PR?** Add a user setting to decide image
support: display, show placeholder instead, supress fully

Fixes #1289

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**< NO >**_

authored by

jpirnay and committed by
GitHub
ce0b439a 019587bb

+48 -17
+14 -9
lib/Epub/Epub/Section.cpp
··· 10 10 #include "parsers/ChapterHtmlSlimParser.h" 11 11 12 12 namespace { 13 - constexpr uint8_t SECTION_FILE_VERSION = 16; 13 + constexpr uint8_t SECTION_FILE_VERSION = 17; 14 14 constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(uint8_t) + 15 15 sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(bool) + sizeof(bool) + 16 - sizeof(uint32_t); 16 + sizeof(uint8_t) + sizeof(uint32_t); 17 17 } // namespace 18 18 19 19 uint32_t Section::onPageComplete(std::unique_ptr<Page> page) { ··· 36 36 void Section::writeSectionFileHeader(const int fontId, const float lineCompression, const bool extraParagraphSpacing, 37 37 const uint8_t paragraphAlignment, const uint16_t viewportWidth, 38 38 const uint16_t viewportHeight, const bool hyphenationEnabled, 39 - const bool embeddedStyle) { 39 + const bool embeddedStyle, const uint8_t imageRendering) { 40 40 if (!file) { 41 41 LOG_DBG("SCT", "File not open for writing header"); 42 42 return; ··· 44 44 static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) + 45 45 sizeof(extraParagraphSpacing) + sizeof(paragraphAlignment) + sizeof(viewportWidth) + 46 46 sizeof(viewportHeight) + sizeof(pageCount) + sizeof(hyphenationEnabled) + 47 - sizeof(embeddedStyle) + sizeof(uint32_t), 47 + sizeof(embeddedStyle) + sizeof(imageRendering) + sizeof(uint32_t), 48 48 "Header size mismatch"); 49 49 serialization::writePod(file, SECTION_FILE_VERSION); 50 50 serialization::writePod(file, fontId); ··· 55 55 serialization::writePod(file, viewportHeight); 56 56 serialization::writePod(file, hyphenationEnabled); 57 57 serialization::writePod(file, embeddedStyle); 58 + serialization::writePod(file, imageRendering); 58 59 serialization::writePod(file, pageCount); // Placeholder for page count (will be initially 0 when written) 59 60 serialization::writePod(file, static_cast<uint32_t>(0)); // Placeholder for LUT offset 60 61 } 61 62 62 63 bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing, 63 64 const uint8_t paragraphAlignment, const uint16_t viewportWidth, 64 - const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle) { 65 + const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle, 66 + const uint8_t imageRendering) { 65 67 if (!Storage.openFileForRead("SCT", filePath, file)) { 66 68 return false; 67 69 } ··· 84 86 uint8_t fileParagraphAlignment; 85 87 bool fileHyphenationEnabled; 86 88 bool fileEmbeddedStyle; 89 + uint8_t fileImageRendering; 87 90 serialization::readPod(file, fileFontId); 88 91 serialization::readPod(file, fileLineCompression); 89 92 serialization::readPod(file, fileExtraParagraphSpacing); ··· 92 95 serialization::readPod(file, fileViewportHeight); 93 96 serialization::readPod(file, fileHyphenationEnabled); 94 97 serialization::readPod(file, fileEmbeddedStyle); 98 + serialization::readPod(file, fileImageRendering); 95 99 96 100 if (fontId != fileFontId || lineCompression != fileLineCompression || 97 101 extraParagraphSpacing != fileExtraParagraphSpacing || paragraphAlignment != fileParagraphAlignment || 98 102 viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight || 99 - hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle) { 103 + hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle || 104 + imageRendering != fileImageRendering) { 100 105 file.close(); 101 106 LOG_ERR("SCT", "Deserialization failed: Parameters do not match"); 102 107 clearCache(); ··· 129 134 bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing, 130 135 const uint8_t paragraphAlignment, const uint16_t viewportWidth, 131 136 const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle, 132 - const std::function<void()>& popupFn) { 137 + const uint8_t imageRendering, const std::function<void()>& popupFn) { 133 138 const auto localPath = epub->getSpineItem(spineIndex).href; 134 139 const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html"; 135 140 ··· 179 184 return false; 180 185 } 181 186 writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth, 182 - viewportHeight, hyphenationEnabled, embeddedStyle); 187 + viewportHeight, hyphenationEnabled, embeddedStyle, imageRendering); 183 188 std::vector<uint32_t> lut = {}; 184 189 185 190 // Derive the content base directory and image cache path prefix for the parser ··· 201 206 epub, tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth, 202 207 viewportHeight, hyphenationEnabled, 203 208 [this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); }, 204 - embeddedStyle, contentBase, imageBasePath, popupFn, cssParser); 209 + embeddedStyle, contentBase, imageBasePath, imageRendering, popupFn, cssParser); 205 210 Hyphenator::setPreferredLanguage(epub->getLanguage()); 206 211 success = visitor.parseAndBuildPages(); 207 212
+4 -3
lib/Epub/Epub/Section.h
··· 16 16 17 17 void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment, 18 18 uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, 19 - bool embeddedStyle); 19 + bool embeddedStyle, uint8_t imageRendering); 20 20 uint32_t onPageComplete(std::unique_ptr<Page> page); 21 21 22 22 public: ··· 30 30 filePath(epub->getCachePath() + "/sections/" + std::to_string(spineIndex) + ".bin") {} 31 31 ~Section() = default; 32 32 bool loadSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment, 33 - uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle); 33 + uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle, 34 + uint8_t imageRendering); 34 35 bool clearCache() const; 35 36 bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment, 36 37 uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled, bool embeddedStyle, 37 - const std::function<void()>& popupFn = nullptr); 38 + uint8_t imageRendering, const std::function<void()>& popupFn = nullptr); 38 39 std::unique_ptr<Page> loadPageFromSectionFile(); 39 40 };
+8 -1
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp
··· 243 243 } 244 244 } 245 245 246 - if (!src.empty()) { 246 + // imageRendering: 0=display, 1=placeholder (alt text only), 2=suppress entirely 247 + if (self->imageRendering == 2) { 248 + self->skipUntilDepth = self->depth; 249 + self->depth += 1; 250 + return; 251 + } 252 + 253 + if (!src.empty() && self->imageRendering != 1) { 247 254 LOG_DBG("EHP", "Found image: src=%s", src.c_str()); 248 255 249 256 {
+4 -2
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
··· 48 48 bool hyphenationEnabled; 49 49 const CssParser* cssParser; 50 50 bool embeddedStyle; 51 + uint8_t imageRendering; 51 52 std::string contentBase; 52 53 std::string imageBasePath; 53 54 int imageCounter = 0; ··· 94 95 const uint16_t viewportHeight, const bool hyphenationEnabled, 95 96 const std::function<void(std::unique_ptr<Page>)>& completePageFn, 96 97 const bool embeddedStyle, const std::string& contentBase, 97 - const std::string& imageBasePath, const std::function<void()>& popupFn = nullptr, 98 - const CssParser* cssParser = nullptr) 98 + const std::string& imageBasePath, const uint8_t imageRendering = 0, 99 + const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr) 99 100 100 101 : epub(epub), 101 102 filepath(filepath), ··· 111 112 popupFn(popupFn), 112 113 cssParser(cssParser), 113 114 embeddedStyle(embeddedStyle), 115 + imageRendering(imageRendering), 114 116 contentBase(contentBase), 115 117 imageBasePath(imageBasePath) {} 116 118
+4
lib/I18n/translations/english.yaml
··· 92 92 STR_HIDE_BATTERY: "Hide Battery %" 93 93 STR_EXTRA_SPACING: "Extra Paragraph Spacing" 94 94 STR_TEXT_AA: "Text Anti-Aliasing" 95 + STR_IMAGES: "Images" 96 + STR_IMAGES_DISPLAY: "Display" 97 + STR_IMAGES_PLACEHOLDER: "Placeholder" 98 + STR_IMAGES_SUPPRESS: "Suppress" 95 99 STR_SHORT_PWR_BTN: "Short Power Button Click" 96 100 STR_ORIENTATION: "Reading Orientation" 97 101 STR_FRONT_BTN_LAYOUT: "Front Button Layout"
+7
src/CrossPointSettings.h
··· 134 134 // UI Theme 135 135 enum UI_THEME { CLASSIC = 0, LYRA = 1, LYRA_3_COVERS = 2 }; 136 136 137 + // Image rendering in EPUB reader 138 + enum IMAGE_RENDERING { IMAGES_DISPLAY = 0, IMAGES_PLACEHOLDER = 1, IMAGES_SUPPRESS = 2, IMAGE_RENDERING_COUNT }; 139 + 137 140 // Sleep screen settings 138 141 uint8_t sleepScreen = DARK; 139 142 // Sleep screen cover mode settings ··· 192 195 uint8_t fadingFix = 0; 193 196 // Use book's embedded CSS styles for EPUB rendering (1 = enabled, 0 = disabled) 194 197 uint8_t embeddedStyle = 1; 198 + // Show hidden files/directories (starting with '.') in the file browser (0 = hidden, 1 = show) 199 + uint8_t showHiddenFiles = 0; 200 + // Image rendering mode in EPUB reader 201 + uint8_t imageRendering = IMAGES_DISPLAY; 195 202 196 203 ~CrossPointSettings() = default; 197 204
+3
src/SettingsList.h
··· 62 62 StrId::STR_CAT_READER), 63 63 SettingInfo::Toggle(StrId::STR_TEXT_AA, &CrossPointSettings::textAntiAliasing, "textAntiAliasing", 64 64 StrId::STR_CAT_READER), 65 + SettingInfo::Enum(StrId::STR_IMAGES, &CrossPointSettings::imageRendering, 66 + {StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS}, 67 + "imageRendering", StrId::STR_CAT_READER), 65 68 // --- Controls --- 66 69 SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout, 67 70 {StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS),
+4 -2
src/activities/reader/EpubReaderActivity.cpp
··· 571 571 572 572 if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(), 573 573 SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth, 574 - viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) { 574 + viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, 575 + SETTINGS.imageRendering)) { 575 576 LOG_DBG("ERS", "Cache not found, building..."); 576 577 577 578 const auto popupFn = [this]() { GUI.drawPopup(renderer, tr(STR_INDEXING)); }; 578 579 579 580 if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(), 580 581 SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth, 581 - viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, popupFn)) { 582 + viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, 583 + SETTINGS.imageRendering, popupFn)) { 582 584 LOG_ERR("ERS", "Failed to persist page data to SD"); 583 585 section.reset(); 584 586 return;