Merge branch 'master' into toc-parsing-fixes

This commit is contained in:
Arthur Tazhitdinov 2025-12-15 19:44:26 +03:00
commit 496c20cba0
6 changed files with 44 additions and 18 deletions

View File

@ -69,6 +69,9 @@ bool Epub::parseContentOpf(const std::string& contentOpfFilePath) {
// Grab data from opfParser into epub // Grab data from opfParser into epub
title = opfParser.title; title = opfParser.title;
if (!opfParser.coverItemId.empty() && opfParser.items.count(opfParser.coverItemId) > 0) {
coverImageItem = opfParser.items.at(opfParser.coverItemId);
}
constexpr const char* NCX_MEDIA_TYPE = "application/x-dtbncx+xml"; constexpr const char* NCX_MEDIA_TYPE = "application/x-dtbncx+xml";
for (const auto& [id, manifestItem] : opfParser.items) { for (const auto& [id, manifestItem] : opfParser.items) {

View File

@ -90,9 +90,23 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
return; return;
} }
// TODO: Support book cover if (self->state == IN_METADATA && (strcmp(name, "meta") == 0 || strcmp(name, "opf:meta") == 0)) {
// if (self->state == IN_METADATA && (strcmp(name, "meta") == 0 || strcmp(name, "opf:meta") == 0)) { bool isCover = false;
// } std::string coverItemId;
for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "name") == 0 && strcmp(atts[i + 1], "cover") == 0) {
isCover = true;
} else if (strcmp(atts[i], "content") == 0) {
coverItemId = atts[i + 1];
}
}
if (isCover) {
self->coverItemId = coverItemId;
}
return;
}
if (self->state == IN_MANIFEST && (strcmp(name, "item") == 0 || strcmp(name, "opf:item") == 0)) { if (self->state == IN_MANIFEST && (strcmp(name, "item") == 0 || strcmp(name, "opf:item") == 0)) {
std::string itemId; std::string itemId;

View File

@ -35,6 +35,7 @@ class ContentOpfParser final : public Print {
std::string title; std::string title;
std::string tocNcxPath; std::string tocNcxPath;
std::string coverItemId;
std::map<std::string, ManifestItem> items; std::map<std::string, ManifestItem> items;
std::vector<std::string> spineRefs; std::vector<std::string> spineRefs;

View File

@ -207,14 +207,20 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp,
if (is2Bit) { if (is2Bit) {
const uint8_t byte = bitmap[pixelPosition / 4]; const uint8_t byte = bitmap[pixelPosition / 4];
const uint8_t bit_index = (3 - pixelPosition % 4) * 2; const uint8_t bit_index = (3 - pixelPosition % 4) * 2;
// the direct bit from the font is 0 -> white, 1 -> light gray, 2 -> dark gray, 3 -> black
// we swap this to better match the way images and screen think about colors:
// 0 -> black, 1 -> dark grey, 2 -> light grey, 3 -> white
const uint8_t bmpVal = 3 - (byte >> bit_index) & 0x3;
const uint8_t val = (byte >> bit_index) & 0x3; if (renderMode == BW && bmpVal < 3) {
if (fontRenderMode == BW && val > 0) { // Black (also paints over the grays in BW mode)
drawPixel(screenX, screenY, pixelState); drawPixel(screenX, screenY, pixelState);
} else if (fontRenderMode == GRAYSCALE_MSB && val == 1) { } else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
// TODO: Not sure how this anti-aliasing goes on black backgrounds // Light gray (also mark the MSB if it's going to be a dark gray too)
// We have to flag pixels in reverse for the gray buffers, as 0 leave alone, 1 update
drawPixel(screenX, screenY, false); drawPixel(screenX, screenY, false);
} else if (fontRenderMode == GRAYSCALE_LSB && val == 2) { } else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) {
// Dark gray
drawPixel(screenX, screenY, false); drawPixel(screenX, screenY, false);
} }
} else { } else {

View File

@ -7,17 +7,17 @@
class GfxRenderer { class GfxRenderer {
public: public:
enum FontRenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB }; enum RenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB };
private: private:
EInkDisplay& einkDisplay; EInkDisplay& einkDisplay;
FontRenderMode fontRenderMode; RenderMode renderMode;
std::map<int, EpdFontFamily> fontMap; std::map<int, EpdFontFamily> fontMap;
void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState, void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState,
EpdFontStyle style) const; EpdFontStyle style) const;
public: public:
explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), fontRenderMode(BW) {} explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), renderMode(BW) {}
~GfxRenderer() = default; ~GfxRenderer() = default;
// Setup // Setup
@ -41,15 +41,17 @@ class GfxRenderer {
int getTextWidth(int fontId, const char* text, EpdFontStyle style = REGULAR) const; int getTextWidth(int fontId, const char* text, EpdFontStyle style = REGULAR) const;
void drawCenteredText(int fontId, int y, const char* text, bool black = true, EpdFontStyle style = REGULAR) const; void drawCenteredText(int fontId, int y, const char* text, bool black = true, EpdFontStyle style = REGULAR) const;
void drawText(int fontId, int x, int y, const char* text, bool black = true, EpdFontStyle style = REGULAR) const; void drawText(int fontId, int x, int y, const char* text, bool black = true, EpdFontStyle style = REGULAR) const;
void setFontRenderMode(const FontRenderMode mode) { this->fontRenderMode = mode; }
int getSpaceWidth(int fontId) const; int getSpaceWidth(int fontId) const;
int getLineHeight(int fontId) const; int getLineHeight(int fontId) const;
// Grayscale functions
void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
void copyGrayscaleLsbBuffers() const;
void copyGrayscaleMsbBuffers() const;
void displayGrayBuffer() const;
// Low level functions // Low level functions
uint8_t* getFrameBuffer() const; uint8_t* getFrameBuffer() const;
void swapBuffers() const; void swapBuffers() const;
void grayscaleRevert() const; void grayscaleRevert() const;
void copyGrayscaleLsbBuffers() const;
void copyGrayscaleMsbBuffers() const;
void displayGrayBuffer() const;
}; };

View File

@ -301,19 +301,19 @@ void EpubReaderScreen::renderContents(std::unique_ptr<Page> page) {
// TODO: Only do this if font supports it // TODO: Only do this if font supports it
{ {
renderer.clearScreen(0x00); renderer.clearScreen(0x00);
renderer.setFontRenderMode(GfxRenderer::GRAYSCALE_LSB); renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
page->render(renderer, READER_FONT_ID); page->render(renderer, READER_FONT_ID);
renderer.copyGrayscaleLsbBuffers(); renderer.copyGrayscaleLsbBuffers();
// Render and copy to MSB buffer // Render and copy to MSB buffer
renderer.clearScreen(0x00); renderer.clearScreen(0x00);
renderer.setFontRenderMode(GfxRenderer::GRAYSCALE_MSB); renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
page->render(renderer, READER_FONT_ID); page->render(renderer, READER_FONT_ID);
renderer.copyGrayscaleMsbBuffers(); renderer.copyGrayscaleMsbBuffers();
// display grayscale part // display grayscale part
renderer.displayGrayBuffer(); renderer.displayGrayBuffer();
renderer.setFontRenderMode(GfxRenderer::BW); renderer.setRenderMode(GfxRenderer::BW);
} }
} }