/* fnt2bdf.c - converts raw monospaces fonts to BDF */ /* * Copyright (c) 2011 Jon Mayo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include static const char *hextab = "0123456789ABCDEF"; static unsigned width = 8, height = 8; static unsigned dpi = 72; static const char *out_filename = "out.bdf"; static int start_char = -1; static const char *make_font_name(const char *filename) { const char *start, *end; static char name[64]; start = strrchr(filename, '/'); if (!start) start = filename; end = strrchr(start , '.'); if (!end) end = start + strlen(start); snprintf(name, sizeof(name), "-%.*s", end - start, start); return name; } static FILE *open_bin_file(const char *filename, size_t *filelen) { FILE *f; f = fopen(filename, "rb"); if (!f) { perror(filename); return NULL; } if (fseek(f, 0, SEEK_END)) { perror(filename); fclose(f); *filelen = 0; return NULL; } *filelen = ftell(f); fseek(f, 0, SEEK_SET); return f; } static void *read_bin_file(const char *filename, FILE *f, size_t filelen) { void *b; b = malloc(filelen); if (!b) { perror(filename); fclose(f); return 0; } if (fread(b, 1, filelen, f) != filelen) { if (ferror(f)) perror(filename); else fprintf(stderr, "%s:short read\n", filename); free(b); return 0; } return b; } static void write_bdf_header(const char *filename, FILE *f) { const char *font_name; font_name = make_font_name(filename); fprintf(f, "STARTFONT 2.1\n"); fprintf(f, "FONT %s\n", font_name); fprintf(f, "SIZE %u %u %u\n", height, dpi, dpi); fprintf(f, "FONTBOUNDINGBOX 4 8 0 -1\n"); fprintf(f, "STARTPROPERTIES 18\n"); // TODO: calculate fprintf(f, "FONTNAME_REGISTRY \"\"\n"); fprintf(f, "FOUNDRY \"Misc\"\n"); fprintf(f, "FAMILY_NAME \"Fixed\"\n"); fprintf(f, "WEIGHT_NAME \"Medium\"\n"); fprintf(f, "SLANT \"R\"\n"); fprintf(f, "SETWIDTH_NAME \"Normal\"\n"); fprintf(f, "ADD_STYLE_NAME \"\"\n"); fprintf(f, "PIXEL_SIZE %u\n", height); fprintf(f, "POINT_SIZE %u\n", height * 10); fprintf(f, "RESOLUTION_X %u\n", dpi); fprintf(f, "RESOLUTION_Y %u\n", dpi); fprintf(f, "SPACING \"C\"\n"); fprintf(f, "AVERAGE_WIDTH %u\n", width * 10); fprintf(f, "CHARSET_REGISTRY \"ISO8859\"\n"); fprintf(f, "CHARSET_ENCODING \"1\"\n"); fprintf(f, "FONT_DESCENT 1\n"); fprintf(f, "FONT_ASCENT 7\n"); fprintf(f, "DEFAULT_CHAR 0\n"); fprintf(f, "ENDPROPERTIES\n"); } static int write_bdf_char(const char *filename, FILE *f, const void *b, unsigned encoding, const char *glyphname, size_t bytes_per_char) { unsigned y, x; unsigned char v; char buf[256]; size_t bufofs; const char *curr; size_t rowbytes = bytes_per_char / height; fprintf(f, "STARTCHAR %s\n", glyphname); fprintf(f, "ENCODING %u\n", encoding); fprintf(f, "SWIDTH %u 0\n", width * 1000); // TODO: not right fprintf(f, "DWIDTH %u 0\n", width); fprintf(f, "BBX %u %u 0 0\n", width, height); // TODO: not right fprintf(f, "BITMAP\n"); curr = b; for (y = 0; y < height; y++, curr += rowbytes) { bufofs = 0; /* encode up to 8 bits at a time */ for (x = 0; x < width; x += 8) { v = curr[x / CHAR_BIT]; buf[bufofs++] = hextab[(v >> 4) & 15]; if (bufofs >= sizeof(buf) - 1) goto bufoverflow; if (x < width) { buf[bufofs++] = hextab[v & 15]; if (bufofs >= sizeof(buf) - 1) goto bufoverflow; } } buf[bufofs] = 0; fprintf(f, "%s\n", buf); } fprintf(f, "ENDCHAR\n"); return 0; bufoverflow: fprintf(stderr, "%s:buffer overflow!\n", filename); return -1; } static int write_bdf_chars(const char *filename, FILE *f, const void *b, size_t bytes_per_char, unsigned char_count) { unsigned sc; unsigned i; unsigned x; char glyphname[16]; if (start_char < 0) { switch (char_count) { case 96: sc = ' '; break; case 256: sc = 0; break; default: sc = 0; } } else { sc = start_char; } for (x = 0, i = 0; i < char_count; i++) { snprintf(glyphname, sizeof(glyphname), "C%05u", i); if (write_bdf_char(filename, f, (const char*)b + x, sc + i, glyphname, bytes_per_char)) { return -1; } x += bytes_per_char; } return 0; } static inline size_t bytes_per_char(void) { return ((width + CHAR_BIT - 1) / CHAR_BIT) * height; } static int write_bdf(const char *in_filename, const char *out_filename, const void *b, size_t filelen) { FILE *f; int char_count; size_t bc = bytes_per_char(); int ret; char_count = filelen / bc; if (char_count * bc != filelen) /* warning */ fprintf(stderr, "%s: Extra data at end of file\n", in_filename); fprintf(stderr, "DEBUG:char_count=%d filelen=%zu bc=%zu\n", char_count, filelen, bc); if (!out_filename) { f = stdout; out_filename = ""; } else { f = fopen(out_filename, "wx"); if (!f) { perror(out_filename); return -1; } } write_bdf_header(out_filename, f); fprintf(f, "CHARS %u\n", char_count); ret = write_bdf_chars(out_filename, f, b, bc, char_count); fprintf(f, "ENDFONT\n"); fclose(f); return ret; } static int process_file(const char *filename) { FILE *f; size_t filelen; void *b; int ret = 0; f = open_bin_file(filename, &filelen); b = read_bin_file(filename, f, filelen); fclose(f); if (!b) return -1; if (write_bdf(filename, out_filename, b, filelen)) { free(b); return -1; } free(b); return ret; } static const char *progname(const char *argv0) { const char *progname; progname = strrchr(argv0, '/'); if (!progname) progname = argv0; else progname++; return progname; } static void usage(const char *argv0, const char *reason) { const char *p = progname(argv0); if (reason) fprintf(stderr, "%s: %s\n", p, reason); fprintf(stderr, "usage: %s \n", p); exit(EXIT_FAILURE); } static const char *str_arg(int *i, int argc, char **argv) { if (*i >= argc) usage(argv[0], "Missing arguments"); return argv[++*i]; } static long num_arg(int *i, int argc, char **argv) { long n; if (*i >= argc) { usage(argv[0], "Missing arguments"); } n = strtol(argv[++*i], 0, 0); return n; } static void process_flags(const char *flags, int *i, int argc, char **argv) { while (*flags) { switch (*flags) { case 'o': out_filename = str_arg(i, argc, argv); break; case 'h': usage(argv[0], NULL); case 'W': width = num_arg(i, argc, argv); if (width <= 0 || width > 256) usage(argv[0], "Argument out of range"); case 'H': height = num_arg(i, argc, argv); if (height <= 0 || height > 256) usage(argv[0], "Argument out of range"); break; } flags++; } } static void process_args(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') process_flags(argv[i] + 1, &i, argc, argv); else if (process_file(argv[i])) exit(EXIT_FAILURE); } } int main(int argc, char **argv) { process_args(argc, argv); return 0; }