pixelit-project/PixelIt

[FEATURE REQUEST] Cyrillic font (ready-made font and code)

Closed this issue · 10 comments

At the moment, Pixelit does not support the Cyrillic font. I would like to see the Cyrillic alphabet in future firmware releases, for this I created a "UPPERCASE font" of 5px and a "lowercase font" of 4px. I also wrote the HEX-code for these fonts (only the addresses need to be edited). Please let me know if I can now count on Cyrillic support in future projects?

PIXELIT_Cyrillic_UPPERCASE_font PIXELIT_Cyrillic_lowercase_font

`

// PIXELIT Cyrillic Font

// Ukrainian Cyrillic (4 CAPITAL letters)
0xA0, 0x00, 0xE0, 0x80, 0xC0, 0x80, 0xE0, // [202 | 1025 | 0x401] Ё (0x401)
0x60, 0x80, 0xC0, 0x80, 0x60,             // [203 | 1028 | 0x404] Є (0x404)
0x80, 0x80, 0x80, 0x80, 0x80,             // [204 | 1030 | 0x406] І (0x406)
0xA0, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // [205 | 1031 | 0x407] Ї (0x407)
// Russian Cyrillic (full)
0xE0, 0xA0, 0xE0, 0xA0, 0xA0,             // [206 | 1040 | 0x410] А (0x410)
0xE0, 0x80, 0xE0, 0xA0, 0xC0,             // [207 | 1041 | 0x411] Б (0x411)
0xC0, 0xA0, 0xE0, 0xA0, 0xC0,             // [208 | 1042 | 0x412] В (0x412)
0xE0, 0x80, 0x80, 0x80, 0x80,             // [209 | 1043 | 0x413] Г (0x413)
0x60, 0x50, 0x50, 0x50, 0xE8,             // [210 | 1044 | 0x414] Д (0x414)
0xE0, 0x80, 0xC0, 0x80, 0xE0,             // [211 | 1045 | 0x415] Е (0x415)
0xA8, 0xA8, 0x70, 0xA8, 0xA8,             // [212 | 1046 | 0x416] Ж (0x416)
0xC0, 0x20, 0x60, 0x20, 0xE0,             // [213 | 1047 | 0x417] З (0x417)
0xA0, 0xA0, 0xA0, 0xA0, 0xC0,             // [214 | 1048 | 0x418] И (0x418)
0x40, 0x00, 0xA0, 0xA0, 0xA0, 0xA0, 0xC0, // [215 | 1049 | 0x419] Й (0x419)
0xA0, 0xA0, 0xC0, 0xA0, 0xA0,             // [216 | 1050 | 0x41A] К (0x41A)
0x60, 0xA0, 0xA0, 0xA0, 0xA0,             // [217 | 1051 | 0x41B] Л (0x41B)
0x88, 0xD8, 0xA8, 0x88, 0x88,             // [218 | 1052 | 0x41C] М (0x41C)
0xA0, 0xA0, 0xE0, 0xA0, 0xA0,             // [219 | 1053 | 0x41D] Н (0x41D)
0xE0, 0xA0, 0xA0, 0xA0, 0xE0,             // [220 | 1054 | 0x41E] О (0x41E)
0xE0, 0xA0, 0xA0, 0xA0, 0xA0,             // [221 | 1055 | 0x41F] П (0x41F)
0xE0, 0xA0, 0xE0, 0x80, 0x80,             // [222 | 1056 | 0x420] Р (0x420)
0xE0, 0x80, 0x80, 0x80, 0xE0,             // [223 | 1057 | 0x421] С (0x421)
0xE0, 0x40, 0x40, 0x40, 0x40,             // [224 | 1058 | 0x422] Т (0x422)
0xA0, 0xA0, 0xE0, 0x40, 0x40,             // [225 | 1059 | 0x423] У (0x423)
0xF8, 0xA8, 0xF8, 0x20, 0x20,             // [226 | 1060 | 0x424] Ф (0x424)
0xA0, 0xA0, 0x40, 0xA0, 0xA0,             // [227 | 1061 | 0x425] Х (0x425)
0xA0, 0xA0, 0xA0, 0xA0, 0xD0,             // [228 | 1062 | 0x426] Ц (0x426)
0xA0, 0xA0, 0x60, 0x20, 0x20,             // [229 | 1063 | 0x427] Ч (0x427)
0xA8, 0xA8, 0xA8, 0xA8, 0xF8,             // [230 | 1064 | 0x428] Ш (0x428)
0xA8, 0xA8, 0xA8, 0xA8, 0xF4,             // [231 | 1065 | 0x429] Щ (0x429)
0xC0, 0x40, 0x70, 0x50, 0x70,             // [232 | 1066 | 0x42A] Ъ (0x42A)
0x88, 0x88, 0xE8, 0xA8, 0xE8,             // [233 | 1067 | 0x42B] Ы (0x42B)
0x80, 0x80, 0xE0, 0xA0, 0xE0,             // [234 | 1068 | 0x42C] Ь (0x42C)
0xC0, 0x20, 0x60, 0x20, 0xC0,             // [235 | 1069 | 0x42D] Э (0x42D)
0xB8, 0xA8, 0xE8, 0xA8, 0xB8,             // [236 | 1070 | 0x42E] Ю (0x42E)
0xE0, 0xA0, 0x60, 0xA0, 0xA0,             // [237 | 1071 | 0x42F] Я (0x42F)
0xC0, 0x60, 0xA0, 0xE0,                   // [238 | 1072 | 0x430] а (0x430)
0x60, 0xC0, 0xA0, 0xE0,                   // [239 | 1073 | 0x431] б (0x431)
0x40, 0xA0, 0xC0, 0xA0, 0xC0,             // [240 | 1074 | 0x432] в (0x432)
0xE0, 0xA0, 0x80, 0x80,                   // [241 | 1075 | 0x433] г (0x433)
0x60, 0x50, 0x50, 0xE8,                   // [242 | 1076 | 0x434] д (0x434)
0x60, 0xA0, 0xC0, 0x60,                   // [243 | 1077 | 0x435] е (0x435)
0xA8, 0x70, 0xA8, 0xA8,                   // [244 | 1078 | 0x436] ж (0x436)
0x20, 0x40, 0x20, 0xE0,                   // [245 | 1079 | 0x437] з (0x437)
0xA0, 0xA0, 0xA0, 0xC0,                   // [246 | 1080 | 0x438] и (0x438)
0x40, 0x00, 0xA0, 0xA0, 0xA0, 0xC0,       // [247 | 1081 | 0x439] й (0x439)
0xA0, 0xC0, 0xA0, 0xA0,                   // [248 | 1082 | 0x43A] к (0x43A)
0x60, 0xA0, 0xA0, 0xA0,                   // [249 | 1083 | 0x43B] л (0x43B)
0x88, 0xD8, 0xA8, 0x88,                   // [250 | 1084 | 0x43C] м (0x43C)
0xA0, 0xA0, 0xE0, 0xA0,                   // [251 | 1085 | 0x43D] н (0x43D)
0x40, 0xA0, 0xA0, 0x40,                   // [252 | 1086 | 0x43E] о (0x43E)
0xE0, 0xA0, 0xA0, 0xA0,                   // [253 | 1087 | 0x43F] п (0x43F)
0xC0, 0xA0, 0xE0, 0x80,                   // [254 | 1088 | 0x440] р (0x440)
0x60, 0x80, 0x80, 0x60,                   // [255 | 1089 | 0x441] с (0x441)
0xE0, 0x40, 0x40, 0x40,                   // [256 | 1090 | 0x442] т (0x442)
0xA0, 0xE0, 0x20, 0xC0,                   // [257 | 1091 | 0x443] у (0x443)
0x78, 0xA8, 0xF0, 0x20,                   // [258 | 1092 | 0x444] ф (0x444)
0xA0, 0x40, 0xA0, 0xA0,                   // [259 | 1093 | 0x445] х (0x445)
0xA0, 0xA0, 0xA0, 0xD0,                   // [260 | 1094 | 0x446] ц (0x446)
0xA0, 0xA0, 0x60, 0x20,                   // [261 | 1095 | 0x447] ч (0x447)
0x88, 0xA8, 0xA8, 0x70,                   // [262 | 1096 | 0x448] ш (0x448)
0x88, 0xA8, 0xA8, 0x74,                   // [263 | 1097 | 0x449] щ (0x449)
0xC0, 0x60, 0x50, 0x60,                   // [264 | 1098 | 0x44A] ъ (0x44A)
0x88, 0xC8, 0xA8, 0xC8,                   // [265 | 1099 | 0x44B] ы (0x44B)
0x80, 0xC0, 0xA0, 0xC0,                   // [266 | 1100 | 0x44C] ь (0x44C)
0xC0, 0x20, 0x60, 0x20, 0xC0,             // [267 | 1101 | 0x44D] э (0x44D)
0x98, 0xA8, 0xE8, 0xB0,                   // [268 | 1102 | 0x44E] ю (0x44E)
0x60, 0xA0, 0x60, 0xA0,                   // [269 | 1103 | 0x44F] я (0x44F)
0xA0, 0x00, 0x60, 0xA0, 0xC0, 0x60,       // [270 | 1105 | 0x451] ё (0x451)
// Ukrainian Cyrillic (4 small letters)
0x60, 0x80, 0xC0, 0x80, 0x60,             // [271 | 1108 | 0x454] є (0x454)
0x80, 0x00, 0x80, 0x80, 0x80, 0x80,       // [272 | 1110 | 0x456] і (0x456)
0xA0, 0x00, 0x40, 0x40, 0x40, 0x40,       // [273 | 1111 | 0x457] ї (0x457)
// Belarusian Cyrillic (1 CAPITAL letter)
0xA0, 0x40, 0x00, 0xA0, 0xA0, 0x40, 0x80  // 274 | 1038 | 0x40E] Ў (0x40E)
// Belarusian Cyrillic (1 small letter)
0xA0, 0x40, 0x00, 0xA0, 0x40, 0x80        // 275 | 1118 | 0x45E] ў (0x45E)

// PIXELIT Glyphs settings Cyrillic_basic //
{916, 8, 7, 4, 0, -7},  // [202 | 1025 | 0x401] Ё (0x401)
{923, 8, 5, 4, 0, -5},  // [203 | 1028 | 0x404] Є (0x404)
{928, 8, 5, 2, 0, -5},  // [204 | 1030 | 0x406] І (0x406)
{933, 8, 7, 4, 0, -7},  // [205 | 1031 | 0x407] Ї (0x407)
{940, 8, 5, 4, 0, -5},  // [206 | 1040 | 0x410] А (0x410)
{945, 8, 5, 4, 0, -5},  // [207 | 1041 | 0x411] Б (0x411)
{950, 8, 5, 4, 0, -5},  // [208 | 1042 | 0x412] В (0x412)
{955, 8, 5, 4, 0, -5},  // [209 | 1043 | 0x413] Г (0x413)
{960, 8, 5, 6, 0, -5},  // [210 | 1044 | 0x414] Д (0x414)
{965, 8, 5, 4, 0, -5},  // [211 | 1045 | 0x415] Е (0x415)
{970, 8, 5, 6, 0, -5},  // [212 | 1046 | 0x416] Ж (0x416)
{975, 8, 5, 4, 0, -5},  // [213 | 1047 | 0x417] З (0x417)
{980, 8, 5, 4, 0, -5},  // [214 | 1048 | 0x418] И (0x418)
{985, 8, 7, 4, 0, -7},  // [215 | 1049 | 0x419] Й (0x419)
{992, 8, 5, 4, 0, -5},  // [216 | 1050 | 0x41A] К (0x41A)
{997, 8, 5, 4, 0, -5},  // [217 | 1051 | 0x41B] Л (0x41B)
{1002, 8, 5, 6, 0, -5}, // [218 | 1052 | 0x41C] М (0x41C)
{1007, 8, 5, 4, 0, -5}, // [219 | 1053 | 0x41D] Н (0x41D)
{1012, 8, 5, 4, 0, -5}, // [220 | 1054 | 0x41E] О (0x41E)
{1017, 8, 5, 4, 0, -5}, // [221 | 1055 | 0x41F] П (0x41F)
{1022, 8, 5, 4, 0, -5}, // [222 | 1056 | 0x420] Р (0x420)
{1027, 8, 5, 4, 0, -5}, // [223 | 1057 | 0x421] С (0x421)
{1032, 8, 5, 4, 0, -5}, // [224 | 1058 | 0x422] Т (0x422)
{1037, 8, 5, 4, 0, -5}, // [225 | 1059 | 0x423] У (0x423)
{1042, 8, 5, 6, 0, -5}, // [226 | 1060 | 0x424] Ф (0x424)
{1047, 8, 5, 4, 0, -5}, // [227 | 1061 | 0x425] Х (0x425)
{1052, 8, 5, 5, 0, -5}, // [228 | 1062 | 0x426] Ц (0x426)
{1057, 8, 5, 4, 0, -5}, // [229 | 1063 | 0x427] Ч (0x427)
{1062, 8, 5, 6, 0, -5}, // [230 | 1064 | 0x428] Ш (0x428)
{1067, 8, 5, 7, 0, -5}, // [231 | 1065 | 0x429] Щ (0x429)
{1072, 8, 5, 5, 0, -5}, // [232 | 1066 | 0x42A] Ъ (0x42A)
{1077, 8, 5, 6, 0, -5}, // [233 | 1067 | 0x42B] Ы (0x42B)
{1082, 8, 5, 4, 0, -5}, // [234 | 1068 | 0x42C] Ь (0x42C)
{1087, 8, 5, 4, 0, -5}, // [235 | 1069 | 0x42D] Э (0x42D)
{1092, 8, 5, 6, 0, -5}, // [236 | 1070 | 0x42E] Ю (0x42E)
{1097, 8, 5, 4, 0, -5}, // [237 | 1071 | 0x42F] Я (0x42F)
{1102, 8, 4, 4, 0, -4}, // [238 | 1072 | 0x430] а (0x430)
{1106, 8, 4, 4, 0, -4}, // [239 | 1073 | 0x431] б (0x431)
{1110, 8, 5, 4, 0, -5}, // [240 | 1074 | 0x432] в (0x432)
{1115, 8, 4, 4, 0, -4}, // [241 | 1075 | 0x433] г (0x433)
{1119, 8, 4, 6, 0, -4}, // [242 | 1076 | 0x434] д (0x434)
{1123, 8, 4, 4, 0, -4}, // [243 | 1077 | 0x435] е (0x435)
{1127, 8, 4, 6, 0, -4}, // [244 | 1078 | 0x436] ж (0x436)
{1131, 8, 5, 4, 0, -5}, // [245 | 1079 | 0x437] з (0x437)
{1136, 8, 4, 4, 0, -4}, // [246 | 1080 | 0x438] и (0x438)
{1140, 8, 6, 4, 0, -6}, // [247 | 1081 | 0x439] й (0x439)
{1146, 8, 4, 4, 0, -4}, // [248 | 1082 | 0x43A] к (0x43A)
{1150, 8, 4, 4, 0, -4}, // [249 | 1083 | 0x43B] л (0x43B)
{1154, 8, 4, 6, 0, -4}, // [250 | 1084 | 0x43C] м (0x43C)
{1158, 8, 4, 4, 0, -4}, // [251 | 1085 | 0x43D] н (0x43D)
{1162, 8, 4, 4, 0, -4}, // [252 | 1086 | 0x43E] о (0x43E)
{1166, 8, 4, 4, 0, -4}, // [253 | 1087 | 0x43F] п (0x43F)
{1170, 8, 4, 4, 0, -4}, // [254 | 1088 | 0x440] р (0x440)
{1174, 8, 4, 4, 0, -4}, // [255 | 1089 | 0x441] с (0x441)
{1178, 8, 4, 4, 0, -4}, // [256 | 1090 | 0x442] т (0x442)
{1182, 8, 4, 4, 0, -4}, // [257 | 1091 | 0x443] у (0x443)
{1186, 8, 4, 6, 0, -4}, // [258 | 1092 | 0x444] ф (0x444)
{1190, 8, 4, 4, 0, -4}, // [259 | 1093 | 0x445] х (0x445)
{1194, 8, 4, 5, 0, -4}, // [260 | 1094 | 0x446] ц (0x446)
{1198, 8, 4, 4, 0, -4}, // [261 | 1095 | 0x447] ч (0x447)
{1202, 8, 4, 6, 0, -4}, // [262 | 1096 | 0x448] ш (0x448)
{1206, 8, 4, 7, 0, -4}, // [263 | 1097 | 0x449] щ (0x449)
{1210, 8, 4, 5, 0, -4}, // [264 | 1098 | 0x44A] ъ (0x44A)
{1214, 8, 4, 6, 0, -4}, // [265 | 1099 | 0x44B] ы (0x44B)
{1218, 8, 4, 4, 0, -4}, // [266 | 1100 | 0x44C] ь (0x44C)
{1222, 8, 5, 4, 0, -5}, // [267 | 1101 | 0x44D] э (0x44D)
{1227, 8, 4, 6, 0, -4}, // [268 | 1102 | 0x44E] ю (0x44E)
{1231, 8, 4, 4, 0, -4}, // [269 | 1103 | 0x44F] я (0x44F)
{1235, 8, 6, 4, 0, -6}, // [270 | 1105 | 0x451] ё (0x451)
{1241, 8, 5, 4, 0, -5}, // [271 | 1108 | 0x454] є (0x454)
{1246, 8, 6, 2, 0, -6}, // [272 | 1110 | 0x456] і (0x456)
{1252, 8, 6, 4, 0, -6}, // [273 | 1111 | 0x457] ї (0x457)

`

Thanks for your contribution! The offsets should continue from the main PixelItGlyphs font and then UTF letter assignments can be made in the Utf8ToAscii helper function. You can search the code for 😀 to find an example of how the mapping is done for this emoji.

For Russian letters you provided, we'll need to map Unicode symbols U+0410 .. U+044F according to https://en.wikipedia.org/wiki/List_of_Unicode_characters#Cyrillic

By the way, did you create this font yourself or it is taken from some permissive source?

I can take a look later and create the mapping (since it's linear it can be done in a single case statement similar to Latin1 Supplement)

Thanks for your contribution! The offsets should continue from the main PixelItGlyphs font and then UTF letter assignments can be made in the Utf8ToAscii helper function. You can search the code for 😀 to find an example of how the mapping is done for this emoji.

For Russian letters you provided, we'll need to map Unicode symbols U+0410 .. U+044F according to https://en.wikipedia.org/wiki/List_of_Unicode_characters#Cyrillic

By the way, did you create this font yourself or it is taken from some permissive source?

I can take a look later and create the mapping (since it's linear it can be done in a single case statement similar to Latin1 Supplement)

I created it myself and wrote the HEX code for it. At the moment, I have changed the encoding to UTF-16 and edited the glyphs settings. Does it look right now? Can you check it out? If not, write about it and I will fix it.

My font can also be changed by me for the convenience of reading it.

const uint8_t PixelItBitmaps[] PROGMEM = {
    .
    .
    0xC0, 0x40, 0x20, 0x40, 0xC0,       // [ 93 | 125 | 0x7D] braceright (0x7D)
    0x60, 0xC0,                         // [ 94 | 126 | 0x7E] asciitilde (0x7E)
                                       // Basic Cyrillic (Decimal 1025-1111)
    0xA0, 0x00, 0xE0, 0x80, 0xC0, 0x80, 0xE0, // [95 | 1025 | 0x401] Ё (0x401)
    0x60, 0x80, 0xC0, 0x80, 0x60,             // [96 | 1028 | 0x404] Є (0x404)
    0x80, 0x80, 0x80, 0x80, 0x80,             // [97 | 1030 | 0x406] І (0x406)
    0xA0, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // [98 | 1031 | 0x407] Ї (0x407)
    0xE0, 0xA0, 0xE0, 0xA0, 0xA0,             // [99 | 1040 | 0x410] А (0x410)

const GFXglyph PixelItGlyphs[] PROGMEM = {
    .
    .
    {411, 8, 5, 4, 0, -5}, // [ 93 | 125 | 0x7D] braceright (0x7D)
    {416, 8, 2, 4, 0, -5}, // [ 94 | 126 | 0x7E] asciitilde (0x7E)
                           // Glyphs setting Basic Cyrillic (Decimal 1025-1111)
    {418, 8, 7, 4, 0, -7}, // [95 | 1025 | 0x401] Ё (0x401)
    {425, 8, 5, 4, 0, -5}, // [96 | 1028 | 0x404] Є (0x404)
    {430, 8, 5, 2, 0, -5}, // [97 | 1030 | 0x406] І (0x406)
    {435, 8, 7, 4, 0, -7}, // [98 | 1031 | 0x407] Ї (0x407)
    {442, 8, 5, 4, 0, -5}, // [99 | 1040 | 0x410] А (0x410)

jekader
I tried to test my font and added the first 5 lines of my Cyrillic font code. But my symbols «Ё, Є, І, Ї, А» are not displayed, instead I get an empty screen. I also set up the "Glyphs" offset according to the continuation of the line code [94]..
Also in the file " Tools.h " via "Utf8ToAscii" I added the following code:

case 1025 ... 1040: // Basic Cyrillic (Decimal 1025-1111)
	result = ascii;
	break;

But all to no avail.

Could you tell me what can be done to make it work? I'm not an expert, but I figured out how the pixel font is encoded in "HEX", what Decimal and ASCII are. And I really want my font to finally display on my pixel clock. I also spend a lot of time to redo the code of my Cyrillic font for the Pixelit project.

Thanks for any information.

Hi, the range for the glyphs in UTF-8 should be D081 (Ё U+0401) to D197 (ї U+0457)

here's a placeholder for the contiguous range А..я which just prints question marks instead of the glyphs:

	case 0xD090 ... 0xD0BF: // Russian Cyrillic (Decimal 206-253)
		result = 0x3F;
		break;
	case 0xD180 ... 0xD18F: // Russian Cyrillic (Decimal 254-269)
		result = 0x3F;
		break;

What is left is to add the offset (0x90 becomes 0xEE and so on) - I am also working on a patch, will let you know the right math once I have it working. For other non-contiguous symbols we'll have to add them individually or draw the missing ones

Some more thoughts after playing around:

  1. the glyph number needs to be changed on the font object when updating the font to enable new letters
  2. setting the max number higher than 0xFF breaks the screen for me
  3. there's already 201 glyphs and the limit is 224 which is just 13 more symbols
  4. the pixelit font is 5px tall but some of the new letters are 7 pixels tall
  5. newly provided Cyrillic letters have a different drawing style than existing Latin matching ones (ABC for instance) - this might need adjustment once we figure out the rendering issue
  6. some offsets are off starting with з when previewing via https://tchapi.github.io/Adafruit-GFX-Font-Customiser/

With this, I was able to show some of the chars successfully:
image

So besides the minor bugs in the font itself I thing the issue with glyph limits is the biggest. I don't have much experience with the GFX Library - maybe @foorschtbar can comment on this. The last attribute is uint16_t according to the reference so it should be able to go higher than 256. The font customizer also has no problem displaying all the glyphs.

UPD: as a temporary hack, since we're stuck with 1-byte encodings, I've hacked up a patch that replaces latin extended glyphs with your font - it can be found in this branch:
https://github.com/jekader/PixelIt/tree/cyrillic-font

This only covers the contiguous Russian alphabet mapping in Utf8ToAscii at the moment for simplicity. All glyphs work fine (I've trimmed down everything to max 6 pixels high).

Feel free to build this branch and improve on it, should give you the result you need while we figure out a proper solution if one is even possible for embedded devices.

I've added extended Cyrillic glyphs to my branch. Looks like Ґ and ґ were missing from your font so I've created those and added them as well. Now all East-Slavic Cyrillic languages should fully work.

Looking at the patch, seems like having a separate repo which would rebase with each PixelIt release would be a reasonable solution: whoever needs a PixelIt with Cyrillic support can just install the relevant binary. WDYT? Alternatively, having a separate set of _cyrillic image builds right in this repo is an option - also possible with minor refactoring of some of the sources and adding some build flags.

jekader
Thank you for your feedback and your work! Sorry for not responding earlier.
At some point, I realized that it was not enough just to add a HEX code for Cyrillic to make it work and my hands dropped.
As I understand it, you created a fork of the project and instead of extended Latin characters, you added Cyrillic for the experiment?
I still do not understand how the function works when entering a character from the keyboard for subsequent transmission to Utf8ToAscii and 1-byte encodings. It is configured in the src/Tools.h file ?

Yes, correct. Tools.h has a switch statement which loops through user input chars in UTF-8 format and converts them to a symbol position in the font which is 0..255

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days