From f343983184d891ce5a780fef3c753bb4b2f4f5d3 Mon Sep 17 00:00:00 2001 From: dejvino Date: Sat, 1 Feb 2020 01:04:11 +0100 Subject: [PATCH] Implemented typesetter to allow exact paging. Improved spacing between chars. --- components/epaper/EPD.c | 7 ++-- components/epaper/EPD.h | 1 + main/Page.h | 1 + main/PagePrinter.cpp | 5 +-- main/PagePrinter.h | 2 -- main/PageSettingsProvider.cpp | 48 +++++++++++++++++++++++++ main/PageSettingsProvider.h | 12 +++++++ main/TextReader.cpp | 2 +- main/Typesetter.cpp | 66 ++++++++++++++++++++++++++++++----- main/Typesetter.h | 8 +++++ main/main.cpp | 20 ++++++++--- 11 files changed, 150 insertions(+), 22 deletions(-) create mode 100644 main/PageSettingsProvider.cpp create mode 100644 main/PageSettingsProvider.h diff --git a/components/epaper/EPD.c b/components/epaper/EPD.c index 03f4e9a..2872e4c 100644 --- a/components/epaper/EPD.c +++ b/components/epaper/EPD.c @@ -44,6 +44,7 @@ uint8_t font_transparent; // if not 0 draw fonts transparent uint8_t font_forceFixed; // if not zero force drawing proportional fonts with fixed width uint8_t font_buffered_char; uint8_t font_line_space; // additional spacing between text lines; added to font height +uint8_t font_x_space; // additional spacing between characters in x axis uint8_t text_wrap; // if not 0 wrap long text to the new line, else clip color_t _fg; // current foreground color for fonts color_t _bg; // current background for non transparent fonts @@ -1732,10 +1733,10 @@ int EPD_getStringWidth(char* str) char* tempStrptr = str; while (*tempStrptr != 0) { if (getCharPtr(*tempStrptr++)) { - strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + 1); + strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + font_x_space); } } - strWidth--; + strWidth -= font_x_space; } return strWidth; } @@ -1980,7 +1981,7 @@ void EPD_print(char *st, int x, int y) { // Let's print the character if (cfont.x_size == 0) { // == proportional font - if (font_rotate == 0) EPD_X += printProportionalChar( EPD_X, EPD_Y) + 1; + if (font_rotate == 0) EPD_X += printProportionalChar( EPD_X, EPD_Y) + font_x_space; else { // rotated proportional font offset += rotatePropChar(x, y, offset); diff --git a/components/epaper/EPD.h b/components/epaper/EPD.h index 26c442e..ba82252 100644 --- a/components/epaper/EPD.h +++ b/components/epaper/EPD.h @@ -45,6 +45,7 @@ extern uint8_t font_transparent; // if not 0 draw fonts transparent extern uint8_t font_forceFixed; // if not zero force drawing proportional fonts with fixed width extern uint8_t font_buffered_char; extern uint8_t font_line_space; // additional spacing between text lines; added to font height +extern uint8_t font_x_space; // additional spacing between characters in x axis extern uint8_t text_wrap; // if not 0 wrap long text to the new line, else clip extern color_t _fg; // current foreground color for fonts extern color_t _bg; // current background for non transparent fonts diff --git a/main/Page.h b/main/Page.h index b3cd05b..4993a98 100644 --- a/main/Page.h +++ b/main/Page.h @@ -7,6 +7,7 @@ class Page public: Page(); + size_t start; char* text; size_t len; diff --git a/main/PagePrinter.cpp b/main/PagePrinter.cpp index 0478aa2..a4f0169 100644 --- a/main/PagePrinter.cpp +++ b/main/PagePrinter.cpp @@ -5,7 +5,8 @@ #include "esp_log.h" static const char *TAG = "PagePrinter"; -int font = DEJAVU18_FONT;//DEFAULT_FONT; +//int pageFont = DEFAULT_FONT; +int pageFont = DEJAVU18_FONT; PagePrinter::PagePrinter() {} @@ -19,7 +20,7 @@ void PagePrinter::print(Page* page) if (page->len == 0) { return; } - EPD_setFont(font, NULL); + EPD_setFont(pageFont, NULL); text_wrap = 1; EPD_print(page->text, 0, 0); //EPD_UpdateScreen(); diff --git a/main/PagePrinter.h b/main/PagePrinter.h index 2e54764..2bf85d5 100644 --- a/main/PagePrinter.h +++ b/main/PagePrinter.h @@ -6,6 +6,4 @@ public: PagePrinter(); void print(Page* page); - -private: }; diff --git a/main/PageSettingsProvider.cpp b/main/PageSettingsProvider.cpp new file mode 100644 index 0000000..d314384 --- /dev/null +++ b/main/PageSettingsProvider.cpp @@ -0,0 +1,48 @@ +#include "PageSettingsProvider.h" +#include "EPD.h" +#include "EPDspi.h" // TODO: remove after display config is extracted + +int PageSettingsProvider::getWidth() +{ + return EPD_DISPLAY_WIDTH; +} + +int PageSettingsProvider::getHeight() +{ + return EPD_DISPLAY_HEIGHT; +} + +int PageSettingsProvider::getCharWidth(char c) +{ + char txt[2] = { c, 0x00 }; + return this->getStringWidth(txt); +} + +extern int pageFont; +void activatePageFont() +{ + EPD_setFont(pageFont, NULL); // TODO: hack to get the same font as the printer +} + +int PageSettingsProvider::getStringWidth(char* string) +{ + activatePageFont(); + int ret = EPD_getStringWidth(string); + return ret; +} + +int PageSettingsProvider::getCharSpace() +{ + return font_x_space; +} + +int PageSettingsProvider::getLineHeight() +{ + activatePageFont(); + return EPD_getfontheight(); +} + +int PageSettingsProvider::getLineSpace() +{ + return font_line_space; +} diff --git a/main/PageSettingsProvider.h b/main/PageSettingsProvider.h new file mode 100644 index 0000000..81df3f4 --- /dev/null +++ b/main/PageSettingsProvider.h @@ -0,0 +1,12 @@ +class PageSettingsProvider +{ +public: + int getWidth(); + int getHeight(); + + int getCharWidth(char c); + int getStringWidth(char* string); + int getCharSpace(); + int getLineHeight(); + int getLineSpace(); +}; diff --git a/main/TextReader.cpp b/main/TextReader.cpp index c7e3019..38a4bdc 100644 --- a/main/TextReader.cpp +++ b/main/TextReader.cpp @@ -32,7 +32,7 @@ size_t TextReader::read(long pos, char* text, size_t len) fseek(this->f, pos, SEEK_SET); size_t read = fread(text, 1, len, this->f); if (read > 0) { - ESP_LOGI(TAG, "Read content: %s", text); + //ESP_LOGI(TAG, "Read content: %s", text); } else { ESP_LOGI(TAG, "End of file. Closing."); fclose(this->f); diff --git a/main/Typesetter.cpp b/main/Typesetter.cpp index ff566ee..638e6c1 100644 --- a/main/Typesetter.cpp +++ b/main/Typesetter.cpp @@ -1,27 +1,38 @@ #include #include "Typesetter.h" -Typesetter::Typesetter() -{} +#include "esp_log.h" +static const char *TAG = "Typesetter"; -Page* Typesetter::preparePage(char* text, size_t len) +Typesetter::Typesetter() +{ + this->pageSettingsProvider = new PageSettingsProvider(); // TODO: make it a param +} + +Typesetter::~Typesetter() +{ + delete this->pageSettingsProvider; +} + +static Page* extractPage(char* text, size_t len) { Page* page = new Page; page->text = new char[len+1]; memcpy(page->text, text, len); page->text[len] = 0; page->len = len; + ESP_LOGI(TAG, "Extracted page (%d bytes):\n%s\n----", page->len, page->text); return page; } +Page* Typesetter::preparePage(char* text, size_t len) +{ + return this->preparePageInternal(text, len, 0); +} + Page* Typesetter::preparePreviousPage(char* text, size_t len) { - Page* page = new Page; - page->text = new char[len+1]; - memcpy(page->text, text, len); - page->text[len] = 0; - page->len = len; - return page; + return this->preparePageInternal(text, len, 1); } void Typesetter::destroyPage(Page* page) @@ -32,3 +43,40 @@ void Typesetter::destroyPage(Page* page) delete page->text; delete page; } + +Page* Typesetter::preparePageInternal(char* text, size_t len, int reverse) +{ + int page_width = this->pageSettingsProvider->getWidth(); + int page_height = this->pageSettingsProvider->getHeight(); + int line_height = this->pageSettingsProvider->getLineHeight() + + this->pageSettingsProvider->getLineSpace(); + int line_count = page_height / line_height; + + char buf[len+1]; + memset(buf, 0, len+1); + + int line_start = 0; + ESP_LOGI(TAG, " === Typesetting%s page === ", reverse ? " reversed" : ""); + for (int line = 0; line < line_count && line_start < len; line++) { + int i; + for (i = line_start; i < len; i++) { + buf[i] = text[reverse ? (len - i) : (i)]; + if (buf[i] == '\n') { + break; + } + int line_width = this->pageSettingsProvider->getStringWidth(&buf[line_start]); + if (line_width > page_width) { + // backtrack + buf[i] = 0; + i--; + break; + } + } + ESP_LOGI(TAG, "Line %d | %s", line, &buf[line_start]); + //ESP_LOGI(TAG, "Line %d [%04d:%04d] | %s | %03d / %03d", line, line_start, i, &buf[line_start], + // this->pageSettingsProvider->getStringWidth(&buf[line_start]), page_width); + line_start = i + 1; + } + + return extractPage(text, line_start); +} \ No newline at end of file diff --git a/main/Typesetter.h b/main/Typesetter.h index cb9e3e2..b1d4995 100644 --- a/main/Typesetter.h +++ b/main/Typesetter.h @@ -1,12 +1,20 @@ #include #include "Page.h" +#include "PageSettingsProvider.h" class Typesetter { public: Typesetter(); + ~Typesetter(); Page* preparePage(char* text, size_t len); Page* preparePreviousPage(char* text, size_t len); void destroyPage(Page* page); + +private: + Page* preparePageInternal(char* text, size_t len, int direction); + + PageSettingsProvider* pageSettingsProvider; // TODO: expose so it may be changed }; + diff --git a/main/main.cpp b/main/main.cpp index 7720943..0f4ab82 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -70,11 +70,20 @@ extern "C" void app_main() if (textReader != NULL) { if (pageCurrent == NULL) { size_t read = textReader->read(bookmark, text, sizeof(text)); - pageCurrent = typesetter.preparePage(text, sizeof(text)); + pageCurrent = typesetter.preparePage(text, read); + pageCurrent->start = bookmark; } if (pageLast == NULL) { - size_t read = textReader->read(bookmark - sizeof(text), text, sizeof(text)); - pageLast = typesetter.preparePreviousPage(text, sizeof(text)); + // align with the start? + if (bookmark < sizeof(text)) { + size_t read = textReader->read(0, text, sizeof(text)); + pageLast = typesetter.preparePage(text, read); + pageLast->start = 0; + } else { + size_t read = textReader->read((bookmark - sizeof(text)), text, sizeof(text)); + pageLast = typesetter.preparePreviousPage(text, read); + pageLast->start = bookmark - pageLast->len; + } } } else { typesetter.destroyPage(pageCurrent); @@ -97,7 +106,8 @@ extern "C" void app_main() if (buttons_pressed_plus()) { ESP_LOGI(TAG, "Turn page PLUS."); if (pageCurrent != NULL) { - bookmark += pageCurrent->len; + bookmark = pageCurrent->start + pageCurrent->len; + // TODO: limit bookmark to file size typesetter.destroyPage(pageLast); pageLast = pageCurrent; pageCurrent = NULL; @@ -109,7 +119,7 @@ extern "C" void app_main() if (buttons_pressed_minus()) { ESP_LOGI(TAG, "Turn page MINUS."); if (pageLast != NULL) { - bookmark -= pageLast->len; + bookmark = pageLast->start; typesetter.destroyPage(pageCurrent); pageCurrent = pageLast; pageLast = NULL;