fix: prevent Serial.printf from blocking when USB disconnected
All checks were successful
CI / build (push) Successful in 2m23s

On ESP32-C3 with USB CDC, Serial.printf() blocks indefinitely when USB
is not connected. This caused device freezes when booted without USB.

Solution: Call Serial.setTxTimeoutMs(0) after Serial.begin() to make
all Serial output non-blocking.

Also added if (Serial) guards to high-traffic logging paths in
EpubReaderActivity as belt-and-suspenders protection.

Includes documentation of the debugging process and Serial call inventory.

Also applies clang-format to fix pre-existing formatting issues.
This commit is contained in:
cottongin
2026-01-28 15:57:31 -05:00
parent f3075002c1
commit 4db384edb6
59 changed files with 989 additions and 621 deletions

View File

@@ -251,8 +251,8 @@ bool Epub::parseCssFiles() {
SdMan.remove(tmpCssPath.c_str());
}
Serial.printf("[%lu] [EBP] Loaded %zu CSS style rules from %zu files (~%zu bytes)\n", millis(), cssParser->ruleCount(),
cssFiles.size(), cssParser->estimateMemoryUsage());
Serial.printf("[%lu] [EBP] Loaded %zu CSS style rules from %zu files (~%zu bytes)\n", millis(),
cssParser->ruleCount(), cssFiles.size(), cssParser->estimateMemoryUsage());
return true;
}
@@ -757,8 +757,8 @@ bool Epub::generateAllCovers(const std::function<void(int)>& progressCallback) c
SdMan.openFileForWrite("EBP", getCoverBmpPath(false), coverBmp)) {
const int targetWidth = 480;
const int targetHeight = (480 * jpegHeight) / jpegWidth;
const bool success =
JpegToBmpConverter::jpegFileToBmpStreamWithSize(coverJpg, coverBmp, targetWidth, targetHeight, makeSubProgress(50, 75));
const bool success = JpegToBmpConverter::jpegFileToBmpStreamWithSize(coverJpg, coverBmp, targetWidth,
targetHeight, makeSubProgress(50, 75));
coverJpg.close();
coverBmp.close();
if (!success) {
@@ -776,8 +776,8 @@ bool Epub::generateAllCovers(const std::function<void(int)>& progressCallback) c
SdMan.openFileForWrite("EBP", getCoverBmpPath(true), coverBmp)) {
const int targetHeight = 800;
const int targetWidth = (800 * jpegWidth) / jpegHeight;
const bool success =
JpegToBmpConverter::jpegFileToBmpStreamWithSize(coverJpg, coverBmp, targetWidth, targetHeight, makeSubProgress(75, 100));
const bool success = JpegToBmpConverter::jpegFileToBmpStreamWithSize(coverJpg, coverBmp, targetWidth,
targetHeight, makeSubProgress(75, 100));
coverJpg.close();
coverBmp.close();
if (!success) {

View File

@@ -57,12 +57,12 @@ class Page {
public:
// the list of block index and line numbers on this page
std::vector<std::shared_ptr<PageElement>> elements;
// Byte offset in source HTML where this page's content begins
// Used for restoring reading position after re-indexing due to font/setting changes
// This is stored in the Section file's LUT, not in Page serialization
uint32_t firstContentOffset = 0;
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const;
bool serialize(FsFile& file) const;
static std::unique_ptr<Page> deserialize(FsFile& file);

View File

@@ -186,7 +186,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
}
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
viewportHeight, hyphenationEnabled);
// LUT entries: { filePosition, contentOffset } pairs
struct LutEntry {
uint32_t filePos;
@@ -202,8 +202,8 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
const uint32_t contentOffset = page->firstContentOffset;
const uint32_t filePos = this->onPageComplete(std::move(page));
lut.push_back({filePos, contentOffset});
}, progressFn,
epub->getCssParser());
},
progressFn, epub->getCssParser());
Hyphenator::setPreferredLanguage(epub->getLanguage());
success = visitor.parseAndBuildPages();
@@ -217,7 +217,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
// Add placeholder to LUT
const uint32_t filePos = this->onPageComplete(std::move(placeholderPage));
lut.push_back({filePos, 0});
// If we still have no pages, the placeholder creation failed
if (pageCount == 0) {
Serial.printf("[%lu] [SCT] Failed to create placeholder page\n", millis());
@@ -262,13 +262,13 @@ std::unique_ptr<Page> Section::loadPageFromSectionFile() {
file.seek(HEADER_SIZE - sizeof(uint32_t));
uint32_t lutOffset;
serialization::readPod(file, lutOffset);
// LUT entries are now 8 bytes each: { filePos (4), contentOffset (4) }
file.seek(lutOffset + LUT_ENTRY_SIZE * currentPage);
uint32_t pagePos;
serialization::readPod(file, pagePos);
// Skip contentOffset for now - we don't need it when just loading the page
file.seek(pagePos);
auto page = Page::deserialize(file);
@@ -300,15 +300,15 @@ int Section::findPageForContentOffset(uint32_t targetOffset) const {
while (left <= right) {
const int mid = left + (right - left) / 2;
// Read content offset for page 'mid'
// LUT entry format: { filePos (4), contentOffset (4) }
f.seek(lutOffset + LUT_ENTRY_SIZE * mid + sizeof(uint32_t)); // Skip filePos
uint32_t midOffset;
serialization::readPod(f, midOffset);
if (midOffset <= targetOffset) {
result = mid; // This page could be the answer
result = mid; // This page could be the answer
left = mid + 1; // Look for a later page that might also qualify
} else {
right = mid - 1; // Look for an earlier page
@@ -322,7 +322,7 @@ int Section::findPageForContentOffset(uint32_t targetOffset) const {
f.seek(lutOffset + LUT_ENTRY_SIZE * result + sizeof(uint32_t));
uint32_t resultOffset;
serialization::readPod(f, resultOffset);
while (result > 0) {
f.seek(lutOffset + LUT_ENTRY_SIZE * (result - 1) + sizeof(uint32_t));
uint32_t prevOffset;

View File

@@ -36,7 +36,7 @@ class Section {
const std::function<void()>& progressSetupFn = nullptr,
const std::function<void(int)>& progressFn = nullptr);
std::unique_ptr<Page> loadPageFromSectionFile();
// Methods for content offset-based position tracking
// Used to restore reading position after re-indexing due to font/setting changes
int findPageForContentOffset(uint32_t targetOffset) const;

View File

@@ -83,7 +83,7 @@ void ChapterHtmlSlimParser::updateEffectiveInlineStyle() {
// Flush the contents of partWordBuffer to currentTextBlock
void ChapterHtmlSlimParser::flushPartWordBuffer() {
if (partWordBufferIndex == 0) return;
// Determine font style using effective styles
EpdFontFamily::Style fontStyle = EpdFontFamily::REGULAR;
if (effectiveBold && effectiveItalic) {
@@ -93,7 +93,7 @@ void ChapterHtmlSlimParser::flushPartWordBuffer() {
} else if (effectiveItalic) {
fontStyle = EpdFontFamily::ITALIC;
}
// Flush the buffer
partWordBuffer[partWordBufferIndex] = '\0';
currentTextBlock->addWord(partWordBuffer, fontStyle, effectiveUnderline);
@@ -290,7 +290,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
} else {
placeholder = "[Image unavailable]";
}
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth);
self->depth += 1;
@@ -478,7 +478,7 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
if (self->skipUntilDepth < self->depth) {
return;
}
// Capture byte offset of this character data for page position tracking
if (self->xmlParser) {
self->lastCharDataOffset = XML_GetCurrentByteIndex(self->xmlParser);
@@ -647,7 +647,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
const size_t totalSize = file.size();
size_t bytesRead = 0;
int lastProgress = -1;
// Initialize offset tracking - first page starts at offset 0
currentPageStartOffset = 0;
lastCharDataOffset = 0;
@@ -739,7 +739,7 @@ void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
currentPage->firstContentOffset = static_cast<uint32_t>(currentPageStartOffset);
}
completePageFn(std::move(currentPage));
// Start new page - offset will be set when first content is added
currentPage.reset(new Page());
currentPageStartOffset = lastCharDataOffset; // Use offset from when content was parsed

View File

@@ -58,11 +58,11 @@ class ChapterHtmlSlimParser {
bool effectiveBold = false;
bool effectiveItalic = false;
bool effectiveUnderline = false;
// Byte offset tracking for position restoration after re-indexing
XML_Parser xmlParser = nullptr; // Store parser for getting current byte index
size_t currentPageStartOffset = 0; // Byte offset when current page was started
size_t lastCharDataOffset = 0; // Byte offset of last character data (captured during parsing)
XML_Parser xmlParser = nullptr; // Store parser for getting current byte index
size_t currentPageStartOffset = 0; // Byte offset when current page was started
size_t lastCharDataOffset = 0; // Byte offset of last character data (captured during parsing)
void updateEffectiveInlineStyle();
void startNewTextBlock(TextBlock::Style style);

View File

@@ -5,13 +5,9 @@
// Global high contrast mode flag
static bool g_highContrastMode = false;
void setHighContrastMode(bool enabled) {
g_highContrastMode = enabled;
}
void setHighContrastMode(bool enabled) { g_highContrastMode = enabled; }
bool isHighContrastMode() {
return g_highContrastMode;
}
bool isHighContrastMode() { return g_highContrastMode; }
// Brightness/Contrast adjustments:
constexpr bool USE_BRIGHTNESS = false; // true: apply brightness/gamma adjustments

View File

@@ -327,7 +327,8 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
// Calculate screen Y position
const int screenYStart = y + static_cast<int>(std::floor(logicalY * scale));
// For upscaling, calculate the end position for this source row
const int screenYEnd = isUpscaling ? (y + static_cast<int>(std::floor((logicalY + 1) * scale))) : (screenYStart + 1);
const int screenYEnd =
isUpscaling ? (y + static_cast<int>(std::floor((logicalY + 1) * scale))) : (screenYStart + 1);
// Draw to all Y positions this source row maps to (for upscaling, this fills gaps)
for (int screenY = screenYStart; screenY < screenYEnd; screenY++) {
@@ -340,7 +341,8 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
// Calculate screen X position
const int screenXStart = x + static_cast<int>(std::floor(srcX * scale));
// For upscaling, calculate the end position for this source pixel
const int screenXEnd = isUpscaling ? (x + static_cast<int>(std::floor((srcX + 1) * scale))) : (screenXStart + 1);
const int screenXEnd =
isUpscaling ? (x + static_cast<int>(std::floor((srcX + 1) * scale))) : (screenXStart + 1);
const uint8_t val = outputRow[bmpX / 4] >> (6 - ((bmpX * 2) % 8)) & 0x3;
@@ -409,7 +411,8 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y,
// Calculate screen Y position
const int screenYStart = y + static_cast<int>(std::floor(logicalY * scale));
// For upscaling, calculate the end position for this source row
const int screenYEnd = isUpscaling ? (y + static_cast<int>(std::floor((logicalY + 1) * scale))) : (screenYStart + 1);
const int screenYEnd =
isUpscaling ? (y + static_cast<int>(std::floor((logicalY + 1) * scale))) : (screenYStart + 1);
// Draw to all Y positions this source row maps to (for upscaling, this fills gaps)
for (int screenY = screenYStart; screenY < screenYEnd; screenY++) {
@@ -420,7 +423,8 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y,
// Calculate screen X position
const int screenXStart = x + static_cast<int>(std::floor(bmpX * scale));
// For upscaling, calculate the end position for this source pixel
const int screenXEnd = isUpscaling ? (x + static_cast<int>(std::floor((bmpX + 1) * scale))) : (screenXStart + 1);
const int screenXEnd =
isUpscaling ? (x + static_cast<int>(std::floor((bmpX + 1) * scale))) : (screenXStart + 1);
// Get 2-bit value (result of readNextRow quantization)
const uint8_t val = outputRow[bmpX / 4] >> (6 - ((bmpX * 2) % 8)) & 0x3;
@@ -998,26 +1002,38 @@ int mapPhysicalToLogicalEdge(int bezelEdge, GfxRenderer::Orientation orientation
return bezelEdge;
case GfxRenderer::LandscapeClockwise:
switch (bezelEdge) {
case 0: return 2; // Physical bottom -> logical left
case 1: return 3; // Physical top -> logical right
case 2: return 1; // Physical left -> logical top
case 3: return 0; // Physical right -> logical bottom
case 0:
return 2; // Physical bottom -> logical left
case 1:
return 3; // Physical top -> logical right
case 2:
return 1; // Physical left -> logical top
case 3:
return 0; // Physical right -> logical bottom
}
break;
case GfxRenderer::PortraitInverted:
switch (bezelEdge) {
case 0: return 1; // Physical bottom -> logical top
case 1: return 0; // Physical top -> logical bottom
case 2: return 3; // Physical left -> logical right
case 3: return 2; // Physical right -> logical left
case 0:
return 1; // Physical bottom -> logical top
case 1:
return 0; // Physical top -> logical bottom
case 2:
return 3; // Physical left -> logical right
case 3:
return 2; // Physical right -> logical left
}
break;
case GfxRenderer::LandscapeCounterClockwise:
switch (bezelEdge) {
case 0: return 3; // Physical bottom -> logical right
case 1: return 2; // Physical top -> logical left
case 2: return 0; // Physical left -> logical bottom
case 3: return 1; // Physical right -> logical top
case 0:
return 3; // Physical bottom -> logical right
case 1:
return 2; // Physical top -> logical left
case 2:
return 0; // Physical left -> logical bottom
case 3:
return 1; // Physical right -> logical top
}
break;
}
@@ -1074,23 +1090,34 @@ void GfxRenderer::getOrientedViewableTRBL(int* outTop, int* outRight, int* outBo
*outLeft = getViewableMarginLeft();
break;
case LandscapeClockwise:
*outTop = BASE_VIEWABLE_MARGIN_LEFT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 1 ? bezelCompensation : 0);
*outRight = BASE_VIEWABLE_MARGIN_TOP + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 3 ? bezelCompensation : 0);
*outBottom = BASE_VIEWABLE_MARGIN_RIGHT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 0 ? bezelCompensation : 0);
*outLeft = BASE_VIEWABLE_MARGIN_BOTTOM + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 2 ? bezelCompensation : 0);
*outTop =
BASE_VIEWABLE_MARGIN_LEFT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 1 ? bezelCompensation : 0);
*outRight =
BASE_VIEWABLE_MARGIN_TOP + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 3 ? bezelCompensation : 0);
*outBottom =
BASE_VIEWABLE_MARGIN_RIGHT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 0 ? bezelCompensation : 0);
*outLeft =
BASE_VIEWABLE_MARGIN_BOTTOM + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 2 ? bezelCompensation : 0);
break;
case PortraitInverted:
*outTop = BASE_VIEWABLE_MARGIN_BOTTOM + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 1 ? bezelCompensation : 0);
*outRight = BASE_VIEWABLE_MARGIN_LEFT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 3 ? bezelCompensation : 0);
*outBottom = BASE_VIEWABLE_MARGIN_TOP + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 0 ? bezelCompensation : 0);
*outLeft = BASE_VIEWABLE_MARGIN_RIGHT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 2 ? bezelCompensation : 0);
*outTop =
BASE_VIEWABLE_MARGIN_BOTTOM + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 1 ? bezelCompensation : 0);
*outRight =
BASE_VIEWABLE_MARGIN_LEFT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 3 ? bezelCompensation : 0);
*outBottom =
BASE_VIEWABLE_MARGIN_TOP + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 0 ? bezelCompensation : 0);
*outLeft =
BASE_VIEWABLE_MARGIN_RIGHT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 2 ? bezelCompensation : 0);
break;
case LandscapeCounterClockwise:
*outTop = BASE_VIEWABLE_MARGIN_RIGHT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 1 ? bezelCompensation : 0);
*outRight = BASE_VIEWABLE_MARGIN_BOTTOM + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 3 ? bezelCompensation : 0);
*outBottom = BASE_VIEWABLE_MARGIN_LEFT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 0 ? bezelCompensation : 0);
*outLeft = BASE_VIEWABLE_MARGIN_TOP + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 2 ? bezelCompensation : 0);
*outTop =
BASE_VIEWABLE_MARGIN_RIGHT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 1 ? bezelCompensation : 0);
*outRight =
BASE_VIEWABLE_MARGIN_BOTTOM + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 3 ? bezelCompensation : 0);
*outBottom =
BASE_VIEWABLE_MARGIN_LEFT + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 0 ? bezelCompensation : 0);
*outLeft =
BASE_VIEWABLE_MARGIN_TOP + (mapPhysicalToLogicalEdge(bezelEdge, orientation) == 2 ? bezelCompensation : 0);
break;
}
}

View File

@@ -94,10 +94,10 @@ class GfxRenderer {
// Handles current render mode (BW, GRAYSCALE_MSB, GRAYSCALE_LSB)
void fillRectGray(int x, int y, int width, int height, uint8_t grayLevel) const;
void drawImage(const uint8_t bitmap[], int x, int y, int width, int height) const;
void drawImageRotated(const uint8_t bitmap[], int x, int y, int width, int height,
ImageRotation rotation, bool invert = false) const;
void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0,
float cropY = 0, bool invert = false) const;
void drawImageRotated(const uint8_t bitmap[], int x, int y, int width, int height, ImageRotation rotation,
bool invert = false) const;
void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0, float cropY = 0,
bool invert = false) const;
void drawBitmap1Bit(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, bool invert = false) const;
void fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state = true) const;

View File

@@ -150,8 +150,7 @@ std::string DictHtmlParser::extractTagName(const std::string& html, size_t start
std::string tagName = html.substr(nameStart, pos - nameStart);
// Convert to lowercase
std::transform(tagName.begin(), tagName.end(), tagName.begin(),
[](unsigned char c) { return std::tolower(c); });
std::transform(tagName.begin(), tagName.end(), tagName.begin(), [](unsigned char c) { return std::tolower(c); });
return tagName;
}
@@ -160,17 +159,11 @@ bool DictHtmlParser::isBlockTag(const std::string& tagName) {
tagName == "ol" || tagName == "ul" || tagName == "dt" || tagName == "dd" || tagName == "html";
}
bool DictHtmlParser::isBoldTag(const std::string& tagName) {
return tagName == "b" || tagName == "strong";
}
bool DictHtmlParser::isBoldTag(const std::string& tagName) { return tagName == "b" || tagName == "strong"; }
bool DictHtmlParser::isItalicTag(const std::string& tagName) {
return tagName == "i" || tagName == "em";
}
bool DictHtmlParser::isItalicTag(const std::string& tagName) { return tagName == "i" || tagName == "em"; }
bool DictHtmlParser::isUnderlineTag(const std::string& tagName) {
return tagName == "u" || tagName == "ins";
}
bool DictHtmlParser::isUnderlineTag(const std::string& tagName) { return tagName == "u" || tagName == "ins"; }
bool DictHtmlParser::isSuperscriptTag(const std::string& tagName) { return tagName == "sup"; }

View File

@@ -10,7 +10,7 @@ class GfxRenderer;
/**
* DictHtmlParser parses HTML dictionary definitions into ParsedText.
*
*
* Supports:
* - Bold: <b>, <strong>
* - Italic: <i>, <em>
@@ -25,7 +25,7 @@ class DictHtmlParser {
/**
* Parse HTML definition and populate ParsedText with styled words.
* Each paragraph/block creates a separate ParsedText via the callback.
*
*
* @param html The HTML definition text
* @param fontId Font ID for text width calculations
* @param renderer Reference to renderer for layout

View File

@@ -588,8 +588,12 @@ static std::string decodeHtmlEntity(const std::string& html, size_t& i) {
const char* replacement;
};
static const EntityMapping entities[] = {
{"&nbsp;", " "}, {"&lt;", "<"}, {"&gt;", ">"},
{"&amp;", "&"}, {"&quot;", "\""}, {"&apos;", "'"},
{"&nbsp;", " "},
{"&lt;", "<"},
{"&gt;", ">"},
{"&amp;", "&"},
{"&quot;", "\""},
{"&apos;", "'"},
{"&mdash;", "\xe2\x80\x94"}, // —
{"&ndash;", "\xe2\x80\x93"}, //
{"&hellip;", "\xe2\x80\xa6"}, // …
@@ -688,8 +692,8 @@ std::string StarDict::stripHtml(const std::string& html) {
// Extract tag name
size_t tagEnd = tagStart;
while (tagEnd < html.length() && !std::isspace(static_cast<unsigned char>(html[tagEnd])) &&
html[tagEnd] != '>' && html[tagEnd] != '/') {
while (tagEnd < html.length() && !std::isspace(static_cast<unsigned char>(html[tagEnd])) && html[tagEnd] != '>' &&
html[tagEnd] != '/') {
tagEnd++;
}

View File

@@ -32,7 +32,7 @@ class StarDict {
struct DictzipInfo {
uint32_t chunkLength = 0; // Uncompressed chunk size (usually 58315)
uint16_t chunkCount = 0;
uint32_t headerSize = 0; // Total header size to skip
uint32_t headerSize = 0; // Total header size to skip
uint16_t* chunkSizes = nullptr; // Array of compressed chunk sizes
bool loaded = false;
};

View File

@@ -205,8 +205,8 @@ bool Txt::generateThumbBmp() const {
}
constexpr int THUMB_TARGET_WIDTH = 240;
constexpr int THUMB_TARGET_HEIGHT = 400;
const bool success =
JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(coverJpg, thumbBmp, THUMB_TARGET_WIDTH, THUMB_TARGET_HEIGHT);
const bool success = JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(coverJpg, thumbBmp, THUMB_TARGET_WIDTH,
THUMB_TARGET_HEIGHT);
coverJpg.close();
thumbBmp.close();
@@ -276,8 +276,8 @@ bool Txt::generateMicroThumbBmp() const {
}
constexpr int MICRO_THUMB_TARGET_WIDTH = 45;
constexpr int MICRO_THUMB_TARGET_HEIGHT = 60;
const bool success = JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(coverJpg, microThumbBmp,
MICRO_THUMB_TARGET_WIDTH, MICRO_THUMB_TARGET_HEIGHT);
const bool success = JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(
coverJpg, microThumbBmp, MICRO_THUMB_TARGET_WIDTH, MICRO_THUMB_TARGET_HEIGHT);
coverJpg.close();
microThumbBmp.close();