diff --git a/FreeTypeDemo/CMakeLists.txt b/FreeTypeDemo/CMakeLists.txt new file mode 100644 index 0000000..d6db09e --- /dev/null +++ b/FreeTypeDemo/CMakeLists.txt @@ -0,0 +1,14 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS ../components/ssd1306) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ssd1306) + +# Create a SPIFFS image from the contents of the 'font' directory +# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that +# the generated image should be flashed when the entire project is flashed to +# the target with 'idf.py -p PORT flash +spiffs_create_partition_image(fonts fonts FLASH_IN_PROJECT) diff --git a/FreeTypeDemo/README.md b/FreeTypeDemo/README.md new file mode 100644 index 0000000..72cab3b --- /dev/null +++ b/FreeTypeDemo/README.md @@ -0,0 +1,24 @@ +# FreeTypeDemo for SSD1306 + +FreeType components are published in the ESP Component Registry. +The github page is [here](https://github.com/espressif/idf-extra-components/tree/master/freetype). +This component can convert a True Type Font to a bitmap image. + +___Please note that if you use a proportional font, some fonts may not convert correctly.___ +Monospaced fonts can be converted correctly. +You can find Monospaced fonts [here](https://en.wikipedia.org/wiki/List_of_monospaced_typefaces). + +![FreeTypeDemo](https://github.com/user-attachments/assets/13892a84-8ed8-48b9-8e1e-8e1f7235f8cb) + +# How to use true type font. + +- Download Monospaced fonts from internet. + +- Copy font file to fonts directory. + +- Select font + load_font("/fonts/consola.ttf"); + +- Specify the display position and threshold + render_text(&dev, 0, 16, 128, "FreeType"); + diff --git a/FreeTypeDemo/fonts/FiraMono-Regular.ttf b/FreeTypeDemo/fonts/FiraMono-Regular.ttf new file mode 100644 index 0000000..67bbd42 Binary files /dev/null and b/FreeTypeDemo/fonts/FiraMono-Regular.ttf differ diff --git a/FreeTypeDemo/fonts/consola.ttf b/FreeTypeDemo/fonts/consola.ttf new file mode 100644 index 0000000..e881ca4 Binary files /dev/null and b/FreeTypeDemo/fonts/consola.ttf differ diff --git a/FreeTypeDemo/fonts/monof55.ttf b/FreeTypeDemo/fonts/monof55.ttf new file mode 100644 index 0000000..9aebf80 Binary files /dev/null and b/FreeTypeDemo/fonts/monof55.ttf differ diff --git a/FreeTypeDemo/main/CMakeLists.txt b/FreeTypeDemo/main/CMakeLists.txt new file mode 100644 index 0000000..ee6e475 --- /dev/null +++ b/FreeTypeDemo/main/CMakeLists.txt @@ -0,0 +1,16 @@ +set(COMPONENT_SRCS "main.c") +set(COMPONENT_ADD_INCLUDEDIRS "") + +register_component() +#idf_component_register(SRCS "freetype-example.c" INCLUDE_DIRS "." PRIV_REQUIRES spiffs) + +# Download the example font into a directory "spiffs" in the build directory +#set(URL "https://github.com/espressif/esp-docs/raw/f036a337d8bee5d1a93b2264ecd29255baec4260/src/esp_docs/fonts/DejaVuSans.ttf") +#set(FILE "DejaVuSans.ttf") +set(SPIFFS_DIR "../spiffs") +#message(SPIFFS_DIR="${SPIFFS_DIR}") +#file(MAKE_DIRECTORY ${SPIFFS_DIR}) +#file(DOWNLOAD ${URL} ${SPIFFS_DIR}/${FILE} SHOW_PROGRESS) + +# Create a partition named "fonts" with the example font +#spiffs_create_partition_image(fonts ${SPIFFS_DIR} FLASH_IN_PROJECT) diff --git a/FreeTypeDemo/main/idf_component.yml b/FreeTypeDemo/main/idf_component.yml new file mode 100644 index 0000000..27b21f3 --- /dev/null +++ b/FreeTypeDemo/main/idf_component.yml @@ -0,0 +1,4 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/freetype: + version: "^2.13.0~3" diff --git a/FreeTypeDemo/main/main.c b/FreeTypeDemo/main/main.c new file mode 100644 index 0000000..a45a053 --- /dev/null +++ b/FreeTypeDemo/main/main.c @@ -0,0 +1,222 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +//#include "esp_err.h" +#include "esp_spiffs.h" +#include "ft2build.h" +#include FT_FREETYPE_H + +#include "ssd1306.h" + +static const char *tag = "MAIN"; + +#define BITMAP_WIDTH 20 +#define BITMAP_HEIGHT 16 + +static FT_Library s_library; +static FT_Face s_face; +static uint8_t s_bitmap[BITMAP_HEIGHT][BITMAP_WIDTH]; + +static void load_font(char *font) +{ + FT_Error error = FT_New_Face( s_library, font, 0, &s_face ); + if (error) { + ESP_LOGE(tag, "Error loading font: %d", error); + abort(); + } + ESP_LOGI(tag, "Font [%s] loaded", font); +} + +static void render_text(SSD1306_t * dev, int xpos, int ypos, int threshold, char *text) +{ + /* Configure character size. */ + //const int font_size = 14; + const int font_size = 16; + const int freetype_scale = 64; + FT_Error error = FT_Set_Char_Size(s_face, 0, font_size * freetype_scale, 0, 0 ); + if (error) { + ESP_LOGE(tag, "Error setting font size: %d", error); + abort(); + } + + int num_chars = strlen(text); + + /* current drawing position */ + int x = 0; + int y = 12; + + for (int n = 0; n < num_chars; n++) { + memset(s_bitmap, 0, BITMAP_WIDTH*BITMAP_HEIGHT); + ESP_LOGI(tag, "Rendering char: '%c'", text[n]); + + /* retrieve glyph index from character code */ + FT_UInt glyph_index = FT_Get_Char_Index( s_face, text[n] ); + + /* load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( s_face, glyph_index, FT_LOAD_DEFAULT ); + //error = FT_Load_Glyph( s_face, glyph_index, FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO); + if (error) { + ESP_LOGE(tag, "Error loading glyph: %d", error); + abort(); + } + + /* convert to a bitmap */ + error = FT_Render_Glyph( s_face->glyph, FT_RENDER_MODE_NORMAL ); + if (error) { + ESP_LOGE(tag, "Error rendering glyph: %d", error); + abort(); + } + + /* copy the glyph bitmap into the overall bitmap */ + FT_GlyphSlot slot = s_face->glyph; + ESP_LOGD(tag, "font_size=%d", font_size); + ESP_LOGD(tag, "slot->bitmap.rows=%d", slot->bitmap.rows); + ESP_LOGD(tag, "slot->bitmap.width=%d", slot->bitmap.width); + ESP_LOGD(tag, "slot->bitmap_top=%d", slot->bitmap_top); + ESP_LOGD(tag, "slot->bitmap_left=%d", slot->bitmap_left); + ESP_LOGD(tag, "slot->advance.x/64=%"PRIi32, slot->advance.x/64); + int width = 0; + for (int iy = 0; iy < slot->bitmap.rows; iy++) { + for (int ix = 0; ix < slot->bitmap.width; ix++) { + /* bounds check */ + //int res_x = ix + x; + int res_x = ix + x + slot->bitmap_left; + if (res_x < 0) res_x = 0; + int res_y = y + iy - slot->bitmap_top; + if (res_y < 0) res_y = 0; + ESP_LOGD(tag,"res_x=%d res_y=%d", res_x, res_y); + if (res_x >= BITMAP_WIDTH || res_y >= BITMAP_HEIGHT) { + ESP_LOGW(tag, "bitmap size too large. res_x=%d res_y=%d", res_x, res_y); + continue; + } + ESP_LOGD(tag, "iy=%d ix=%d res_y=%d res_x=%d", iy, ix, res_y, res_x); + s_bitmap[res_y][res_x] = slot->bitmap.buffer[ix + iy * slot->bitmap.width]; + if (res_x > width) width = res_x; + } + } + + uint8_t bitmap[BITMAP_HEIGHT]; + memset(bitmap, 0, BITMAP_HEIGHT); + ESP_LOGD(tag, "width=%d", width); + for (int iy = 0; iy < BITMAP_HEIGHT; iy++) { + for (int ix = 0; ix < width; ix++) { + int val = s_bitmap[iy][ix]; + if (val > 128) { + putchar('#'); + } else if (val > 64) { + putchar('+'); + } else if (val > 32) { + putchar('.'); + } else { + putchar('_'); + } + + uint8_t wk = 0; + if (val > threshold) wk = 1; + wk = wk << ix; + bitmap[iy] = bitmap[iy] | wk; + ESP_LOGD(tag, "val=%d threshold=%d ix=%d iy=%d wk=0x%x bitmap[iy]=0x%x", val, threshold, ix, iy, wk, bitmap[iy]); + + } + putchar('\n'); + } + + //ESP_LOG_BUFFER_HEXDUMP(tag, bitmap, BITMAP_HEIGHT, ESP_LOG_INFO); + for (int i=0;iadvance.x / 64; + } +} + +void app_main(void) +{ + SSD1306_t dev; + //int top, bottom; + //char lineChar[20]; + +#if CONFIG_I2C_INTERFACE + ESP_LOGI(tag, "INTERFACE is i2c"); + ESP_LOGI(tag, "CONFIG_SDA_GPIO=%d",CONFIG_SDA_GPIO); + ESP_LOGI(tag, "CONFIG_SCL_GPIO=%d",CONFIG_SCL_GPIO); + ESP_LOGI(tag, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO); + i2c_master_init(&dev, CONFIG_SDA_GPIO, CONFIG_SCL_GPIO, CONFIG_RESET_GPIO); +#endif // CONFIG_I2C_INTERFACE + +#if CONFIG_SPI_INTERFACE + ESP_LOGI(tag, "INTERFACE is SPI"); + ESP_LOGI(tag, "CONFIG_MOSI_GPIO=%d",CONFIG_MOSI_GPIO); + ESP_LOGI(tag, "CONFIG_SCLK_GPIO=%d",CONFIG_SCLK_GPIO); + ESP_LOGI(tag, "CONFIG_CS_GPIO=%d",CONFIG_CS_GPIO); + ESP_LOGI(tag, "CONFIG_DC_GPIO=%d",CONFIG_DC_GPIO); + ESP_LOGI(tag, "CONFIG_RESET_GPIO=%d",CONFIG_RESET_GPIO); + spi_master_init(&dev, CONFIG_MOSI_GPIO, CONFIG_SCLK_GPIO, CONFIG_CS_GPIO, CONFIG_DC_GPIO, CONFIG_RESET_GPIO); +#endif // CONFIG_SPI_INTERFACE + +#if CONFIG_FLIP + dev._flip = true; + ESP_LOGW(tag, "Flip upside down"); +#endif + +#if CONFIG_SSD1306_128x64 + ESP_LOGI(tag, "Panel is 128x64"); + ssd1306_init(&dev, 128, 64); +#endif // CONFIG_SSD1306_128x64 +#if CONFIG_SSD1306_128x32 + ESP_LOGI(tag, "Panel is 128x32"); + ssd1306_init(&dev, 128, 32); +#endif // CONFIG_SSD1306_128x32 + + // Initialize SPIFFS + esp_vfs_spiffs_conf_t conf = { + .base_path = "/fonts", + .partition_label = "fonts", + .max_files = 1, + }; + ESP_ERROR_CHECK(esp_vfs_spiffs_register(&conf)); + + // Initialize FreeType + FT_Error error = FT_Init_FreeType( &s_library ); + if (error) { + ESP_LOGE(tag, "Error initializing FreeType library: %d", error); + abort(); + } + ESP_LOGI(tag, "FreeType library initialized"); + + ssd1306_clear_screen(&dev, false); + ssd1306_contrast(&dev, 0xff); + + // Bold style + load_font("/fonts/consola.ttf"); + render_text(&dev, 0, 0, 32, "FreeType"); + FT_Done_Face( s_face ); + + // Slim style + load_font("/fonts/consola.ttf"); + render_text(&dev, 0, 16, 128, "FreeType"); + FT_Done_Face( s_face ); + +#if CONFIG_SSD1306_128x64 + //load_font("/fonts/FiraMono-Regular.ttf"); + load_font("/fonts/monof55.ttf"); + render_text(&dev, 0, 32, 32, "FreeType"); + FT_Done_Face( s_face ); + + load_font("/fonts/FiraMono-Regular.ttf"); + render_text(&dev, 0, 48, 64, "FreeType"); + FT_Done_Face( s_face ); +#endif + + FT_Done_FreeType( s_library ); +} diff --git a/FreeTypeDemo/partitions.csv b/FreeTypeDemo/partitions.csv new file mode 100644 index 0000000..a388c80 --- /dev/null +++ b/FreeTypeDemo/partitions.csv @@ -0,0 +1,5 @@ +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +fonts, data, spiffs, , 0xF0000, +#fonts, data, spiffs, , 0x1F0000, diff --git a/FreeTypeDemo/sdkconfig.defaults b/FreeTypeDemo/sdkconfig.defaults new file mode 100644 index 0000000..23109a2 --- /dev/null +++ b/FreeTypeDemo/sdkconfig.defaults @@ -0,0 +1,9 @@ +# +# Partition Table +# +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +#CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000 +#CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y