annotate tools/fontconv.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
rev   line source
paulo@0 1 #define USE_CONSOLE
paulo@0 2 #include <allegro.h>
paulo@0 3 #include <stdio.h>
paulo@0 4
paulo@0 5 const RGB fontPalette[6] = {
paulo@0 6 {63, 0,63},
paulo@0 7 {63,63,63},
paulo@0 8 {42,42,42},
paulo@0 9 { 0, 0, 0},
paulo@0 10 {63, 0, 0},
paulo@0 11 {63,63, 0}
paulo@0 12 };
paulo@0 13
paulo@0 14 typedef struct Rect {
paulo@0 15 signed short l, t, r, b;
paulo@0 16 } Rect;
paulo@0 17
paulo@0 18
paulo@0 19 BITMAP *fontImg;
paulo@0 20 const int cellHeight = 12;
paulo@0 21 Rect glyphs[256];
paulo@0 22 unsigned short glyphDataOffsets[256];
paulo@0 23
paulo@0 24 #define MIN_GLYPH 0
paulo@0 25 #define N_GLYPHS 256
paulo@0 26
paulo@0 27 char fontdata[65536];
paulo@0 28 size_t fontdata_len = 0;
paulo@0 29 size_t fontdata_shift = 0;
paulo@0 30
paulo@0 31 // stats
paulo@0 32 size_t eols = 0;
paulo@0 33 size_t xparents = 0;
paulo@0 34 size_t opaques = 0;
paulo@0 35 size_t xlucents = 0;
paulo@0 36
paulo@0 37 void collectStats(int c) {
paulo@0 38 for (int y = glyphs[c].t; y < glyphs[c].b; ++y) {
paulo@0 39
paulo@0 40 // Find right side of each row of glyph
paulo@0 41 int right = glyphs[c].l;
paulo@0 42 for (int x = glyphs[c].l; x < glyphs[c].r; ++x) {
paulo@0 43 int c = getpixel(fontImg, x, y);
paulo@0 44 if (c == 2 || c == 3) {
paulo@0 45 right = x + 1;
paulo@0 46 }
paulo@0 47 }
paulo@0 48
paulo@0 49 // Count transparent, semitransparent, and opaque
paulo@0 50 // pixels within row
paulo@0 51 for (int x = glyphs[c].l; x < right; ++x) {
paulo@0 52 switch (getpixel(fontImg, x, y)) {
paulo@0 53 case 1:
paulo@0 54 ++xparents;
paulo@0 55 break;
paulo@0 56 case 2:
paulo@0 57 ++xlucents;
paulo@0 58 break;
paulo@0 59 case 3:
paulo@0 60 ++opaques;
paulo@0 61 break;
paulo@0 62 }
paulo@0 63 }
paulo@0 64 ++eols;
paulo@0 65 }
paulo@0 66 }
paulo@0 67
paulo@0 68
paulo@0 69 void drawChar(int c) {
paulo@0 70 int left = glyphs[c].l;
paulo@0 71 int top = glyphs[c].t;
paulo@0 72 int right = glyphs[c].r;
paulo@0 73 int bottom = glyphs[c].b;
paulo@0 74 if ((c & 0x1F) == 0) {
paulo@0 75 rectfill(screen,
paulo@0 76 0, 288, SCREEN_W - 1, 288 + 32 * 4,
paulo@0 77 5);
paulo@0 78 }
paulo@0 79
paulo@0 80 int x = (c & 0x07) * (SCREEN_W / 8);
paulo@0 81 int y = 288 + 32 * ((c & 0x18) >> 3);
paulo@0 82
paulo@0 83 textprintf_ex(screen, font, x, y + bottom - top - 4, 3, -1,
paulo@0 84 "%c=", c);
paulo@0 85 stretch_blit(fontImg, screen,
paulo@0 86 left, top, right - left, bottom - top,
paulo@0 87 x + 16, y, (right - left) * 2, (bottom - top) * 2);
paulo@0 88 if ((c & 0x1F) == 0x1F) {
paulo@0 89 readkey();
paulo@0 90 }
paulo@0 91 }
paulo@0 92
paulo@0 93 // color 0: border around kernbox
paulo@0 94 // color 1: background
paulo@0 95 // color 2: mix bg+fg
paulo@0 96 // color 3: foreground
paulo@0 97 void findCharacters(void) {
paulo@0 98 int curChar = MIN_GLYPH;
paulo@0 99 int x = 0;
paulo@0 100 int y = 12;
paulo@0 101
paulo@0 102 for(y = 0; y < fontImg->h; y += cellHeight) {
paulo@0 103 for (x = 0; x < fontImg->w; ++x) {
paulo@0 104 // Skip if border pixel
paulo@0 105 if (getpixel(fontImg, x, y) != 0) {
paulo@0 106
paulo@0 107 // find left and right extents
paulo@0 108 int left = x;
paulo@0 109 int right;
paulo@0 110 for (right = x;
paulo@0 111 right < fontImg->w && getpixel(fontImg, right, y) != 0;
paulo@0 112 ++right) {
paulo@0 113 }
paulo@0 114
paulo@0 115 // record them
paulo@0 116 glyphs[curChar].l = left;
paulo@0 117 glyphs[curChar].t = y;
paulo@0 118 glyphs[curChar].r = right;
paulo@0 119 glyphs[curChar].b = y + cellHeight;
paulo@0 120 x = right;
paulo@0 121 ++curChar;
paulo@0 122 }
paulo@0 123 }
paulo@0 124 }
paulo@0 125
paulo@0 126 #if 0
paulo@0 127 int maxChar = curChar;
paulo@0 128 for (curChar = MIN_GLYPH; curChar < maxChar; ++curChar) {
paulo@0 129 collectStats(curChar);
paulo@0 130 drawChar(curChar);
paulo@0 131 }
paulo@0 132 #endif
paulo@0 133 }
paulo@0 134
paulo@0 135 void displayStats(void) {
paulo@0 136 rectfill(screen, 0, 288, 255, 479, 5);
paulo@0 137 textprintf_ex(screen, font, 4, 298, 3, -1,
paulo@0 138 "xparents: %d", xparents);
paulo@0 139 textprintf_ex(screen, font, 4, 308, 3, -1,
paulo@0 140 "xlucents: %d", xlucents);
paulo@0 141 textprintf_ex(screen, font, 4, 318, 3, -1,
paulo@0 142 "opaques: %d", opaques);
paulo@0 143 textprintf_ex(screen, font, 4, 328, 3, -1,
paulo@0 144 "end of lines: %d", eols);
paulo@0 145 textprintf_ex(screen, font, 4, 338, 3, -1,
paulo@0 146 "total number of bits: %d",
paulo@0 147 (xparents + xlucents + opaques + eols + 3) * 2);
paulo@0 148 }
paulo@0 149
paulo@0 150 /* Details of the font encoding
paulo@0 151
paulo@0 152 Header:
paulo@0 153 u8 offsetToEncodingTable;
paulo@0 154 u8 minGlyph;
paulo@0 155 u8 nGlyphs;
paulo@0 156 u8 fontHeight;
paulo@0 157
paulo@0 158 First the encoding table (nglyphs/2 bytes):
paulo@0 159 u16 offsetToGlyphData;
paulo@0 160 u8 glyphWidth;
paulo@0 161 u8 reserved;
paulo@0 162
paulo@0 163 Each glyph data element consists of a stream of bytes.
paulo@0 164 Each byte contains four 2-bit values packed little-endian:
paulo@0 165 0: Move pen to start of next line
paulo@0 166 1: Move pen to right
paulo@0 167 2: Draw pixel using 50% opacity and move pen to right
paulo@0 168 3: Draw pixel using 100% opacity and move pen to right
paulo@0 169 The glyph data is done when "Move pen to start of next line"
paulo@0 170 has run fontHeight times.
paulo@0 171
paulo@0 172 */
paulo@0 173 void compressPadByte(void) {
paulo@0 174 if (fontdata_shift > 0) {
paulo@0 175 fontdata_shift = 0;
paulo@0 176 ++fontdata_len;
paulo@0 177 }
paulo@0 178 }
paulo@0 179
paulo@0 180 void compressWriteCode(unsigned int code) {
paulo@0 181 fontdata[fontdata_len] |= code << fontdata_shift;
paulo@0 182 fontdata_shift += 2;
paulo@0 183 if (fontdata_shift >= 8) {
paulo@0 184 compressPadByte();
paulo@0 185 }
paulo@0 186 }
paulo@0 187
paulo@0 188 void compressGlyph(unsigned int c) {
paulo@0 189 glyphDataOffsets[c] = fontdata_len;
paulo@0 190 for (int y = glyphs[c].t; y < glyphs[c].b; ++y) {
paulo@0 191
paulo@0 192 // Find right side of each row of glyph
paulo@0 193 int right = glyphs[c].l;
paulo@0 194 for (int x = glyphs[c].l; x < glyphs[c].r; ++x) {
paulo@0 195 int c = getpixel(fontImg, x, y);
paulo@0 196 if (c == 2 || c == 3) {
paulo@0 197 right = x + 1;
paulo@0 198 }
paulo@0 199 }
paulo@0 200
paulo@0 201 // Write transparent, semitransparent, and opaque
paulo@0 202 // pixels within row
paulo@0 203 for (int x = glyphs[c].l; x < right; ++x) {
paulo@0 204 int code = getpixel(fontImg, x, y) & 3;
paulo@0 205 if (code == 0) {
paulo@0 206 code = 1;
paulo@0 207 }
paulo@0 208 compressWriteCode(code);
paulo@0 209 }
paulo@0 210
paulo@0 211 // Signal eol
paulo@0 212 compressWriteCode(0);
paulo@0 213 }
paulo@0 214 compressPadByte();
paulo@0 215 }
paulo@0 216
paulo@0 217 void compressFont(void) {
paulo@0 218 unsigned int minGlyph = MIN_GLYPH;
paulo@0 219 size_t nGlyphs = N_GLYPHS;
paulo@0 220 for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) {
paulo@0 221 compressGlyph(i);
paulo@0 222 }
paulo@0 223 }
paulo@0 224
paulo@0 225 int writeFont(const char *dstName) {
paulo@0 226 FILE *dst = fopen(dstName, "wb");
paulo@0 227 unsigned int minGlyph = MIN_GLYPH;
paulo@0 228 size_t nGlyphs = N_GLYPHS;
paulo@0 229 size_t headerLen = 4;
paulo@0 230 size_t glyphDataBase = nGlyphs * 4 + headerLen;
paulo@0 231
paulo@0 232 if (!dst) {
paulo@0 233 return EXIT_FAILURE;
paulo@0 234 }
paulo@0 235 fputc(4, dst); // offset to encoding table
paulo@0 236 fputc(minGlyph, dst);
paulo@0 237 fputc(nGlyphs, dst);
paulo@0 238 fputc(cellHeight, dst);
paulo@0 239
paulo@0 240 for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) {
paulo@0 241 size_t glyphDataOffset = glyphDataBase + glyphDataOffsets[i];
paulo@0 242 fputc(glyphDataOffset & 0xFF, dst);
paulo@0 243 fputc((glyphDataOffset >> 8) & 0xFF, dst);
paulo@0 244 fputc(glyphs[i].r - glyphs[i].l, dst);
paulo@0 245 fputc(0, dst);
paulo@0 246 }
paulo@0 247 fwrite(fontdata, fontdata_len, 1, dst);
paulo@0 248 fclose(dst);
paulo@0 249 return 0;
paulo@0 250 }
paulo@0 251
paulo@0 252 #define WATCHING 0
paulo@0 253
paulo@0 254 int main(int argc, const char *const *argv) {
paulo@0 255
paulo@0 256 if (argc != 3) {
paulo@0 257 fputs("syntax: fontconv fontbitmapname outname\n", stderr);
paulo@0 258 return EXIT_FAILURE;
paulo@0 259 }
paulo@0 260
paulo@0 261 allegro_init();
paulo@0 262 install_timer();
paulo@0 263
paulo@0 264 set_color_depth(8);
paulo@0 265 #if WATCHING
paulo@0 266 if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 256, 480, 0, 0) < 0) {
paulo@0 267 allegro_message("Could not open a dual screen sized window.\n");
paulo@0 268 return EXIT_FAILURE;
paulo@0 269 }
paulo@0 270 set_palette_range(fontPalette,
paulo@0 271 0, sizeof(fontPalette)/sizeof(fontPalette[0]) - 1,
paulo@0 272 1);
paulo@0 273 clear_bitmap(screen);
paulo@0 274 rectfill(screen, 0, 192, 255, 287, 2);
paulo@0 275 rectfill(screen, 0, 288, 255, 479, 5);
paulo@0 276 install_keyboard();
paulo@0 277 #endif
paulo@0 278
paulo@0 279 fontImg = load_bitmap(argv[1], NULL);
paulo@0 280 if (!fontImg) {
paulo@0 281 allegro_exit();
paulo@0 282 fprintf(stderr, "fontconv could not load %s\n",
paulo@0 283 argv[1]);
paulo@0 284 return EXIT_FAILURE;
paulo@0 285 }
paulo@0 286 findCharacters();
paulo@0 287 #if WATCHING
paulo@0 288 blit(fontImg, screen, 0, 0, 0, 0, fontImg->w, fontImg->h);
paulo@0 289 readkey();
paulo@0 290 displayStats();
paulo@0 291 readkey();
paulo@0 292 #endif
paulo@0 293 compressFont();
paulo@0 294 return writeFont(argv[2]);
paulo@0 295 } END_OF_MAIN();
paulo@0 296