Skip to content

Commit

Permalink
feat(freetype): add freetype example
Browse files Browse the repository at this point in the history
  • Loading branch information
igrr committed Apr 19, 2024
1 parent db1d7ec commit 4f9b34e
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 0 deletions.
5 changes: 5 additions & 0 deletions freetype/examples/freetype-example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.17)

set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(freetype-example)
51 changes: 51 additions & 0 deletions freetype/examples/freetype-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# FreeType Example

This is a simple example of initializing FreeType library, loading a font from a filesystem, and rendering a line of text.

The font file (DejaVu Sans) is downloaded at compile time and is added into a SPIFFS filesystem image. The filesystem is flashed to the board together with the application. The example loads the font file and renders "FreeType" text into the console as ASCII art.

This example doesn't require any special hardware and can run on any development board.

## Building and running

Run the application as usual for an ESP-IDF project. For example, for ESP32:
```
idf.py set-target esp32
idf.py -p PORT flash monitor
```

## Example output

The example should output the following:

```
I (468) main_task: Calling app_main()
I (538) example: FreeType library initialized
I (1258) example: Font loaded
I (1268) example: Rendering char: 'F'
I (1388) example: Rendering char: 'r'
I (1528) example: Rendering char: 'e'
I (1658) example: Rendering char: 'e'
I (1798) example: Rendering char: 'T'
I (1938) example: Rendering char: 'y'
I (2078) example: Rendering char: 'p'
I (2208) example: Rendering char: 'e'
######. #########
## +#
## ##### +###+ +###+ +# +# ######## +###+
## ##+ +#. .#+ +#. .#+ +# #+ #+##+ .#+ +#. .#+
###### ## #+ +# #+ +# +# ## +# ## +# #+ +#
## ## .####### .####### +# .# ## ## .# .#######
## ## .#. .#. +# #+.#. ## .# .#.
## ## #+ #+ +# +### ## +# #+
## ## ##+ ++ ##+ ++ +# ##+ ##+ .#+ ##+ ++
## ## +#### +#### +# ## ###### +####
## ##
+#. ##
##+ ##
```
13 changes: 13 additions & 0 deletions freetype/examples/freetype-example/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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 "${CMAKE_BINARY_DIR}/spiffs")
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)
150 changes: 150 additions & 0 deletions freetype/examples/freetype-example/main/freetype-example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/


#include <stdlib.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_spiffs.h"
#include "ft2build.h"
#include FT_FREETYPE_H

static const char *TAG = "example";

static void init_filesystem(void);
static void init_freetype(void);
static void load_font(void);
static void render_text(void);

#define BITMAP_WIDTH 80
#define BITMAP_HEIGHT 18

static FT_Library s_library;
static FT_Face s_face;
static uint8_t s_bitmap[BITMAP_HEIGHT][BITMAP_WIDTH];


void app_main(void)
{
init_filesystem();
init_freetype();
load_font();
render_text();
}

static void init_filesystem(void)
{
esp_vfs_spiffs_conf_t conf = {
.base_path = "/fonts",
.partition_label = "fonts",
.max_files = 1,
};

ESP_ERROR_CHECK(esp_vfs_spiffs_register(&conf));
}

static void init_freetype(void)
{
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");
}

static void load_font(void)
{
FT_Error error = FT_New_Face( s_library,
"/fonts/DejaVuSans.ttf",
0,
&s_face );
if (error) {
ESP_LOGE(TAG, "Error loading font: %d", error);
abort();
}

ESP_LOGI(TAG, "Font loaded");

}

static void render_text(void)
{
/* Configure character size. */
const int font_size = 14;
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();
}

const char *text = "FreeType";
int num_chars = strlen(text);

/* current drawing position */
int x = 0;
int y = 12;

for (int n = 0; n < num_chars; n++) {
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 );
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;
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_y = y + iy - slot->bitmap_top;
if (res_x >= BITMAP_WIDTH || res_y >= BITMAP_HEIGHT) {
continue;
}
s_bitmap[res_y][res_x] = slot->bitmap.buffer[ix + iy * slot->bitmap.width];
}
}

/* increment horizontal position */
x += slot->advance.x / 64;
if (x >= BITMAP_WIDTH) {
break;
}
}

/* output the resulting bitmap to console */
for (int iy = 0; iy < BITMAP_HEIGHT; iy++) {
for (int ix = 0; ix < x; ix++) {
int val = s_bitmap[iy][ix];
if (val > 127) {
putchar('#');
} else if (val > 64) {
putchar('+');
} else if (val > 32) {
putchar('.');
} else {
putchar(' ');
}
}
putchar('\n');
}
}
4 changes: 4 additions & 0 deletions freetype/examples/freetype-example/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies:
espressif/freetype:
version: "*"
override_path: "../../.."
4 changes: 4 additions & 0 deletions freetype/examples/freetype-example/partitions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
fonts, data, spiffs, , 0xF0000,
5 changes: 5 additions & 0 deletions freetype/examples/freetype-example/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"

CONFIG_ESP_MAIN_TASK_STACK_SIZE=20000
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y

0 comments on commit 4f9b34e

Please sign in to comment.