bzt
Posts: 373
Joined: Sat Oct 14, 2017 9:57 pm

Displaying fonts

Tue May 28, 2019 1:56 am

Hi,

I saw in this topic that others may be interested in my little project.

I wanted to display UTF-8 strings in my bare metal app. At first glance it doesn't seem difficult, right? But if you dig deeper, you'll see how far that rabbit hole goes...

The first problem is bitmap fonts. 8x16 is perfectly fine for Latin, but there's no way you can shrink CJK ideograms into. 16x16 is the bare minimum, but Latin letters look terrible at that width. So you need proportional fonts for sure, which means you can forget about PSF. Second problem is scaling. You gonna need vector fonts, but there's no way you could integrate freetype2 into a bare metal application. So what's the solution?

To solve these problems, I've created a font rendering library, which some of you may find useful. Written in a single ANSI C header file and licensed under MIT license, it's very easy to integrate to any project. The compiled code size is about 20 Kilobytes, and it is virtually dependency free. It only relies on memset(), memcmp(), realloc() and free() (all of which provided by GNU gcc as built-ins, btw.). For those who cannot afford memory allocation, there's a special function which renders unscaled bitmap glyphs directly to the framebuffer, and uses no function calls whatsoever (compiles to about 800 bytes).

Scalable Screen Font

I think the best would be to show you a demo:
Image

The renderer uses it's own format, which uses data-loss compression on vector fonts, so you can choose between quality and font size depending on your needs. With the same quality as an OpenType font, SSFN font usually takes only half the size. Command line utilities are provided to compress the following formats into SSFN fonts:
  • PostScript Type 1
  • TrueType (TTF)
  • OpenType (OTF)
  • PC Screen Font (PSFU)
  • X11 Bitmap Distribution Format (BDF)
  • TARGA (for pixel fonts)
Cheers,
bzt

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Displaying fonts

Tue May 28, 2019 2:01 pm

Awesome..!

I will try your solution on pi 3b OPENVG.

Thanks bzt.
--zeo
Let there be some light .../\...

bzt
Posts: 373
Joined: Sat Oct 14, 2017 9:57 pm

Re: Displaying fonts

Wed Jun 05, 2019 1:43 pm

You're welcome! Please keep me posted how it goes! Sounds like a great project!

To help you with that: in outline mode, ssfn_render() will return line paths (all curves and splines are converted to series of lines). Coordinates are scaled up to 255 x 255 (which is quite a big character even for Full HD).

If you want higher precision or the raw information (all the quadratic curves, cubic curves etc.), then you have to read the SSFN file yourself. Or alternatively you can convert the font to SSFN ASCII and parse that with sscanf(), it looks like this:

Code: Select all

+!---36-447-0---U+000024-'$'---
m 363,855
l 329,855
l 328,752
q 257,744 293,751
...
These coordinates are in the font's precision. As for the provided examples, all are 1024 x 1024.

Cheers,
bzt

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Displaying fonts

Wed Jun 26, 2019 6:59 am

bzt I was going to compare render speed but ran into a problem

Can you tell me what the story is with Vera fonts?
None of the VERA fonts have SFNN in the first 4 bytes .. is this a different format or something?

bzt
Posts: 373
Joined: Sat Oct 14, 2017 9:57 pm

Re: Displaying fonts

Wed Jun 26, 2019 9:27 am

Hi,
LdB wrote:
Wed Jun 26, 2019 6:59 am
bzt I was going to compare render speed but ran into a problem
Thanks for checking out!
LdB wrote:Can you tell me what the story is with Vera fonts?
None of the VERA fonts have SFNN in the first 4 bytes .. is this a different format or something?
Well, the correct magic is SSFN, and all Vera fonts have that, I've checked again, just in case :-) Except for Vera.sfn, which is a font collection that includes all the other Vera fonts (regular, bold, italic etc.). Collections are concatenated sfn fonts with an 8 byte header, which starts with the magic SFNC. Documentation. There's a very-very simple tool sfnconv/sfn2sfn to handle them, for example to list the fonts in a collection:

Code: Select all

$ ./sfn2sfn Vera.sfn
1 .. Bitstream Vera Sans
1 b. Bitstream Vera Sans Bold
1 .i Bitstream Vera Sans Oblique
1 bi Bitstream Vera Sans Bold Oblique
See Creating and extracting font collections.

Cheers,
bzt

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Displaying fonts

Wed Jun 26, 2019 1:01 pm

Okay there is a problem or I am not getting something here ... I won't waste you time I was just going to benchmark your renderer

I just downloaded all the Vera fonts again they all begin the same way like this 1F 8B 08 00
I don't get SNFC anywhere and I am just confused ... anyhow it's probably me and something is going over my head
Image

bzt
Posts: 373
Joined: Sat Oct 14, 2017 9:57 pm

Re: Displaying fonts

Thu Jun 27, 2019 2:59 pm

LdB wrote:
Wed Jun 26, 2019 1:01 pm
I just downloaded all the Vera fonts again they all begin the same way like this 1F 8B 08 00
Haha, ok, I get it now! As I wrote in the documentation:
If the file starts with the bytes 0x1f and 0x8b, then you have to inflate it first
using a gzip decompression filter. For command line, use gzip -d .
I've totally forgot to add ".gz" to the names because I'm using Midnight Commander, which automatically decompresses the files when I press F3 - View on them :-) Also all converters and the editor checks the magic bytes and do not care about the ".gz" file extension. Sorry about that!

Your options:
1) rename it to "Vera.sfn.gz" and use "gzip -d" from command line (simplest solution, no coding needed)
2) use zlib's gzopen() and gzread() instead of fopen() and fread() when you read the file into memory (that directly reads uncompressed data from the file, example code here, in bit2sfn because BDF files are usually compressed the same way)
3) use zlib's z_stream decompression before you pass it to ssfn_load() (this the "standard" way, example code here, if sfnedit compiled with zlib)
4) use Joergen Ibzen's tiny inflate (example code here, if sfnedit compiled without zlib. I'm using this for decompressing initrd images in my bootloader too because it's a simple implementation that does not require memory allocation)

I think you should simply use

Code: Select all

mv Vera.sfn Vera.sfn.gz; gzip -d Vera.sfn.gz
and you're good to go. The SSFN specification mentions that Huffman+LZW filter can be used on the font (like gzip, bz2, 7z etc.), but the API expects inflated fonts because reading the font into memory is not part of the renderer. Hope this helps, and sorry about the missing ".gz" extensions!

Cheers,
bzt

EDIT: I've renamed the fonts to ".sfn.gz", and I have uploaded the Vera.sfn without gzip compression too just in case. That's 84k without gzip, including all 4 styles, using only my geometric glyph compression algorithm (handled by the API, no manual decompression needed).

Return to “Bare metal, Assembly language”