Compressed TrueType fonts for Micro-Controllers with Lcd display - Page 1
Forum section: electronics / projects

author: Krakenwak
author_rank: Newbie
timestamp: February 01, 2019, 03:01:15 pm
content: Hi People,A few years ago I started playing with a STM32F411RE & 7 inch 800x480Lcd display using an SSD1963 controller just to pass the time.When I required larger fonts such as 72pt numeric characters I foundThe memory requirements for the font to be prohibitively large. AfterLooking around for a font compression app I was unable to find one,but I did come across ‘The Dot Factory’ source by Pavius in C# on Github.https://github.com/pavius/the-dot-factory‘The Dot Factory’ did everything I wanted except give me a compressedfont output. After looking at the source I found a suitable place to break inand add my own output code. (This is used via a dropdown menu)I’ve only used MSVC6 & winapi and not worked with C# before so pleasekeep this in mind when critically viewing the source.The new output (If selected) will now generate Run-Length-Encoded fontdata and spit-out some size statistics to help decide if it’s worthwhile.Snippet below:( Ignore ‘Continuous Bitmap’ I lost interest before completing it)// *** Font Encoding Statistics ***//// This font has been encoded with 'The Dot Factory'// using Run-Length-Encoding (RLE) from a 72-Pt// TrueType font called "Monofonto"// '+' (Ascii 43) has the smallest width at 43 Pixels Wide// '+' (Ascii 43) has the greatest width at 43 Pixels Wide// '+' (Ascii 43) has the smallest height at 84 Pixels high// '+' (Ascii 43) has the greatest height at 84 Pixels high// The total Horizontal RLE bytes created for this font = 2183// The total Vertical RLE bytes created for this font = 1653// The total Vert+Horiz RLE bytes created for this font = 1619// The total Continuous Bitmap bytes created for this font = 6328// The total Standard Bitmap bytes created for this font = 7056As you can see from generating 14 72pt chars ‘0123456789.,-+’ using aFixed font for a digital meter display, RLE only needs 1619 bytes.(There are also some house-keeping arrays which need to be added to that figure for RLE)Normally I would have just uploaded the new code to Github and letnature take it’s course, and it would be found sooner or latter.But As I’m still on XP with an old version of Firefox, I foundI could no longer upload files to Github and so ended up zippingIt up and putting it on SourceForge.https://sourceforge.net/projects/dot-factory-rle/files/latest/downloadAs I’m not sure whether SourceForge is really used anymore I thoughtI’d let people know that the app exists. Hopefully someone will find it usefuland maybe improve it and even load it up to Github.

author: mariush
author_rank: Super Contributor
timestamp: February 01, 2019, 04:22:17 pm
content: You should provide a binary as well, I don't have C# installed at the moment.With such big fonts there are other tricks you can use, techniques similar to sprites etc* arrange the image of a character in 4x4 pixel blocks, gather statistics over all the characters, which 4x4 sprites are most common ...* use different amount of bits depending on how used sprite is ex 4 bits for the most used 7 sprites (0b0xxx) (use 0000 as sprite not in the "pallete") , 8 bits for the most common 7..63 sprites (0b1xxx0xxx) , 12 bits for 63..512 .... build palette of sprites as you go along ex [4 bits run length] [4-12 bits palette offset] [if data not preset in palette 16 bit follow with sprite info or if value is offset is 0 aka not in palette]* could add two bits per block which tell you if the sprite is flipped vertical or horizontal (to improve run length encoding) etcmaybe investigate if you can "optimize" a font to have a limited number of sprites and overlap/xor a couple of sprites to get a third sprite..Now that I think about it, palmdoc compression (the one used in mobi files, a kind of LZ77 compression) would probably work well for "big fonts"QuoteI'm reminded of this amazing presentation, where this talented guy makes clouds appear or buildings or have animated waterfalls just by playing with the color palettes and shifting colors in the images:

author: T3sl4co1l
author_rank: Super Contributor
timestamp: February 01, 2019, 04:41:44 pm
content: This may be of interest:https://github.com/T3sl4co1l/st7735_gfxIf you have the power to decode and use ttf (32F4, hell yeah you do!), and assuming you find a good library for it, absolutely, do that. It'll look great!If you don't need as much flexibility, and overhead, it may be easier to draw the individual glyphs (in whatever font sizes are needed), in which case this may be useful. It still may not look great, since antialiasing (with the help of a frame buffer or canvas system) isn't so easy to incorporate with this.I'm not actually using this method for fonts, on the project I've been playing with over the last yearish; that's just because I'm using a small LCD and the actual fonts are small (~10pt), better encoded differently (for which I also have a (less fancy) tool, that's not really in a publishable format, unfortunately). I am using this for large graphics (backgrounds, buttons..). (Example image: takes up about... oh what was it, 9kB data+code?https://www.seventransistorlabs.com/Images/ActiveLoad_ImageTest.pnghttps://www.seventransistorlabs.com/Images/ActiveLoadLCD6.jpgNote that, if you need more and bigger images, and better compression, you'll be much better served with a proper LZ-based (or the like) library.) That's the thing that brings this to mind, the large glyphs with transparent (but not alpha-blended) areas should compress pretty nicely in this format.Tim

author: tooki
author_rank: Super Contributor
timestamp: February 01, 2019, 09:07:39 pm
content: Quote from: mariush on February 01, 2019, 04:22:17 pmUmmmm… palette shifting (aka color cycling) is a technique that was widely used in the era of 8-bit color gaming to create repeating animations that affected a lot of pixels while using nearly zero CPU. It was most common for things like backgrounds (waves in water and lava, etc), but a notable exception was SimCity 2000, which used palette shifting to create nearly all of its background motion.Basically, giving the graphics card an updated color palette takes practically no CPU at all, and the graphics card takes care of actually updating the pixels. This way, you can animate anunlimitednumber of pixels with the same near-zero CPU hit.

author: Krakenwak
author_rank: Newbie
timestamp: February 01, 2019, 09:44:03 pm
content: Hi,Just to clarify.There is an exe file included, it needs DotNet installed to run.Also there is a Readme which contains more details on using the app, andsome code snippets showing how I contain the fonts in .h files and renderpixels in a putc & puts format.Actual truetype fonts:- I did spend a few days trying to implement real ttf butgot no where due to memory limitations.

author: bson
author_rank: Unknown
timestamp: February 03, 2019, 05:23:53 pm
content: One technique I've been using is to define:Code:#define FONTMAP(FONTLIST, CHARS) (CHARS)Then I run a tool to extract all of these (sed will do it, but my font tools are in python so I use regex matching) during the build (with C++ preprocessing so only get that which is used). Being completely syntactically unaware, it finds every appearance of e.g. FONTMAP(big72, "0123456789") so I can put these either in code or in a comment:Code:// FONTMAP((big72pt, small5x7), "0123456789")// FONTMAP((small5x7), "abcddefghjijklmopqrstuvAEGJM") // Only some uppercase chars used// FONTMAP((graphic_elements), "\001\004\010")orCode:const uchar _digits = FONTMAP((big72pt, small5x7), "0123456789");or both.orCode:#ifdef DEBUG_panel.drawMessage(NOTICE_X, NOTICE_Y, Fonts::med10pt, FONTMAP((med10pt), "ADC timeout, reading #") "%u", adc_counter);#endifThis lets me automatically determine which characters are actually used in each font. Which in turn lets me have generic complete fonts but only embed the glyphs actually used. This means for large glyphs where I only use maybe digits and a few symbols I don't need the whole thing since even RLE'd it can take up a few tens of k. Maybe not a big deal on a part with 1MB flash, but in general I don't like to include any code or data that is unused if it can be prevented. The usage information for each font is then used while the font is turned into C data (arrays of bytes) that are compiled and relocated to a flash section.This is not unlike how gettext() is canonically used to collect strings for translation.(Actually, it's a bit more complicated than a #define, but it works out the same.)