file alongside the image.
The basic format is line-based. Empty lines, or those starting with a hash
-sign (#), should be ignored. Data lines consist of fields separated with
-spaces.
+sign (#), should be ignored. Data lines consist of a keyword followed by
+space-separated fields.
-The first data line contains five fields with overall information about the
-image and the font:
+The keyword "font" is followed by five fields with overall information about
+the image and the font:
Fields 1-2: width and height of the image
Field 3: nominal size of the font
Fields 4-5: ascent and descent of the font
-Subsequent data lines each describe a single glyph and contain eight fields:
+The keyword "glyph" is followed by eight fields describing a single glyph:
Field 1: the code point of the glyph
Fields 2-3: x and y position of the glyph in the image
Fields 6-7: x and y offset of the glyph from its base point
Field 8: advance from this glyph to the next
+The keyword "kern" is followed by three fields describing kerning between two
+glyphs:
+
+ Field 1: the code point of the left-hand glyph
+ Field 2: the code point of the right-hand glyph
+ Field 3: kerning distance between the glyphs
+
The following ASCII art image illustrates most of these metrics. Note that in
some fonts, not all of the glyphs fit completely inside the character box.
- Improve the packing algorithm
- Non-square cells for grid mode
- Option to invert colors
+- Include kerning information in definition file
0.3
- Restructure the code
typedef struct sGlyph
{
+ unsigned index;
unsigned code;
Image image;
unsigned x, y;
int advance;
} Glyph;
+typedef struct sKerning
+{
+ unsigned left_code;
+ unsigned right_code;
+ int distance;
+} Kerning;
+
typedef struct sFont
{
unsigned size;
int descent;
unsigned n_glyphs;
Glyph *glyphs;
+ unsigned n_kerning;
+ Kerning *kerning;
Image image;
} Font;
void init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autohinter)
{
- unsigned i;
+ unsigned i, j;
unsigned size = 0;
font->ascent = (face->size->metrics.ascender+63)>>6;
}
glyph = &font->glyphs[font->n_glyphs++];
+ glyph->index = n;
glyph->code = i;
glyph->image.w = bmp->width;
glyph->image.h = bmp->rows;
if(verbose>=1)
printf("Loaded %u glyphs\n", font->n_glyphs);
+
+ size = 0;
+ font->n_kerning = 0;
+ font->kerning = NULL;
+ for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
+ if(j!=i)
+ {
+ FT_Vector kerning;
+ FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
+
+ /* FreeType documentation says that vertical kerning is practically
+ never used, so we ignore it. */
+ if(kerning.x)
+ {
+ Kerning *kern;
+
+ if(font->n_kerning>=size)
+ {
+ size += 16;
+ font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
+ }
+
+ kern = &font->kerning[font->n_kerning++];
+ kern->left_code = font->glyphs[i].code;
+ kern->right_code = font->glyphs[j].code;
+ kern->distance = kerning.x/64;
+ }
+ }
+
+ if(verbose>=1)
+ printf("Loaded %d kerning pairs\n", font->n_kerning);
}
void render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, int seq)
fprintf(out, "# Image/font info:\n");
fprintf(out, "# width height size ascent descent\n");
- fprintf(out, "%d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
+ fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
fprintf(out, "\n# Glyph info:\n");
fprintf(out, "# code x y width height offset_x offset_y advance\n");
for(i=0; i<font->n_glyphs; ++i)
{
const Glyph *g = &font->glyphs[i];
- fprintf(out, "%u %u %u %u %u %d %d %d\n", g->code, g->x, g->y, g->image.w, g->image.h, g->offset_x, g->offset_y, g->advance);
+ fprintf(out, "glyph %u %u %u %u %u %d %d %d\n", g->code, g->x, g->y, g->image.w, g->image.h, g->offset_x, g->offset_y, g->advance);
+ }
+ fprintf(out, "\n# Kerning info:\n");
+ fprintf(out, "# left right distance\n");
+ for(i=0; i<font->n_kerning; ++i)
+ {
+ const Kerning *k = &font->kerning[i];
+ fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
}
fclose(out);