static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/pk.c,v 1.7 90/10/19 09:54:55 jjc Exp $"; #include "dvitops.h" #define pk_id 89 #if 0 enum pk_command { pk_xxx1 = 240, pk_xxx2 = 241, pk_xxx3 = 242, pk_xxx4 = 243, pk_yyy = 244, pk_post = 245, pk_no_op = 246, pk_pre = 247 }; #else #define pk_xxx1 240 #define pk_xxx2 241 #define pk_xxx3 242 #define pk_xxx4 243 #define pk_yyy 244 #define pk_post 245 #define pk_no_op 246 #define pk_pre 247 #endif static struct { integer llx, lly, urx, ury; } bb; /* bounding box for the entire font */ #ifdef PROTO static void out_byte(PROMOTED_UNSIGNED_CHAR c, FILE *psfp); static void blacken(integer start, integer n, unsigned char *buf); static integer packed_num(int dyn_f); static void bitmap_char(integer h, integer w, FILE *psfp); static integer makeinteger(unsigned char *p); static int generate_char(PROMOTED_UNSIGNED_CHAR flag, unsigned char *data, size_t len, FILE *psfp); #else static void out_byte(); static void blacken(); static integer packed_num(); static void bitmap_char(); static integer makeinteger(); static int generate_char(); #endif static struct pk_info { integer ds; integer hppp; integer vppp; unsigned char flag[MAXCHARS]; size_t len[MAXCHARS]; unsigned char *data[MAXCHARS]; } *pk_table[MAXFONTS]; static integer nbytes; char *find_pk_file(name, mag) char *name; int mag; { FILE *pkfp; int i; static char buf[10*FILENAME_MAX]; char *ptr = buf; static char sep[2] = {AREA_LIST_SEP, '\0'}; for (i = 0; texpk[i] != '\0'; i++) if (texpk[i] == '%') { switch(texpk[i+1]) { case 'f': case 'F': strcpy(ptr, name); break; case 'd': case 'D': sprintf(ptr, "%d", mag); break; default: sprintf(ptr, "%c", texpk[i+1]); } ++i; ptr += strlen(ptr); } else *ptr++ = texpk[i]; *ptr = '\0'; for (ptr = strtok(buf, sep); ptr != NULL; ptr = strtok((char *)NULL, sep)) { if ((pkfp = FOPEN_RB(ptr)) != NULL) { fclose(pkfp); return ptr; } } return NULL; } int load_pk_font(f, name, used, at_size, checksum, width, rounded_width) int f; char *name, *used; integer at_size, checksum, *width, *rounded_width; { FILE *pkfp; integer n; integer cs; double sppp; int i; if ((pkfp = FOPEN_RB(name)) == NULL) { message(ERROR, "can't find pk file for %s: using white space instead", name); return 0; } #ifdef HAVE_SETVBUF setvbuf(pkfp, (char *)NULL, _IOFBF, 8192); #endif if ((pk_table[f] = (struct pk_info *) calloc(1, sizeof(struct pk_info))) == NULL) out_of_memory(); if (uread1(pkfp) != pk_pre) goto bad; if (uread1(pkfp) != pk_id) goto bad; n = uread1(pkfp); fseek(pkfp, n, 1); pk_table[f]->ds = sread4(pkfp); cs = sread4(pkfp); pk_table[f]->hppp = sread4(pkfp); pk_table[f]->vppp = sread4(pkfp); /* sppp = scaled points per pixel sppp*dx = width in scaled points */ sppp = (double)at_size*1048576.0*65536.0 /((double)pk_table[f]->ds*(double)pk_table[f]->hppp); if (cs != checksum) message(WARNING, "%s: checksums don't match\n", name); for (;;) { unsigned char command = uread1(pkfp); if (feof(pkfp) || ferror(pkfp)) goto bad; if (((unsigned)command >> 4) == 15) { switch (command) { case pk_xxx1 : n = uread1(pkfp); break; case pk_xxx2 : n = uread2(pkfp); break; case pk_xxx3 : n = uread3(pkfp); break; case pk_xxx4 : n = sread4(pkfp); break; case pk_yyy : (void) sread4(pkfp); break; case pk_post : for (i = 0; i < MAXCHARS; i++) if (used[i] && width[i] == (integer) LONG_MAX) goto bad; fclose(pkfp); return 1; case pk_no_op : break; default: goto bad; } if (pk_xxx1 <= command && command <= pk_xxx4) fseek(pkfp, n, 1); } else { integer cc, pl; integer tfm; double dx; unsigned char c; size_t len; unsigned char flag = command; command &= 0x07; if (command == 0x07) { pl = sread4(pkfp); cc = sread4(pkfp); tfm = sread4(pkfp); dx = (double)sread4(pkfp)/65536.0; fseek(pkfp, -4L, 1); pl -= 4; } else if (command & 0x04) { pl = uread2(pkfp); pl |= (integer)(command & 0x03) << 16; cc = uread1(pkfp); tfm = uread3(pkfp); dx = (double)uread2(pkfp); fseek(pkfp, -2L, 1); pl -= 3; } else { pl = uread1(pkfp); pl |= (command & 0x03) << 8; cc = uread1(pkfp); tfm = uread3(pkfp); dx = (double)uread1(pkfp); fseek(pkfp, -1L, 1); pl -= 3; } if (cc < 0 || cc >= MAXCHARS) { fseek(pkfp, pl, SEEK_CUR); continue; } c = (unsigned char)cc; if (!used[c]) { pk_table[f]->data[c] = NULL; fseek(pkfp, pl, SEEK_CUR); } else { if (pl < 0 || pl > SIZE_MAX) goto bad; len = (size_t)pl; width[c] = scale(tfm, at_size); rounded_width[c] = (integer)(dx*sppp); pk_table[f]->flag[c] = flag; pk_table[f]->len[c] = len; if ((pk_table[f]->data[c] = (unsigned char *)malloc(len)) == NULL) out_of_memory(); if (fread((char *)pk_table[f]->data[c], 1, len, pkfp) != len) goto bad; } } } /* can't get here */ bad: message(ERROR, "%s: bad pk file: using white space instead", name); return 0; } static unsigned char *ptr; static char biti; static integer rc; #define get_nyb() (biti == 0 ? (biti=4, (unsigned)*ptr>>4) \ : (biti = 0, *ptr++ & 0x0f)) static integer packed_num(dyn_f) int dyn_f; { integer i, j; integer n; i = get_nyb(); if (i == 0) { do { j = get_nyb(); i++; } while (j == 0); while (i > 0) { j = (j << 4) + get_nyb(); i--; } n = (j - 15 + ((13 - dyn_f) << 4) + dyn_f); } else if (i <= dyn_f) n = i; else if (i < 14) n = ((i - dyn_f - 1) << 4) + get_nyb() + dyn_f + 1; else { rc = i == 14 ? packed_num(dyn_f) : 1; n = packed_num(dyn_f); } return n; } /* this can be made a lot more efficient later */ static void blacken(start, n, buf) integer start, n; unsigned char *buf; { integer i; for (i = start; i < start + n; i++) buf[(size_t)(i/8)] |= (unsigned)128 >> (int)(i & 7); } static char *hex = "0123456789ABCDEF"; static void out_byte(c, psfp) unsigned char c; FILE *psfp; { static int cols = 0; putc(hex[(unsigned)(c) >> 4],psfp); putc(hex[(c) & 15],psfp); if ((cols += 2) > 70) { cols = 0; putc('\n', psfp); } ++nbytes; } /* postscript requires that the bitmap of each row be padded out to an integral number of bytes, so unfortunately we can't just copy the bitmap in the pk file; this function could probably be made faster, but most of the characters that pk format represents by bitmaps are fairly small */ static void bitmap_char(h, w, psfp) integer h, w; FILE *psfp; { integer i, j; unsigned mask = 0x80; unsigned char curbyte = 0; unsigned curmask = 0x80; for (i = 0; i < h; i++) for (j = 0; j < w; j++) { if (*ptr & mask) curbyte |= curmask; if ((mask >>= 1) == 0) { mask = 0x80; ptr++; } if ((curmask >>= 1) == 0 || j == w - 1) { out_byte(curbyte, psfp); curbyte = 0; curmask = 0x80; } } /* the value of ptr is checked on return to make sure we have used the right number of bytes */ if (mask != 0x80) ptr++; } static integer makeinteger(p) unsigned char *p; { return (((integer)p[0]<<24) | ((integer)p[1]<<16) | (p[2]<<8) | p[3]); } /* output strings have one of the following forms: (4 byte integers are always signed) flag[1] dm[1] w[1] h[1] hoff[+1] voff[+1] flag = 0 flag[1] dm[2] w[2] h[2] hoff[+2] voff[+2] flag = 1 flag[1] dx[4] dy[4] w[4] h[4] hoff[4] voff[4] flag = 2 */ /* returns 0 on error != 0 otherwise */ static int generate_char(flag, data, len, psfp) unsigned char flag; unsigned char *data; size_t len; FILE *psfp; { int black = (flag & 0x08) != 0; integer h, w; int dyn_f; integer hoff, voff; integer curcol, currow; unsigned char *rowbuf; size_t buflen; dyn_f = (unsigned)flag >> 4; ptr = data; rc = 0; biti = 0; fputc('<',psfp); if ((flag & 0x07) == 0x07) { int i; out_byte(2, psfp); for (i = 0; i < 24; i++) out_byte(ptr[i], psfp); ptr += 8; w = makeinteger(ptr); ptr += 4; h = makeinteger(ptr); ptr += 4; hoff = makeinteger(ptr); ptr += 4; voff = makeinteger(ptr); ptr += 4; } else if (flag & 0x04) { int i; out_byte(1, psfp); for (i = 0; i < 10; i++) out_byte(ptr[i], psfp); ptr += 2; w = (ptr[0] << 8) | ptr[1]; ptr += 2; h = (ptr[0] << 8) | ptr[1]; ptr += 2; hoff = *ptr++; if (hoff >= 128) hoff -= 256; hoff <<= 8; hoff |= *ptr++; voff = *ptr++; if (voff >= 128) voff -= 256; voff <<= 8; voff |= *ptr++; } else { int i; out_byte(0, psfp); for (i = 0; i < 5; i++) out_byte(ptr[i], psfp); ptr++; w = *ptr++; h = *ptr++; hoff = *ptr++; if (hoff >= 128) hoff -= 256; voff = *ptr++; if (voff >= 128) voff -= 256; } if (-hoff < bb.llx) bb.llx = -hoff; if (w-hoff > bb.urx) bb.urx = w-hoff; if (voff + 1 - h < bb.lly) bb.lly = voff + 1 - h; if (voff + 1 > bb.ury) bb.ury = voff + 1; if (dyn_f == 14) { bitmap_char(h, w, psfp); if (data + len != ptr) return 0; fputc('>',psfp); return 1; } currow = curcol = 0; buflen = (size_t)((w + 7) / 8); if (buflen == SIZE_MAX) /* we'd get an infinite loop if we allowed this */ return 0; rowbuf = (unsigned char *)calloc(1, buflen); if (rowbuf == NULL) out_of_memory(); while (currow < h) { integer run = packed_num(dyn_f); while (curcol + run >= w) { size_t i; integer j; if (black) blacken(curcol, w - curcol, rowbuf); for (j = 0; j <= rc; j++) { for (i = 0; i < buflen; i++) out_byte(rowbuf[i],psfp); } for (i = 0; i < buflen; i++) rowbuf[i] = 0; currow++; currow += rc; rc = 0; run -= w - curcol; curcol = 0; } if (black) blacken(curcol, run, rowbuf); curcol += run; black = !black; } if (biti > 0) ptr++; if (data + len != ptr) return 0; fputc('>',psfp); free((char *)rowbuf); return 1; } integer emit_pk_font(f, name, used, psfp) int f; char *name; char *used; FILE *psfp; { int i, nused; nbytes = 0; if (pk_table[f] == NULL) cant_happen(); fprintf(psfp, "%%%%BeginFont: %s\n", name); fprintf(psfp, "/%s %ld %ld %ld\n", name, (long)(pk_table[f]->ds), (long)(pk_table[f]->hppp), (long)(pk_table[f]->vppp)); bb.llx = bb.lly = bb.urx = bb.ury = 0; nused = 0; fputs("EmptyEncoding 256 array copy\n", psfp); for (i = 0; i < MAXCHARS; i++) if (used[i]) { fprintf(psfp, "dup %d /c%d put\n", i, i); ++nused; } /* allow room for /.notdef */ fprintf(psfp, "\n%d dict dup begin\n", nused+1); for (i = 0; i < MAXCHARS; i++) if (used[i]) { if (pk_table[f]->data[i] == NULL) cant_happen(); fprintf(psfp, "/c%d", i); if (!generate_char(pk_table[f]->flag[i], pk_table[f]->data[i], pk_table[f]->len[i], psfp)) message(FATAL_ERROR, "char %d in the .pk file for %s is bad: use pktype", i, name); fputs("def\n", psfp); } fprintf(psfp, "end %ld %ld %ld %ld DefinePKFont\n", (long)(bb.llx), (long)(bb.lly), (long)(bb.urx), (long)(bb.ury)); fputs("%%EndFont\n", psfp); /* this is a fairly good estimate of the overhead for each font */ return nbytes + 1024 + 2000 + 20*(nused+1); /* nbytes for the strings, 1024 for the encoding vector, 20 for each of the nused+1 entries in the dictionary plus 2000 for general overhead */ } void free_pk_font(n) int n; { int i; struct pk_info *p = pk_table[n]; if (pk_table[n] == NULL) cant_happen(); for (i = 0; i < MAXCHARS; i++) if (p->data[i] != NULL) free((char *)(p->data[i])); free((char *)p); pk_table[n] = NULL; } /* Local Variables: c-indent-level: 4 c-continued-statement-offset: 4 c-brace-offset: -4 c-argdecl-indent: 0 c-label-offset: -4 tab-width: 4 End: */