diff --git a/docs/libs/freetype.rst b/docs/libs/freetype.rst
index 8adf5c047..46bdf0f5c 100644
--- a/docs/libs/freetype.rst
+++ b/docs/libs/freetype.rst
@@ -4,7 +4,7 @@
FreeType support
================
-Interface to FreeType library to generate font bitmaps run time.
+Interface to FreeType library to generate font bitmap at run time.
Detailed introduction: https://www.freetype.org
@@ -89,14 +89,18 @@ software, and can be set with reference to the following values:
They can be combined.eg:
:cpp:expr:`LV_FREETYPE_FONT_STYLE_BOLD | LV_FREETYPE_FONT_STYLE_ITALIC`.
+The FreeType extension also supports colored bitmap glyphs such as emojis. Note
+that only bitmaps are supported at this time. Colored vector graphics cannot be
+rendered. An example on how to draw a colored bitmap glyph is shown below.
+
Use the :cpp:func:`lv_freetype_font_create` function to create a font. To
delete a font, use :cpp:func:`lv_freetype_font_delete`. For more detailed usage,
please refer to example code.
.. _freetype_example:
-Example
--------
+Examples
+--------
.. include:: ../examples/libs/freetype/index.rst
diff --git a/docs/overview/font.rst b/docs/overview/font.rst
index 807c6f3cb..7e39357ad 100644
--- a/docs/overview/font.rst
+++ b/docs/overview/font.rst
@@ -428,12 +428,9 @@ LVGL's font interface is designed to be very flexible but, even so, you
can add your own font engine in place of LVGL's internal one. For
example, you can use `FreeType `__ to
real-time render glyphs from TTF fonts or use an external flash to store
-the font's bitmap and read them when the library needs them.
+the font's bitmap and read them when the library needs them. FreeType can be used in LVGL as described in :ref:`Freetype `.
-A ready to use FreeType can be found in
-`lv_freetype `__ repository.
-
-To do this, a custom :cpp:type:`lv_font_t` variable needs to be created:
+To add a new font engine, a custom :cpp:type:`lv_font_t` variable needs to be created:
.. code:: c
diff --git a/examples/libs/freetype/NotoColorEmoji-32.subset.ttf b/examples/libs/freetype/NotoColorEmoji-32.subset.ttf
new file mode 100644
index 000000000..581f54a07
Binary files /dev/null and b/examples/libs/freetype/NotoColorEmoji-32.subset.ttf differ
diff --git a/examples/libs/freetype/OFL.txt b/examples/libs/freetype/OFL.txt
new file mode 100644
index 000000000..6c28f45dc
--- /dev/null
+++ b/examples/libs/freetype/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2021 Google Inc. All Rights Reserved.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
\ No newline at end of file
diff --git a/examples/libs/freetype/index.rst b/examples/libs/freetype/index.rst
index bcb5f8a83..dd183074e 100644
--- a/examples/libs/freetype/index.rst
+++ b/examples/libs/freetype/index.rst
@@ -4,3 +4,8 @@ Open a front with FreeType
.. lv_example:: libs/freetype/lv_example_freetype_1
:language: c
+Use a bitmap font to draw Emojis using FreeType
+-----------------------------------------------
+
+.. lv_example:: libs/freetype/lv_example_freetype_2
+ :language: c
\ No newline at end of file
diff --git a/examples/libs/freetype/lv_example_freetype.h b/examples/libs/freetype/lv_example_freetype.h
index cc7da2e18..28a61c17d 100644
--- a/examples/libs/freetype/lv_example_freetype.h
+++ b/examples/libs/freetype/lv_example_freetype.h
@@ -26,6 +26,7 @@ extern "C" {
* GLOBAL PROTOTYPES
**********************/
void lv_example_freetype_1(void);
+void lv_example_freetype_2(void);
/**********************
* MACROS
diff --git a/examples/libs/freetype/lv_example_freetype_2.c b/examples/libs/freetype/lv_example_freetype_2.c
new file mode 100644
index 000000000..3067fb70b
--- /dev/null
+++ b/examples/libs/freetype/lv_example_freetype_2.c
@@ -0,0 +1,62 @@
+#include "../../lv_examples.h"
+#if LV_BUILD_EXAMPLES
+#if LV_USE_FREETYPE
+
+#if LV_FREETYPE_USE_LVGL_PORT
+ #define PATH_PREFIX "A:"
+#else
+ #define PATH_PREFIX "../"
+#endif
+
+/**
+ * Load a font with FreeType
+ */
+void lv_example_freetype_2(void)
+{
+ /*Create a font*/
+ lv_font_t * font = lv_freetype_font_create(PATH_PREFIX "lvgl/examples/libs/freetype/Lato-Regular.ttf",
+ LV_FREETYPE_FONT_RENDER_MODE_BITMAP,
+ 24,
+ LV_FREETYPE_FONT_STYLE_NORMAL);
+
+ /* this font is created from a downscaled NotoColorEmoji to 34x32px
+ * Subset containing only a single emoji was created using fonttools:
+ * Command: fonttools subset NotoColorEmoji.ttf --text=😀 */
+ lv_font_t * font_emoji = lv_freetype_font_create(PATH_PREFIX "lvgl/examples/libs/freetype/NotoColorEmoji-32.subset.ttf",
+ LV_FREETYPE_FONT_RENDER_MODE_BITMAP,
+ 24,
+ LV_FREETYPE_FONT_STYLE_NORMAL);
+
+ if(!font || !font_emoji) {
+ LV_LOG_ERROR("freetype font create failed.");
+ return;
+ }
+
+ font->fallback = font_emoji;
+
+ /*Create style with the new font*/
+ static lv_style_t style;
+ lv_style_init(&style);
+ lv_style_set_text_font(&style, font);
+ lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);
+
+ /*Create a label with the new style*/
+ lv_obj_t * label = lv_label_create(lv_screen_active());
+ lv_obj_add_style(label, &style, 0);
+ lv_label_set_text(label, "Hello world\nI'm a font created with FreeType 😀");
+ lv_obj_center(label);
+}
+#else
+
+void lv_example_freetype_2(void)
+{
+ /*TODO
+ *fallback for online examples*/
+
+ lv_obj_t * label = lv_label_create(lv_screen_active());
+ lv_label_set_text(label, "FreeType is not installed");
+ lv_obj_center(label);
+}
+
+#endif
+#endif
diff --git a/src/draw/sw/lv_draw_sw_letter.c b/src/draw/sw/lv_draw_sw_letter.c
index 3dec220d9..ebc9f7d5c 100644
--- a/src/draw/sw/lv_draw_sw_letter.c
+++ b/src/draw/sw/lv_draw_sw_letter.c
@@ -102,7 +102,6 @@ static void LV_ATTRIBUTE_FAST_MEM draw_letter_cb(lv_draw_unit_t * draw_unit, lv_
}
break;
case LV_FONT_GLYPH_FORMAT_IMAGE: {
-#if LV_USE_IMGFONT
lv_draw_image_dsc_t img_dsc;
lv_draw_image_dsc_init(&img_dsc);
img_dsc.rotation = 0;
@@ -111,7 +110,6 @@ static void LV_ATTRIBUTE_FAST_MEM draw_letter_cb(lv_draw_unit_t * draw_unit, lv_
img_dsc.opa = glyph_draw_dsc->opa;
img_dsc.src = glyph_draw_dsc->glyph_data;
lv_draw_sw_image(draw_unit, &img_dsc, glyph_draw_dsc->letter_coords);
-#endif
}
break;
default:
diff --git a/src/libs/freetype/ftoption.h b/src/libs/freetype/ftoption.h
index 141278b01..1a762bb02 100644
--- a/src/libs/freetype/ftoption.h
+++ b/src/libs/freetype/ftoption.h
@@ -258,7 +258,7 @@ FT_BEGIN_HEADER
* options set by those programs have precedence, overwriting the value
* here with the configured one.
*/
-/* #define FT_CONFIG_OPTION_USE_PNG */
+#define FT_CONFIG_OPTION_USE_PNG
/**************************************************************************
*
diff --git a/src/libs/freetype/lv_freetype.c b/src/libs/freetype/lv_freetype.c
index b1da8f13e..94df703cd 100755
--- a/src/libs/freetype/lv_freetype.c
+++ b/src/libs/freetype/lv_freetype.c
@@ -161,7 +161,18 @@ lv_font_t * lv_freetype_font_create(const char * pathname, lv_freetype_font_rend
freetype_on_font_set_cbs(dsc);
FT_Face face = dsc->cache_node->face;
- FT_Set_Pixel_Sizes(face, 0, size);
+ FT_Error error;
+ if(FT_IS_SCALABLE(face)) {
+ error = FT_Set_Pixel_Sizes(face, 0, size);
+ }
+ else {
+ LV_LOG_WARN("font is not scalable, selecting available size");
+ error = FT_Select_Size(face, 0);
+ }
+ if(error) {
+ FT_ERROR_MSG("FT_Set_Pixel_Sizes", error);
+ return NULL;
+ }
lv_font_t * font = &dsc->font;
font->dsc = dsc;
diff --git a/src/libs/freetype/lv_freetype_glyph.c b/src/libs/freetype/lv_freetype_glyph.c
index 7ed217883..da6c55d43 100644
--- a/src/libs/freetype/lv_freetype_glyph.c
+++ b/src/libs/freetype/lv_freetype_glyph.c
@@ -136,8 +136,24 @@ static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void
FT_Face face = dsc->cache_node->face;
FT_UInt glyph_index = FT_Get_Char_Index(face, data->unicode);
- FT_Set_Pixel_Sizes(face, 0, dsc->size);
- error = FT_Load_Glyph(face, glyph_index, FT_LOAD_COMPUTE_METRICS | FT_LOAD_NO_BITMAP | FT_LOAD_NO_AUTOHINT);
+ if(FT_IS_SCALABLE(face)) {
+ error = FT_Set_Pixel_Sizes(face, 0, dsc->size);
+ }
+ else {
+ error = FT_Select_Size(face, 0);
+ }
+ if(error) {
+ FT_ERROR_MSG("FT_Set_Pixel_Sizes", error);
+ lv_mutex_unlock(&dsc->cache_node->face_lock);
+ return false;
+ }
+
+ if(dsc->render_mode == LV_FREETYPE_FONT_RENDER_MODE_OUTLINE) {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_COMPUTE_METRICS | FT_LOAD_NO_BITMAP | FT_LOAD_NO_AUTOHINT);
+ }
+ else if(dsc->render_mode == LV_FREETYPE_FONT_RENDER_MODE_BITMAP) {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_COMPUTE_METRICS | FT_LOAD_NO_AUTOHINT);
+ }
if(error) {
FT_ERROR_MSG("FT_Load_Glyph", error);
lv_mutex_unlock(&dsc->cache_node->face_lock);
@@ -171,7 +187,10 @@ static bool freetype_glyph_create_cb(lv_freetype_glyph_cache_data_t * data, void
dsc_out->ofs_x = glyph->bitmap_left; /*X offset of the bitmap in [pf]*/
dsc_out->ofs_y = glyph->bitmap_top -
dsc_out->box_h; /*Y offset of the bitmap measured from the as line*/
- dsc_out->format = LV_FONT_GLYPH_FORMAT_A8;
+ if(glyph->format == FT_GLYPH_FORMAT_BITMAP)
+ dsc_out->format = LV_FONT_GLYPH_FORMAT_IMAGE;
+ else
+ dsc_out->format = LV_FONT_GLYPH_FORMAT_A8;
}
dsc_out->is_placeholder = glyph_index == 0;
diff --git a/src/libs/freetype/lv_freetype_image.c b/src/libs/freetype/lv_freetype_image.c
index ab7dad292..7073ae4c7 100755
--- a/src/libs/freetype/lv_freetype_image.c
+++ b/src/libs/freetype/lv_freetype_image.c
@@ -127,8 +127,19 @@ static bool freetype_image_create_cb(lv_freetype_image_cache_data_t * data, void
lv_mutex_lock(&dsc->cache_node->face_lock);
FT_Face face = dsc->cache_node->face;
- FT_Set_Pixel_Sizes(face, 0, dsc->size);
- error = FT_Load_Glyph(face, data->glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_AUTOHINT);
+ if(FT_IS_SCALABLE(face)) {
+ error = FT_Set_Pixel_Sizes(face, 0, dsc->size);
+ }
+ else {
+ error = FT_Select_Size(face, 0);
+ }
+ if(error) {
+ FT_ERROR_MSG("FT_Set_Pixel_Sizes", error);
+ lv_mutex_unlock(&dsc->cache_node->face_lock);
+ return false;
+ }
+ error = FT_Load_Glyph(face, data->glyph_index,
+ FT_LOAD_COLOR | FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_AUTOHINT);
if(error) {
FT_ERROR_MSG("FT_Load_Glyph", error);
lv_mutex_unlock(&dsc->cache_node->face_lock);
@@ -154,12 +165,20 @@ static bool freetype_image_create_cb(lv_freetype_image_cache_data_t * data, void
uint16_t box_h = glyph_bitmap->bitmap.rows; /*Height of the bitmap in [px]*/
uint16_t box_w = glyph_bitmap->bitmap.width; /*Width of the bitmap in [px]*/
- uint32_t stride = lv_draw_buf_width_to_stride(box_w, LV_COLOR_FORMAT_A8);
- data->draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, box_w, box_h, LV_COLOR_FORMAT_A8, stride);
+ lv_color_format_t col_format;
+ if(glyph_bitmap->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
+ col_format = LV_COLOR_FORMAT_ARGB8888;
+ }
+ else {
+ col_format = LV_COLOR_FORMAT_A8;
+ }
+ uint32_t pitch = glyph_bitmap->bitmap.pitch;
+ uint32_t stride = lv_draw_buf_width_to_stride(box_w, col_format);
+ data->draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, box_w, box_h, col_format, stride);
for(int y = 0; y < box_h; ++y) {
- lv_memcpy((uint8_t *)(data->draw_buf->data) + y * stride, glyph_bitmap->bitmap.buffer + y * box_w,
- box_w);
+ lv_memcpy((uint8_t *)(data->draw_buf->data) + y * stride, glyph_bitmap->bitmap.buffer + y * pitch,
+ pitch);
}
FT_Done_Glyph(glyph);
diff --git a/tests/ref_imgs/libs/freetype_1.lp32.png b/tests/ref_imgs/libs/freetype_1.lp32.png
index 655380c10..6b01f4b1a 100644
Binary files a/tests/ref_imgs/libs/freetype_1.lp32.png and b/tests/ref_imgs/libs/freetype_1.lp32.png differ
diff --git a/tests/ref_imgs/libs/freetype_1.lp64.png b/tests/ref_imgs/libs/freetype_1.lp64.png
index 655380c10..6b01f4b1a 100644
Binary files a/tests/ref_imgs/libs/freetype_1.lp64.png and b/tests/ref_imgs/libs/freetype_1.lp64.png differ
diff --git a/tests/ref_imgs_vg_lite/libs/freetype_1.lp64.png b/tests/ref_imgs_vg_lite/libs/freetype_1.lp64.png
index c4b15f806..56bed6c02 100644
Binary files a/tests/ref_imgs_vg_lite/libs/freetype_1.lp64.png and b/tests/ref_imgs_vg_lite/libs/freetype_1.lp64.png differ
diff --git a/tests/src/test_cases/libs/test_freetype.c b/tests/src/test_cases/libs/test_freetype.c
index 86768938b..c3396ce92 100644
--- a/tests/src/test_cases/libs/test_freetype.c
+++ b/tests/src/test_cases/libs/test_freetype.c
@@ -417,7 +417,12 @@ void test_freetype_bitmap_rendering_test(void)
12,
LV_FREETYPE_FONT_STYLE_NORMAL);
- if(!font_italic || !font_normal || !font_normal_small) {
+ lv_font_t * font_emoji = lv_freetype_font_create("../examples/libs/freetype/NotoColorEmoji-32.subset.ttf",
+ LV_FREETYPE_FONT_RENDER_MODE_BITMAP,
+ 12,
+ LV_FREETYPE_FONT_STYLE_NORMAL);
+
+ if(!font_italic || !font_normal || !font_normal_small || !font_emoji) {
LV_LOG_ERROR("freetype font create failed.");
TEST_FAIL();
}
@@ -437,6 +442,11 @@ void test_freetype_bitmap_rendering_test(void)
lv_style_init(&style_normal_small);
lv_style_set_text_font(&style_normal_small, font_normal_small);
+ static lv_style_t style_normal_emoji;
+ lv_style_init(&style_normal_emoji);
+ lv_style_set_text_font(&style_normal_emoji, font_emoji);
+ lv_style_set_text_align(&style_normal_emoji, LV_TEXT_ALIGN_CENTER);
+
/*Create a label with the new style*/
lv_obj_t * label0 = lv_label_create(lv_screen_active());
lv_obj_add_style(label0, &style_italic, 0);
@@ -456,6 +466,16 @@ void test_freetype_bitmap_rendering_test(void)
lv_label_set_text(label2, UNIVERSAL_DECLARATION_OF_HUMAN_RIGHTS_JP);
lv_obj_align_to(label2, label1, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
+ /* test emoji rendering
+ * emoji font does not contain normal characters, use fallback to render them */
+ font_emoji->fallback = font_normal;
+
+ lv_obj_t * label_emoji = lv_label_create(lv_screen_active());
+ lv_obj_add_style(label_emoji, &style_normal_emoji, 0);
+ lv_obj_set_width(label_emoji, lv_obj_get_width(lv_screen_active()) - 20);
+ lv_label_set_text(label_emoji, "FreeType Emoji test: 😀");
+ lv_obj_align_to(label_emoji, label2, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
+
TEST_FREETYPE_ASSERT_EQUAL_SCREENSHOT("1");
}