/* * utf8gif -- UTF-8エンコーディングされたテキストファイルを読んで * ビットマップ→GIF変換 * * 0.0: Jun. 24, 2004 by Dai ISHIJIMA (as utf8bitmap) * 0.1: Jul. 1, 2004 (フォント情報のキャッシュ) * 0.2: Jul. 24, 2004 (utf8gif) * 0.3: Aug. 18, 2004 (縦書き) * 0.4: Aug. 26, 2004 (ファイル数上限) * 0.5: Aug. 27, 2004 (縦書き/横書き) */ #include #include #include #define YES 1 #define NO 0 #define MAX_UTF8_BYTES 3 #define PPMTOGIF "/usr/local/netpbm/bin/ppmtogif" #define CMDOPT "2>/dev/null" #define NEWLINE '\n' #define MAXFILES 32 /* 変換後のファイルの上限 */ #define HORZ 'h' #define VERT 'v' char *prog; #define shift --argc; ++argv #define FONTFILE "unifont.bdf" #define OUTPUT_STDOUT "-" #define WIDTH 128 #define HEIGHT 64 #define MAXFONT 65535 #define MAXGRYPH (8 * 1024 * 1024) #define match(s1,s2) strncasecmp((s1), (s2), strlen(s2)) typedef struct { int pos; int width; int height; } fontinfo_t; static fontinfo_t fontinfo[MAXFONT]; static unsigned char fontbuf[MAXGRYPH]; /* BDFフォントファイルを読む */ void readbdf(char *name) { FILE *fp; char s[BUFSIZ]; int pos; int width, height; int code; int b, bytesize, j; pos = 0; if ((fp = fopen(name, "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, name); } while (fgets(s, BUFSIZ, fp) != NULL) { if (match(s, "ENCODING") == 0) { /* 文字コード */ if (sscanf(s, "%*s %d", &code) < 1) { fprintf(stderr, "%s: can't get code: %s\n", prog, s); code = 0; } } if (match(s, "BBX") == 0) { /* フォントサイズ */ if (sscanf(s, "%*s %d %d", &width, &height) < 2) { fprintf(stderr, "%s: can't get width and height: %s\n", prog, s); width = height = 0; } } if (match(s, "BITMAP") == 0) { /* ビットマップ */ fontinfo[code].pos = pos; fontinfo[code].width = width; fontinfo[code].height = height; while (fgets(s, BUFSIZ, fp) != NULL) { if (match(s, "ENDFONT") == 0) { break; } if (sscanf(s, "%x", &b) < 1) { break; } bytesize = (width + 7) / 8; for (j = 0; j < bytesize; j++) { if (pos + bytesize - j - 1 >= MAXGRYPH) { fprintf(stderr, "%s: font buffer overflow\n", prog); exit(1); } fontbuf[pos + bytesize - j - 1] = b & 0x00ff; b >>= 8; } pos += bytesize; } } } fclose(fp); /* キャッシュ書き出し */ strcpy(s, name); strcat(s, ".cache"); if ((fp = fopen(s, "w")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, s); } fwrite(fontinfo, sizeof(fontinfo_t), MAXFONT, fp); fwrite(fontbuf, 1, pos, fp); fclose(fp); } /* フォント初期化 */ void initfont(char *name) { char s[BUFSIZ]; FILE *fp; strcpy(s, name); strcat(s, ".cache"); if ((fp = fopen(s, "r")) != NULL) { fread(fontinfo, sizeof(fontinfo_t), MAXFONT, fp); fread(fontbuf, 1, MAXGRYPH, fp); fclose(fp); } else { readbdf(name); } } /* 文字コード code のフォントを返す */ char *getfont(int code, int *width, int *height) { *width = fontinfo[code].width; *height = fontinfo[code].height; return(&fontbuf[fontinfo[code].pos]); } /* フォントのあるビットの状態 */ int bit(int width, int height, char *fontbuf, int x, int y) { int pos, bit; pos = (x / 8) + y * ((width + 7) / 8); bit = 0x0080 >> (x % 8); return(fontbuf[pos] & bit); } /* ビットマップのあるビットをセット */ void bitset(int width, int height, char *bitmap, int x, int y) { int pos, bit; pos = (x / 8) + y * ((width + 7) / 8); bit = 0x0080 >> (x % 8); bitmap[pos] |= bit; } /* フォントを描画 */ void putfont(int width, int height, char *canvas, int x, int y, char *fontbuf, int w, int h) { int i, j; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { if (bit(w, h, fontbuf, j, i)) { bitset(width, height, canvas, x + j, y + i); } } } } /* UTF-8のバイト長 */ int utf8length(unsigned char ch) { if (ch < 0x0080) { return(1); } else if (ch < 0x00e0) { return(2); } else { return(3); } } /* UTF-8文字列を16ビットUnicodeに変換 */ unsigned short utf8unicode(unsigned char *utf8) { int n; unsigned char hi, lo, mi; unsigned short unicode; n = utf8length(*utf8); if (n == 1) { n = 1; unicode = *utf8; } else if (n == 2) { hi = *utf8 & 0x1f; ++utf8; lo = *utf8 & 0x3f; unicode = ((unsigned short)hi << 6) + (unsigned short)lo; } else { hi = *utf8 & 0x0f; ++utf8; mi = *utf8 & 0x3f; ++utf8; lo = *utf8 & 0x3f; unicode = ((unsigned short)hi << 12) + ((unsigned short)mi << 6) + (unsigned short)lo; } return(unicode); } /* ビットマップ領域を描画 */ void showcanvas(int width, int height, char *canvas, char *output, int no) { FILE *pp; char cmd[BUFSIZ]; sprintf(cmd, "%s %s > %s-%03d.gif", PPMTOGIF, CMDOPT, output, no); if (strcmp(output, "-") == 0) { pp = stdout; } else if ((pp = popen(cmd, "w")) == NULL) { fprintf(stderr, "%s: can't open '%s'\n", prog, cmd); exit(1); } fprintf(pp, "P4\n%d %d\n", width, height); fwrite(canvas, (width + 7) / 8, height, pp); if (strcmp(output, "-") != 0) { if (pclose(pp) < 0) { fprintf(stderr, "%s: can't close '%s'\n", prog, cmd); } } } /* ファイルを読んでビットマップに変換 */ void utf8gif(FILE *fp, int width, int height, char *output, int linspc, int maxfil, int newlin, int direc) { int ch; unsigned char utf8[MAX_UTF8_BYTES]; int x, y; int w, h; int i; char *canvas, *fontbuf; int nbytes; unsigned short unicode; int fileno; fileno = 0; x = y = 0; if (direc == VERT) { x = width; } canvas = (char *)calloc(height, (width + 7) / 8); bzero(canvas, height * ((width + 7) / 8)); while ((fileno < maxfil) && ((ch = getc(fp)) != EOF)) { nbytes = utf8length(ch); utf8[0] = ch; for (i = 1; i < nbytes; i++) { utf8[i] = getc(fp); } unicode = utf8unicode(utf8); fontbuf = getfont(unicode, &w, &h); if (direc == VERT) { /* 縦書き */ if ((newlin) && (unicode == NEWLINE)) { y += height; } if (w > linspc) { linspc = w; } if (y + h > height) { y = 0; x -= linspc; } if (x - w < 0) { showcanvas(width, height, canvas, output, fileno); ++fileno; y = 0; x = width; bzero(canvas, height * ((width + 7) / 8)); } if (!((newlin) && (unicode == NEWLINE))) { putfont(width, height, canvas, x - w, y, fontbuf, w, h); y += h; } } else { /* 横書き */ if ((newlin) && (unicode == NEWLINE)) { x += width; } if (h > linspc) { linspc = h; } if (x + w > width) { x = 0; y += linspc; } if (y + h > height) { showcanvas(width, height, canvas, output, fileno); ++fileno; x = y = 0; bzero(canvas, height * ((width + 7) / 8)); } if (!((newlin) && (unicode == NEWLINE))) { putfont(width, height, canvas, x, y, fontbuf, w, h); x += w; } } } if ((x > 0) || (y > 0)) { showcanvas(width, height, canvas, output, fileno); } free(canvas); } void usage() { fprintf(stderr, "Usage: %s [options] [file]\n", prog); fputs(" options:\n", stderr); fputs("\t-w width\n", stderr); fputs("\t-h height\n", stderr); fputs("\t-o output_basename\n", stderr); fputs("\t-f font\n", stderr); } int main(int argc, char *argv[]) { FILE *fp; int width, height; char *output; char *fontfile; int linspc; int maxfil; int newlin; int direc; width = WIDTH; height = HEIGHT; linspc = WIDTH; fontfile = FONTFILE; output = OUTPUT_STDOUT; maxfil = MAXFILES; newlin = YES; direc = HORZ; prog = *argv; shift; while ((argc > 0) && (argv[0][0] == '-')) { if (argv[0][1] == 'w') { shift; width = atoi(*argv); } else if (argv[0][1] == 'h') { shift; height = atoi(*argv); } else if (argv[0][1] == 'o') { shift; output = *argv; } else if (argv[0][1] == 'f') { shift; fontfile = *argv; } else if (argv[0][1] == 'l') { shift; linspc = atoi(*argv); } else if (argv[0][1] == 'm') { shift; maxfil = atoi(*argv); } else if (argv[0][1] == 'n') { newlin = !newlin; } else if (argv[0][1] == 'x') { direc = HORZ; } else if (argv[0][1] == 'y') { direc = VERT; } else { usage(); } shift; } initfont(fontfile); if (argc > 0) { if ((fp = fopen(*argv, "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, *argv); exit(1); } utf8gif(fp, width, height, output, linspc, maxfil, newlin, direc); fclose(fp); } else { utf8gif(stdin, width, height, output, linspc, maxfil, newlin, direc); } exit(0); } /* Local Variables: */ /* compile-command:"gcc -Wall -o utf8gif2 utf8gif2.c" */ /* End: */