diff tools/fontconv.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/fontconv.c	Fri Mar 13 00:39:12 2009 -0700
     1.3 @@ -0,0 +1,296 @@
     1.4 +#define USE_CONSOLE
     1.5 +#include <allegro.h>
     1.6 +#include <stdio.h>
     1.7 +
     1.8 +const RGB fontPalette[6] = {
     1.9 +  {63, 0,63},
    1.10 +  {63,63,63},
    1.11 +  {42,42,42},
    1.12 +  { 0, 0, 0},
    1.13 +  {63, 0, 0},
    1.14 +  {63,63, 0}
    1.15 +};
    1.16 +
    1.17 +typedef struct Rect {
    1.18 +  signed short l, t, r, b;
    1.19 +} Rect;
    1.20 +
    1.21 +
    1.22 +BITMAP *fontImg;
    1.23 +const int cellHeight = 12;
    1.24 +Rect glyphs[256];
    1.25 +unsigned short glyphDataOffsets[256];
    1.26 +
    1.27 +#define MIN_GLYPH 0
    1.28 +#define N_GLYPHS 256
    1.29 +
    1.30 +char fontdata[65536];
    1.31 +size_t fontdata_len = 0;
    1.32 +size_t fontdata_shift = 0;
    1.33 +
    1.34 +// stats
    1.35 +size_t eols = 0;
    1.36 +size_t xparents = 0;
    1.37 +size_t opaques = 0;
    1.38 +size_t xlucents = 0;
    1.39 +
    1.40 +void collectStats(int c) {
    1.41 +  for (int y = glyphs[c].t; y < glyphs[c].b; ++y) {
    1.42 +
    1.43 +    // Find right side of each row of glyph
    1.44 +    int right = glyphs[c].l;
    1.45 +    for (int x = glyphs[c].l; x < glyphs[c].r; ++x) {
    1.46 +      int c = getpixel(fontImg, x, y);
    1.47 +      if (c == 2 || c == 3) {
    1.48 +        right = x + 1;
    1.49 +      }
    1.50 +    }
    1.51 +
    1.52 +    // Count transparent, semitransparent, and opaque
    1.53 +    // pixels within row
    1.54 +    for (int x = glyphs[c].l; x < right; ++x) {
    1.55 +      switch (getpixel(fontImg, x, y)) {
    1.56 +      case 1:
    1.57 +        ++xparents;
    1.58 +        break;
    1.59 +      case 2:
    1.60 +        ++xlucents;
    1.61 +        break;
    1.62 +      case 3:
    1.63 +        ++opaques;
    1.64 +        break;
    1.65 +      }
    1.66 +    }
    1.67 +    ++eols;
    1.68 +  }
    1.69 +}
    1.70 +
    1.71 +
    1.72 +void drawChar(int c) {
    1.73 +  int left = glyphs[c].l;
    1.74 +  int top = glyphs[c].t;
    1.75 +  int right = glyphs[c].r;
    1.76 +  int bottom = glyphs[c].b;
    1.77 +  if ((c & 0x1F) == 0) {
    1.78 +    rectfill(screen,
    1.79 +             0, 288, SCREEN_W - 1, 288 + 32 * 4,
    1.80 +             5);
    1.81 +  }
    1.82 +  
    1.83 +  int x = (c & 0x07) * (SCREEN_W / 8);
    1.84 +  int y = 288 + 32 * ((c & 0x18) >> 3);
    1.85 +  
    1.86 +  textprintf_ex(screen, font, x, y + bottom - top - 4, 3, -1,
    1.87 +                "%c=", c);
    1.88 +  stretch_blit(fontImg, screen,
    1.89 +               left, top, right - left, bottom - top,
    1.90 +               x + 16, y, (right - left) * 2, (bottom - top) * 2);
    1.91 +  if ((c & 0x1F) == 0x1F) {
    1.92 +    readkey();
    1.93 +  }
    1.94 +}
    1.95 +
    1.96 +// color 0: border around kernbox
    1.97 +// color 1: background
    1.98 +// color 2: mix bg+fg
    1.99 +// color 3: foreground
   1.100 +void findCharacters(void) {
   1.101 +  int curChar = MIN_GLYPH;
   1.102 +  int x = 0;
   1.103 +  int y = 12;
   1.104 +
   1.105 +  for(y = 0; y < fontImg->h; y += cellHeight) {
   1.106 +    for (x = 0; x < fontImg->w; ++x) {
   1.107 +      // Skip if border pixel
   1.108 +      if (getpixel(fontImg, x, y) != 0) {
   1.109 +      
   1.110 +        // find left and right extents
   1.111 +        int left = x;
   1.112 +        int right;
   1.113 +        for (right = x;
   1.114 +             right < fontImg->w && getpixel(fontImg, right, y) != 0;
   1.115 +             ++right) {
   1.116 +        }
   1.117 +
   1.118 +        // record them
   1.119 +        glyphs[curChar].l = left;
   1.120 +        glyphs[curChar].t = y;
   1.121 +        glyphs[curChar].r = right;
   1.122 +        glyphs[curChar].b = y + cellHeight;
   1.123 +        x = right;
   1.124 +        ++curChar;
   1.125 +      }
   1.126 +    }
   1.127 +  }
   1.128 +
   1.129 +#if 0  
   1.130 +  int maxChar = curChar;
   1.131 +  for (curChar = MIN_GLYPH; curChar < maxChar; ++curChar) {
   1.132 +    collectStats(curChar);
   1.133 +    drawChar(curChar);
   1.134 +  }
   1.135 +#endif
   1.136 +}
   1.137 +
   1.138 +void displayStats(void) {
   1.139 +  rectfill(screen, 0, 288, 255, 479, 5);
   1.140 +  textprintf_ex(screen, font, 4, 298, 3, -1,
   1.141 +                "xparents: %d", xparents);
   1.142 +  textprintf_ex(screen, font, 4, 308, 3, -1,
   1.143 +                "xlucents: %d", xlucents);
   1.144 +  textprintf_ex(screen, font, 4, 318, 3, -1,
   1.145 +                "opaques: %d", opaques);
   1.146 +  textprintf_ex(screen, font, 4, 328, 3, -1,
   1.147 +                "end of lines: %d", eols);
   1.148 +  textprintf_ex(screen, font, 4, 338, 3, -1,
   1.149 +                "total number of bits: %d",
   1.150 +                (xparents + xlucents + opaques + eols + 3) * 2);
   1.151 +}
   1.152 +
   1.153 +/* Details of the font encoding
   1.154 +
   1.155 +Header:
   1.156 +u8 offsetToEncodingTable;
   1.157 +u8 minGlyph;
   1.158 +u8 nGlyphs;
   1.159 +u8 fontHeight;
   1.160 +
   1.161 +First the encoding table (nglyphs/2 bytes):
   1.162 +u16 offsetToGlyphData;
   1.163 +u8 glyphWidth;
   1.164 +u8 reserved;
   1.165 +
   1.166 +Each glyph data element consists of a stream of bytes.
   1.167 +Each byte contains four 2-bit values packed little-endian:
   1.168 +0: Move pen to start of next line
   1.169 +1: Move pen to right
   1.170 +2: Draw pixel using 50% opacity and move pen to right
   1.171 +3: Draw pixel using 100% opacity and move pen to right
   1.172 +The glyph data is done when "Move pen to start of next line"
   1.173 +has run fontHeight times.
   1.174 +
   1.175 +*/
   1.176 +void compressPadByte(void) {
   1.177 +  if (fontdata_shift > 0) {
   1.178 +    fontdata_shift = 0;
   1.179 +    ++fontdata_len;
   1.180 +  }
   1.181 +}
   1.182 +
   1.183 +void compressWriteCode(unsigned int code) {
   1.184 +  fontdata[fontdata_len] |= code << fontdata_shift;
   1.185 +  fontdata_shift += 2;
   1.186 +  if (fontdata_shift >= 8) {
   1.187 +    compressPadByte();
   1.188 +  }
   1.189 +}
   1.190 +
   1.191 +void compressGlyph(unsigned int c) {
   1.192 +  glyphDataOffsets[c] = fontdata_len;
   1.193 +  for (int y = glyphs[c].t; y < glyphs[c].b; ++y) {
   1.194 +
   1.195 +    // Find right side of each row of glyph
   1.196 +    int right = glyphs[c].l;
   1.197 +    for (int x = glyphs[c].l; x < glyphs[c].r; ++x) {
   1.198 +      int c = getpixel(fontImg, x, y);
   1.199 +      if (c == 2 || c == 3) {
   1.200 +        right = x + 1;
   1.201 +      }
   1.202 +    }
   1.203 +
   1.204 +    // Write transparent, semitransparent, and opaque
   1.205 +    // pixels within row
   1.206 +    for (int x = glyphs[c].l; x < right; ++x) {
   1.207 +      int code = getpixel(fontImg, x, y) & 3;
   1.208 +      if (code == 0) {
   1.209 +        code = 1;
   1.210 +      }
   1.211 +      compressWriteCode(code);
   1.212 +    }
   1.213 +    
   1.214 +    // Signal eol
   1.215 +    compressWriteCode(0);
   1.216 +  }
   1.217 +  compressPadByte();
   1.218 +}
   1.219 +
   1.220 +void compressFont(void) {
   1.221 +  unsigned int minGlyph = MIN_GLYPH;
   1.222 +  size_t nGlyphs = N_GLYPHS;
   1.223 +  for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) {
   1.224 +    compressGlyph(i);
   1.225 +  }
   1.226 +}
   1.227 +
   1.228 +int writeFont(const char *dstName) {
   1.229 +  FILE *dst = fopen(dstName, "wb");
   1.230 +  unsigned int minGlyph = MIN_GLYPH;
   1.231 +  size_t nGlyphs = N_GLYPHS;
   1.232 +  size_t headerLen = 4;
   1.233 +  size_t glyphDataBase = nGlyphs * 4 + headerLen;
   1.234 +
   1.235 +  if (!dst) {
   1.236 +    return EXIT_FAILURE;
   1.237 +  }
   1.238 +  fputc(4, dst); // offset to encoding table
   1.239 +  fputc(minGlyph, dst);
   1.240 +  fputc(nGlyphs, dst);
   1.241 +  fputc(cellHeight, dst);
   1.242 +  
   1.243 +  for (size_t i = minGlyph; i < minGlyph + nGlyphs; ++i) {
   1.244 +    size_t glyphDataOffset = glyphDataBase + glyphDataOffsets[i];
   1.245 +    fputc(glyphDataOffset & 0xFF, dst);
   1.246 +    fputc((glyphDataOffset >> 8) & 0xFF, dst);
   1.247 +    fputc(glyphs[i].r - glyphs[i].l, dst);
   1.248 +    fputc(0, dst);
   1.249 +  }
   1.250 +  fwrite(fontdata, fontdata_len, 1, dst);
   1.251 +  fclose(dst);
   1.252 +  return 0;
   1.253 +}
   1.254 +
   1.255 +#define WATCHING 0
   1.256 +
   1.257 +int main(int argc, const char *const *argv) {
   1.258 +
   1.259 +  if (argc != 3) {
   1.260 +    fputs("syntax: fontconv fontbitmapname outname\n", stderr);
   1.261 +    return EXIT_FAILURE;
   1.262 +  }
   1.263 +
   1.264 +  allegro_init();
   1.265 +  install_timer();
   1.266 +
   1.267 +  set_color_depth(8);
   1.268 +#if WATCHING
   1.269 +  if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 256, 480, 0, 0) < 0) {
   1.270 +    allegro_message("Could not open a dual screen sized window.\n");
   1.271 +    return EXIT_FAILURE;
   1.272 +  }
   1.273 +  set_palette_range(fontPalette,
   1.274 +                    0, sizeof(fontPalette)/sizeof(fontPalette[0]) - 1,
   1.275 +                    1);
   1.276 +  clear_bitmap(screen);
   1.277 +  rectfill(screen, 0, 192, 255, 287, 2);
   1.278 +  rectfill(screen, 0, 288, 255, 479, 5);
   1.279 +  install_keyboard();
   1.280 +#endif
   1.281 +  
   1.282 +  fontImg = load_bitmap(argv[1], NULL);
   1.283 +  if (!fontImg) {
   1.284 +    allegro_exit();
   1.285 +    fprintf(stderr, "fontconv could not load %s\n",
   1.286 +            argv[1]);
   1.287 +    return EXIT_FAILURE;
   1.288 +  }
   1.289 +  findCharacters();
   1.290 +#if WATCHING
   1.291 +  blit(fontImg, screen, 0, 0, 0, 0, fontImg->w, fontImg->h);
   1.292 +  readkey();
   1.293 +  displayStats();
   1.294 +  readkey();
   1.295 +#endif
   1.296 +  compressFont();
   1.297 +  return writeFont(argv[2]);
   1.298 +} END_OF_MAIN();
   1.299 +