// Smolhershey: a smaller library for rendering Hershey stroke fonts // in Kamal Mostafa’s variant of the JHF format. Copyright 02024 // Kragen Javier Sitaker. See smolhershey.md for license. // // See smolhersheyexample.c for an example. // // This library invokes a user-defined draw_line routine repeatedly in // order to draw the characters. Depending on the context, this // routine might do nothing (if you just want to calculate the // escapement of a string), draw an antialiased line in a glyph atlas, // append an element to an SVG, move a plotter pen across a paper, // etc. In smolhersheyexample.c it draws ASCII art, and in // smolhersheyhpgl.c it outputs HP-GL which can be used to control a // pen plotter. // // It requires you to allocate an array of one pointer per glyph plus one (97 // for most of the Mostafa files), plus a pointer and an integer, and // makes a pass over the font data at startup time to fill up the // array. But it doesn’t require copying the font data into RAM. // // In its present, almost-untested form, this library is 57 lines of // C, and for different processors compiles down to these sizes, which // I subjectively feel are pretty small: // // Bytes Instructions CPU // ----- ------------ ----- // 188 74 Cortex-M4 // 250 79 RV64G (with -msave-restore) // 296 74 Cortex-A53 (without -mthumb) // 381 85 AMD64 // 474 237 AVR // // Anyway it’s less than half the size of Mostafa’s excellent // libhersheyfont, and arguably it provides more functionality. // // The /usr/share/hershey-fonts/timesr.jhf used in // smolhersheyexample.c is 5656 bytes, so this library allows you to // render vector Times Roman text with 6K of ROM. #ifndef SMOLHERSHEY_H #define SMOLHERSHEY_H #ifdef __cplusplus extern "C" { #endif typedef unsigned char u8; // Array of JHF line pointers. The last pointer points to EOF. typedef struct { u8 **lines; int n; } sh_font; typedef struct { int x, y; } sh_point; // Graphics context. Can be safely copied and mutated. typedef struct { sh_font *font; sh_point cp; void (*draw_line)(sh_point start, sh_point end, void *userdata); void *userdata; } sh_gc; // sh_load_font(f, buf, n) loads pointers to the font data in buf into // the pointer array of f, so you can later call sh_show. // // Preallocate the array of pointers in f->p to contain f->n items. // f points to a sh_font pre-initialized to point to available memory. // buf is a pointer to the in-memory data of a Mostafa-style JHF file. // n is its length in bytes. // Returns the number of glyphs in the font; if this is greater than // f->n, the allocation wasn’t big enough, and loading failed. But // now you know how big the allocation needs to be. int sh_load_font(sh_font *f, u8 *buf, int n); // Invoke the GC’s user-defined draw_line function to draw the glyph // identified by glyph_index at the GC’s current point, advancing that current // point. Run this in a loop to draw a string. Glyph indices for ASCII // are the ASCII value minus 32. void sh_show(sh_gc *gc, unsigned glyph_index); #ifdef __cplusplus } #endif #endif