Scalable Screen Font: Difference between revisions
[unchecked revision] | [unchecked revision] |
m Added text directions |
m Bot: Replace deprecated source tag with syntaxhighlight |
||
(10 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
Scalable Screen Font is a compressed font format which comes with a small, free, MIT licensed rendering library. It was designed specially for hobby OS developers, therefore it has minimal dependencies. |
Scalable Screen Font is a compressed font format which comes with a small, free, MIT licensed rendering library. It was designed specially for hobby OS developers, therefore it has minimal dependencies. It is also floating-point arithmetic free, so it will work even if your kernel hasn't initialized the FPU or SSE yet. |
||
= Supported Font Types = |
= Supported Font Types = |
||
* Bitmap - you can convert [[PC Screen Font]] with UNICODE table into SSFN directly. X11 Bitmap Distribution Format also supported. |
* Bitmap - you can convert [[PC Screen Font]] with UNICODE table into SSFN directly. X11 Bitmap Distribution Format, Portable Compiled Fonts and Windows FNT/FON files are also supported. |
||
* Pixmap - to have colorful emoji icons, you can convert TGA files into SSFN fonts. |
* Pixmap - to have colorful emoji icons, you can convert TGA and PNG files into SSFN fonts. |
||
* Vector - vector based fonts can be converted from OpenType and TrueType fonts. |
* Vector - vector based fonts can be converted from PostScript Type1, OpenType and [[TrueType_Fonts|TrueType fonts]]. |
||
Fonts are compressed, and in case of vector fonts, with a data-loss compression |
Fonts are compressed, and in case of vector fonts, with a data-loss compression. With a typical OpenType file, the SSFN font usually takes only the half the file size (or less). |
||
= Library = |
= Library = |
||
The SSFN package comes with a single ANSI C/C++ header file, which has two renderers. The header contains everything, no shared library nor static linking needed. |
The SSFN package comes with a single ANSI C/C++ header file, which has two renderers. The header contains everything, no shared library nor static linking needed. They are compatible with both [[VESA]] and [[GOP]] framebuffers. |
||
== Simple Renderer == |
== Simple Renderer == |
||
Designed specially for OS consoles, has only one function. It can render unscaled bitmap fonts directly to the framebuffer. Has absolutely no dependencies, and compiles to less than |
Designed specially for OS consoles, has only one function. It can render unscaled bitmap fonts directly to the framebuffer. Has absolutely no dependencies, and compiles to less than two kilobytes of code. |
||
< |
<syntaxhighlight lang="c"> |
||
#define |
#define SSFN_CONSOLEBITMAP_TRUECOLOR /* use the special renderer for 32 bit truecolor packed pixels */ |
||
#define SSFN_CONSOLEBITMAP_HICOLOR /* use the special renderer for hicolor packed pixels */ |
|||
#include <ssfn.h> |
#include <ssfn.h> |
||
/* set up context by global variables */ |
/* set up context by global variables */ |
||
ssfn_src = &_binary_console_sfn_start; /* the bitmap font to use */ |
|||
ssfn_dst.ptr = 0xE0000000; /* framebuffer address and bytes per line */ |
|||
ssfn_dst.p = 4096; |
|||
ssfn_dst.fg = 0xFFFFFFFF; /* colors, white on black */ |
|||
ssfn_dst.bg = 0; |
|||
ssfn_dst.x = 100; /* coordinates to draw to */ |
|||
ssfn_dst.y = 200; |
|||
/* render |
/* render text directly to the screen and then adjust ssfn_dst.x and ssfn_dst.y */ |
||
ssfn_putc( |
ssfn_putc('H'); |
||
ssfn_putc('e'); |
|||
</source> |
|||
ssfn_putc('l'); |
|||
ssfn_putc('l'); |
|||
ssfn_putc('o'); |
|||
</syntaxhighlight> |
|||
== Normal Renderer == |
== Normal Renderer == |
||
There's another for user space applications. This one can render all three types of fonts, it can scale, |
There's another for user space applications. This one can render all three types of fonts, supports gzip compressed fonts, it can scale, anti-alias and kern glyphs. Has minimal libc dependencies (memset, memcmp, realloc, free) and compiles to about 28 kilobytes of code. (Just for completeness, you can compile it in total dependency-free mode if you define SSFN_MAXLINES, but then there'll be no internal glyph cache and you must provide inflated fonts only to ssfn_load().) |
||
< |
<syntaxhighlight lang="c"> |
||
#define SSFN_IMPLEMENTATION /* use the normal renderer implementation */ |
|||
#include <ssfn.h> |
#include <ssfn.h> |
||
ssfn_t ctx; /* the renderer context */ |
ssfn_t ctx; /* the renderer context */ |
||
ssfn_buf_t buf; /* the destination pixel buffer */ |
|||
/* you don't need to initialize the library, just make sure the context is zerod out */ |
/* you don't need to initialize the library, just make sure the context is zerod out */ |
||
Line 58: | Line 62: | ||
ssfn_select(&ctx, |
ssfn_select(&ctx, |
||
SSFN_FAMILY_SERIF, NULL, /* family */ |
SSFN_FAMILY_SERIF, NULL, /* family */ |
||
SSFN_STYLE_REGULAR | SSFN_STYLE_UNDERLINE, |
SSFN_STYLE_REGULAR | SSFN_STYLE_UNDERLINE, /* style */ |
||
64 /* size */ |
|||
); |
); |
||
/* describe the destination buffer. Could be a 32 bit linear framebuffer as well */ |
|||
/* rasterize a glyph for the 0x41 UNICODE code point into a newly allocated bitmap */ |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
/* rasterize the first glyph in an UTF-8 string into a 32 bit packed pixel buffer. Returns how many bytes were consumed from the string */ |
|||
/* display the bitmap on your screen */ |
|||
ssfn_render(&ctx, &buf, "Hello"); |
|||
my_draw_glyph( |
|||
ssfn_render(&ctx, &buf, "ello"); |
|||
pen_x, pen_y - glyph->baseline, /* coordinates to draw to */ |
|||
ssfn_render(&ctx, &buf, "llo"); /* assuming there's a ligature for "ll" in the font */ |
|||
glyph->w, glyph->h, glyph->pitch, /* bitmap dimensions */ |
|||
⚫ | |||
⚫ | |||
); |
|||
⚫ | |||
⚫ | |||
/* free resources */ |
/* free resources */ |
||
free(glyph); /* no special treatment for freeing glyphs */ |
|||
ssfn_free(&ctx); /* free the renderer context's internal buffers */ |
ssfn_free(&ctx); /* free the renderer context's internal buffers */ |
||
</syntaxhighlight> |
|||
</source> |
|||
The renderer takes care of the font direction, it uses horizontal or vertical alignment automatically. It cannot determine right-to-left though, for that you'll need |
|||
⚫ | a minimal BiDi state machine too. That has to be implemented in the text renderer (or text shaping library) that's built on top of the low level rasterizer. The [http://www.unicode.org/reports/tr9/ algorithm to properly display bidirectional texts] is specified by UNICODE. But once you have decided that you need to draw a glyph in right-to-left direction, just pass SSFN_STYLE_RTL to ssfn_select(). |
||
=== Left-to-right text === |
|||
This is the default. Left to right requires nothing special, only to subtract baseline and add the advance value to your current pen position. |
|||
<source lang="c"> |
|||
my_draw_glyph(pen_x, pen_y - glyph->baseline, ...); /* position the glyph vertically */ |
|||
⚫ | |||
</source> |
|||
=== Vertical text === |
|||
To display vertical fonts properly, you should subtract the baseline from the X coordinate before you draw. |
|||
<source lang="c"> |
|||
my_draw_glyph(pen_x - glyph->baseline, pen_y, ...); /* position the glyph horizontally */ |
|||
⚫ | |||
</source> |
|||
=== Right-to-left text === |
|||
⚫ | |||
<source lang="c"> |
|||
my_draw_glyph(pen_x - glyph->w, pen_y, ...); /* subtract the glyph's width first */ |
|||
pen_x -= glyph->adv_x; /* and subtract the advance instead of adding */ |
|||
</source> |
|||
Putting every direction variations all together: |
|||
<source lang="c"> |
|||
if(glyph->adv_y) { /* things to temporarily adjust before drawing */ |
|||
x = pen_x - glyph->baseline; |
|||
y = pen_y; |
|||
} else { |
|||
x = pen_x; |
|||
y = pen_y - glyph->baseline; |
|||
} |
|||
if(rtl) |
|||
x -= glyph->w; |
|||
my_draw_glyph(x, y, ...); |
|||
⚫ | |||
pen_x -= glyph->adv_x; |
|||
else |
|||
pen_x += glyph->adv_x; |
|||
pen_y += glyph->adv_y; |
|||
</source> |
|||
= Links = |
= Links = |
||
Line 134: | Line 93: | ||
== External Links == |
== External Links == |
||
* [https://forum.osdev.org/viewtopic.php?f=2&t=33719 OSDEV forum] on Scalable Screen Fonts |
* [https://forum.osdev.org/viewtopic.php?f=2&t=33719 OSDEV forum] on Scalable Screen Fonts |
||
* https://gitlab.com/bztsrc/scalable- |
* https://gitlab.com/bztsrc/scalable-font2 source code repository |
||
* [https://gitlab.com/bztsrc/scalable- |
* [https://gitlab.com/bztsrc/scalable-font2/blob/master/docs/sfn_format.md .sfn file format] description |
||
* [https://gitlab.com/bztsrc/scalable- |
* [https://gitlab.com/bztsrc/scalable-font2/blob/master/docs/API.md SSFN API] documentation |
||
[[Category:Graphical UI]] |
|||
[[Category:Fonts]] |
Latest revision as of 05:46, 9 June 2024
Scalable Screen Font is a compressed font format which comes with a small, free, MIT licensed rendering library. It was designed specially for hobby OS developers, therefore it has minimal dependencies. It is also floating-point arithmetic free, so it will work even if your kernel hasn't initialized the FPU or SSE yet.
Supported Font Types
- Bitmap - you can convert PC Screen Font with UNICODE table into SSFN directly. X11 Bitmap Distribution Format, Portable Compiled Fonts and Windows FNT/FON files are also supported.
- Pixmap - to have colorful emoji icons, you can convert TGA and PNG files into SSFN fonts.
- Vector - vector based fonts can be converted from PostScript Type1, OpenType and TrueType fonts.
Fonts are compressed, and in case of vector fonts, with a data-loss compression. With a typical OpenType file, the SSFN font usually takes only the half the file size (or less).
Library
The SSFN package comes with a single ANSI C/C++ header file, which has two renderers. The header contains everything, no shared library nor static linking needed. They are compatible with both VESA and GOP framebuffers.
Simple Renderer
Designed specially for OS consoles, has only one function. It can render unscaled bitmap fonts directly to the framebuffer. Has absolutely no dependencies, and compiles to less than two kilobytes of code.
#define SSFN_CONSOLEBITMAP_TRUECOLOR /* use the special renderer for 32 bit truecolor packed pixels */
#include <ssfn.h>
/* set up context by global variables */
ssfn_src = &_binary_console_sfn_start; /* the bitmap font to use */
ssfn_dst.ptr = 0xE0000000; /* framebuffer address and bytes per line */
ssfn_dst.p = 4096;
ssfn_dst.fg = 0xFFFFFFFF; /* colors, white on black */
ssfn_dst.bg = 0;
ssfn_dst.x = 100; /* coordinates to draw to */
ssfn_dst.y = 200;
/* render text directly to the screen and then adjust ssfn_dst.x and ssfn_dst.y */
ssfn_putc('H');
ssfn_putc('e');
ssfn_putc('l');
ssfn_putc('l');
ssfn_putc('o');
Normal Renderer
There's another for user space applications. This one can render all three types of fonts, supports gzip compressed fonts, it can scale, anti-alias and kern glyphs. Has minimal libc dependencies (memset, memcmp, realloc, free) and compiles to about 28 kilobytes of code. (Just for completeness, you can compile it in total dependency-free mode if you define SSFN_MAXLINES, but then there'll be no internal glyph cache and you must provide inflated fonts only to ssfn_load().)
#define SSFN_IMPLEMENTATION /* use the normal renderer implementation */
#include <ssfn.h>
ssfn_t ctx; /* the renderer context */
ssfn_buf_t buf; /* the destination pixel buffer */
/* 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_select(&ctx,
SSFN_FAMILY_SERIF, NULL, /* family */
SSFN_STYLE_REGULAR | SSFN_STYLE_UNDERLINE, /* style */
64 /* size */
);
/* describe the destination buffer. Could be a 32 bit linear framebuffer as well */
buf.ptr = sdlsurface->pixels; /* address of the buffer */
buf.w = sdlsurface->w; /* width */
buf.h = sdlsurface->h; /* height */
buf.p = sdlsurface->pitch; /* bytes per line */
buf.x = buf.y = 100; /* pen position */
buf.fg = 0xFF808080; /* foreground color */
/* rasterize the first glyph in an UTF-8 string into a 32 bit packed pixel buffer. Returns how many bytes were consumed from the string */
ssfn_render(&ctx, &buf, "Hello");
ssfn_render(&ctx, &buf, "ello");
ssfn_render(&ctx, &buf, "llo"); /* assuming there's a ligature for "ll" in the font */
ssfn_render(&ctx, &buf, "o");
/* free resources */
ssfn_free(&ctx); /* free the renderer context's internal buffers */
The renderer takes care of the font direction, it uses horizontal or vertical alignment automatically. It cannot determine right-to-left though, for that you'll need a minimal BiDi state machine too. That has to be implemented in the text renderer (or text shaping library) that's built on top of the low level rasterizer. The algorithm to properly display bidirectional texts is specified by UNICODE. But once you have decided that you need to draw a glyph in right-to-left direction, just pass SSFN_STYLE_RTL to ssfn_select().
Links
See Also
External Links
- OSDEV forum on Scalable Screen Fonts
- https://gitlab.com/bztsrc/scalable-font2 source code repository
- .sfn file format description
- SSFN API documentation