// Host harness for kernel/dev/ttf.c. // // A rasteriser is checked by looking at it. This renders a string with the real // font and writes a PGM, which is the smallest image format that needs no // compression -- the point is the glyphs, not the container. // // build/tools/ttftest "text" out.pgm #include #include #include #define TTF_HOST #include "../kernel/dev/ttf.c" int ttf_render(struct ttf *, uint32, struct glyph *, unsigned char *, int, int *, int *); int main(int argc, char **argv) { if (argc < 5) { fprintf(stderr, "usage: ttftest font.ttf px \"text\" out.pgm\n"); return 1; } const char *path = argv[1]; int px = atoi(argv[2]); const char *text = argv[3]; FILE *fp = fopen(path, "rb"); if (!fp) { perror(path); return 1; } fseek(fp, 0, SEEK_END); long n = ftell(fp); fseek(fp, 0, SEEK_SET); unsigned char *buf = malloc(n); if (fread(buf, 1, n, fp) != (size_t)n) { fprintf(stderr, "short read\n"); return 1; } fclose(fp); struct ttf f; if (ttf_open(&f, buf, (uint32)n, px) != 0) { fprintf(stderr, "not a TrueType font this can read\n"); return 1; } printf("unitsPerEm %d, %d glyphs, ascent %d descent %d, %s loca\n", f.units_per_em, f.num_glyphs, f.ascent, f.descent, f.long_loca ? "long" : "short"); struct font *fo = ttf_font(&f); int H = fo->ops->height(fo) + px; // room for descenders and padding int base = fo->ops->baseline(fo) + px / 2; int W = 16; for (const char *p = text; *p; p++) W += px; // generous unsigned char *img = calloc(W * H, 1); int pen = 8, drawn = 0, missing = 0; for (const char *p = text; *p; p++) { struct glyph g; // Through the provider, not ttf_render, so the glyph cache is on the // path being tested rather than bypassed by the harness. if (fo->ops->glyph(fo, (unsigned char)*p, &g) != 0) { missing++; pen += px / 2; continue; } for (int gy = 0; gy < g.h; gy++) for (int gx = 0; gx < g.w; gx++) { int X = pen + g.bearing_x + gx; int Y = base - g.bearing_y + gy; if (X < 0 || Y < 0 || X >= W || Y >= H) continue; int v = img[Y * W + X] + g.cov[gy * g.w + gx]; img[Y * W + X] = v > 255 ? 255 : v; } pen += g.advance; drawn++; } // White on black inverted to black on white, which is how text is read. for (int i = 0; i < W * H; i++) img[i] = 255 - img[i]; FILE *o = fopen(argv[4], "wb"); fprintf(o, "P5\n%d %d\n255\n", W, H); fwrite(img, 1, W * H, o); fclose(o); printf("%d glyphs drawn, %d missing, %d px advance, image %dx%d -> %s\n", drawn, missing, pen - 8, W, H, argv[4]); return drawn ? 0 : 1; }