// Example program for Smolhershey font library. Copyright 02024 // Kragen Javier Sitaker. See smolhershey.md for license. // // Render Times Roman text in ASCII art with Hershey fonts. // // The program’s output is in a comment at the end of the file. // // Cleaned-up and enhanced GPT-4 output. // // See also smolhersheyhpgl.c for a more elaborate example. #include #include #include #include #include "smolhershey.h" enum { CANVAS_WIDTH = 210, CANVAS_HEIGHT = 30, }; // Canvas for ASCII art. char canvas[CANVAS_HEIGHT][CANVAS_WIDTH]; void init_canvas() { memset(canvas, ' ', sizeof canvas); } void print_canvas() { for (int y = 0; y < CANVAS_HEIGHT; y++) { fwrite(canvas[y], CANVAS_WIDTH, 1, stdout); putchar('\n'); } } // Bresenham’s line algorithm implementation for ASCII drawing. void ascii_draw_line(sh_point start, sh_point end, void *userdata) { int dx = abs(end.x - start.x), sx = start.x < end.x ? 1 : -1; int dy = -abs(end.y - start.y), sy = start.y < end.y ? 1 : -1; int err = dx + dy; for (;;) { if (start.x >= 0 && start.x < CANVAS_WIDTH && start.y >= 0 && start.y < CANVAS_HEIGHT) { canvas[start.y][start.x] = '#'; // Draw point at current position } if (start.x == end.x && start.y == end.y) break; int e2 = 2 * err; if (e2 >= dy) { err += dy; start.x += sx; } if (e2 <= dx) { err += dx; start.y += sy; } } } // Read an entire text file into malloced memory. int slurp_file(u8 **buf, int *buflen, const char *name) { FILE *font_file = fopen(name, "r"); if (!font_file) return 0; // Get file size. fseek(font_file, 0L, SEEK_END); *buflen = ftell(font_file); rewind(font_file); // Allocate memory for font data. *buf = malloc(*buflen); if (!*buf) { fclose(font_file); return 0; } // Read font data into memory. fread(*buf, 1, *buflen, font_file); fclose(font_file); return 1; } int main(int argc, char **argv) { // Load Hershey font data from a file. char *font_file_path = "/usr/share/hershey-fonts/timesr.jhf"; u8 *font_data; int font_data_length; if (!slurp_file(&font_data, &font_data_length, font_file_path)) { int err = errno; perror(font_file_path); if (err == ENOENT) { fprintf(stderr, "Maybe: sudo apt install hershey-fonts-data # or equivalent\n"); } return 1; } // Allocate space for glyph pointers (assuming 96 glyphs + EOF). u8 *glyph_pointers[97]; // One extra for EOF // Initialize sh_font structure with one extra slot for EOF. sh_font my_font = { .lines = glyph_pointers, .n = 97 }; int num_glyphs = sh_load_font(&my_font, font_data, font_data_length); if (num_glyphs > my_font.n) { fprintf(stderr, "Font allocation wasn’t big enough.\n"); free(font_data); return 1; } // Initialize graphics context. sh_gc gc = { .font = &my_font, .cp = {0, 12}, // Starting at {0, 12} .draw_line = ascii_draw_line, }; char *text_to_render = argc == 1 ? "Hello, World!" : argv[1]; init_canvas(); for (char *p = text_to_render; *p; p++) { sh_show(&gc, *p - ' '); } print_canvas(); free(font_data); return 0; } /* The program outputs: ######## ######## ##### ##### ######## ## ####### ##### ##### # ## ## ## ## ## ## # ## ## ## ## ## ## ## ## ## # ## ## ### ## ## ## ## ## # ## # ## ## ### ## ## ## ## ## # ## # ## ## ### ## ## ## ## ## # ## # ## ## ### ## ## ## ## ## # ## # ## ## ### ## ## ###### ## ## ##### ## # ## # ##### ##### ##### ## ##### ## ### ## ## ### # ## ## ### ## ## # ## # ### ## ## # ## ## ### # ## ## ## ## ## ## ## ## ## ## ## # ## # ## ## ## # # # ## ## ### # ############### ## # ## ## ## ## ## # ## # ## ## ### # ## ## ## # ## ## ## ## ## ## ## ## ## # ## # ## ## ### ## ## ## # ## ## ## ## ## ## ## ## ## # ## # ## ## ## ## ## ## # ## ## ############## ## ## ## ## ## # ## # ## ## ## ## ## ## # ## ## ## ## ## ## ## ### ### ## ## ## ## ## ## # ## ## ## ## ## ## ## ### ### ## ## ## ## ## ## ## ## ## ## ## ## ## # ### ### ## ## ## ## ## ## ## ## ## ## ## ## ## # # # # # # ## ## ## ## ## ## ## ## ## # ## ## ## ## ## # # # # ## ## ## ## ## ## ## ## ## # ## ## ## ## # # # ## ## ## ## ## ### # ## ## ## ## ## ## ## ### # # # ## ### ## ## ## ## ## # # ######## ######## ##### ######## ######## ##### # # # ##### ######## ######## #### ##### # */