links/graphics/generate_font.c
2021-08-28 18:37:32 +03:00

203 lines
5.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <png.h>
#define MAX_LETTERS 65536
static FILE *output;
struct letter {
unsigned unicode;
unsigned length;
unsigned x, y;
unsigned sequence;
};
static struct letter letters_system[MAX_LETTERS];
static struct letter letters_normal[MAX_LETTERS];
static struct letter letters_bold[MAX_LETTERS];
static struct letter letters_monospaced[MAX_LETTERS];
static unsigned n_letters_system;
static unsigned n_letters_normal;
static unsigned n_letters_bold;
static unsigned n_letters_monospaced;
static unsigned global_sequence = 0;
static int compare_letters(const void *l1, const void *l2)
{
const struct letter *letter1 = l1;
const struct letter *letter2 = l2;
return (int)letter1->unicode - (int)letter2->unicode;
}
static void get_png_dimensions(FILE *stream, int *x, int *y)
{
png_structp png_ptr;
png_infop info_ptr;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, stream);
png_read_info(png_ptr, info_ptr);
*x = png_get_image_width(png_ptr,info_ptr);
*y = png_get_image_height(png_ptr,info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
}
static int char_pos=0; /* To not makes lines excessively long. */
/* Returns forbidden_0_to_7 for next char. */
static int print_char(FILE *output, int c, int forbidden_0_to_7)
{
if (char_pos >= 70){
fputs("\"\n\"", output);
char_pos = 0;
}
switch (c) {
case '\n':
fputs("\\n", output);
two:
char_pos += 2;
forbidden_0_to_7 = 0;
break;
case '\t':
fputs("\\t", output); goto two;
case '\b':
fputs("\\b", output); goto two;
case '\r':
fputs("\\r", output); goto two;
case '\f':
fputs("\\f", output); goto two;
case '\\':
fputs("\\\\", output); goto two;
case '\'':
fputs("\\\'", output); goto two;
default:
if (c < ' ' || c== '"' || c=='?' || c > 126 ||
(c >= '0' && c <= '7' && forbidden_0_to_7)) {
fprintf(output, "\\%o", c);
if (c >= 0100) char_pos += 4;
else if (c >= 010) char_pos += 3;
else char_pos += 2;
forbidden_0_to_7 = c < 0100;
} else {
putc(c, output);
char_pos++;
forbidden_0_to_7 = 0;
}
break;
}
return forbidden_0_to_7;
}
static void process_file(FILE *f, struct letter *l)
{
int c;
int forbidden_0_to_7;
int count = 0;
fprintf(output, "static_const unsigned char letter_%u[] = \"", global_sequence);
l->sequence = global_sequence;
char_pos = 38;
forbidden_0_to_7 = 0;
while (EOF != (c = fgetc(f))){
forbidden_0_to_7 = print_char(output, c, forbidden_0_to_7);
count++;
}
fprintf(output, "\";\n\n");
l->length = ftell(f);
global_sequence++;
rewind(f);
get_png_dimensions(f, &l->x, &l->y);
/*fprintf(stderr, "%d %d\n", letters[i].x, letters[i].y);*/
}
static void load_letters(struct letter letters[MAX_LETTERS], unsigned *n, char *path)
{
DIR *d;
struct dirent *de;
unsigned i;
*n = 0;
d = opendir(path);
if (!d) perror(path), exit(1);
while ((de = readdir(d))) {
char *end;
unsigned unicode = strtoul(de->d_name, &end, 16);
if (end == de->d_name + 6 && !strcmp(end, ".png")) {
if (*n >= MAX_LETTERS) fprintf(stderr, "too many letters\n"), exit(1);
letters[(*n)++].unicode = unicode;
}
}
if (closedir(d)) perror("closedir"), exit(1);
qsort(letters, *n, sizeof(struct letter), compare_letters);
for (i = 0; i < *n; i++) {
char fullpath[128];
FILE *f;
snprintf(fullpath, sizeof fullpath, "%s/%06x.png", path, letters[i].unicode);
f = fopen(fullpath, "r");
if (!f) perror(fullpath), exit(1);
process_file(f, &letters[i]);
if (fclose(f)) perror("fclose"), exit(1);
}
}
static void write_letters(struct letter letters[MAX_LETTERS], unsigned n)
{
unsigned i;
for (i = 0; i < n; i++) {
struct letter *l = &letters[i];
fprintf(output, "\t{ letter_%u, 0x%08x, 0x%08x, %3u, %3u, NULL },\n", l->sequence, l->length, l->unicode, l->x, l->y);
}
}
static void write_font(char *name, unsigned start, unsigned length)
{
fprintf(output, "\t{ %u, %u },\n", start, length);
}
int main(void)
{
output = fopen("font_inc.c", "w");
if (!output) perror("font_inc.c"), exit(1);
fprintf(output, "#include \"cfg.h\"\n\n#ifdef G\n\n#include \"links.h\"\n\n");
load_letters(letters_system, &n_letters_system, "font/system");
load_letters(letters_normal, &n_letters_normal, "font/normal");
load_letters(letters_bold, &n_letters_bold, "font/bold");
load_letters(letters_monospaced, &n_letters_monospaced, "font/monospaced");
fprintf(output, "struct letter letter_data[%u] = {\n", global_sequence);
write_letters(letters_system, n_letters_system);
write_letters(letters_normal, n_letters_normal);
write_letters(letters_bold, n_letters_bold);
write_letters(letters_monospaced, n_letters_monospaced);
fprintf(output, "};\n\n");
fprintf(output, "struct font font_table[4] = {\n");
write_font("system", 0, n_letters_system);
write_font("normal", n_letters_system, n_letters_normal);
write_font("bold", n_letters_system + n_letters_normal, n_letters_bold);
write_font("monospaced", n_letters_system + n_letters_normal + n_letters_bold, n_letters_monospaced);
fprintf(output, "};\n");
fprintf(output, "\n#endif\n");
if (fclose(output)) perror("fclose"), exit(1);
}