Powrót

Kurs Arduino – Problemy z polonizacją GFX

Ostatnio (UR028) stworzyliśmy i spolonizowaliśmy font GFX, jednak przy próbie wyświetlenia napisu wystąpił błąd, a w istocie dwa pokrewne błędy. Spróbujemy poznać przyczyny i znaleźć sposoby rozwiązania problemu.

Nasze polskie litery powinny mieć kody powyżej zakresu ASCII, czyli 128…145 (0x80…0x91). A na razie tak nie jest. Już w opisie wygenerowanego fontu jest informacja, że obejmuje on tylko kody 32…126 (0x20…0x7E).

Pierwszy problem: przy realizacji większego fontu w pliku FontEdW20.h) zapomnieliśmy o kodzie numer 127 (0x7F), który uwzględniliśmy w pierwszym, mniejszym foncie FontEdW.h), żeby zachować ciągłość. To nasze przeoczenie i na pewno trzeba dodać kod 127.

Do tablicy FontEdW20Glyphs[] możemy skopiować znak spacji – kod 32 (0x20), choćby dlatego, że w kodzie podstawowym ASCII na pozycji 127 miała to być spacja nierozdzielająca (NBSP). Do tablicy FontEdW20Bitmap[] też moglibyśmy skopiować opis spacji z samego początku tej tablicy, ale akurat w przypadku spacji możemy go… pominąć.

O oto drugi problem: w naszym foncie brak symbolu tyldy (~), która powinna mieć kod 126 (0x7F)! Ostatnim znakiem jest klamra zamykająca (}), która ma numer 125. Problem tkwi więc przede wszystkim w dolnej tablicy FontEdW20Glyphs[], bo tam nie ma w ogóle pozycji dla kodu 126, który powinien wyświetlać znak tyldy (~). Nie ma też graficznego opisu wyglądu tyldy w tablicy Font­EdW20Glyphs[]. To nie jest nasze przeoczenie, tylko niedoróbka przy konwersji czcionki na stronie:

http://oleddisplay.squix.ch/,

jak pokazuje to szkic 1.

Szkic 1:

// Created by http://oleddisplay.squix.ch/ Consider a donation

//In case of problems make sure that you are using the font file with the correct version!

const uint8_t Open_Sans_Condensed_Bold_20Bitmaps[] PROGMEM = {

 // Bitmap Data:

 0x00, // ' '

 0xEE,0xEE,0xEE,0xEE,0x60,0x0E,0xEE, // '!'

 0xEE,0xEE,0xEE,0xC6,0x44, // '"'

(...)

 0x7C,0x7C,0x1C,0x1C,0x18,0x38,0x30,0x70,0x70,0xFE,0xFE, // 'z'

 0x0E,0x1E,0x18,0x18,0x18,0x18,0x18,0xF8,0xE0,0xF8,0x18,0x18,0x18,0x18,0x18,0x1E,0x0E,//'{'

 0xDB,0x6D,0xB6,0xDB,0x6D,0xB6,0xDB,0x60, // '|'

 0xE0,0xF0,0x30,0x30,0x30,0x30,0x30,0x3E,0x0E,0x3E,0x30,0x30,0x30,0x30,0x30,0xF0,0xE0 //'}'

};

const GFXglyph Open_Sans_Condensed_Bold_20Glyphs[] PROGMEM = {

// bitmapOffset, width, height, xAdvance, xOffset, yOffset

 {     0,   1,   1,   6,    0,    0 }, // ' '

 {     1,   4,  14,   6,    1,  -14 }, // '!'

 {     8,   8,   5,  10,    1,  -14 }, // '"'

  (...)

 {  1286,   8,  11,   8,    0,  -11 }, // 'z'

 {  1297,   8,  17,   8,    0,  -14 }, // '{'

 {  1314,   3,  20,  11,    4,  -15 }, // '|'

 {  1322,   8,  17,   8,    0,  -14 } // '}' - to jest kod nr 125 (0x7D)

};

const GFXfont Open_Sans_Condensed_Bold_20 PROGMEM = {

(uint8_t *)Open_Sans_Condensed_Bold_20Bitmaps,

GFXglyph *)Open_Sans_Condensed_Bold_20Glyphs,0x20,0x7E,28};

 

Aby przywrócić porządek, trzeba więc dodać do naszego fontu brakujące dwa kody o numerach 126 i 127.

A konkretnie co należy dodać?

Zastanówmy się: kodu 127 nie będziemy nigdy wykorzystywać, bo mamy zwykłą spację pod numerem 32. Znak tyldy (~) jest wykorzystywany niezmiernie rzadko i też możemy uznać, że nie będzie nam potrzebny.

Jeśli nie będziemy ich używać, to wystarczy jedynie wstawić do tablicy FontEdW20Glyphs[] dwie pozycje o wymaganej strukturze i o dowolnej zawartości. Tak – o dowolnej zawartości. Przykładowo:

{   0,  0,  0,  0,  0,  0},

{   0,  0,  0,  0,  0,  0},

albo na przykład:

{  9999,  99,  99,  99,   99,  99 },

{  9999,  99,  99,  99,   99,  99 },

Do tablicy FontEdW20Bitmap[] niczego nie musimy dodawać, bo program nigdy nie będzie sięgał do nieużywanych kodów.

A jeżeli chodzi o odnalezienie omawianego właśnie błędu, to spostrzegawczy Czytelnicy zapewne szybko wykryli go na podstawie rysunku 6 z poprzedniego odcinka – widać tam wyraźnie, że pierwsza dodana przez nas litera (A) wylądowała na miejscu tyldy o kodzie 0x7E (126), a nie jako kod 128.

W ostatniej wersji pliku FontEdW20.h tylko w tablicy Font­EdW20Glyphs[] dodajmy dwa puste miejsca (nie zapominając o przecinkach). Przy okazji zobaczymy, że skrypt ze strony https://tchapi.github.io/Adafruit-GFX-Font-Customiser/ połączył wszystkie bajty tablicy FontEdW20Glyphs[] w jedną nieczytelną całość i usunął stamtąd komentarze, a za to dodał własne komentarze w tablicy FontEdW20Glyphs[] opisujące znaki, a ponadto śmiesznie poustawiał tam przecinki na początku linii. Tu też wyraźnie widać, że w linii opisującej znak tyldy wylądowała literka Ą.

Jeżeli dodamy dwie „puste” linijki   według szkicu 2 (nie zapominając o przecinkach!) i zmienimy odstęp między liniami tekstu z 28 na 22 piksele, to po wczytaniu pliku FontEdW20.h na stronie https://tchapi.github.io/Adafruit-GFX-Font-Customiser/ zobaczymy obraz jak na rysunku 1.

Szkic 2:

const uint8_t FontEdW20Bitmaps[] PROGMEM = {

 0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0x60, 0x0E, 0xEE, 0xEE, 0xEE, 0xEE, 0xC6,

 0x44, 0x0D, 0x80, 0x98, 0x19, 0x81, 0x98, 0x7F, 0xE7, 0xFE, 0x1B, 0x01,

 (...)

 0x1C, 0x18, 0x38, 0x30, 0x70, 0x70, 0x60, 0xFE, 0xFE, 0x08, 0xFE, 0x7C,

 0x5C, 0x1C, 0x38, 0x30, 0x70, 0x70, 0x60, 0xFE, 0xFE

}

const GFXglyph FontEdW20Glyphs[] PROGMEM = {

  {     0,   1,   1,   6,    0,    0 }   // ' '

 ,{     1,   4,  14,   6,    1,  -14 }   // '!'

 ,{     8,   8,   5,  10,    1,  -14 }   // '"'

 (...)

 ,{  1286,   8,  11,   8,    0,  -11 }   // 'z'

 ,{  1297,   8,  17,   8,    0,  -14 }   // '{'

 ,{  1314,   3,  20,  11,    4,  -15 }   // '|'

 ,{  1322,   8,  17,   8,    0,  -14 }   // '}'

, {     0,   0,   0,   0,    0,    0 } //dodany pusty znak 126=0x7E

, {     0,   0,   0,   0,    0,    0 } //dodany pusty znak 126=0x7F

 ,{  1339,  12,  15,  12,    0,  -14 }   //

 ,{  1362,   9,  15,  10,    1,  -15 }   // tu mamy

 ,{  1380,   8,  15,  10,    1,  -14 }   // dodane przez nas

 ,{  1395,   8,  14,   9,    1,  -14 }   // 18 polskich liter

 ,{  1409,  12,  15,  14,    1,  -15 }   //

 ,{  1432,  11,  15,  13,    1,  -15 }   //

 ,{  1454,   8,  15,   9,    1,  -15 }   //

 ,{  1469,  10,  15,  10,    0,  -15 }   //

 ,{  1489,  10,  15,  10,    0,  -15 }   //

 ,{  1509,   8,  12,  10,    1,  -11 }   //

 ,{  1521,   7,  12,   8,    1,  -12 }   //

 ,{  1532,   8,  12,  10,    1,  -11 }   //

 ,{  1544,   5,  15,   6,    1,  -15 }   //

 ,{  1554,   9,  12,  11,    1,  -12 }   //

 ,{  1568,   9,  12,  11,    1,  -12 }   //

 ,{  1582,   7,  12,   8,    1,  -12 }   //

 ,{  1593,   8,  12,   8,    0,  -12 }   //

 ,{  1605,   8,  12,   8,    0,  -12 }   //

};

const GFXfont FontEdW20 PROGMEM = {

(uint8_t  *)FontEdW20Bitmaps,(GFXglyph *)FontEdW20Glyphs,0x20, 0x91, 22};

Rysunek 1

Natomiast po ponownym skompilowaniu szkicu A2603.ino (lub identycznego A2701.ino), na ekranie zobaczymy prawidłowy napis, jak pokazuje fotografia 2.

SUKCES! Możemy uznać, że opanowaliśmy polonizowanie fontów GFX!

W zasadzie tak, ale dociekliwi Czytelnicy dopatrzą się, że na rysunku 1 nie widać kształtu symbolu klamry zamykającej – kod 125=0x7D. Będą się też zastanawiać, jak można dodać obrazek pokazujący wygląd tyldy o kodzie 126=0x7E i jak zapewnić prawidłowe działanie spacji z kodu 127. To zadanie domowe dla chętnych, a ja podpowiem, że w skrypcie na stronie tchapi.github.io można dodać brakującą bitmapę, klikając Rows+, Cols+. A spacja jest w pewnym sensie „znakiem pustym” i nie musi mieć definiującej ją bitmapy. Wystarczająca jest informacja, o ile pikseli kod 32 (i kod 127) ma przesunąć kursor w poziomie. A ta informacja jest zawarta w czwartym polu (xAdvance) tablicy FontEdWGlyphs[].

Inne możliwości

Przedstawiony sposób polonizowania fontów GFX nie jest jedyny i zapewne też nie jest najlepszy. Czytelnicy mający większe doświadczenie oraz najbardziej dociekliwi mogą wypróbować inne metody. Ważne, żeby rozumieć, na czym polega przeróbka i jaki jest jej cel. W każdym razie my musimy do istniejącego fontu dodać 18 polskich liter.

W trudniejszej sytuacji są na przykład Rosjanie i wszyscy inni posługującymi się niełacińskimi alfabetami. Wtedy wymagana jest poważniejsza przeróbka fontu. Warto wiedzieć, że na stronie https://forum.arduino.cc/index.php?topic=447956.0

w skrócie: https://bit.ly/37gmweV

udostępniony jest zrealizowany przez rosyjskich programistów edytor – konwerter fontów dla różnych bibliotek Arduino, w tym także dla Adafruit GFX. W pierwszym poście w tym wątku jest wiele odnośników, którymi nie trzeba się zajmować. Należy tylko pobrać zazipowany plik binFontsTool-0.2.7.xlsm, jak pokazuje czerwona strzałka na rysunku 3.  Po rozpakowaniu otrzymujemy plik .xlsm i od razu warto zrobić kilka jego kopii, bo po użyciu może nastąpić zmiana w jego ustawieniach.

Rysunek 3

Rozpakowany plik .xlsm w zasadzie można otworzyć w różnych programach. Jednak u mnie próba otwarcia za pomocą LibreOffice, który jest moim głównym pakietem do pisania, skończyła się fiaskiem, przede wszystkim z powodu makr, które są domyślnie blokowane. Otworzyłem go w Excelu.

Aby konwerter zadziałał, po otwarciu arkusza w Excelu, pomimo ostrzeżenia o niebezpieczeństwie, najpierw trzeba włączyć skrypty, jak pokazuje czerwona strzałka na rysunku 4. Potem klikając „Open C file”, jak pokazuje niebieska strzałka, trzeba wczytać plik fontu GFX.

Rysunek 4

Ja wstępne testy przeprowadziłem wcześniej z użyciem starego pliku FontEdW.h o wielkości 10 punktów, jak pokazuje rysunek 5.

Rysunek 5

Po otwarciu pliku fontu, z lewej strony ekranu zobaczymy wygląd naszych znaków. Na rysunku 6 czerwonym kolorem dopisałem, jakie numery mają poszczególne znaki „na pograniczu” kodów oryginalnych i dodanych.

Rysunek 6

Przyznaję, że nie doprowadziłem do satysfakcjonującego spolonizowania fontu za pomocą tego narzędzia. Zresztą jest ono w pierwszej kolejności przeznaczone dla alfabetu rosyjskiego. Niemniej warto o nim wiedzieć, bowiem narzędzie to ma bardzo duże możliwości, mnóstwo opcji i na pewno może służyć choćby tylko do podglądania zawartości i wyglądu różnych fontów bitmapowych, nie tylko GFX. Jeżeli ktoś z Czytelników z powodzeniem wykorzysta je do polonizacji fontów GFX, niech napisze do redakcji (edw@elportal.pl).

Kończymy temat fontów Arduino. W praktyce zapewne potrzebne będą Wam spolonizowane fonty o różnej wielkości i kroju, dlatego mocno zachęcam wszystkich Czytelników, żeby samodzielnie przeprowadzili przeróbkę choćby jednego pliku fontu GFX. Tyle odcinków kursu było opublikowanych w czasopiśmie EdW. Na życzenie Czytelników do wybranych wątków tego cyklu możemy wrócić na łamach czasopisma Zrozumieć Elektronikę. Możliwości kontaktu podane są na stronie Zapytaj, odpowiedz.

Piotr Górecki