fcft_from_name(3)

๐Ÿ’– fcft_from_name(3) โ€” the manual page, but make it make sense

okay so bestie, welcome to the fcft_from_name(3) page from the fcft manual set ๐ŸŽ€ this is the one that spawns a whole entire font for you, and honestly? it's giving main character energy. let's get into it โœจ


๐ŸŒธ NAME ๐ŸŒธ

fcft_from_name โ€” instantiate a new font ๐Ÿ’…

like, literally make a font exist. out of nothing. from a name. iconic.


๐Ÿฆ‹ SYNOPSIS ๐Ÿฆ‹

#include <fcft/fcft.h>

struct fcft_font *fcft_from_name(
    size_t count, const char *names[static count], const char
    *attributes);

โœจ DESCRIPTION โœจ

So fcft_from_name() instantiates a new fcft font object from FontConfig-formatted font names. The first element in names is the primary font, and the remaining elements (if there are any) are fallback fonts. That's the whole vibe. ๐Ÿ’ซ

You must supply at least one font name. Non-negotiable, bestie. ๐Ÿ™…โ€โ™€๏ธ

All aspects of the font โ€” size, DPI, variant, etc. โ€” are configured through the font name, using colon separated attribute=value pairs, e.g. "Serif:size=26:slant=italic". colon-separated king behavior fr fr ๐Ÿ‘‘

attributes is a convenient way to apply a set of attributes to all fonts in names. attributes may be NULL, in which case no extra attributes are appended to the strings in names. no notes, slay ๐Ÿซถ

The font size is set as part of the font name, e.g. Helvetica:size=12, or Helvetica:pixelsize=12. pick your fighter.

To implement desktop scaling, simply multiply the font's size with the desktop scaling factor. math girlies rise ๐Ÿงฎโœจ

The primary font will be instantiated immediately, and any failure to do so will result in an error. periodt. Fallback fonts are instantiated on demand, and any failure to do so will result in that fallback font being ignored, and the next one in the list is tried instead. fallback chain said "next!!" ๐Ÿ’€


๐Ÿ‘‘ RETURN VALUE ๐Ÿ‘‘

On success, fcft_from_name() returns a pointer to an allocated fcft_font object. On error, NULL is returned. no in-between, no "it's complicated."

struct fcft_font {
    int height;
    int descent;
    int ascent;

    struct {
        int x;
        int y;
    } max_advance;

    struct {
        int x;
        int y;
    } space_advance;

    struct {
        int position;
        int thickness;
    } underline;

    struct {
        int position;
        int thickness;
    } strikeout;
};

okay let's go field by field, because every single one matters ๐Ÿ”

  • height โ€” the line height, in pixels. ๐Ÿ“
  • descent โ€” the distance between the baseline and the font's lowest descending glyph, in pixels. In fcft's case, it is generally positive (a negative value means the descent stretches up from the baseline). ๐Ÿ™ƒ
  • ascent โ€” the distance between the baseline and the font's highest ascending glyph, in pixels. Generally a positive number (a negative value means the ascent stretches down below the baseline). upsidedown core ๐ŸŒ€
  • ascent + descent is often the same as height, but not necessarily!! height may be larger, meaning the font intentionally adds extra (vertical) space between lines. Or it may be smaller, in which case lines overlap. overlap?? bold choice, but okay ๐Ÿ’€
  • max_advance โ€” the amount, in pixels, the font's widest glyph advances the pen position; x for a horizontal layout, and y for a vertical layout. widest glyph said "I'll take it from here" ๐Ÿ”ฅ
  • space_advance โ€” the amount, in pixels, the glyph for space (0x20) advances the pen position; x for a horizontal layout, and y for a vertical layout. yeah the space bar has lore now ๐Ÿซถ
  • underline โ€” describes how to render underlines. position is the distance, in pixels, from the baseline. A positive value means above the baseline, and a negative value means below the baseline. thickness is the line's thickness, in pixels. underline girlies understand ๐ŸŽ€
  • strikeout โ€” describes how to render strikeouts. See underline for a description of its members. same energy, different line โœ‚๏ธ

๐ŸŒˆ EXAMPLE ๐ŸŒˆ

In this example, we instantiate Times New Roman at a point size of 8 as the primary font.

We also tell it to use Serif Bold (point size 10) as a fallback font โ€” ngl, it is usually better to let FontConfig handle fallback to generic fonts like this. just a lil tip from the original, not me being bossy ๐Ÿ’…

Furthermore, both fonts will be Italic, and will be using DPI=140. fancy.

We then proceed to render the string hello world. You are assumed to know how to create and use a pixman image. This example only shows how one can use fcft to instantiate a font, rasterize glyphs and then blend them onto a target pixman image. you got this, i believe in you ๐Ÿงš

#include <stdlib.h>
#include <uchar.h>
#include <fcft/fcft.h>

int
main(void)
{
    setlocale(LC_CTYPE, "en_US.UTF-8");

    if (!fcft_set_scaling_filter(FCFT_SCALING_FILTER_LANCZOS3))
       return EXIT_FAILURE;

    struct fcft_font *font = fcft_from_name(
        2,
        (const char *[]){
            "Times New Roman:size=8",
            "Serif:size=10:weight=bold",
        },
        "slant=italic:dpi=140");

    if (font == NULL)
        return EXIT_FAILURE;

    /* Here you need to instantiate a 'target' pixman image, to blend
       with */
    pixman_image_t *canvas = ...;

    /* String to print */
    static const char32_t const hello[] = U"hello world";

    /*
     * Pen position in canvas. The numbers chosen here are more or less
     * random. Note however, that the composite calls below assume 'y'
     * is the font's baseline (and thus the glyphs will be rendered
     * above 'y')
     */
    struct {
        int x;
        int y;
    } pen = {.x = 25, .y = 50};

    /* Glyphs will be rendered in white */
    pixman_image_t *color = pixman_image_create_solid_fill(
        &(struct pixman_color_t){
            .red = 0xffff,
            .green = 0xffff,
            .blue = 0xffff,
            .alpha = 0xffff,
        });

    for (size_t i = 0; i < sizeof(hello) / sizeof(hello[0]) - 1; i++) {
        const struct fcft_glyph *glyph = fcft_codepoint_rasterize(
            font, hello[i], FCFT_SUBPIXEL_DEFAULT);

        if (glyph == NULL)
            continue;

        /* Kerning */
        long x_kern = 0;
        if (i > 0) {
            fcft_kerning(font, hello[i - 1], hello[i], &x_kern, NULL);

        pen.x += x_kern;

        if (glyph->is_color_glyph) {
            /* Glyph is a pre-rendered image; typically a color emoji */
            pixman_image_composite32(
                PIXMAP_OP_OVER, glyph->pix, NULL, canvas, 0, 0, 0, 0,
                pen.x + glyph->x, pen.y + font->ascent - glyph->y,
                glyph->width, glyph->height);
        }

        else {
            /* Glyph is an alpha mask */
            pixman_image_composite32(
                PIXMAN_OP_OVER, color, glyph->pix, canvas, 0, 0, 0, 0,
                pen.x + glyph->x, pen.y + font->ascent - glyph->y,
                glyph->width, glyph->height);
        }

        /* Advance pen position */
        pen.x += glyph->advance.x;
    }

    pixman_image_unref(src);

    fcft_destroy(font);
    return EXIT_SUCCESS;
}
โš ๏ธ heads up bestie โ€” that example is pasted exactly as-is from the original page. don't come for me about PIXMAP_OP_OVER or src, i am simply the messenger ๐Ÿ’€ copy verbatim, that's the rule.

๐Ÿ”ฅ SEE ALSO ๐Ÿ”ฅ

  • fcft_from_name2()
  • fcft_clone()
  • fcft_destroy()
  • fcft_codepoint_rasterize()
  • fcft_kerning()

go read those next, they're all in their own little sections and they're all worth it ๐Ÿซถ


โœจ and that's the page!! โœจ this lil beauty lives in the fcft manual, version 3.3.3, dated 2026-04-09 ๐ŸŽ€ mwah, go instantiate some fonts, you're gonna slay ๐Ÿ’–

๐Ÿ“ฆ where this page comes from