Commit 2f637012 authored by bzt's avatar bzt

Initial commit

Copyright (C) 2019 bzt (bztsrc@gitlab)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Scalable Screen Font
This is a single ANSI C/C++ header file, scalable bitmap and vector font renderer. It has only memory related
libc dependency and it does not use floating point numbers. It's extremely small (approx. 21k) and it is very
easy on memory, perfect for embedded systems and hobby OS kernels. It was a hobby project for me, so donations
and contributions would be much appreciated if it turns out to be useful to you.
<img alt="Scalable Screen Font Features" src="">
SSFN renderer does not use existing font formats directly (because most formats are inefficient or just insane),
so you first have to compress those into [SSFN](
There're a handful of small ANSI C [utilities](
to do that (they support PS Type1, OpenType, TrueType, X11 Bitmap Distribution Format, Linux Console fonts, GNU
unifont and others). This means your fonts will require less space, and also the renderer can work
a lot faster than other renderer libraries. Check out [comparition](
with other font formats.
- [ssfn.h]( the SSFN renderer itself
- [sfnconv]( SSFN font converters / compressors
- [sfntest]( test applications and [API]( usage examples
The SSFN renderer comes in two flavours: there's the normal renderer with a few functions and libc dependency, and a
specialized renderer for OS kernel consoles with just one function and no dependencies at all.
Example Code
### Normal Renderer
Very easy to use, here's an example without error handling:
#include <ssfn.h>
ssfn_t ctx; /* the renderer context */
ssfn_glyph_t *glyph; /* the returned rasterized bitmap */
/* you don't need to initialize the library, just make sure the context is zerod out */
memset(&ctx, 0, sizeof(ssfn_t));
/* add one or more fonts to the context. Fonts must be already in memory */
ssfn_load(&ctx, &_binary_times_sfn_start); /* you can add different styles... */
ssfn_load(&ctx, &_binary_timesbold_sfn_start);
ssfn_load(&ctx, &_binary_timesitalic_sfn_start);
ssfn_load(&ctx, &_binary_emoji_sfn_start); /* ...or different UNICODE ranges */
ssfn_load(&ctx, &_binary_cjk_sfn_start);
/* select the typeface to use */
SSFN_MODE_BITMAP /* rendering mode */
/* rasterize a glyph for the 0x41 UNICODE code point into a newly allocated bitmap */
glyph = ssfn_render(&ctx, 0x41);
/* display the bitmap on your screen */
pen_x, pen_y - glyph->baseline, /* coordinates to draw to */
glyph->w, glyph->h, glyph->pitch, /* bitmap dimensions */
&glyph->data /* bitmap data */
pen_x += glyph->adv_x; /* adjust the cursor */
pen_y += glyph->adv_y; /* ssfn handles vertical fonts too */
/* free resources */
free(glyph); /* no special treatment for freeing glyphs */
ssfn_free(&ctx); /* free the renderer context's internal buffers */
There's more, you can select font by it's name and you can also query kerning info for example, read the
[API reference](
To keep the memory footprint of this renderer small, it can render glyphs up to 255 x 255 pixels. (Note
this is a limitation of this particular renderer implementation, the SSFN format is capable of storing
glyph data with 4096 x 4096 grid point precision just fine.)
An example `my_draw_glyph()` for SDL can be found [here](
### Simple Renderer
#define SSFN_NOIMPLEMENTATION /* don't include the normal renderer implementation */
#define SSFN_CONSOLEBITMAP_HICOLOR /* use the special renderer for hicolor packed pixels */
#include <ssfn.h>
/* set up context by global variables */
ssfn_font = &_binary_console_sfn_start; /* the bitmap font to use */
ssfn_dst_ptr = 0xE0000000; /* framebuffer address and bytes per line */
ssfn_dst_pitch = 4096;
ssfn_fg = 0xFFFF; /* colors, white on black */
ssfn_bg = 0;
ssfn_x = 100; /* coordinates to draw to */
ssfn_y = 200;
/* render one glyph directly to the screen and then adjust ssfn_x and ssfn_y */
As you see this renderer implementation is very simple, extremely small (less than 1k). It can only render
bitmap fonts. It does not allocate memory or need libc. It can't scale, but it can handle proportional fonts
(like 8x16 for Latin letters, and 16x16 for CJK ideograms), so you can implement a true UNICODE console with
this renderer.
Both the renderers and the converter utilities are licensed under the terms of MIT license in the hope that
they will be useful.
IMPORTANT NOTE: although the renderers and the file format is licensed under MIT, it is possible that the font
stored in a SSFN file is NOT! Always consult the license field in the font's header! See `sfn2asc -h`.
The simple renderer calls no functions at all and therefore has no dependencies whatsoever (not even libc
or compiler built-ins). Absolutely nothing save for it's global variables.
As for the normal renderer (all dependencies are provided as built-ins by gcc):
- standard C integer defines from stdint.h
- `realloc()` and `free()` from libc (stdlib.h)
- `memcmp()` and `memset()` from libc (string.h)
The scalable font converter is built on the freetype2 library to read vector font files. The bitmap font
converter has no dependencies other than libc, but can be built optionally with zlib to read and write LZW
compressed (gzip deflate) files on-the-fly.
The test applications use SDL2 to create a window and display the rendered texts.
Known Bugs
Not that I know of. But no programmer can test their own code properly. I've run SSFN renderer through valgrind
with many different font files with all the tests without problems. If you find a bug, please use the Issue
Tracker on gitlab and let me know.
Future Development (Whishlist)
The bitmap compressor works with the fragments as it reads them. It would be much better to read all fragments
first and only afterwards find the best matches to achieve a magnitude better compression rate. Now accents are
only stored separately if a plain letter comes first (like "Á" only splitted into "'" and an "A" if there was a
bitmap for "A" already).
The [autohinting]( code is very very basic
at the moment, it only use one axis partitions instead of boxes.
A portable SSFN editor with GUI. I'm already on it.
SSFN format, converters and renderers: bzt
Scalable Screen Font Renderer API
Font Metrics
Before you can use any font renderer, you must be familiar with its font metrics:
................. ^
___................. | bearing top
^ ,,,,,,,,,,,,,,,,,______v
| ....:.XXX.XX:.... ^ ^ ^
size | ....:XX..XX.:.... | | |
| ....:XX..XX.:.... | | | horizontal baseline
| ....:XX..XX.:.... | | |
| ....:XX..XX.:.... | | |
| ....:XX..XX.:.... | | |
....:....XX.:.... | |
....|XX..XX.:.... | | glyph height
....:...:...:.... |
....:...:...:.... | advance y
| | | | | (font width, font height)
| | | | |
| |<->| | | vertical baseline (center of the glyph, always width / 2)
| |<----->| | glyph width
| |<------->| advance x
| |<---->| advance x with kerning x
|<->| bearing left
Glyphs must be aligned on `baseline`. When displaying, horizontal baseline must be
substracted from current pen y position, or when advance y is not zero, then vertical
baseline must be substracted from pen x.
The `advance` tells how much you should move your pen (cursor pointer) after the glyph is
drawn on screen (usually not the same as font width). It typically equals to width plus a
little, or in case of vertical letters (when advance y is not zero), height plus a little.
`Kerning` is very similar to advance, but it tells how much you should move your cursor
if the next character is a particular one. For example the advance is different for 'f'
if it's followed by 'M' or an 'i'. The advance is bigger for 'fM' and smaller for 'fi'.
`Size` is how SSFN specifies a glyph's size. It's from the bearing top minimum of all
glyphs to the horizontal baseline. This in unortodox, but guarantees that you get
approximately similar sized glyphs regardless to font metrics and quality (I hate when
I get totally different pixel sizes for different TTF fonts when I ask for the same size).
Passing `SSFN_STYLE_ABS_SIZE` will avoid this scheme, and will scale the glyph's height
to size as usual in other renderers.
Because the renderer is a single ANSI C header file, no shared library needed. It depends
only on libc memory allocation, nothing else. You can configure the renderers by defining
special defines.
/* configure the renderer here with defines */
#include <ssfn.h>
Once you have the include, you can start using the library, no need for initialization, but you must
make sure that the initial context is zerod out (by putting it in the bss segment it will be, or call
memset zero manually).
As my favourite principle is K.I.S.S., there're only a few, clearly named functions in the API:
- load one or more fonts into the context using `ssfn_load` on program start.
- set up rendering configuration by specifing font family, style, size and rendering mode with `ssfn_select`.
- if you want to change the size for example, you can call `ssfn_select` again, no need to load the fonts again.
- use `ssfn_utf8` to decode an UTF-8 multibyte character into UNICODE code point.
- call `ssfn_render` to rasterize a glyph in the given style and size for that UNICODE code point.
- draw the returned bitmap on your screen at cursor position.
- move the cursor by the returned advance offsets.
- repeat the last 4 steps until you reach the end of the UTF-8 string.
- when not needed any more, free the rasterized glyphs
- when done with rendering, call `ssfn_free`.
Do not include the normal renderer implementation, only the file format defines and function prototypes.
Only one of these can be specified at once. These include the simple renderer which is totally independent
from the rest of the API. It is a very specialized renderer, limited and optimized for OS kernel consoles.
Variable Types
| typedef | Description |
| -------------- | ----------- |
| `ssfn_t` | the renderer context, it's internals are irrelevant |
| `ssfn_font_t` | the font stucture, same as the [SSFN file header]( |
| `ssfn_glyph_t` | the returned rasterized glyph (see `ssfn_render()`) |
| `int` | the returned error code (if any) |
Error Codes
Most functions return an integer error code. If not, then you can query the last error code with `ssfn_lasterr(ctx)`.
To get the human readable string representation of the error code in English, use `ssfn_error(errcode)`.
| Error | Numeric | Description |
| ------------------- | ------: | ----------- |
| `SSFN_OK` | 0 | success |
| `SSFN_ERR_ALLOC` | 1 | memory allocation error |
| `SSFN_ERR_NOFACE` | 2 | no font face selected, call `ssfn_select()` first |
| `SSFN_ERR_INVINP` | 3 | invalid input parameter (usually a NULL pointer) |
| `SSFN_ERR_BADFILE` | 4 | bad SSFN file format |
| `SSFN_ERR_BADSTYLE` | 5 | unsupported style |
| `SSFN_ERR_BADSIZE` | 6 | unsupported size |
| `SSFN_ERR_BADMODE` | 7 | unsupported mode |
| `SSFN_ERR_NOGLYPH` | 8 | glyph (or it's kerning info) not found |
Normal Renderer Functions
The following functions are only available if the header is included without `SSFN_NOIMPLEMENTATION` define.
They allocate memory and therefore depend on libc (or crafted compilers like gcc have all four functions
as built-ins), hence are expected to be used by normal user space applications. If you really want to use
this renderer from a kernel, you can replace all dependent functions with your own implemenations using the
following defines:
#define SSFN_memcmp memcmp
#define SSFN_memset memset
#define SSFN_realloc realloc
#define SSFN_free free
If you don't specify these, then the SSFN header will try to figure it out if they are supported as built-ins
or provided by libc.
That's all, no more dependencies. :-)
int ssfn_load(ssfn_t *ctx, ssfn_font_t *font);
Loads a font into the renderer context.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| ctx | pointer to the renderer's context |
| font | pointer to an in memory font |
You can load an SSFN file and pass it's address, or you can also use `ld -b binary` to convert an SSFN file
into an object and link that with your code. In this case you'll have a `_binary_(filename)_start` label.
## Return value
Error code. `SSFN_ERR_BADFILE` means bad (incorrect or inconsistent) SSFN format. Hint: use `sfn2asc -d` to
debug what's wrong with it.
int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size, int mode);
Sets up renderer context to use a particular font family, style, size and rendering mode.
In `SSFN_MODE_OUTLINE`, the font's grid is scaled to `size`. In other modes the difference
of bounding box and the baseline is scaled. In other words, if you set `size` to 32, then
you'll get an exatly 32 pixel tall 'A', see Font Metrics above. Passing `SSFN_STYLE_ABS_SIZE`
will scale the glyph's height to `size`. This is also the default for monospace fonts.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| ctx | pointer to the renderer's context |
| family | font family group, see below |
| name | pointer to an UTF-8 string with font's unique name if family is `SSFN_FAMILY_BYNAME` |
| style | one or more font style defines OR'd together, see below |
| size | rendered font's size in pixels, from 8 to 255 (sizes smaller than 16 are not readable very much) |
| mode | rendering mode, see below |
Parameter defines:
| family | Description |
| ----------------------- | ----------- |
| `SSFN_FAMILY_SERIF` | selects Serif fonts (letters with "feet", like Times New Roman) |
| `SSFN_FAMILY_SANS` | selects Sans Serif fonts (letters without "feet", like Helvetica) |
| `SSFN_FAMILY_DECOR` | selects Decorative fonts (like Dingbats or Fraktur) |
| `SSFN_FAMILY_MONOSPACE` | selects Monospace fonts (like Fixed or GNU unifont) |
| `SSFN_FAMILY_HAND` | selects Handwriting fonts (like Cursive) |
| `SSFN_FAMILY_ANY` | don't care, pick the first font which has the glyph |
| `SSFN_FAMILY_BYNAME` | use the `name` field to select precisely one font |
| style | Description |
| ----------------------- | ----------- |
| `SSFN_STYLE_REGULAR` | regular style |
| `SSFN_STYLE_BOLD` | bold weight. If no font found, the renderer will mimic bold |
| `SSFN_STYLE_ITALIC` | italic or oblique slant. If no font found, the renderer will transform glyphs to make them italic |
| `SSFN_STYLE_UNDERLINE` | under line glyphs. This is not stored in fonts, always generated |
| `SSFN_STYLE_STHROUGH` | strike-through glyphs. Not stored either, always generated |
| `SSFN_STYLE_NOHINTING` | don't use hinting grid, outline will be blurry but typeface correct |
| `SSFN_STYLE_ABS_SIZE` | use absolute size (glyph's total height will be scaled to size) |
| [mode]( | Description |
| ----------------------- | ----------- |
| `SSFN_MODE_NONE` | do not render the glyph, just select the font (see kerning below) |
| `SSFN_MODE_OUTLINE` | return the glyph's outline |
| `SSFN_MODE_BITMAP` | rasterize glyph as bitmap, 1 bit for each pixel |
| `SSFN_MODE_ALPHA` | rasterize glyph as an alpha channel, 1 byte for each pixel |
| `SSFN_MODE_CMAP` | rasterize in color map mode, 1 byte for each pixel (see `SSFN_CMAP_TO_RGBA()` macro) |
## Return value
Error code. `SSFN_ERR_NOFACE` returned if no font could be found, otherwise `SSFN_ERR_BADx` refers to
the invalid argument.
uint32_t ssfn_utf8(char **str);
Decodes an UTF-8 multibyte character. Be careful, this function does not check its input, expects that pointer is
valid and points to a string with only valid UTF-8 sequences. The behaviour with invalid input is undefined. All
the other functions check for valid input, this is an exception.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| str | pointer to a UTF-8 string pointer |
## Return value
UNICODE code point, and `str` pointer adjusted to the next multibyte sequence.
ssfn_glyph_t *ssfn_render(ssfn_t *ctx, uint32_t unicode);
Render a glyph. It is possible to load more fonts with different UNICODE code range coverage, the
renderer will pick the ones which have a glyph defined for `unicode`. If more fonts have glyphs for this
character, then the renderer will look for the best style match to figure out which font to use, unless
you've asked for a specific font with `SSFN_FAMILY_BYNAME`. If there's no font for the requested style,
then the renderer will mimic bold or italic.
## Parameters
| Parameter | Description |
| ----------- | ----------- |
| ctx | pointer to the renderer's context |
| unicode | UNICODE code point of the character to be rendered (see `ssfn_utf8()`) |
## Return value
Returns `NULL` on error (and you can get the error code with `ssfn_lasterr(ctx)`. On success, it returns a newly
allocated `ssfn_glyph_t` structure.
| ssfn_glyph_t | Description |
| ------------ | ----------- |
| mode | equals to the selected mode, specifies the format of the data buffer |
| baseline | the baseline of the glyph in pixels (1) |
| w | width of the rendered glyph in pixels |
| h | height of the rendered glyph in pixels |
| adv_x | advance x, you should add this to your cursor poisiton after draw |
| adv_y | advance y |
| pitch | number of bytes per lines in the data buffer, or number of outline coordinates |
| cmap | if mode `SSFN_MODE_CMAP`, then pointer to a color map, otherwise `NULL` |
| data | rendered glyph outline / bitmap / pixmap data, it's `pitch` times `h` bytes |
Note(1): if advance y is not zero, then it's the vertical baseline, otherwise it's the horizontal.
If mode is `SSFN_MODE_NONE`, then it will not render anything, it just selects the font with the best match
and returns NULL. This mode is useful to select a font for kerning (see `ssfn_kern()`).
Otherwise you should iterate on the `data` array `h` times, starting at offset 0 and adding `pitch` to the
pointer for every row. Within a row, you should extract `w` pixels for each row. The description of how to
decode the data can be found in [](
I suggest to store the returned glyph in a cache. Once you've done with it, you can free the glyph with a
standard libc `free()` call, no special treatment needed.
int ssfn_kern(ssfn_t *ctx, uint32_t unicode, uint32_t nextunicode, int *x, int *y);
Apply the relative advance modifier for two UNICODE code points. This will use the kerning info in
the font that was last used by `ssfn_render`, meaning you have to render at least one glyph apriori
to get valid results. For this purpose, you can pass `SSFN_MODE_NONE` to the renderer (or use
`SSFN_FAMILY_BYNAME` to select exactly one font, and then you don't have to call ssfn_render). If
the character or the kerning pair not found, `x`and `y` will be left unchanged.
## Parameters
| Parameter | Description |
| ----------- | ----------- |
| ctx | pointer to the renderer's context |
| unicode | UNICODE code point of the current character (on the left or above) |
| nextunicode | UNICODE code point of the next character (on the right or below) |
| x | pointer to a signed integer, relative coordinate in pixels |
| y | pointer to a singed integer, relative coordinate in pixels |
## Return value
Error code, and relative kerning offsets adjusted to `x` and `y`.
int ssfn_mem(ssfn_t *ctx);
Returns how much memory a particular renderer context consumes. It is typically less than 32k, but strongly depends
on how complex a font is (how many contour commands it has) and how big glyphs you're rendering. When the renderer
is rasterizing a new character which requires less memory than the previous one, then no memory allocation will
take place, the existing buffers will be reused. Internal buffers can be freed with `ssfn_free()`.
The contour coordinates are internally stored on 2 bytes, with 4096 x 4096 grid system and 0 - 15 precision
(12 + 4 bits). Rasterization and hinting also use 2 bytes per pixel, but in a 256 x 256 grid and 0 - 255
precision (8 + 8 bits), and there's a separate raster line for each row.
## Parameters
| Parameter | Description |
| ----------- | ----------- |
| ctx | pointer to the renderer's context |
## Return value
Total memory consumed in bytes.
void ssfn_free(ssfn_t *ctx);
Destructor of the renderer context. Frees all internal buffers and clears the context.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| ctx | pointer to the renderer's context |
## Return value
int ssfn_lasterr(ssfn_t *ctx)
Returns the error code for the last error occured. Passing a NULL to this function results in
an undefined behaviour, because it's implemented as a macro.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| ctx | pointer to the renderer's context |
## Return value
The error code or `SSFN_OK` if there was no error.
const char *ssfn_error(int errcode)
Returns the human readable string equivalent of an error code in English. Also implemented as a macro.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| errcode | error code |
## Return value
Pointer to a string constant. `SSFN_OK` returns an empty string, not NULL nor "Success".
Simple Renderer Function
The following function is only available if the header is included with one of the `SSFN_CONSOLEBITMAP_x` defines
(independently to `SSFN_NOIMPLEMENTATION`).
This is a very specialized renderer that renders directly to the screen and does not use ssfn_t context. It operates
on one font only, can't scale or dynamically style the glyph, and it can only handle bitmap fonts. It doesn't care
about baseline, but it handles advances. For these limitations in return it does not allocate memory at all, has
exactly zero dependency and compiles to about 1 kilobyte.
int ssfn_putc(uint32_t unicode);
Render a character to screen. Unlike the functions in the normal renderer, this function does not check its input,
passing invalid parameters results in an undefined behaviour. This is as simple as it gets.
## Parameters
| Parameter | Description |
| --------- | ----------- |
| unicode | UNICODE code point to render |
Configuration is passed to it in global variables (exclusive to this function, the normal renderer does not use them):
| Global Variable | Description |
| -------------------------- | ----------- |
| `ssfn_font_t *ssfn_font` | pointer to an SSFN font with bitmap glyphs only |
| `uint8_t *ssfn_dst_ptr` | the destination buffer's address (probably the linear frame buffer, but could be off-screen) |
| `uint32_t ssfn_dst_pitch` | the destination buffer's bytes per lines |
| `uint32_t ssfn_dst_w` | the desitnation buffer's width in pixels (optional) |
| `uint32_t ssfn_dst_h` | the desitnation buffer's height in pixels (optional) |
| `uint32_t ssfn_fg` | the foreground color in destination buffer's native format |
| `uint32_t ssfn_bg` | the background color |