adafruit / Adafruit-GFX-Library

Adafruit GFX graphics core Arduino library, this is the 'core' class that all our other graphics libraries derive from
https://learn.adafruit.com/adafruit-gfx-graphics-library
Other
2.33k stars 1.52k forks source link

Fonts compression explanation #148

Open ihouses opened 6 years ago

ihouses commented 6 years ago

Hello,

I would like to understand how the fonts are compressed. Reading the code I see that there is a pointer in GFXglyph that points to the beginning of the compressed character within the GFXfont structe. What I don't understand is how the bytes are interpreted. Is there any explanation or tutorial regarding this topic anywhere?

Thanks by advance.

pljakobs commented 6 years ago

your best bet would be to look at the fontconvert code, basically, the format uses the minimum amount of bytes to represent all pixels that make up a character.

pj

ihouses commented 6 years ago

Hi,

I have check the code but I really dont't undertand it. Since I have been reading regarding the font compression and the idea is when the byte that you read from the buffer has the most significant bit to 1 it means that the rest of the bits (the 7 remaning bits) are the pixel information, otherwise if the bit is 0 it means that there a long list of repeated pixels (same value). Am I right with this?

But when I check the code I see that sometimes is calling the function draw_rectangle with a square shape of (size x size). :?

pljakobs commented 6 years ago

It's been a while since I wrote this code and I think there was some enhancement to it, too. However, I just looked at both the fontconvert as well as the drawChar code and I believe you're confusing two things. The bit fields for the gfxFont are just that: plain bits, no run length encoding (I've done that for some bitmap graphics, but not here, since usually, fonts are not that highly repetitive. Encoding the bits would mean that every byte can only hold seven bits, so from the get-go, the format would be 12,5% less efficient. For fonts less than 16px wide, I guess the compression would be negative) What you see is the crude scaling mechanism that adafruitGFX implements where you can set a 'size' parameter which results on every pixel being scaled by a factor of 'size' - hence the drawRect() s

PaintYourDragon commented 6 years ago

There is no compression in the font data. Each glyph is an uncompressed bitmap, fitted to the individual glyph bounds, rows padded to a byte boundary where necessary (width & 7 != 0).

mohammadkhoshsiar commented 6 years ago

hi i am persian and use fontconvert.exe for persian font. but adress off alphabet in windows character map are diffrent with glyph in font.h how i can use persian font in with adres off charactermap for example in character map ع adress is U+ 0639 but in .h file is not

pljakobs commented 6 years ago

Hi Mohammad, in short: currently, the implementation in AdafruitGFX by default only handles a seven bit charset. You can create larger font files to contain more glyphs, but that will only work up to character position 255. If you want to continue this discussion, please open a new issue for it, this one was concerning the actual storage format, you are asking for utf-8 and international character support.

PaintYourDragon commented 6 years ago

utf-8 support will probably never happen in GFX. This all has to fit on an AVR.

Plan was to support extended character sets with a 'code page' approach (i.e. multiple 8-bit fonts as needed). While it's inelegant and harkens back to DOS-type stuff, it's within the scope of the AVR, the approach is still used in memory-constrained devices such as thermal receipt printers.

GFX could handle this right now, I think, but none of the required code hasn't been implemented in fontconvert. This would need to pluck individual glyphs out of a larger font and assign them slots between 1 and 255 in a GFX raster font. Even the means of specifying the inputs and outputs has not been defined.

pljakobs commented 6 years ago

@PaintYourDragon well... what I have (somewhere) is some very basic code to map iso codepages to utf-8 and vice versa. I believe while we could theoretically do something simpler (like: having an interface that only deals with single byte characters), the way the print functions work, we do get utf-8, thus mapping to/from iso 8859 character sets would preserve the most "natural" experience for anyone writing code. One of the things that held me back is that for the more complex utf->iso mappings, we'll need quite a few if statements, potentially slowing down the code and making it difficult to read. It's still on my list though. Where are those pixies that write your code, when you ever need them? pj

ps: oh, and iso8869-6 would require bidirectional writing, too.. not sure if that would be an easy thing to do.

pps: it seems to be more complicated for the persian language: http://www.pooyesh.com/palapal/isofarsiplan.html

ihouses commented 6 years ago

Thanks a lot for you comments. I was very confused because I have read somewhere that the fonts where compressed. But now everything works fine.

Thanks again.

eltomjan commented 5 years ago

I made compression a bit better than LZW, but pull request is waiting more than year yet... You can check it in my VS C++ .Net/ Windows simulator: https://github.com/eltomjan/ETEhomeTools/tree/master/ArduinoSimulator Or directly in forked library https://github.com/eltomjan/Adafruit-GFX-Library In case you like 40-50% smaller fonts... There are 2 quite simple tricks now - I am using XOR between rows (bottom2top when creating font and top2bottom during print) to increase #of zeros and then there is a split to block logic now (whole char bitmap is taken as blocks of particular bit size and in case block has only zero bits, it is replaced by 0 bit, if there are any non-zeros, then data are encoded by 1 high bit and original data), each char starts with 1B holding block size. Rest works same as common GFX fonts - bits are decoded during print and sent as before (columns, rows from top-left corner). There is only row buffer added to be able to (Un-)XOR back data of current line. In case you like a graphic demo, there is a big font with XORed version and older row/column non-zero byte bitmap (also 1/0 statistics added, but no encoding yet): https://github.com/eltomjan/ETEhomeTools/blob/master/CSharp/FreeSerifBold24ptDemo.txt Or here is similar font from latest version of fontconvert (binary with bit & new/oldByte sizes in comments): https://github.com/eltomjan/ETEhomeTools/blob/master/ArduinoSimulator/Arial24pt.h

eltomjan commented 5 years ago

Finished also encoding and there is also very simple reader and "editor" in JScript if someone want to play with GFX format without need of toolset except browser and ev. debugger. Now have also very simple GFX editor (show/update/save char, recreate font) in JScript (legacy format + convertion of glyphs table option) here https://github.com/eltomjan/ETEhomeTools/blob/master/HTM_HTA/GFX/fontShowConvert.htm