Simple font rendering library

This forums is for OS project announcements including project openings, new releases, update notices, test requests, and job openings (both paying and volunteer).
lmemsm
Posts: 18
Joined: Wed Jul 17, 2019 2:27 pm
Contact:

Re: Simple font rendering library

Post by lmemsm »

bzt wrote:There are several ways for combining characters:
1. if UNICODE has specified a combined ligature, then you can use its UTF-8 sequence (mostly in Latin-1 supplement, Extended Latin-A, B and in Alphabetic Presentation Forms blocks, but the latest UNICODE standard has code points for combined Devanagari letters too for example)
2. if combined code point is not specified, then you can get two or more UTF-8 sequences for the combination, all having zero advances except for the last one (as specified by UNICODE in the Combining Diacritical Marks and other blocks)
3. with ssfn_render(), use kerning to zero out the left glyph's advance value
4. with ssfn_render(), ignore the advance values returned, do as you want. This is a low level rendering library, meaning it returns the rasterized glyphs, and you can combine those on screen as you please.
So I've very curious about your mention of combining a UTF-8 character with zero width UTF-8 characters. You mentioned that they all have zero width except for the last one. When I was trying to research this, most of the standards (web, Unicode, etc.) used the non-zero width character first and then combined it with the zero width character(s). Putting the zero width characters first (not incrementing location) and then adding a standard character would seem to make more sense from a programmatic viewpoint. I only remember finding one other solution that did it that way though. The rest of the references I looked at did the reverse. Did you end up doing it this way because it made the most sense for the library or were there some other standards you followed? If there are other standards/references that do it this way, do you have some pointers to them? Thanks.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Hi,

Thanks for checking out my font library!
lmemsm wrote:You mentioned that they all have zero width except for the last one. When I was trying to research this, most of the standards (web, Unicode, etc.) used the non-zero width character first and then combined it with the zero width character(s). Putting the zero width characters first (not incrementing location) and then adding a standard character would seem to make more sense from a programmatic viewpoint. I only remember finding one other solution that did it that way though. The rest of the references I looked at did the reverse. Did you end up doing it this way because it made the most sense for the library or were there some other standards you followed? If there are other standards/references that do it this way, do you have some pointers to them? Thanks.
Considering that you adjust the cursor after drawing the glyph, it makes only sense to write the zero adjustment glyphs first. Consider this: you have an acute ' with zero adjustment (in UNICODE combining marks block) and an A (in UNICODE standard Latin block) with some. If you draw the accent first then the letter, then you'll start drawing the letter A at the same position as the acute, and since the last glyph has an adjustment, the cursor will be moved to the next character's position correctly. On the other hand if you write it the other way around, then you would first draw the letter, move the cursor then draw the acute without moving the cursor, therefore it would appear above the next glyph, and not above the letter A.
Of course you could draw them in that order too, if you specify a negative kerning value for the A and ' combination. In this case you would draw the A, adjust the cursor, then subtract a value from the cursor because of the kerning, draw the acute and move the cursor after the letter A.

Cheers,
bzt
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Craze Frog wrote:Unfortunately, the rendering quality doesn't look all that good. Do you want to give a brief overview of the algorithm it uses?
What's wrong with it? I'd appreciate any constructive criticism.

Assuming you have problem with the outline, it's using a simple anti-aliasing algorithm, in which I draw the outline with 8 bit precision. I shift it so that 127 is complete background, 255 (or -1) and 1 is almost foreground. Then I use that value for the alpha channel mask. The goal was a very simple, integer-only implementation, even in the price of quality. You can find the algorithm here. For bitmaps, I've implemented a reentrant pixel addition function (small code size), which decreases the alpha channel by each recursion. A pixel is added if there's at least two foreground neighbouring pixels. That can be found here (recursion converted into an iteration for smaller stack usage).

If by rendering quality you refer to the shape's quality, that's configurable. Most compressed, worst quality ratio uses 16x16 grid, while the less compressed but best quality uses 4096x4096 grid. According to my findings, 256x256 is usually offers good compression without loosing significant typeface details. Of course a font with 64x64 grid would yield much worse rendering quality (but smaller file size) than a 1024x1024 grid font for example. More about font quality.
Image

Cheers,
bzt
User avatar
eekee
Member
Member
Posts: 881
Joined: Mon May 22, 2017 5:56 am
Location: Kerbin
Discord: eekee
Contact:

Re: Simple font rendering library

Post by eekee »

The image in the last post shows there's not enough space between the characters for me. I have always had this problem with Ariel, actually. At some sizes, the gap between characters is no wider than the lines, while the spaces within characters is many times larger. If my eyes are even a little bit tired or my screen less than perfectly sharp, it turns into bizarre alien glyphs!

Another problem: inter-char spacing is erratic, especially at 1024x1024. Compare 'am' in 'amet' with 'ps' in 'ipsum' for the extremes. The gap between 'a' and 'm' is almost large enough to look like space between words, while the p and the s are actually touching. See 'ons' in 'consectetur' for general erraticness, less terrible but still enough to cause me trouble on a bad day. The gap between o and n is fine, but n and s are very close to merging. I think it might help to have 'margins' in the font so that important parts of adjacent characters may be prevented from merging. These margins would be permitted to overlap with each other, but not with solid areas.

To be honest, my eyes are really hard on font renderers. :) After using Freetype for 25 years plus some experience with professional font renderers rendering professional fonts, (Apple and Microsoft,) I decided to severely limit my use of scalable font rendering in my own work. I'll use it in high-dpi screens, but I won't even try on regular screens. By "high-dpi", I mean "4k" up to 28 inches, (not larger!) or just-about any tablet or smartphone. Even with professional font rendering, I've just configured a console, full-screen in 1920x1080, for 70x20 characters to give my eyes a break. :)
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Hi,
eekee wrote:The image in the last post shows there's not enough space between the characters for me.
When converting OTF to SSFN with ttf2sfn tool you can specify a delta adjustment on the command line. For example "-a 2" will add 2 grid pixels to the advance to increase the spacing between all glyphs.
eekee wrote:I have always had this problem with Ariel, actually. At some sizes, the gap between characters is no wider than the lines, while the spaces within characters is many times larger. If my eyes are even a little bit tired or my screen less than perfectly sharp, it turns into bizarre alien glyphs!
For those bizarre alien glyphs you can add kerning.
eekee wrote:Another problem: inter-char spacing is erratic, especially at 1024x1024. Compare 'am' in 'amet' with 'ps' in 'ipsum' for the extremes. The gap between 'a' and 'm' is almost large enough to look like space between words, while the p and the s are actually touching.
The ttf2sfn tool uses the values that Freetype2 returns with FT_Outline_Decompose. Originally I've used ttf advances, but that was even worse. If it doesn't seem right, that's a Freetype2 issue. The solution is easy, you can modify the spacing as you like in the SSFN font independently to the original font.
eekee wrote:See 'ons' in 'consectetur' for general erraticness, less terrible but still enough to cause me trouble on a bad day. The gap between o and n is fine, but n and s are very close to merging. I think it might help to have 'margins' in the font so that important parts of adjacent characters may be prevented from merging. These margins would be permitted to overlap with each other, but not with solid areas.
Again, ttf2sfn uses the kerning values that Freetype2 returns (see FT_Get_Kerning call here. You can modify the kerning values as you like in the SSFN font.
eekee wrote:To be honest, my eyes are really hard on font renderers. :) After using Freetype for 25 years
I've spent a week to read all the FT2 documentation and make the appropriate FT2 calls. If you can help me to fix these to provide better results, I'd appreciate your help!
eekee wrote:plus some experience with professional font renderers rendering professional fonts, (Apple and Microsoft,) I decided to severely limit my use of scalable font rendering in my own work. I'll use it in high-dpi screens, but I won't even try on regular screens. By "high-dpi", I mean "4k" up to 28 inches, (not larger!) or just-about any tablet or smartphone. Even with professional font rendering, I've just configured a console, full-screen in 1920x1080, for 70x20 characters to give my eyes a break. :)
Besides professional renderers are not an option for a hobby OS :-) I also though that maximum size of a 255x255 pixels rasterized glyph on a 4k screen should be sufficient, that's why my reference SSFN renderer is maximized at that size. This allows me to optimize for a lot smaller memory footprint.


As for the font files, I would suggest to convert them to plain ASCII format, fix the spacing and kerning as you like with a simple text editor, then convert back to binary format. This is well documented. (FYI I'm also working on a font editor with a GUI. It's almost finished, you can load SSFN and ASC files, modify them, but you can only save in ASC format as of now).

As for the reference renderer implementation, the goal was to be embedable as possible, therefore I've made a lot of trade offs: compact size, integer-only arithmetic and low memory consumption was my preference over rasterized quality. One could write another renderer that aims at perfect rasterization using more memory and floating point arithmetic with the data read from the same SSFN files. Would you be interested in that? I'd be great!

Cheers,
bzt
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Hi All,

Scalable Screen Font 2.0 is out!

Uses a completely different approach to rasterize vector fonts, which results in much better quality. The API got much simpler too, internal glyph caching was added, and it renders to buffers directly (does not return the glyph any more). It compiles to 28k of code and includes gzip. The converter utility got simpler as well, but more featureful. Besides OpenType, TrueType, BDF, etc. that already were supported, PNG, X11 PCF, Windows FNT and many other new formats can be converted to SSFN2, which compresses more than SSFN1.

Disadvantages
  • the renderer uses considerably more memory than SSFN 1.0 (~80k vs. ~24k, and with glyph cache enabled probably megabytes).
  • it does not return the outline nor the rasterized glyph any more.
Advantages
  • simpler API, fewer functions (load + select + render + free).
  • high quality, anti-aliased rendering directly to 32 bit pixel buffers.
  • faster rendering with less malloc calls and internal glyph caching.
  • smaller, more compact font files.
  • transparent uncompression of gzipped fonts.
  • support for non-standardized and user-defined ligatures.
  • support for color glyphs.
  • separate libsfn library to manipulate font files.
Check it out:
Image

P.s.: I still have issues with querying the advance values correctly from FreeType2. So you you might need to adjust those manually in fonts.

Cheers,
bzt
klange
Member
Member
Posts: 679
Joined: Wed Mar 30, 2011 12:31 am
Libera.chat IRC: klange
Discord: klange

Re: Simple font rendering library

Post by klange »

The antialiased edges look a lot nicer in this version, well done!
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

klange wrote:The antialiased edges look a lot nicer in this version, well done!
Thanks! This version uses bilinear interpolation with pre-multiplied alpha blending (that's why it does not return the glyph instead renders to the pixel buffer). I still have to figure out how to implement hinting with this method. Most of the time it is not needed at all, but there are a few edge cases, for example take a closer look at the 'i' in BitStream Vera.

If anyone could help how to get advance and kerning values from freetype2, that would be very much appreciated. This time I've turned off FT2's scaling, I query them in font units and scale them myself. This yields much better results, but I'm not entirely satisfied. In FreeSans 'e' and 'o' are too close to 'n' (in "generated" and "font provided" for example). However I'm using the values in the OTF font, so I have no clue how does freetype2 render those correctly.

Cheers,
bzt
User avatar
eekee
Member
Member
Posts: 881
Joined: Mon May 22, 2017 5:56 am
Location: Kerbin
Discord: eekee
Contact:

Re: Simple font rendering library

Post by eekee »

Looking good! It's looking good enough for me (with my problems) to use regularly, if I pick the font carefully. (I always pick the font carefully.)
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

eekee wrote:Looking good! It's looking good enough for me (with my problems) to use regularly,
Thank you! Coming from someone who has many years of experience with freetype means actually a lot! Thanks!
eekee wrote:if I pick the font carefully. (I always pick the font carefully.)
Hopefully I'll finish the GUI font editor soon, so that you can fix the advances to your liking. Until then you can use the ASC format and a plain text editor, just like with SSFN 1.0.

Cheers,
bzt
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Good News, Everyone! :-) Not really editor-related, but I needed these under the hood for the editor.

I've implemented lots and lots of interesting features, including, but not limited to:
  • Performance boost in the normal renderer. Blitting is now twice as fast as before (on my elderly machine renders the feature demo in 0.16 sec, including font load, inflate and sdl init)
  • You can configure the normal renderer to be dependency-free and to use static memory management. Requires about 64k of RAM, but has some limitations (most notably no transparent gzip decompression)
  • Better compression on fonts (replace trivial cubic curves with quadratic ones and few other tricks, the format did not change)
  • By default all dependencies are compiled statically into libsfn. I've managed to seriously strip down freetype2 to only support CFF/OTF/TTF
  • I've implemented natively FontForge's SplineFontDB (.sfd, both vector and bitmap versions), X11 PCF, Windows FNT/FON etc. importers
  • Converting vector fonts to bitmap fonts has been added
  • Vectorisation of bitmap fonts works too (you'll need high-res bitmap font for that, 32 or 64 pixels at least. Don't expect good results from 8x8 pixels)
And the editor related new features:
  • All of these included now with the SSFN editor. Vectorising fonts is just a single click on an icon :-)
  • The main window of the editor is complete, you can load fonts, edit its properties, check UNICODE block coverage, list character table, search for glyphs etc.
Now I'm moving on to glyph window in the editor, so that you can show and edit glyph properties, set kerning and edit layers etc.

Cheers,
bzt
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Hi Everyone,

New features: added the missing GRUB font format (.pf2), so now you can convert literally any fonts that comes with any of the mainstream OSes.

I've made lots and lots of tests with different compilers on both 32 and 64 bit systems. I'm sure the renderers are completely bug-free (I got fed up using valgrind and font combinations, no mem leaks either). The code is also easily portable (at least compiles without any warnings under different Linux distros with different libcs, under MinGW, and under MacOSX with clang), only an ANSI C89 compiler required.
bzt wrote:
eekee wrote:if I pick the font carefully. (I always pick the font carefully.)
Hopefully I'll finish the GUI font editor soon, so that you can fix the advances to your liking.
It took me a wee bit longer than I wanted, but finally the GUI editor is here!

I provide precompiled command line converter (sfnconv) and GUI editor (sfnedit) for Windows, MacOSX and Linux. These are portable executables, no installation required, just unpack the downloaded zip file. For Linux I gave you an Ubuntu, LinuxMint and debian compatible deb package (use "dpkg -i ssfn_*.deb" to install). This also contains manual pages for sfnconv, sfnedit and the ssfn.h API as well.

Image
Under the hood the editor uses the same libsfn library as the converter tool, so it's just a graphical wrapper to modify in-memory structures.

I've used the same colors as GIMP, but if you don't like the colours, you can load a theme from a GIMP palette file :-)

Cheers,
bzt
Ready4Dis
Member
Member
Posts: 571
Joined: Sat Nov 18, 2006 9:11 am

Re: Simple font rendering library

Post by Ready4Dis »

Great job and thanks so much for offering it! Also appreciate the license :). I most likely won't end up ever writing an OS that anyone uses, but it's great that you have a nice tool to use that can save people having to write their own or use a really crappy version until they can write a better one.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Simple font rendering library

Post by bzt »

Ready4Dis wrote:Great job and thanks so much for offering it! Also appreciate the license :)
Thank you very much! I choose the MIT license because I share the views of Stallman and other hackers. But I also wanted to use this in my non-free OS, that's why GPL wasn't feasible. Use as much as you want, just don't forget the proper attribution and give a star to my repo! :-)
Ready4Dis wrote:I most likely won't end up ever writing an OS that anyone uses,
Don't sell yourself short!
Ready4Dis wrote:but it's great that you have a nice tool to use that can save people having to write their own or use a really crappy version until they can write a better one.
Well, my experience is, most people can't write their own font renderer anyway, and freetype2 has huge amount of dependencies making it inappropriate for embedding in kernels. I wouldn't start this project if I weren't felt the niche. If it is useful for you too, then I'm glad! :-)

Cheers,
bzt
Ready4Dis
Member
Member
Posts: 571
Joined: Sat Nov 18, 2006 9:11 am

Re: Simple font rendering library

Post by Ready4Dis »

I'm not selling myself short, I'm not really working on osdev anymore, just like checking up once in a while to see where it is.
I used to write a bunch of graphics code, so I have an understanding how much goes into something like this. Just figured I'd post some encouragement because if people could share a bit more and keep stuff minimal to utilize, maybe everyone can stop.having to write everything over and over and reuse some parts and focus on the stuff they are actually interested in.
Post Reply