diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index f89b11ce..da8bbf57 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -17,6 +17,7 @@ constexpr int NUM_HEADER_TAGS = sizeof(HEADER_TAGS) / sizeof(HEADER_TAGS[0]); // Minimum file size (in bytes) to show indexing popup - smaller chapters don't benefit from it constexpr size_t MIN_SIZE_FOR_POPUP = 10 * 1024; // 10KB +constexpr size_t PARSE_BUFFER_SIZE = 1024; const char* BLOCK_TAGS[] = {"p", "li", "div", "br", "blockquote"}; constexpr int NUM_BLOCK_TAGS = sizeof(BLOCK_TAGS) / sizeof(BLOCK_TAGS[0]); @@ -178,87 +179,89 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* // Resolve the image path relative to the HTML file std::string resolvedPath = FsHelpers::normalisePath(self->contentBase + src); - // Create a unique filename for the cached image - std::string ext; - size_t extPos = resolvedPath.rfind('.'); - if (extPos != std::string::npos) { - ext = resolvedPath.substr(extPos); - } - std::string cachedImagePath = self->imageBasePath + std::to_string(self->imageCounter++) + ext; - - // Extract image to cache file - FsFile cachedImageFile; - bool extractSuccess = false; - if (Storage.openFileForWrite("EHP", cachedImagePath, cachedImageFile)) { - extractSuccess = self->epub->readItemContentsToStream(resolvedPath, cachedImageFile, 4096); - cachedImageFile.flush(); - cachedImageFile.close(); - delay(50); // Give SD card time to sync - } - - if (extractSuccess) { - // Get image dimensions - ImageDimensions dims = {0, 0}; - ImageToFramebufferDecoder* decoder = ImageDecoderFactory::getDecoder(cachedImagePath); - if (decoder && decoder->getDimensions(cachedImagePath, dims)) { - LOG_DBG("EHP", "Image dimensions: %dx%d", dims.width, dims.height); - - // Scale to fit viewport while maintaining aspect ratio - int maxWidth = self->viewportWidth; - int maxHeight = self->viewportHeight; - float scaleX = (dims.width > maxWidth) ? (float)maxWidth / dims.width : 1.0f; - float scaleY = (dims.height > maxHeight) ? (float)maxHeight / dims.height : 1.0f; - float scale = (scaleX < scaleY) ? scaleX : scaleY; - if (scale > 1.0f) scale = 1.0f; - - int displayWidth = (int)(dims.width * scale); - int displayHeight = (int)(dims.height * scale); - - LOG_DBG("EHP", "Display size: %dx%d (scale %.2f)", displayWidth, displayHeight, scale); - - // Create page for image - only break if image won't fit remaining space - if (self->currentPage && !self->currentPage->elements.empty() && - (self->currentPageNextY + displayHeight > self->viewportHeight)) { - self->completePageFn(std::move(self->currentPage)); - self->currentPage.reset(new Page()); - if (!self->currentPage) { - LOG_ERR("EHP", "Failed to create new page"); - return; - } - self->currentPageNextY = 0; - } else if (!self->currentPage) { - self->currentPage.reset(new Page()); - if (!self->currentPage) { - LOG_ERR("EHP", "Failed to create initial page"); - return; - } - self->currentPageNextY = 0; - } - - // Create ImageBlock and add to page - auto imageBlock = std::make_shared(cachedImagePath, displayWidth, displayHeight); - if (!imageBlock) { - LOG_ERR("EHP", "Failed to create ImageBlock"); - return; - } - int xPos = (self->viewportWidth - displayWidth) / 2; - auto pageImage = std::make_shared(imageBlock, xPos, self->currentPageNextY); - if (!pageImage) { - LOG_ERR("EHP", "Failed to create PageImage"); - return; - } - self->currentPage->elements.push_back(pageImage); - self->currentPageNextY += displayHeight; - - self->depth += 1; - return; - } else { - LOG_ERR("EHP", "Failed to get image dimensions"); - Storage.remove(cachedImagePath.c_str()); + if (ImageDecoderFactory::isFormatSupported(resolvedPath)) { + // Create a unique filename for the cached image + std::string ext; + size_t extPos = resolvedPath.rfind('.'); + if (extPos != std::string::npos) { + ext = resolvedPath.substr(extPos); } - } else { - LOG_ERR("EHP", "Failed to extract image"); - } + std::string cachedImagePath = self->imageBasePath + std::to_string(self->imageCounter++) + ext; + + // Extract image to cache file + FsFile cachedImageFile; + bool extractSuccess = false; + if (Storage.openFileForWrite("EHP", cachedImagePath, cachedImageFile)) { + extractSuccess = self->epub->readItemContentsToStream(resolvedPath, cachedImageFile, 4096); + cachedImageFile.flush(); + cachedImageFile.close(); + delay(50); // Give SD card time to sync + } + + if (extractSuccess) { + // Get image dimensions + ImageDimensions dims = {0, 0}; + ImageToFramebufferDecoder* decoder = ImageDecoderFactory::getDecoder(cachedImagePath); + if (decoder && decoder->getDimensions(cachedImagePath, dims)) { + LOG_DBG("EHP", "Image dimensions: %dx%d", dims.width, dims.height); + + // Scale to fit viewport while maintaining aspect ratio + int maxWidth = self->viewportWidth; + int maxHeight = self->viewportHeight; + float scaleX = (dims.width > maxWidth) ? (float)maxWidth / dims.width : 1.0f; + float scaleY = (dims.height > maxHeight) ? (float)maxHeight / dims.height : 1.0f; + float scale = (scaleX < scaleY) ? scaleX : scaleY; + if (scale > 1.0f) scale = 1.0f; + + int displayWidth = (int)(dims.width * scale); + int displayHeight = (int)(dims.height * scale); + + LOG_DBG("EHP", "Display size: %dx%d (scale %.2f)", displayWidth, displayHeight, scale); + + // Create page for image - only break if image won't fit remaining space + if (self->currentPage && !self->currentPage->elements.empty() && + (self->currentPageNextY + displayHeight > self->viewportHeight)) { + self->completePageFn(std::move(self->currentPage)); + self->currentPage.reset(new Page()); + if (!self->currentPage) { + LOG_ERR("EHP", "Failed to create new page"); + return; + } + self->currentPageNextY = 0; + } else if (!self->currentPage) { + self->currentPage.reset(new Page()); + if (!self->currentPage) { + LOG_ERR("EHP", "Failed to create initial page"); + return; + } + self->currentPageNextY = 0; + } + + // Create ImageBlock and add to page + auto imageBlock = std::make_shared(cachedImagePath, displayWidth, displayHeight); + if (!imageBlock) { + LOG_ERR("EHP", "Failed to create ImageBlock"); + return; + } + int xPos = (self->viewportWidth - displayWidth) / 2; + auto pageImage = std::make_shared(imageBlock, xPos, self->currentPageNextY); + if (!pageImage) { + LOG_ERR("EHP", "Failed to create PageImage"); + return; + } + self->currentPage->elements.push_back(pageImage); + self->currentPageNextY += displayHeight; + + self->depth += 1; + return; + } else { + LOG_ERR("EHP", "Failed to get image dimensions"); + Storage.remove(cachedImagePath.c_str()); + } + } else { + LOG_ERR("EHP", "Failed to extract image"); + } + } // isFormatSupported } } @@ -638,8 +641,10 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, characterData); + // Compute the time taken to parse and build pages + const uint32_t chapterStartTime = millis(); do { - void* const buf = XML_GetBuffer(parser, 1024); + void* const buf = XML_GetBuffer(parser, PARSE_BUFFER_SIZE); if (!buf) { LOG_ERR("EHP", "Couldn't allocate memory for buffer"); XML_StopParser(parser, XML_FALSE); // Stop any pending processing @@ -650,7 +655,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { return false; } - const size_t len = file.read(buf, 1024); + const size_t len = file.read(buf, PARSE_BUFFER_SIZE); if (len == 0 && file.available() > 0) { LOG_ERR("EHP", "File read error"); @@ -675,6 +680,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { return false; } } while (!done); + LOG_DBG("EHP", "Time to parse and build pages: %lu ms", millis() - chapterStartTime); XML_StopParser(parser, XML_FALSE); // Stop any pending processing XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks