/***************************************************************************** * Xerox Alto font dump. * * Copyright (C) 2007 by Juergen Buchmueller * Partially based on info found in Eric Smith's Alto simulator: Altogether * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * This is a tool to visualize a Xerox Alto *.AL font file. * It can handle fonts with iat most one extension, i.e. max width = 32. * * The output can be plain text (default), or a PNG image containing * zoomed bitmaps of the font's glyphs. * * $Id: aldump.c,v 1.2 2008/07/27 10:07:13 pm Exp $ *****************************************************************************/ #include #include #include #include #include #include #include #include "png.h" #include "md5.h" /** @brief number of 32 bit words per glyph bitmap line */ #define BITMAPW (256/32) int verbose; /** @brief structure of an Alto font */ typedef struct { /** @brief word: font height in scanlines */ unsigned char fontheight[2]; /** @brief bits 7-0: font max. width, bits 14-8: font ascent, bit 15: fixed font flag */ unsigned char fonttype[2]; /** @brief self relative offset to the character XW (0..255) */ unsigned char xw[256*2]; /** @brief data words (more following) */ unsigned char data[2]; } alto_font_t; static int png_write(void *cookie, uint8_t *buff, int size) { FILE *fp = (FILE *)cookie; if (size == fwrite(buff, 1, size, fp)) return -1; return 0; } static void png_bits(png_t *png, int x0, int y0, int pw, int ph, int w, int y, uint32_t *bitmap) { int x, x1, y1; for (x = 0; x < w; x++) { if (bitmap[x/32] & (0x80000000 >> (x % 32))) { for (y1 = y * ph; y1 < (y + 1) * ph; y1++) for (x1 = x * pw; x1 < (x + 1) * pw; x1++) png_put_pixel(png, x0 + x1, y0 + y1, 1, 0); } } } #define FONTW 6 #define FONTH 10 #define FONTC 2 /* color palette index to use for png_putch and png_printf */ static const uint8_t chargen[128*FONTH] = { 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x00,0x08,0x18,0x38,0x78,0x78,0x38,0x18,0x08,0x00, 0x00,0x80,0xc0,0xe0,0xf0,0xf0,0xe0,0xc0,0x80,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, 0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x50,0xf8,0x50,0x50,0xf8,0x50,0x00,0x00, 0x20,0x70,0xa8,0xa0,0x70,0x28,0xa8,0x70,0x20,0x00, 0x00,0xc8,0xc8,0x10,0x20,0x40,0x98,0x98,0x00,0x00, 0x00,0x40,0xa0,0xa0,0x40,0xa8,0x90,0x68,0x00,0x00, 0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x10,0x20,0x20,0x40,0x40,0x40,0x20,0x20,0x10,0x00, 0x40,0x20,0x20,0x10,0x10,0x10,0x20,0x20,0x40,0x00, 0x00,0x20,0xa8,0x70,0x20,0x70,0xa8,0x20,0x00,0x00, 0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xc0,0x00, 0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00, 0x00,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0x00,0x00, 0x00,0x30,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00, 0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x00,0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00,0x00, 0x00,0xf8,0x08,0x10,0x30,0x08,0x88,0x70,0x00,0x00, 0x00,0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0x00, 0x00,0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00,0x00, 0x00,0x30,0x40,0x80,0xf0,0x88,0x88,0x70,0x00,0x00, 0x00,0xf8,0x08,0x10,0x10,0x20,0x20,0x20,0x00,0x00, 0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x00, 0x00,0x70,0x88,0x88,0x78,0x08,0x10,0x60,0x00,0x00, 0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x00,0x00, 0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0xc0,0x00, 0x00,0x00,0x10,0x20,0x40,0x20,0x10,0x00,0x00,0x00, 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00, 0x00,0x00,0x40,0x20,0x10,0x20,0x40,0x00,0x00,0x00, 0x00,0x70,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, 0x00,0x70,0x88,0xb8,0xa8,0xb8,0x80,0x70,0x00,0x00, 0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0x00,0xf0,0x48,0x48,0x70,0x48,0x48,0xf0,0x00,0x00, 0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,0x00, 0x00,0xf0,0x48,0x48,0x48,0x48,0x48,0xf0,0x00,0x00, 0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x00, 0x00,0x70,0x88,0x80,0x80,0x98,0x88,0x70,0x00,0x00, 0x00,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x00,0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00, 0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00,0x00, 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x00, 0x00,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x00,0x00, 0x00,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88,0x00,0x00, 0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x00, 0x00,0x70,0x88,0x88,0x88,0xa8,0x90,0x68,0x00,0x00, 0x00,0xf0,0x88,0x88,0xf0,0xa0,0x90,0x88,0x00,0x00, 0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,0x00, 0x00,0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0x00,0x88,0x88,0x88,0x88,0x50,0x50,0x20,0x00,0x00, 0x00,0x88,0x88,0x88,0x88,0xa8,0xa8,0x50,0x00,0x00, 0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x00, 0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00, 0x00,0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x00, 0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00, 0x00,0x80,0x40,0x40,0x20,0x10,0x10,0x08,0x00,0x00, 0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, 0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00,0x00, 0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00,0x00, 0x00,0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00,0x00, 0x00,0x00,0x00,0x70,0x88,0xf0,0x80,0x70,0x00,0x00, 0x00,0x30,0x48,0x40,0xe0,0x40,0x40,0x40,0x00,0x00, 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x70, 0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00,0x00, 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x48,0x30, 0x00,0x80,0x80,0x88,0x90,0xe0,0x90,0x88,0x00,0x00, 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x00,0x00,0x00,0xd0,0xa8,0xa8,0xa8,0xa8,0x00,0x00, 0x00,0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00, 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0x00,0x00,0x00,0xf0,0x88,0x88,0x88,0xf0,0x80,0x80, 0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x78,0x08,0x08, 0x00,0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00, 0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00,0x00, 0x00,0x20,0x20,0xf8,0x20,0x20,0x20,0x18,0x00,0x00, 0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00, 0x00,0x00,0x00,0x88,0x88,0xa8,0xa8,0x50,0x00,0x00, 0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00, 0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x40,0x80, 0x00,0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x00, 0x10,0x20,0x20,0x20,0x40,0x20,0x20,0x20,0x10,0x00, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, 0x40,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x40,0x00, 0x00,0x00,0x00,0x48,0xa8,0x90,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; static void png_putch(png_t *png, int x0, int y0, int n) { int x, y; const uint8_t *src = &chargen[n * FONTH]; for (y = 0; y < FONTH; y++) { for (x = 0; x < FONTW; x++) { if (src[y] & (0x80 >> x)) png_put_pixel(png, x0 + x, y0 + y, FONTC, 0); } } } static void png_printf(png_t *png, int x0, int y0, const char *fmt, ...) { char buff[256]; size_t i, len; va_list ap; va_start(ap, fmt); len = vsnprintf(buff, sizeof(buff), fmt, ap); va_end(ap); for (i = 0; i < len; i++) png_putch(png, x0 + i * FONTW, y0, buff[i]); } static const char *binstr(uint32_t *bitmap, int width) { static char str[256+1]; int i; for (i = 0; i < width; i++) str[i] = (bitmap[i/32] & (0x80000000 >> (i%32))) ? '#' : '.'; str[i] = '\0'; return str; } int extract_xw(uint32_t *bitmap, int *cw, alto_font_t *al, int size, int ch, int fw, int fh) { int xw; int extent; int hd; int xh; int wo; int w; int y; /* get the XW pointer for this character */ xw = ch + al->xw[2*ch+0] + 256 * al->xw[2*ch+1] - 256; /* erase all glyph bitmap bits */ memset(bitmap, 0, BITMAPW * fh * sizeof(uint32_t)); /* invalid XW pointer - return 0 */ if (xw < 0 || xw > size) return 0; /* get the word at XW */ extent = al->data[2*xw] + 256 * al->data[2*xw+1]; /* if extent is odd, it's 2*width+1, otherwise it's 2*extent character code */ if (extent & 1) { w = extent / 2; extent = 0; } else { w = 16; extent = extent / 2; } /* height of the data before xw */ hd = al->data[2*xw+2]; /* skip xh lines from the top of the character */ xh = al->data[2*xw+3]; if (w == 0 || hd == 0) return 0; *cw = w; for (y = 0; y < fh; y++) { int offs, data, lsb = 0; if (y < xh || y >= xh + hd) continue; offs = xw - hd + (y - xh); data = al->data[2*offs] + 256 * al->data[2*offs+1]; /* least significant 1 bit */ if (data & 0x0001) lsb = 16; else if (data & 0x0002) lsb = 15; else if (data & 0x0004) lsb = 14; else if (data & 0x0008) lsb = 13; else if (data & 0x0010) lsb = 12; else if (data & 0x0020) lsb = 11; else if (data & 0x0040) lsb = 10; else if (data & 0x0080) lsb = 9; else if (data & 0x0100) lsb = 8; else if (data & 0x0200) lsb = 7; else if (data & 0x0400) lsb = 6; else if (data & 0x0800) lsb = 5; else if (data & 0x1000) lsb = 4; else if (data & 0x2000) lsb = 3; else if (data & 0x4000) lsb = 2; else if (data & 0x8000) lsb = 1; /* lsb still inside max. width? */ if (lsb > w && lsb <= fw) { /* assume wrong XW width, and report the true least significant 1 */ *cw = lsb; } bitmap[y*BITMAPW] = data << 16; } /* no extent, just leave as it is */ if (!extent) return fh; /* word offset = 1 */ wo = 1; while (extent && wo < BITMAPW*2) { int ew; /* extent width */ /* extent is character >= 256 */ ch = extent; /* get the XW pointer for this character */ xw = ch + al->xw[2*ch+0] + 256 * al->xw[2*ch+1] - 256; /* get the word at XW */ extent = al->data[2*xw] + 256 * al->data[2*xw+1]; /* if extent is odd, it's 2*width+1, otherwise it's 2*extent character code */ if (extent & 1) { /* final extent */ ew = extent / 2; extent = 0; } else { /* even more extents */ ew = 16; extent = extent / 2; } /* height of the data before xw */ hd = al->data[2*xw+2]; /* skip xh lines from the top of the character */ xh = al->data[2*xw+3]; for (y = 0; y < fh; y++) { int offs, data, lsb = 0; if (y < xh || y >= xh + hd) continue; offs = xw - hd + (y - xh); data = al->data[2*offs] + 256 * al->data[2*offs+1]; /* least significant 1 bit */ if (data & 0x0001) lsb = 16; else if (data & 0x0002) lsb = 15; else if (data & 0x0004) lsb = 14; else if (data & 0x0008) lsb = 13; else if (data & 0x0010) lsb = 12; else if (data & 0x0020) lsb = 11; else if (data & 0x0040) lsb = 10; else if (data & 0x0080) lsb = 9; else if (data & 0x0100) lsb = 8; else if (data & 0x0200) lsb = 7; else if (data & 0x0400) lsb = 6; else if (data & 0x0800) lsb = 5; else if (data & 0x1000) lsb = 4; else if (data & 0x2000) lsb = 3; else if (data & 0x4000) lsb = 2; else if (data & 0x8000) lsb = 1; /* w + lsb still inside max. width? */ if (lsb > ew && lsb <= fw) { /* assume wrong XW width, and report the true least significant 1 */ ew = lsb; } bitmap[y*BITMAPW+(wo/2)] |= (wo & 1) ? data : data << 16; } w += ew; *cw = w; /* next word offset */ wo++; } return fh; } static int dump_font(char *filename, char *pngfile) { char *basename; alto_font_t *al; FILE *font_fp; int fw; int fh; int fixed; int ascent; int size; uint32_t *bitmap; int rw; int rh; int w; int h; int x; int y; int i; basename = strrchr(filename, '/'); if (basename) basename++; else basename = filename; al = malloc(131072); if (!al) { perror("malloc"); return 1; } font_fp = fopen(filename, "rb"); if (!font_fp) { perror(filename); return 2; } size = fread(al, 1, 131072, font_fp); fclose(font_fp); fh = al->fontheight[0] + 256 * al->fontheight[1]; /* font height >= 256 is most probably byte swapped */ if (fh >= 256) { unsigned char *pb = (unsigned char *)al; for (i = 0; i < size; i += 2) { unsigned char tmp = pb[i]; pb[i] = pb[i+1]; pb[i+1] = tmp; } } /* font height */ fh = al->fontheight[0] + 256 * al->fontheight[1]; /* font max width, ascent and type */ fw = al->fonttype[0] + 256 * al->fonttype[1]; fixed = (~fw >> 15) & 1; ascent = (fw >> 8) & 0177; fw = fw & 0377; /* BITMAPW * 32 bits per row */ bitmap = (uint32_t *)calloc(BITMAPW * fh, sizeof(uint32_t)); /* characters per HTML table row */ rw = 16; rh = 16; if (pngfile) { png_t *png; FILE *png_fp; int pw = 5; /* zoomed pixel width */ int ph = 5; /* zoomed pixel height */ int aw = 6; /* additional width per glyph */ int ah = FONTH + 4; /* additional height per glyph */ int mw = 0; /* max width found in the glyphs */ int first = -1; /* first defined glyph */ int last = 0; /* last defined glyph */ if (strcmp(pngfile, "-md5")) { png_fp = fopen(pngfile, "wb"); if (!png_fp) { fprintf(stderr, "Cannot create '%s'\n", pngfile); return -1; } } else { char filename[FILENAME_MAX]; snprintf(filename, sizeof(filename), "%s.png", md5_digest((uint8_t *)al, size)); png_fp = fopen(filename, "wb"); if (!png_fp) { fprintf(stderr, "Cannot create '%s'\n", filename); return -1; } } /* scan font for first and last */ for (i = 0; i < 256; i++) { h = extract_xw(bitmap, &w, al, size, i, fw, fh); if (0 == h) continue; /* undefined character */ /* check for true max. width */ if (w > mw) mw = w; if (-1 == first) first = i - (i % rw); last = i; } if (mw > fw) { int tmp; if (verbose) fprintf(stderr, "Font '%s' has wrong header max. width:%d, found:%d\n", filename, fw, mw); tmp = fw; fw = mw; mw = tmp; } else if (mw < fw) { int tmp; if (verbose) fprintf(stderr, "Font '%s' has wrong header max. width:%d, found:%d\n", filename, fw, mw); tmp = fw; fw = mw; mw = tmp; } rh = (last + rw - first - 1) / rw; /* scale down zoom if the image becomes too big */ while (pw > 1) { if (rw*(pw*fw+aw) > 1152 || 24+rh*(ph*fh+ah) > 1152) { pw--; ph--; } else break; } /* other than 8bpp is broken, so use that for now */ png = png_create( (pw * fw + aw) * rw, /* image width */ 24 + (ph * fh + ah) * rh, /* image height */ COLOR_PALETTE, /* palette image */ 2, /* 2 bits per pixel */ png_fp, /* output cookie */ png_write); /* output callback */ if (!png) { fprintf(stderr, "Fatal: creation of PNG image failed (%s)\n", strerror(errno)); return -1; } png_set_palette(png, 0, PNG_RGB(255,255,255)); png_set_palette(png, 1, PNG_RGB( 0, 0, 0)); png_set_palette(png, 2, PNG_RGB( 32, 32,160)); png_set_palette(png, 3, PNG_RGB(128,128,128)); png->comment = "Created by aldump"; png->author = "Juergen Buchmueller "; /* draw a border around the image */ for (x = 0; x < (pw * fw + aw) * rw; x++) { png_put_pixel(png, x, 0, 3, 0); png_put_pixel(png, x, 23, 3, 0); png_put_pixel(png, x, 24 + (ph * fh + ah) * rh - 1, 3, 0); } for (y = 0; y < 24 + (ph * fh + ah) * rh; y++) { png_put_pixel(png, 0, y, 3, 0); png_put_pixel(png, (pw * fw + aw) * rw - 1, y, 3, 0); } png_printf(png, 2, 2, "Font: %s; size: %d words; MD5: %s", basename, size/2, md5_digest((uint8_t *)al, size)); if (mw != fw) { png_printf(png, 2, 2 + FONTH, "max. width: %d (header: %d); height: %d; ascent: %d; fixed: %s", fw, mw, fh, ascent, fixed ? "yes" : "no"); } else { png_printf(png, 2, 2 + FONTH, "max. width: %d; height: %d; ascent: %d; fixed: %s", fw, fh, ascent, fixed ? "yes" : "no"); } for (i = first; i <= last; i++) { int x0 = (pw * fw + aw) * (i % rw) + 2; int y0 = 24 + (ph * fh + ah) * ((i - first) / rw) + ah - 3; h = extract_xw(bitmap, &w, al, size, i, fw, fh); if (0 == h) continue; /* undefined character */ png_printf(png, x0, y0 - FONTH, "[%d]", i); if (pw > 1) { /* draw a grid for the character */ for (x = 0; x < pw * w; x++) { for (y = 0; y <= ph * fh; y += ph) { png_put_pixel(png, x0 + x, y0 + y, y == ascent * ph ? 2 : 3, 0); } } for (y = 0; y < ph * fh; y++) { for (x = 0; x <= pw * w; x += pw) { png_put_pixel(png, x0 + x, y0 + y, 3, 0); } } } else { /* draw a border for the character */ for (x = 0; x < pw * w; x++) { png_put_pixel(png, x0 + x, y0 - 1, 1, 0); png_put_pixel(png, x0 + x, y0 + ph*fh, 3, 0); } for (y = 0; y < ph * fh; y++) { png_put_pixel(png, x0 - 1, y0 + y, 1, 0); png_put_pixel(png, x0 + pw*w, y0 + y, 3, 0); } } for (y = 0; y < fh; y++) png_bits(png, x0, y0, pw, ph, w, y, &bitmap[y*BITMAPW]); } png_finish(png); fclose(png_fp); } else { printf("font size is %d words\n", size / 2); printf("max. width: %d\n", fw); printf("height : %d\n", fh); printf("ascent : %d\n", ascent); printf("fixed font: %d\n", fixed); for (i = 0; i < 256; i++) { h = extract_xw(bitmap, &w, al, size, i, fw, fh); if (0 == h) continue; printf("\nchar:%d (%#x, '%c') w:%d h:%d\n", i, i, i >= 32 && i < 127 ? i : '.', w, h); for (y = 0; y < fh; y++) printf("[%s]\n", binstr(&bitmap[y*BITMAPW], w)); } } free(bitmap); free(al); return 0; } int main(int argc, char **argv) { char *pngfile = NULL; char *program; int i; program = strrchr(argv[0], '/'); if (program) program++; else program = argv[0]; if (argc < 2) { printf("usage: %s [options] altofont.al\n", program); printf("options may be one of:\n"); printf("-png filename.png\toutput PNG image of the font.\n"); printf("-md5\t\toutput PNG image to a file .png\n"); printf("-v\t\tverbose operation\n"); return 1; } for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (!strcmp(argv[i], "-png")) { ++i; pngfile = argv[i]; } if (!strcmp(argv[i], "-md5")) { pngfile = argv[i]; } if (!strcmp(argv[i], "-v")) { verbose = 1; } } else { dump_font(argv[i], pngfile); } } return 0; }