/* * esc2ps -- ESC/P to PostScript print format translator * * revision history: * 0.0: Oct. 30, 1996 by Dai Ishijima * 0.1: Nov. 15, 1996 * 0.2: Dec. 2, 1996 */ #include #ifdef MSDOS #include #include #ifdef NEED_STDLIB /* for LSI C-86 Ver 3.30c 試食版 */ #include #endif #ifndef HAVE_FSETBIN /* for Turbo C++ 1.0 2nd Ed., Borland C++ 2.0 */ #define fsetbin(fp) setmode(fileno(fp), O_BINARY); #endif #endif #define YES 1 #define NO 0 #define EOS '\0' #define BACKSLASH '\\' /* * PostScriptでの日本語フォントの扱い */ #define CHECKKANJI /* プリンタに装備されている日本語フォントをチェック */ #undef USE_HEISEI /* 日本語フォントとして平成フォントを使う */ /* * プリントバッファ */ /* サイズ */ #ifdef MSDOS #define MAXDBUF (20 * 1024) #else #define MAXDBUF (64 * 1024) #endif #define MAXPBUF 100 /* データの格納場所 */ unsigned char dbuf[MAXDBUF]; int nd; typedef struct { int type; /* バッファのタイプ */ int xpos; /* x座標 */ int width; /* ピクセル単位であらわした幅 */ int len; /* バイト単位のサイズ */ int chrwid; /* 一文字の幅 */ long attr; /* 属性 */ unsigned char *buf; /* データそのものの場所 -> dbuf */ } pbuf_t; /* プリントバッファ */ pbuf_t pbuf[MAXPBUF]; int np; /* プリントバッファのタイプ */ #define STRINGS 'S' /* 文字列 */ #define IMAGE8 'I' /* 8ドット ビットイメージ */ #define IMAGE24 'J' /* 24ドット ビットイメージ */ #define IMAGE24 'J' /* 24ドット ビットイメージ */ #define WHITEIMAGE 'W' /* 全部空白のビットイメージ */ /* pbuf.attr の値 */ /* ESC ! + n の属性 */ #define A_ELITE 0x00001L #define A_PROP 0x00002L #define A_CONDEN 0x00004L #define A_EMPHA 0x00008L #define A_DBLSTRK 0x00010L #define A_ENLARGE 0x00020L #define A_SLANT 0x00040L #define A_UNDRLIN 0x00080L /* FS ! + n の属性 */ #define A_KTATE 0x00100L #define A_KHAN 0x00200L #define A_KYOKOBAI 0x00400L #define A_KTATEBAI 0x00800L #define A_KSMALL 0x01000L #define A_KSCRIPT 0x02000L /* unused 0x04000L */ #define A_KUNDLIN 0x08000L /* */ #define A_AUTO 0x10000L /* 自動解除 */ #define A_CPI15 0x20000L /* 15CPI */ #define A_KANJI 0x40000L /* 漢字 */ /* * 長さの単位 */ #define BRES 1440L /* このトランスレータの単位長 (dpi) */ #define PRES 72 /* PostScriptの単位長 */ #define DRES 180 /* ESC/P-24の単位長 */ /* 単位の変換 */ #define MM(x) ((int)(((double)(x)) * BRES / 25.4)) #define INCH(x) ((int)(((double)(x)) * BRES)) /* 用紙サイズ */ #define PAPERHEIGHT MM(294) #define XOFF MM(4) #define YOFF MM(22) int xcur, ycur; /* 現在位置 (どちらもつねに >= 0) */ int xpos, ypos; /* ypos は使っていない */ int linspc; /* 行ピッチ */ int chrspc; /* 文字間スペース */ int rikspc; /* 漢字右スペース */ int lekspc; /* 漢字左スペース */ int draft; /* ドラフトモード */ int lemarg; /* 左マージン */ int rimarg; /* 右マージン */ int paglen; /* ページ長 */ int iattr; int oattr; int painted; /* タブ位置 */ #define MAXTAB 32 int tabpos[MAXTAB]; /* * コントロールコード */ #define BEL 7 #define BS 8 #define HT 9 #define LF 10 #define VT 11 #define FF 12 #define CR 13 #define SO 14 #define SI 15 #define DC2 18 #define DC4 20 #define CAN 24 #define ESC 27 #define FS 28 #define DEL 127 #define isctrl(ch) (((0 <= (ch)) && ((ch) <= 0x1f)) || ((ch) == 127)) /* * ビットイメージ */ /* 一行あたりの16進ダンプの数 */ #define NBYTES8 32 #define NBYTES24 24 /* ビットイメージモードの表 */ typedef struct { int mode; int bytes; int xres; /* x方向の解像度 */ int yres; /* y方向の解像度 */ int maxdots; } bitlist; static bitlist bits[] = { /* num, bytes, xres, yres, maxdots */ 0, 1, 60, 60, 480, 1, 1, 120, 60, 960, 2, 1, 120, 60, 960, 3, 1, 240, 60, 1920, 4, 1, 80, 60, 640, 6, 1, 90, 60, 720, 32, 3, 60, 180, 480, 33, 3, 120, 180, 960, 38, 3, 90, 180, 720, 39, 3, 180, 180, 1440, 40, 3, 360, 180, 2880, -1, -1, -1, -1, -1, }; /* ESC ? のビットイメージの対応表 */ #define BIT_K 0 #define BIT_L 1 #define BIT_Y 2 #define BIT_Z 3 /* K L Y Z */ static int bitconv[] = {0, 1, 2, 3}; /* * フォントの情報 */ typedef struct { char *name; char *scale; int size; } fontinfo; /* 属性値からフォントを返す */ fontinfo *font(int attr) { static fontinfo f; #ifdef USE_ROMAN f.name = "/Times-Roman"; #else f.name = "/Courier"; #endif f.scale = "[240 0 0 240 0 0]"; f.size = BRES / 10; if (attr & A_ELITE) { f.scale = "[200 0 0 240 0 0]"; f.size = BRES / 12; } if (attr & A_KANJI) { #if defined(CHECKKANJI) f.name = "Mincho"; #elif defined(USE_HEISEI) f.name = "/HeiseiMincho-W3"; #else f.name = "/Ryumin-Light-H"; #endif f.scale = "[192 0 0 192 0 0]"; f.size = 24 * BRES / DRES; } return(&f); } /* ページ開始処理 */ void pagestart() { puts("%%"); printf("%d %d div dup scale\n", PRES, (int)BRES); printf("%d %d translate\n", XOFF, PAPERHEIGHT - YOFF); ycur = 0; xcur = -1; } /* ページ終了処理 */ void pagefinish() { puts("showpage\n%\n"); painted = NO; } /* * コントロール文字、ESCシーケンス用テーブル */ typedef void (*noarg)(); typedef void (*witharg)(FILE *fp); /* 引数なし */ typedef struct { int code; noarg action; } cmdlst; /* 引数あり */ typedef struct { int code; witharg action; } fcmdlst; /* * 表示処理 */ /* 8ビット ビットイメージ */ void showimage8(pbuf_t *p) { int i; printf("gsave\n"); printf("currentpoint translate\n"); printf("%d %d scale\n", (int)(BRES / bits[p->attr].xres), (int)(BRES / bits[p->attr].yres)); printf("8 %d 1\n[0 1 -1 0 8 0]\n", p->len); printf("{currentfile 1 string readhexstring pop}\n"); printf("image\n"); for (i = 0; i < p->len; i++) { printf("%02x", (~p->buf[i]) & 0xff); if ((i % NBYTES8) == NBYTES8 - 1) { printf("\n"); } } if (((i - 1) % NBYTES8) != NBYTES8 - 1) { printf("\n"); } printf("grestore\n"); } /* 24ビット ビットイメージ */ void showimage24(pbuf_t *p) { int i; printf("gsave\n"); printf("currentpoint translate\n"); printf("%d %d scale\n", (int)(BRES / bits[p->attr].xres), (int)(BRES / bits[p->attr].yres)); printf("24 %d 1\n[0 1 -1 0 24 0]\n", p->len / 3); printf("{currentfile 3 string readhexstring pop}\n"); printf("image\n"); for (i = 0; i < p->len; i++) { printf("%02x", (~p->buf[i]) & 0xff); if ((i % NBYTES24) == NBYTES24 - 1) { printf("\n"); } } if (((i - 1) % NBYTES24) != NBYTES24 - 1) { printf("\n"); } printf("grestore\n"); } /* リテラル文字列で特別の意味を持つ文字 */ #define special(ch) (((ch) < ' ') || ('~' < (ch)) \ || ((ch) == '(') || ((ch) == ')') || ((ch) == BACKSLASH)) /* 文字列をPostScriptのリテラル文字列に変換 */ char *string(char *s) { static char buf[BUFSIZ]; char *t; t = &buf[0]; while (*s != EOS) { if (special(*s)) { /* 特別な文字は \ddd (8進数) 形式に */ *t++ = BACKSLASH; *t++ = '0' + *s / 64; *t++ = '0' + (*s / 8) % 8; *t++ = '0' + *s % 8; ++s; } else { *t++ = *s++; } } *t = EOS; return(&buf[0]); } /* 文字列の表示 */ void showstr(pbuf_t *p) { fontinfo *f; f = font(p->attr); if (oattr != p->attr) { oattr = p->attr; printf("%s findfont ", f->name); printf("%s makefont setfont\n", f->scale); } if (oattr & A_KANJI) { printf("(%s) %d kmonoshow\n", string(p->buf), p->chrwid); } else { printf("(%s) %d monoshow\n", string(p->buf), p->chrwid); } } /* バッファに入っているデータを表示 */ void showbuf() { int i; if ((np > 0) && (painted == NO)) { pagestart(); } for (i = 0; i < np; i++) { if (pbuf[i].xpos != xcur) { printf("%d %d moveto\n", pbuf[i].xpos, -ycur); } if (pbuf[i].type == STRINGS) { showstr(&pbuf[i]); xcur = pbuf[i].xpos + pbuf[i].width; } else if (pbuf[i].type == IMAGE8) { showimage8(&pbuf[i]); } else if (pbuf[i].type == IMAGE24) { showimage24(&pbuf[i]); } else if (pbuf[i].type == WHITEIMAGE) { puts("% blank bitimages supressed"); } else { fprintf(stderr, "Unknown buffer type (%d).\n", pbuf[i].type); } painted = YES; } } /* 行バッファをクリア */ void clrbuf() { nd = 0; np = 0; } /* * 入力処理 */ /* 文字列をバッファにためる */ void fillbuf(FILE *fp, int ch) { fontinfo *f; f = font(iattr); pbuf[np].type = STRINGS; pbuf[np].attr = iattr; pbuf[np].xpos = xpos; pbuf[np].len = 0; pbuf[np].buf = &dbuf[nd]; dbuf[nd] = ch; ++nd; ++pbuf[np].len; while ((ch = getc(fp)) != EOF) { if (isctrl(ch)) { ungetc(ch, fp); break; } dbuf[nd] = ch; ++nd; ++pbuf[np].len; } dbuf[nd] = EOS; if (iattr & A_KANJI) { pbuf[np].chrwid = f->size + rikspc + lekspc; pbuf[np].width = pbuf[np].chrwid * pbuf[np].len / 2; } else { pbuf[np].chrwid = f->size + chrspc; pbuf[np].width = pbuf[np].chrwid * pbuf[np].len; } xpos += pbuf[np].width; ++nd; ++pbuf[np].len; ++np; if (np >= MAXPBUF) { showbuf(); clrbuf(); } } /* * 引数をとらないESCシーケンス処理 */ /* ESC @ */ void escpinit() { linspc = BRES / 6; chrspc = 0; lemarg = 0; rimarg = 8 * BRES; paglen = BRES * 10.5; iattr = 0; oattr = -1; } /* ESC P */ void setpica() { iattr = iattr & ~A_ELITE; } /* ESC M */ void setelite() { iattr = iattr | A_ELITE; } /* ESC 0 */ void linspc8() { linspc = BRES / 8; } /* ESC 2 */ void linspc6() { linspc = BRES / 6; } /* * 引数をとるESCシーケンス処理 */ /* ESC Q */ void setrimarg(FILE *fp) { int ch; fontinfo *f; ch = getc(fp); f = font(iattr & ~A_KANJI); rimarg = ch * (f->size + chrspc); } /* ESC l */ void setlemarg(FILE *fp) { int ch; fontinfo *f; ch = getc(fp); f = font(iattr & ~A_KANJI); lemarg = ch * (f->size + chrspc); if (xpos < lemarg) { xpos = lemarg; } } /* ESC x */ void draftmode(FILE *fp) { int ch; ch = getc(fp); if (ch & 1) { draft = NO; } else { draft = YES; } } /* ESC D */ void settab(FILE *fp) { int ch; int p; fontinfo *f; f = font(iattr & ~A_KANJI); for (p = 0; p < MAXTAB; p++) { ch = getc(fp); if ((ch <= 0) || ((p > 0) && (ch <= tabpos[p - 1]))) { break; } tabpos[p] = ch; } for (; p < MAXTAB; p++) { tabpos[p] = 0; } for (p = 0; p < MAXTAB; p++) { if (tabpos[p] > 0) { tabpos[p] = tabpos[p] * (f->size + chrspc) + lemarg; } } } /* 各種ビットイメージをバッファにためる */ void bitimage(FILE *fp, int mode) { int i; int n; int h, l; int isblank; for (i = 0; bits[i].mode >= 0; i++) { if (mode == bits[i].mode) { break; } } if (bits[i].mode < 0) { fprintf(stderr, "Unknown bitimage mode (%d)\n", mode); i = 0; mode = bits[i].mode; } l = getc(fp); h = getc(fp); if (bits[i].bytes == 3) { pbuf[np].type = IMAGE24; pbuf[np].len = (h * 256 + l) * 3; } else { pbuf[np].type = IMAGE8; pbuf[np].len = h * 256 + l; } pbuf[np].xpos = xpos; pbuf[np].width = (h * 256 + l) * BRES / bits[i].xres; xpos += pbuf[np].width; pbuf[np].attr = i; pbuf[np].buf = &dbuf[nd]; isblank = 0; for (n = 0; n < pbuf[np].len; n++) { dbuf[nd] = getc(fp); isblank |= dbuf[nd]; ++nd; } if (isblank == 0) { pbuf[np].type = WHITEIMAGE; } ++np; if (np >= MAXPBUF) { showbuf(); clrbuf(); } } /* ESC * */ void bitimg_star(FILE *fp) { int mode; mode = getc(fp); bitimage(fp, mode); } /* ESC K */ void bitimg_k(FILE *fp) { bitimage(fp, bitconv[BIT_K]); } /* ESC L */ void bitimg_l(FILE *fp) { bitimage(fp, bitconv[BIT_L]); } /* ESC Y */ void bitimg_y(FILE *fp) { bitimage(fp, bitconv[BIT_Y]); } /* ESC Z */ void bitimg_z(FILE *fp) { bitimage(fp, bitconv[BIT_Z]); } /* ESC 3 */ void setlinspc(FILE *fp) { int ch; ch = getc(fp); linspc = ch * BRES / DRES; } /* ESC A */ void setlinspc60(FILE *fp) { int ch; ch = getc(fp); linspc = ch * BRES / 60; } /* ESC J */ void paperfeed(FILE *fp) { int ch; ch = getc(fp); showbuf(); clrbuf(); ycur = ycur + ch * BRES / DRES; if (ycur >= paglen) { pagefinish(); ycur = 0; } } /* ESC j */ void revfeed(FILE *fp) { int ch; ch = getc(fp); showbuf(); clrbuf(); ycur = ycur - ch * BRES / DRES; if (ycur < 0) { ycur = 0; } } /* ESC \ */ void dotspace(FILE *fp) { int h, l; l = getc(fp); h = getc(fp); xpos = xpos + (signed short)(h * 256 + l) * BRES / DRES; if (xpos < lemarg) { xpos = lemarg; } } /* 引数をとらないESCシーケンスの表 */ cmdlst esc_tab1[] = { '@', escpinit, 'P', setpica, 'M', setelite, '0', linspc8, '2', linspc6, -1, NULL, }; /* 引数をとるESCシーケンスの表 */ fcmdlst esc_tab2[] = { 'Q', setrimarg, 'l', setlemarg, 'x', draftmode, 'D', settab, 'K', bitimg_k, 'L', bitimg_l, 'Y', bitimg_y, 'Z', bitimg_z, '*', bitimg_star, '3', setlinspc, 'A', setlinspc60, 'J', paperfeed, 'j', revfeed, '\\', dotspace, -1, NULL, }; /* ESCシーケンスの処理 */ void escape(FILE *fp) { int ch; int i; ch = getc(fp); for (i = 0; esc_tab1[i].action != NULL; i++) { if (esc_tab1[i].code == ch) { break; } } if (esc_tab1[i].action != NULL) { (*esc_tab1[i].action)(); } else { for (i = 0; esc_tab2[i].action != NULL; i++) { if (esc_tab2[i].code == ch) { break; } } if (esc_tab2[i].action != NULL) { (*esc_tab2[i].action)(fp); } else { if (isctrl(ch)) { fprintf(stderr, "Unknown escape sequence: ESC %02x\n", ch); } else { fprintf(stderr, "Unknown escape sequence: ESC %c\n", ch); } } } } /* * 引数をとらないFSシーケンス処理 */ /* FS & */ void kanji_in() { iattr = iattr | A_KANJI; } /* FS . */ void kanji_out() { iattr = iattr & ~A_KANJI; } /* * 引数をとるFSシーケンス処理 */ /* FS S */ void setkspc(FILE *fp) { int ch; ch = getc(fp); rikspc = ch * BRES / DRES; ch = getc(fp); lekspc = ch * BRES / DRES; } /* 引数をとらないFSシーケンスの表 */ cmdlst fs_tab1[] = { '&', kanji_in, '.', kanji_out, -1, NULL, }; /* 引数をとるFSシーケンスの表 */ fcmdlst fs_tab2[] = { 'S', setkspc, 'x', draftmode, -1, NULL, }; /* FSシーケンスの処理 */ void fs(FILE *fp) { int ch; int i; ch = getc(fp); for (i = 0; fs_tab1[i].action != NULL; i++) { if (fs_tab1[i].code == ch) { break; } } if (fs_tab1[i].action != NULL) { (*fs_tab1[i].action)(); } else { for (i = 0; fs_tab2[i].action != NULL; i++) { if (fs_tab2[i].code == ch) { break; } } if (fs_tab2[i].action != NULL) { (*fs_tab2[i].action)(fp); } else { if (isctrl(ch)) { fprintf(stderr, "Unknown escape sequence: FS %02x\n", ch); } else { fprintf(stderr, "Unknown escape sequence: FS %c\n", ch); } } } } /* * コントロール文字の処理 */ /* TAB */ void tab() { int i; for (i = 0; i < MAXTAB; i++) { if (xpos < tabpos[i]) { break; } } if (i < MAXTAB) { xpos = tabpos[i]; } } /* BS */ void bs() { fontinfo *f; f = font(iattr & ~A_KANJI); xcur -= (f->size + chrspc); if (xcur < lemarg) { xcur = lemarg; } } /* CR */ void cr() { showbuf(); clrbuf(); xpos = lemarg; } /* LF */ void lf() { showbuf(); clrbuf(); xpos = lemarg; ycur += linspc; if (ycur >= paglen) { pagefinish(); ycur = 0; } } /* FF */ void ff() { if (painted) { pagefinish(); } } /* 引数をとらないコントロール文字の表 */ cmdlst ctrl_tab1[] = { BS, bs, HT, tab, CR, cr, LF, lf, FF, ff, -1, NULL, }; /* 引数をとるコントロール文字の表 */ fcmdlst ctrl_tab2[] = { ESC, escape, FS, fs, -1, NULL, }; /* コントロール文字の処理 */ void control(FILE *fp, int ch) { int i; for (i = 0; ctrl_tab1[i].action != NULL; i++) { if (ctrl_tab1[i].code == ch) { break; } } if (ctrl_tab1[i].action != NULL) { (*ctrl_tab1[i].action)(); } else { for (i = 0; ctrl_tab2[i].action != NULL; i++) { if (ctrl_tab2[i].code == ch) { break; } } if (ctrl_tab2[i].action != NULL) { (*ctrl_tab2[i].action)(fp); } else { fprintf(stderr, "Unknown control code (%02x)\n", ch); } } } /* ESC/PをPostScriptに変換 */ void esc2ps(FILE *fp) { int ch; clrbuf(); while ((ch = getc(fp)) != EOF) { if (isctrl(ch)) { control(fp, ch); } else { fillbuf(fp, ch); } } if (np > 0) { cr(); } if (painted == YES) { pagefinish(); } } /* PostScriptの初期化 */ void psinit() { puts("%!"); puts(""); puts("% mono space show"); puts("/onechar (1) def"); puts("/charwidth 1 def"); puts("/spacing 1 def"); puts("/monoshow { % def"); puts(" /charwidth exch def"); puts(" { % forall"); puts(" onechar exch 0 exch put"); puts(" onechar dup"); puts(" stringwidth pop"); puts(" charwidth exch sub 2 div"); puts(" /spacing exch def"); puts(" spacing 0 rmoveto"); puts(" show"); puts(" spacing 0 rmoveto"); puts(" } forall"); puts("} def %monoshow"); puts(""); puts("% kanji mono space show"); puts("/twochar (12) def"); puts("/nbyte 1 def"); puts("/kmonoshow { % def"); puts(" /charwidth exch def"); puts(" /nbyte 1 def"); puts(" { % forall"); puts(" nbyte 1 eq { % ifelse"); puts(" twochar exch 0 exch put"); puts(" /nbyte 2 def"); puts(" } { % else"); puts(" twochar exch 1 exch put"); puts(" /nbyte 1 def"); puts(" twochar dup"); puts(" stringwidth pop"); puts(" charwidth exch sub 2 div"); puts(" /spacing exch def"); puts(" spacing 0 rmoveto"); puts(" show"); puts(" spacing 0 rmoveto"); puts(" } ifelse % nbyte 1 eq"); puts(" } forall"); puts("} def %kmonoshow"); puts(""); #ifdef CHECKKANJI puts("% check kanji font"); puts("FontDirectory /Ryumin-Light-H known"); puts("{ % if"); puts(" /Mincho /Ryumin-Light-H def"); puts("} { % else"); puts(" /Mincho /HeiseiMincho-W3 def"); puts("} ifelse"); puts(""); #endif } void main() { #ifdef MSDOS fsetbin(stdin); #endif escpinit(); painted = NO; psinit(); esc2ps(stdin); exit(0); } /* Local Variables: */ /* compile-command:"gcc -o esc2ps esc2ps.c" */ /* End: */