Solved Creating .fnt files for use with the vt console

I just created a new font using fontforge. It's a 11x11 font designed for playing roguelikes without x/y distortion and without straining my eyes with FreeBSD's included 8x8 font. How can I convert it to the .fnt format that vt accepts?
 
Actually it does, too bad it doesn't seem to support 11x11. I'm assuming this is unsupported by vt itself. I did test it with an 8x8 .hex font file (unscii), it works as expected with unicode support.
 
Does anyone know which widths are supported? I tried 10 and it doesn't work either. If -w is specified. vtfontcvt won't complain and will generate the file, but vt fails to render it properly. It looks as if there is no gravity on the tty, lowercase letters float straight to the top of the line. I'll be damned if vt only supports widths that are a multiple of 8. That leaves me stuck with 8x8 only, since 16 is too wide.
 
Does anyone know which widths are supported? I tried 10 and it doesn't work either. If -w is specified. vtfontcvt won't complain and will generate the file, but vt fails to render it properly. It looks as if there is no gravity on the tty, lowercase letters float straight to the top of the line. I'll be damned if vt only supports widths that are a multiple of 8. That leaves me stuck with 8x8 only, since 16 is too wide.
I have successfully converted BDF fonts that are 12 pixels wide. I would guess that 11 pixels should work too – If there were any restrictions, they should be mentioned in the manual page. Maybe something else is wrong or non-standard with your font? Are you sure it is a mono-space font? I don't think proportional fonts are handled correctly.
 
I have successfully converted BDF fonts that are 12 pixels wide. I would guess that 11 pixels should work too – If there were any restrictions, they should be mentioned in the manual page. Maybe something else is wrong or non-standard with your font? Are you sure it is a mono-space font? I don't think proportional fonts are handled correctly.

I noticed Gallant is 12 pixels wide, and it works fine, even though vtfontcvt also seems to complain about 12 being unsupported. I'll just post the log of me attempting font conversion to demonstrate the messages:

Code:
deadcatco% ls                                        diesel:~/docs/digitaldevil
DD.sfd                  digitaldevil-11.bdf                                
deadcatco% vtfontcvt digitaldevil-11.bdf digitaldevil.fnt                  
vtfontcvt: Bitmap with unsupported width 11!                                

deadcatco% ls                                     :( diesel:~/docs/digitaldevil
DD.sfd                  digitaldevil-11.bdf                                
deadcatco% vtfontcvt -v -w 11 -h 11 digitaldevil-11.bdf digitaldevil.fnt    
Statistics:
- glyph_total:                    234
- glyph_normal:                   234
- glyph_normal_right:               0
- glyph_bold:                       0
- glyph_bold_right:                 0
- glyph_unique:                   105
- glyph_dupe:                     129
- mapping_total:                  234
- mapping_normal:                 234
- mapping_normal_folded:          142
- mapping_normal_right:             0
- mapping_normal_right_folded:      0
- mapping_bold:                     0
- mapping_bold_folded:              0
- mapping_bold_right:               0
- mapping_bold_right_folded:        0
- mapping_unique:                 234
- mapping_dupe:                     0
deadcatco% ls                                        diesel:~/docs/digitaldevil
DD.sfd                  digitaldevil-11.bdf     digitaldevil.fnt

You can see that when I specify -w and -h it converts the font, but vt still fails to render the resulting file correctly (after copying it to /usr/share/vt/fonts/ and choosing it with vidfont, of course). The main problem I noticed is that the empty space on top of glyphs that don't go all the way up. such as lowercase letters, is rendered below them instead, which makes them appear as floating.

Although the font design could be labeled as unorthodox, I don't think there's anything technically wrong with the font itself. When I open it in fontforge all characters are now moved a pixel down than I had originally designed. I don't know why this happens, I think it's a bug in fontforge. Either way, I also tried to convert another font made by someone else, ohsnap, and I get the exact same problems as with my font. Also, to answer your question, the font is monospaced. I don't think there's anything wrong with the spacing. The "g" glyph was narrower by accident before and that caused vt to render that glyph by half, but I fixed it since. This did not seem to affect the problems with the other glyphs.

The only thing I found weird is that xfontsel won't pick up this font, even after adding the FontPath to X11's Files section. Fontconfig recognizes the font and terminals such as terminator render it flawlessly. This is a real drag, since I can't find any terminal emulator using fontconfig that isn't terribly slow, at least when compared to urxvt, xterm or the system console.
 
Last edited:
[…]The main problem I noticed is that the empty space on top of glyphs that don't go all the way up. such as lowercase letters, is rendered below them instead, which makes them appear as floating.
Well, the font that I used doesn't have unused space; the bounding boxes of all characters are the same. The empty spaces are just filled with “0” bits. I wrote a very simple BDF font editor that only supports such a simplified variant of BDF font. I guess that vtfontcvf does not support the complete BDF standard, but only a subset. So, maybe your font uses features that are technically correct, but not supported by vtfontvft. But that's just a guess; I haven't studied the code.
 
Thanks a lot olli@, it seems like your guess was correct. I'm now using gbdfed, it's a great editor for bitmap fonts, it's very fast and lightweight and by default it fills in blank space with 0 bits. It seems like vt has no trouble rendering fonts made from this program.
 
Ī̲ confirm that 10-, 12-, and 14-pixel wide fonts work with vt(4) on 12.1-RELEASE. As for vtfontcvt, only after commenting out the
C:
    if (spc != 'c' && spc != 'C')
        errx(1, "font spacing \"C\" (character cell) required");
piece was the program compiled off vtfontcvt.c able to process bdf files which resulted from psf2bdf --iso10646 --fontname=name source_file result_file; otherwise the error happened, on out-of-the-box vtfontcvt and vtfontcvt-ng alike. The problem does not affect bdf files made by pcf2bdf(1).
Ī̲ did not learn the bdf format layout and have no idea whether the “spc” quibble indicates a bug in psf2bdf(1) or vtfontcvt(1) is itself buggy. But Ī̲ can dump relevant portions of bdf files if one is interested.
 
I just wanted to report in on my experiments in creating a custom FNT for vt. In my case, I had gone through the list at https://github.com/Tecate/bitmap-fonts and was still looking for an alternative that suited me better.

For st I have been using IBMPlexMono, which I found quite pleasing. When I went to use the BDF generated from FontForge, I was running into the same problems as reported above (and elsewhere). Incnis Mrsi gave me the clue, which had me look at the code more carefully. In my case relevant lines are 300-348 at https://github.com/t6/vtfontcvt-ng/blob/master/vtfontcvt-ng.c which relate to parsing the section commented as:

Step 1: Parse FONT logical font descriptor and FONTBOUNDINGBOX bounding box

In any case, here is my recipe:

  1. Use FontForge to load up .OTF file (in the weight of choice).
  2. Force encoding through Encoding > Force Encoding > ISO 8859-1
  3. Generate bitmaps through Element > Bitmap Strikes Available
  4. Generate font through File > Generate Fonts... after selecting BDF output
  5. (Don't worry too much about the other options, as a hand-edit in Part II will take care of things.)
Now the BDF will have a couple of things that will trip up vtfontcvt-ng:

  1. The dreaded font spacing "C" (character cell) required error.
  2. bitmap with unsupported DWIDTH
  3. Even after you fix this you might/will get PIO_FONT: Invalid argument
A couple of edits in the BDF will solve this:

  1. FONTBOUNDINGBOX <fbbw> has to match all the DWIDTH <dwidth> lines below (or x2 according to source, but we'll put that aside). This will require some hand-tuning because if you change fbbw to match dwidth the characters will be scrunched; and if you change dwidth to match fbbw, then your characters will be spaced too far apart. Anyway the important thing is that they match.
  2. The other edit was to delete all characters after 255. The STARTCHAR might be descriptive or not (IBMPlexMono has it as ydieresis), but just delete all of the remaining chars while leaving the final ENDFONT line in place.
  3. In FONT line ensure that SPACING as per X logical font description is 'C'. And also ensure that the line that explicitly states SPACING matches with a corresponding 'C'.
With these changes go ahead and run the usual commands to install:

$ vtfontcvt-ng IBMPlexMono/IBMPlexMono-14.bdf fnt/IBMPlexMono-14.fnt
$ sudo cp fnt/*.fnt /usr/share/vt/fonts
$ sudo vidcontrol -f /usr/share/vt/fonts/IBMPlexMono-14.fnt # While in vt, and not X-


That should give you a path to a font of choice. Of course, this doesn't ensure that the generated font will be at all aesthetically pleasing, and certainly won't be as nice as a handcrafted bitmap font. But it did allow me to get a decent approximation of IBMPlexMono under vt.

Warm regards.

 
As a quick follow up, I have posted my recipe on GitHub along with the FNT files I generated using the said recipe for IBMPlexMono-Light and IBMPlexMono-Medium in pixel height ranges of 12–16, in case some might find it useful.

usonianhorizon/vt-fnt

Warm regards.
 
This has sparked my interest, why not try and get my preferred font (MS' "Consolas") displayed on the vt(4) console as well?

Spoiler, it works but looks quite crappy rasterized to 8x16 cells -- oh well 🙈

I started as described using fontforge to create a rasterized version in BDF format. By trial and error, I found I need to specify a pixel size of 15 to end up with a font that has DWIDTH 8 0 for all glyphs, which certainly is what you need for an 8x16 font.

But then, some glyphs are wider than 8 pixels, and some have really excessive over- and underlengths not fitting into 16 rows, and the result even contained quite some glyphs with an invalid ENCODING value of -1... all in all, no way to feed that to vtfontcvt(8). So, I decided to write myself a very quick and dirty tool converting this mess to "unifont hex" format first, rendering all the glyphs into 8x16 cells (and the few ones that are too wide into 16x16 cells, although I don't know whether vt(4) actually displays them correctly):
C:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char linebuf[128];
uint8_t bitmap[32][2];
int encoding, w, h, x, y, bmr;

int main(int argc, char **argv)
{
    FILE *bdf = 0;
    int rc = 1;
    if (argc != 2 || !(bdf = fopen(argv[1], "r")))
    {
        fputs("Usage: bdf2hex font.bdf\n", stderr);
        goto done;
    }

    bmr = -1;
    while (fgets(linebuf, sizeof linebuf, bdf))
    {
        if (bmr >= 0)
        {
            if (!strncmp(linebuf, "ENDCHAR", 7))
            {
                bmr = -1;
                if (encoding > 0 && encoding < 0x10000)
                {
                    printf("%04X:", (unsigned)encoding);
                    y += 4;
                    int sy = 0;
                    while (h > 16 && y > h) {--y; ++sy; --h;}
                    for (int r = 0; r < 16; ++r)
                    {
                        if (r < 16-(h+y) || sy >= h)
                        {
                            fputs(w>8?"0000":"00", stdout);
                            continue;
                        }
                        if (w > 8)
                        {
                            uint8_t a = bitmap[sy][0];
                            uint8_t b = bitmap[sy][1];
                            for (int sx = x; sx > 0; --sx)
                            {
                                uint8_t c = (a&1)<<7;
                                a >>= 1;
                                b >>= 1;
                                b |= c;
                            }
                            printf("%02hhX%02hhX", a, b);
                        }
                        else printf("%02hhX", (uint8_t)(bitmap[sy][0]>>x));
                        ++sy;
                    }
                    fputs("\n", stdout);
                    rc = 0;
                }
            }
            else
            {
                uint8_t v;
                if (sscanf(linebuf, "%02hhX", &v) > 0) bitmap[bmr][0] = v;
                if (sscanf(linebuf+2, "%02hhX", &v) > 0) bitmap[bmr][1] = v;
                ++bmr;
            }
            continue;
        }
        if (!strncmp(linebuf, "ENCODING ", 9))
        {
            encoding = atoi(linebuf+9);
        }
        else if (!strncmp(linebuf, "BBX ", 4))
        {
            sscanf(linebuf+4, "%d %d %d %d", &w, &h, &x, &y);
        }
        else if (!strncmp(linebuf, "BITMAP", 6))
        {
            memset(bitmap, 0, sizeof bitmap);
            bmr = 0;
        }
    }

done:
    if (bdf) fclose(bdf);
    return rc;
}

Note this tool hardcodes a lot of things (like the target size of 8x16 or 16x16, a fixed y-shift of 4 rows, ...) and also does close to no input validation and error handling. So, use with care and modify as needed ;)

For me, vtfontcvt(8) converted the resulting hex format perfectly fine!
 
Here's how my result looks like. Unfortunately, a camera picture (and thus looking a bit smoother than in reality, but also blurred and with bleeding colors ...) because I found no way to take a screenshot of the console with vt(4) – is it really not possible? :-/

console.jpg
 
Back
Top