home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pbm / pbmtopk.c < prev    next >
C/C++ Source or Header  |  1994-01-31  |  25KB  |  904 lines

  1. /*
  2.   pbmtopk, adapted from "pxtopk.c by tomas rokicki" by AJCD 1/8/90
  3.   
  4.   compile with: cc -o pbmtopk pbmtopk.c -lm -lpbm
  5.   */
  6.  
  7. #include <stdio.h>
  8. #include <math.h>
  9. #include <ctype.h>
  10. #include "pbm.h"
  11.  
  12. #define MAXPKCHAR 256
  13. #define MAXOPTLINE 200
  14. #define MAXWIDTHTAB 256
  15. #define MAXHEIGHTTAB 16
  16. #define MAXDEPTHTAB 16
  17. #define MAXITALICTAB 64
  18. #define MAXPARAMS 30
  19. #define NAMELENGTH 80
  20.  
  21. #define round(a) ((int)(a+.5))
  22. #define fixword(d) ((int)((double)(d)*1048576))
  23. #define unfixword(f) ((double)(f) / 1048576)
  24. #define fixrange(f) ((f) < 16777216 && (f) > -16777216)
  25. #define designunits(p) ((p)*72.27/(double)resolution/unfixword(designsize))
  26.  
  27. /* character flags: in order of appearance in option files. */
  28. #define XOFFSET     1
  29. #define YOFFSET     2
  30. #define HORZESC     4
  31. #define VERTESC     8
  32. #define TFMWIDTH   16
  33. #define TFMHEIGHT  32
  34. #define TFMDEPTH   64
  35. #define TFMITALIC 128
  36.  
  37. typedef int integer ;
  38. typedef char quarterword ;
  39. typedef char boolean ;
  40. typedef quarterword ASCIIcode ;
  41. typedef quarterword eightbits ;
  42. typedef unsigned char byte ;
  43.  
  44. integer resolution, designsize ;
  45. char *filename[MAXPKCHAR] ;
  46.  
  47. integer xoffset[MAXPKCHAR] ;
  48. integer yoffset[MAXPKCHAR] ;
  49. integer horzesc[MAXPKCHAR] ;
  50. integer vertesc[MAXPKCHAR] ;
  51.  
  52. byte tfmindex[MAXPKCHAR] ;
  53. byte hgtindex[MAXPKCHAR] ;
  54. byte depindex[MAXPKCHAR] ;
  55. byte italindex[MAXPKCHAR] ;
  56. byte charflags[MAXPKCHAR] ;
  57.  
  58. bit **bitmap ;
  59. integer smallestch = MAXPKCHAR ;
  60. integer largestch = -1;
  61. integer emwidth  = 0;
  62. integer checksum ;
  63. char *codingscheme = "GRAPHIC" ;
  64. char *familyname = "PBM" ;
  65.  
  66. integer widthtab[MAXWIDTHTAB] = {0}; /* TFM widths */
  67. integer numwidth = 1;      /* number of entries in width table */
  68. integer heighttab[MAXHEIGHTTAB]  = {0};
  69. integer numheight = 1;
  70. integer depthtab[MAXDEPTHTAB] = {0};
  71. integer numdepth = 1;
  72. integer italictab[MAXITALICTAB] = {0};
  73. integer numitalic = 1;
  74. integer parameters[MAXPARAMS] = {0};
  75. integer numparam = 0;
  76.  
  77. static ASCIIcode xord[128] ;
  78. static char xchr[256] = {
  79.    '?', '?', '?', '?', '?', '?', '?', '?',
  80.    '?', '?', '?', '?', '?', '?', '?', '?',
  81.    '?', '?', '?', '?', '?', '?', '?', '?',
  82.    '?', '?', '?', '?', '?', '?', '?', '?',
  83.    ' ', '!', '"', '#', '$', '%', '&', '\'',
  84.    '(', ')', '*', '+', ',', '-', '.', '/',
  85.    '0', '1', '2', '3', '4', '5', '6', '7',
  86.    '8', '9', ':', ';', '<', '=', '>', '?',
  87.    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
  88.    'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
  89.    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
  90.    'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
  91.    '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  92.    'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  93.    'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
  94.    'x', 'y', 'z', '{', '|', '}', '~', '?' };
  95.  
  96. static FILE *tfmfile, *pkfile ;
  97. static char tfmname[NAMELENGTH+1], pkname[NAMELENGTH+1] ;
  98. static integer pbmtopk_pkloc = 0 ;
  99. static integer bitweight ;
  100. static integer outputbyte ;
  101. static integer car ;
  102. static integer hppp ;
  103. static integer width ;
  104. static integer height ;
  105.  
  106. /* checksum not computed at the moment
  107. static integer compute_checksum()
  108. {
  109.      begin
  110.      c0:=bc; c1:=ec; c2:=bc; c3:=ec;
  111.      for c:=bc to ec do if char_wd[c]>0 then
  112.      begin
  113.      temp_width:=memory[char_wd[c]];
  114.      if design_units<>unity then
  115.      temp_width:=round((temp_width/design_units)*1048576.0);
  116.      temp_width:=temp_width + (c+4)*@'20000000; {this should be positive}
  117.      c0:=(c0+c0+temp_width) mod 255;
  118.      c1:=(c1+c1+temp_width) mod 253;
  119.      c2:=(c2+c2+temp_width) mod 251;
  120.      c3:=(c3+c3+temp_width) mod 247;
  121.      end;
  122.      header_bytes[check_sum_loc]:=c0;
  123.      header_bytes[check_sum_loc+1]:=c1;
  124.      header_bytes[check_sum_loc+2]:=c2;
  125.      header_bytes[check_sum_loc+3]:=c3;
  126.      end
  127. }
  128. */
  129.  
  130. #define add_tfmwidth(v) (add_tfmtable(widthtab, &numwidth, v, MAXWIDTHTAB,\
  131.                       "TFM width"))
  132. #define add_tfmheight(v) (add_tfmtable(heighttab, &numheight, v, MAXHEIGHTTAB,\
  133.                        "TFM height"))
  134. #define add_tfmdepth(v) (add_tfmtable(depthtab, &numdepth, v, MAXDEPTHTAB,\
  135.                       "TFM depth"))
  136. #define add_tfmitalic(v) (add_tfmtable(italictab, &numitalic, v, MAXITALICTAB,\
  137.                        "Italic correction"))
  138. static byte
  139. add_tfmtable(table, count, value, max_count, name)
  140.      integer *table, *count, value, max_count;
  141.      char *name;
  142. {
  143.    integer i;
  144.    for (i = 0; i < *count; i++) /* search for value in tfm table */
  145.       if (table[i] == value) return (byte)i;
  146.    if (*count >= max_count)
  147.       pm_error("too many values in %s table", name) ;
  148.    if (!fixrange(value))
  149.       pm_error("%s %f for char %d out of range",
  150.            name, unfixword(value), car);
  151.    table[*count] = value ;
  152.    return (*count)++ ;
  153. }
  154.  
  155. /* add a suffix to a filename in an allocated space */
  156. static void pbmtopk_add_suffix(name, suffix)
  157.      char *name, *suffix ;
  158. {
  159.    char *slash = rindex(name, '/');
  160.    char *dot = rindex(name, '.');
  161.  
  162.    if ((dot && slash ? dot < slash : !dot) && strcmp(name, "-"))
  163.       strcat(name, suffix);
  164. }
  165.  
  166. /* initialize the PK parameters */
  167. static void initialize_pk()
  168. {
  169.    integer i ;
  170.    pm_message("This is PBMtoPK, version 2.4") ;
  171.    for (i = 127 ; i <= 255 ; i ++) xchr[i] = '?' ;
  172.    for (i = 0 ; i <= 127 ; i ++) xord[i] = 32 ;
  173.    for (i = 32 ; i < 127 ; i ++) xord[(int)xchr[i]] = i ;
  174.    for (i = 0; i < MAXPKCHAR; i++) {
  175.       filename[i] = NULL;
  176.       charflags[i] = 0;
  177.    }
  178.    designsize = fixword(1.0) ;
  179. }
  180.  
  181. /* write a single byte to the PK file */
  182. static void pbmtopk_pkbyte(b)
  183.      integer b ;
  184. {
  185.    if (b < 0) b += 256 ;
  186.    putc(b, pkfile) ;
  187.    pbmtopk_pkloc++ ;
  188. }
  189.  
  190. /* write two bytes to the PK file */
  191. static void pkhalfword(a)
  192.      integer a ;
  193. {
  194.    if (a < 0) a += 65536 ;
  195.    pbmtopk_pkbyte(a >> 8) ;
  196.    pbmtopk_pkbyte(a & 255) ;
  197. }
  198.  
  199. /* write three bytes to the PK file */
  200. static void pkthreebytes(a)
  201.      integer a ;
  202. {
  203.    pbmtopk_pkbyte((a>>16) & 255) ;
  204.    pbmtopk_pkbyte((a>>8) & 255) ;
  205.    pbmtopk_pkbyte(a & 255) ;
  206. }
  207.  
  208. /* write four bytes to the PK file */
  209. static void pkword(a)
  210.      integer a ;
  211. {
  212.    pbmtopk_pkbyte((a>>24) & 255) ;
  213.    pbmtopk_pkbyte((a>>16) & 255) ;
  214.    pbmtopk_pkbyte((a>>8) & 255) ;
  215.    pbmtopk_pkbyte(a & 255) ;
  216. }
  217.  
  218. /* write a nibble to the PK file */
  219. static void pknyb(a)
  220.      integer a ;
  221. {
  222.    if (bitweight == 16) {
  223.       outputbyte = (a<<4) ;
  224.       bitweight = 1 ;
  225.    } else {
  226.       pbmtopk_pkbyte(outputbyte + a) ;
  227.       bitweight = 16 ;
  228.    }
  229. }
  230.  
  231. /* write preamble to PK file */
  232. static void writepreamble()
  233. {
  234.    integer i ;
  235.    char *comment = "PBMtoPK 2.4 output" ;
  236.    
  237.    pbmtopk_pkbyte(247) ;                /* PRE command */
  238.    pbmtopk_pkbyte(89) ;                /* PK file type */
  239.    pbmtopk_pkbyte(strlen(comment)) ;            /* output comment */
  240.    for (i = 0 ; i < strlen(comment); i++) pbmtopk_pkbyte(xord[(int)comment[i]]) ;
  241.    pkword(designsize) ;                /* write designsize */
  242.    pkword(checksum) ;        /* write checksum; calculate if possible */
  243.    pkword(hppp) ;                /* write H pixels per point */
  244.    pkword(hppp) ;                /* write V pixels per point */
  245. }
  246.  
  247. /* write postamble to PK file, padded to word length */
  248. static void writepostamble()
  249. {
  250.    pbmtopk_pkbyte(245) ;                /* POST command */
  251.    while (pbmtopk_pkloc % 4)
  252.       pbmtopk_pkbyte(246) ;                /* pad with no-ops */
  253.    pm_message("%d bytes written to packed file.", pbmtopk_pkloc) ;
  254. }
  255.  
  256. /* write a byte to the TFM file */
  257. static void tfmbyte(b)
  258.      integer b ;
  259. {
  260.    if (b < 0) b += 256 ;
  261.    putc(b, tfmfile) ;
  262. }
  263.  
  264. /* write a half word to the TFM file */
  265. static void tfmhalfword(a)
  266.      integer a ;
  267. {
  268.    if (a < 0) a += 65536 ;
  269.    tfmbyte(a >> 8) ;
  270.    tfmbyte(a & 255) ;
  271. }
  272.  
  273. /* write a word to the TFM file */
  274. static void tfmword(a)
  275.      integer a ;
  276. {
  277.    tfmbyte((a>>24) & 255) ;
  278.    tfmbyte((a>>16) & 255) ;
  279.    tfmbyte((a>>8) & 255) ;
  280.    tfmbyte(a & 255) ;
  281. }
  282.  
  283. /* write the whole TFM file for the font */
  284. static void writetfmfile()
  285. {
  286.    integer totallength ;
  287.    integer headersize = 17;
  288.    integer i ;
  289.    
  290.    if (largestch - smallestch < 0) {
  291.       largestch = 0;
  292.       smallestch = 1;
  293.    }
  294.    if (numparam < 7) /* set default parameters */
  295.       switch (numparam) {
  296.       case 0: /* slant */
  297.      parameters[numparam++] = 0 ;
  298.       case 1: /* space */
  299.      parameters[numparam++] = fixword(designunits(emwidth/3.0));
  300.       case 2: /* space_stretch */
  301.      parameters[numparam++] = fixword(unfixword(parameters[1])/2.0) ;
  302.       case 3: /* space_shrink */
  303.      parameters[numparam++] = fixword(unfixword(parameters[1])/3.0) ;
  304.       case 4: /* x_height */
  305.      parameters[numparam++] = fixword(0.45);
  306.       case 5: /* quad */
  307.      parameters[numparam++] = fixword(designunits(emwidth)) ;
  308.       case 6: /* extra_space */
  309.      parameters[numparam++] = fixword(unfixword(parameters[1])/3.0) ;
  310.       }
  311.    totallength = 6 + headersize + (largestch+1-smallestch) +
  312.       numwidth + numheight + numdepth + numitalic + numparam ;
  313.    /* lengths */
  314.    tfmhalfword(totallength) ;            /* write file TFM length */
  315.    tfmhalfword(headersize) ;            /* write TFM header length */
  316.    tfmhalfword(smallestch) ;            /* write lowest char index */
  317.    tfmhalfword(largestch) ;            /* write highest char index */
  318.    tfmhalfword(numwidth) ;            /* write number of widths */
  319.    tfmhalfword(numheight) ;            /* write number of heights */
  320.    tfmhalfword(numdepth) ;            /* write number of depths */
  321.    tfmhalfword(numitalic) ;            /* write number of italcorrs */
  322.    tfmhalfword(0) ;                /* lig/kern table */
  323.    tfmhalfword(0) ;                /* kern table */
  324.    tfmhalfword(0) ;                /* extensible char table */
  325.    tfmhalfword(numparam) ;            /* number of fontdimens */
  326.    /* header */
  327.    tfmword(checksum) ;                /* write checksum */
  328.    tfmword(designsize) ;            /* write designsize */
  329.    if (strlen(codingscheme) > 39) tfmbyte(39) ;    /* write coding scheme len */
  330.    else tfmbyte(strlen(codingscheme)) ;
  331.    for (i = 0; i < 39; i++)            /* write coding scheme */
  332.       if (*codingscheme) tfmbyte(xord[(int)(*codingscheme++)]) ;
  333.       else tfmbyte(0) ;
  334.    if (strlen(familyname) > 19) tfmbyte(19) ;    /* write family length */
  335.    else tfmbyte(strlen(familyname)) ;
  336.    for (i = 0; i < 19; i++)            /* write family */
  337.       if (*familyname) tfmbyte(xord[(int)(*familyname++)]) ;
  338.       else tfmbyte(0) ;
  339.    /* char_info */
  340.    for (car = smallestch; car <= largestch; car++)
  341.       if (filename[car]) {            /* write character info */
  342.      tfmbyte(tfmindex[car]) ;
  343.      tfmbyte((hgtindex[car]<<4) + depindex[car]) ;
  344.      tfmbyte(italindex[car]<<2) ;
  345.      tfmbyte(0) ;
  346.       } else tfmword(0) ;
  347.    /* width table */
  348.    for (i = 0; i < numwidth; i++) tfmword(widthtab[i]) ;
  349.    /* height table */
  350.    for (i = 0; i < numheight; i++) tfmword(heighttab[i]) ;
  351.    /* depth table */
  352.    for (i = 0; i < numdepth; i++) tfmword(depthtab[i]) ;
  353.    /* italic correction table */
  354.    for (i = 0; i < numitalic; i++) tfmword(italictab[i]) ;
  355.    /* no lig_kern, kern, or exten tables */
  356.    /* fontdimen table */
  357.    for (i = 0; i < numparam; i++)
  358.       if (i && !fixrange(parameters[i]))
  359.      pm_error("parameter %d out of range (-p)", i);
  360.       else
  361.      tfmword(parameters[i]) ;
  362.    pm_message("%d bytes written to tfm file.", totallength*4) ;
  363. }
  364.  
  365. /* read a character from a PBM file */
  366. static void readcharacter()
  367. {
  368.    FILE *fp;
  369.    
  370.    fp = pm_openr(filename[car]);
  371.    bitmap = pbm_readpbm(fp, &width, &height) ;
  372.    pm_close(fp) ;
  373.    
  374.    if ((charflags[car] & HORZESC) == 0) horzesc[car] = width ;
  375.    if ((charflags[car] & VERTESC) == 0) vertesc[car] = 0;
  376.    if ((charflags[car] & XOFFSET) == 0) xoffset[car] = 0;
  377.    if ((charflags[car] & YOFFSET) == 0) yoffset[car] = height-1;
  378.    if ((charflags[car] & TFMWIDTH) == 0)
  379.       tfmindex[car] = add_tfmwidth(fixword(designunits(width)));
  380.    if ((charflags[car] & TFMHEIGHT) == 0)
  381.       hgtindex[car] = add_tfmheight(fixword(designunits(yoffset[car]+1)));
  382.    if ((charflags[car] & TFMDEPTH) == 0)
  383.       depindex[car] = add_tfmdepth(fixword(designunits(height-1-yoffset[car])));
  384.    if ((charflags[car] & TFMITALIC) == 0) italindex[car] = 0;
  385.    
  386.    if (car < smallestch) smallestch = car;
  387.    if (car > largestch) largestch = car;
  388.    if (width > emwidth) emwidth = width ;
  389. }
  390.  
  391. /* test if two rows of the PBM are the same */
  392. static int equal(row1, row2)
  393.      bit *row1, *row2 ;
  394. {
  395.    integer i ;
  396.    
  397.    for (i = 0; i < width; i++)
  398.       if (row1[i] != row2[i]) return (0) ;
  399.    return(1) ;
  400. }
  401.  
  402. static void shipcharacter()
  403. {
  404.    integer compsize ;
  405.    integer i, j, k ;
  406.    bit *zerorow, *onesrow ;
  407.    integer *repeatptr, *bitcounts ;
  408.    integer count ;
  409.    integer test ;
  410.    integer curptr, rowptr ;
  411.    integer bitval ;
  412.    integer repeatflag ;
  413.    integer colptr ;
  414.    integer currepeat ;
  415.    integer dynf ;
  416.    integer deriv[14] ;
  417.    integer bcompsize ;
  418.    boolean firston ;
  419.    integer flagbyte ;
  420.    boolean state ;
  421.    boolean on ;
  422.    integer hbit ;
  423.    integer pbit ;
  424.    boolean ron, son ;
  425.    integer rcount, scount ;
  426.    integer ri, si ;
  427.    integer max2 ;
  428.    integer predpkloc ;
  429.    integer buff ;
  430.    
  431.    integer tfwid = widthtab[tfmindex[car]] ;
  432.    integer hesc = horzesc[car] ;
  433.    integer vesc = vertesc[car] ;
  434.    integer xoff = xoffset[car] ;
  435.    integer yoff = yoffset[car] ;
  436.    
  437.    repeatptr =
  438.       (integer *)malloc((unsigned int)((height+1)*sizeof(integer))) ;
  439.    bitcounts =
  440.       (integer *)malloc((unsigned int)((height*width)*sizeof(integer))) ;
  441.    if (repeatptr == NULL || bitcounts == NULL)
  442.       pm_error("out of memory while allocating bit counts");
  443.    zerorow = pbm_allocrow(width) ;        /* initialise plain rows */
  444.    onesrow = pbm_allocrow(width) ;
  445.    for (i = 0 ; i < width ; i++) {
  446.       zerorow[i] = PBM_WHITE ;
  447.       onesrow[i] = PBM_BLACK ;
  448.    }
  449.    for (i=0; i < height; i = k) {        /* set repeat pointers */
  450.       k = i + 1;
  451.       if (!equal(bitmap[i], zerorow) && !equal(bitmap[i], onesrow)) {
  452.      while (k < height && equal(bitmap[i], bitmap[k]))
  453.         k++;
  454.      repeatptr[i] = k - i - 1;
  455.       } else {
  456.      repeatptr[i] = 0;
  457.       }
  458.    }
  459.    repeatptr[height] = 0 ;
  460.    colptr = width - 1 ;
  461.    repeatflag = currepeat = curptr = count = rowptr = 0 ;
  462.    test = PBM_WHITE ;
  463.    do {
  464.       colptr++ ;
  465.       if (colptr == width) {            /* end of row, get next row */
  466.      colptr = 0 ;
  467.      rowptr = currepeat ;
  468.      if (repeatptr[currepeat] > 0) {
  469.         repeatflag = repeatptr[currepeat] ;
  470.         currepeat += repeatflag ;
  471.         rowptr += repeatflag ;
  472.      }
  473.      currepeat++ ;
  474.       }
  475.       if (rowptr >= height) bitval = -1 ;
  476.       else bitval = bitmap[rowptr][colptr] ;
  477.       if (bitval == test) count++ ;        /* count repeated pixels */
  478.       else {                    /* end of pixel run */
  479.      bitcounts[curptr++] = count ;
  480.      if (curptr+3 >= height*width)
  481.         pm_error("out of memory while saving character counts");
  482.      count = 1 ;
  483.      test = bitval ;
  484.      if (repeatflag > 0) {
  485.         bitcounts[curptr++] = -repeatflag ;
  486.         repeatflag = 0 ;
  487.      }
  488.       }
  489.    } while (test != -1) ;
  490.    bitcounts[curptr] = 0 ;
  491.    bitcounts[curptr + 1] = 0 ;
  492.    for (i = 1 ; i <= 13 ; i ++) deriv[i] = 0 ;
  493.    i = firston = (bitcounts[0] == 0) ;
  494.    compsize = 0 ;
  495.    while (bitcounts[i] != 0) {            /* calculate dyn_f */
  496.       j = bitcounts[i] ;
  497.       if (j == -1) compsize++ ;
  498.       else {
  499.      if (j < 0) {
  500.         compsize++ ;
  501.         j = -j ;
  502.      }
  503.      if (j < 209) compsize += 2 ;
  504.      else {
  505.         k = j - 193 ;
  506.         while (k >= 16) {
  507.            k >>= 4 ;
  508.            compsize += 2 ;
  509.         }
  510.         compsize++ ;
  511.      }
  512.      if (j < 14) (deriv[j])-- ;
  513.      else if (j < 209) (deriv[(223 - j) / 15])++ ;
  514.      else {
  515.         k = 16 ;
  516.         while (((k<<4) < j + 3)) k <<= 4 ;
  517.         if (j - k <= 192)
  518.            deriv[(207 - j + k) / 15] += 2 ;
  519.      }
  520.       }
  521.       i++ ;
  522.    }
  523.    bcompsize = compsize ;
  524.    dynf = 0 ;
  525.    for (i = 1 ; i <= 13 ; i ++) {
  526.       compsize += deriv[i] ;
  527.       if (compsize <= bcompsize) {
  528.      bcompsize = compsize ;
  529.      dynf = i ;
  530.       }
  531.    }
  532.    compsize = ((bcompsize + 1)>>1) ;
  533.    if ((compsize > ((height*width+7)>>3)) || (height*width == 0)) {
  534.       compsize = ((height*width+7)>>3) ;
  535.       dynf = 14 ;
  536.    }
  537.    flagbyte = (dynf<<4) ;
  538.    if (firston) flagbyte |= 8 ;
  539.    if (tfwid > 16777215 || tfwid < 0 || hesc < 0 || vesc != 0 ||
  540.        compsize > 196579 || width > 65535 || height > 65535 ||
  541.        xoff > 32767 || yoff > 32767 || xoff < -32768 || yoff < -32768) {
  542.       flagbyte |= 7 ;                /* long form preamble */
  543.       pbmtopk_pkbyte(flagbyte) ;
  544.       compsize += 28 ;
  545.       pkword(compsize) ;            /* char packet size */
  546.       pkword(car) ;                /* character number */
  547.       predpkloc = pbmtopk_pkloc + compsize ;
  548.       pkword(tfwid) ;                /* TFM width */
  549.       pkword(hesc<<16) ;            /* horiz escapement */
  550.       pkword(vesc<<16) ;            /* vert escapement */
  551.       pkword(width) ;                /* bounding box width */
  552.       pkword(height) ;                /* bounding box height */
  553.       pkword(xoff) ;                /* horiz offset */
  554.       pkword(yoff) ;                /* vert offset */
  555.    } else if (hesc > 255 || width > 255 || height > 255 ||
  556.           xoff > 127 || yoff > 127 || xoff < -128 ||
  557.           yoff < -128 || compsize > 1016) {
  558.       compsize += 13 ;                /* extended short preamble */
  559.       flagbyte += (compsize>>16) + 4 ;
  560.       pbmtopk_pkbyte(flagbyte) ;
  561.       pkhalfword(compsize & 65535) ;        /* char packet size */
  562.       pbmtopk_pkbyte(car) ;                /* character number */
  563.       predpkloc = pbmtopk_pkloc + compsize ;
  564.       pkthreebytes(tfwid) ;            /* TFM width */
  565.       pkhalfword(hesc) ;            /* horiz escapement */
  566.       pkhalfword(width) ;            /* bounding box width */
  567.       pkhalfword(height) ;            /* bounding box height */
  568.       pkhalfword(xoff) ;            /* horiz offset */
  569.       pkhalfword(yoff) ;            /* vert offset */
  570.    } else {
  571.       compsize += 8 ;                /* short form preamble */
  572.       flagbyte = flagbyte + (compsize>>8) ;
  573.       pbmtopk_pkbyte(flagbyte) ;
  574.       pbmtopk_pkbyte(compsize & 255) ;            /* char packet size */
  575.       pbmtopk_pkbyte(car) ;                /* character number */
  576.       predpkloc = pbmtopk_pkloc + compsize ;
  577.       pkthreebytes(tfwid) ;            /* TFM width */
  578.       pbmtopk_pkbyte(hesc) ;                /* horiz escapement */
  579.       pbmtopk_pkbyte(width) ;                /* bounding box width */
  580.       pbmtopk_pkbyte(height) ;                /* bounding box height */
  581.       pbmtopk_pkbyte(xoff) ;                /* horiz offset */
  582.       pbmtopk_pkbyte(yoff) ;                /* vert offset */
  583.    }
  584.    if (dynf != 14) {                /* write packed character */
  585.       bitweight = 16 ;
  586.       max2 = 208 - 15 * dynf ;
  587.       i = firston ;
  588.       while (bitcounts[i] != 0) {
  589.      j = bitcounts[i] ;
  590.      if (j == - 1) pknyb(15) ;
  591.      else {
  592.         if (j < 0) {
  593.            pknyb(14) ;
  594.            j = -j ;
  595.         }
  596.         if (j <= dynf) pknyb(j) ;
  597.         else if (j <= max2) {
  598.            j -= dynf + 1 ;
  599.            pknyb((j >> 4) + dynf + 1) ;
  600.            pknyb((j & 15)) ;
  601.         } else {
  602.            j -= max2 - 15 ;
  603.            k = 16 ;
  604.            while (k <= j) {
  605.           k <<= 4 ;
  606.           pknyb(0) ;
  607.            }
  608.            while (k > 1) {
  609.           k >>= 4 ;
  610.           pknyb(j / k) ;
  611.           j = j % k ;
  612.            }
  613.         }
  614.      }
  615.      i++ ;
  616.       }
  617.       if (bitweight != 16) pbmtopk_pkbyte(outputbyte) ;
  618.    } else {                    /* write bitmap character */
  619.       buff = 0 ;
  620.       pbit = 8 ;
  621.       i = firston ;
  622.       hbit = width ;
  623.       on = ! firston ;
  624.       state = 0 ;
  625.       count = repeatflag = 0 ;
  626.       while ((bitcounts[i] != 0) || state || (count > 0)) {
  627.      if (state) {
  628.         count = rcount ;
  629.         i = ri ;
  630.         on = ron ;
  631.         repeatflag-- ;
  632.      } else {
  633.         rcount = count ;
  634.         ri = i ;
  635.         ron = on ;
  636.      }
  637.      do {
  638.         if (count == 0) {
  639.            if (bitcounts[i] < 0) {
  640.           if (! state) repeatflag = -bitcounts[i] ;
  641.           i++ ;
  642.            }
  643.            count = bitcounts[i] ;
  644.            i++ ;
  645.            on = !on ;
  646.         }
  647.         if ((count >= pbit) && (pbit < hbit)) {
  648.            if (on) buff += (1 << pbit) - 1 ;
  649.            pbmtopk_pkbyte(buff) ;
  650.            buff = 0 ;
  651.            hbit -= pbit ;
  652.            count -= pbit ;
  653.            pbit = 8 ;
  654.         } else if ((count < pbit) && (count < hbit)) {
  655.            if (on) buff += (1 << pbit) - (1 << (pbit - count)) ;
  656.            pbit -=  count ;
  657.            hbit -= count ;
  658.            count = 0 ;
  659.         } else {
  660.            if (on) buff += (1 << pbit) - (1 << (pbit - hbit)) ;
  661.            count -= hbit ;
  662.            pbit -= hbit ;
  663.            hbit = width ;
  664.            if (pbit == 0) {
  665.           pbmtopk_pkbyte(buff) ;
  666.           buff = 0 ;
  667.           pbit = 8 ;
  668.            }
  669.         }
  670.      } while (hbit != width) ;
  671.      if (state && (repeatflag == 0)) {
  672.         count = scount ;
  673.         i = si ;
  674.         on = son ;
  675.         state = 0 ;
  676.      } else if (! state && (repeatflag > 0)) {
  677.         scount = count ;
  678.         si = i ;
  679.         son = on ;
  680.         state = 1 ;
  681.      }
  682.       }
  683.       if (pbit != 8) pbmtopk_pkbyte(buff) ;
  684.    }
  685.    if (predpkloc != pbmtopk_pkloc)
  686.       pm_error("bad predicted character length: character %d", car);
  687.    pbm_freerow(zerorow); 
  688.    pbm_freerow(onesrow); 
  689.    free((char *)repeatptr);
  690.    free((char *)bitcounts);
  691. }
  692.  
  693. /* check that character is in valid range */
  694. static void checkchar()
  695. {
  696.    if (car < 0 || car >= MAXPKCHAR)
  697.       pm_error("character must be in range 0 to %d", MAXPKCHAR-1) ;
  698. }
  699.  
  700. /* read character information from an option file */
  701. static void optionfile(name)
  702.      char *name ;
  703. {
  704.    FILE *fp ;
  705.    char buffer[MAXOPTLINE] ;
  706.    
  707.    fp = pm_openr(name);
  708.    while (!feof(fp)) {
  709.       char *here = buffer;
  710.       
  711.       if (fgets(buffer, MAXOPTLINE, fp) == NULL) break ;
  712.       while (isspace(*here)) here++ ;
  713.       if (*here && *here == '=') {
  714.      if (sscanf(here+1, "%d", &car) != 1)
  715.         pm_error("bad option file line %s", buffer) ;
  716.       } else if (*here && *here != '%' && *here != '#') {
  717.      char str[NAMELENGTH] ;
  718.      integer i, n;
  719.      
  720.      checkchar() ;
  721.      if (sscanf(here, "%s%n", str, &n) != 1)
  722.         pm_error("bad option file line %s", buffer) ;
  723.      filename[car] =
  724.         (char *)malloc((unsigned int)(sizeof(char)*(strlen(str)+1))) ;
  725.      if (filename[car] == NULL)
  726.         pm_error("out of memory allocating filename %s", str);
  727.      strcpy(filename[car], str) ;
  728.      for (i = 1; i < 256; i<<=1) {
  729.         here += n;
  730.         if (sscanf(here, "%s%n", str, &n) != 1) break ;
  731.         if (strcmp(str, "*")) {
  732.            charflags[car] |= i ;
  733.            switch (i) {
  734.            case XOFFSET:
  735.           xoffset[car] = atoi(str) ;
  736.           break ;
  737.            case YOFFSET:
  738.           yoffset[car] = atoi(str) ;
  739.           break ;
  740.            case HORZESC:
  741.           horzesc[car] = atoi(str) ;
  742.           break ;
  743.            case VERTESC:
  744.           vertesc[car] = atoi(str) ;
  745.           break ;
  746.            case TFMWIDTH:
  747.           tfmindex[car] = add_tfmwidth(fixword(atof(str))) ;
  748.           break ;
  749.            case TFMHEIGHT:
  750.           hgtindex[car] = add_tfmheight(fixword(atof(str))) ;
  751.           break ;
  752.            case TFMDEPTH:
  753.           depindex[car] = add_tfmdepth(fixword(atof(str))) ;
  754.           break ;
  755.            case TFMITALIC:
  756.           italindex[car] = add_tfmitalic(fixword(atof(str))) ;
  757.           break ;
  758.            }
  759.         }
  760.      }
  761.      car++ ;
  762.       }
  763.    }
  764.    pm_close(fp) ;
  765. }
  766.  
  767. int
  768. main(argc, argv)
  769.      int argc ;
  770.      char *argv[] ;
  771. {
  772.    integer i, hesc, vesc, xoff, yoff, tfwid, tfdep, tfhgt, tfital ;
  773.    byte flags ;
  774.    char *usage = "pkfile[.pk] tfmfile[.tfm] dpi [-s designsize] [-p num param...]\n\
  775.         [-C codingscheme ] [-F family] [-c num | <char>]...\n\
  776.    <char> is:\n\
  777.         [-W tfmwidth] [-H tfmheight] [-D tfmdepth] [-I ital_corr] [-h horiz]\n\
  778.         [-v vert] [-x xoffset] [-y yoffset] file\n\
  779.     or:\n\
  780.         -f optfile\n" ;
  781.  
  782.    pbm_init(&argc, argv);
  783.    initialize_pk() ;
  784.    
  785.    if (--argc < 1) pm_usage(usage) ;
  786.    strcpy(pkname, *++argv) ;
  787.    pbmtopk_add_suffix(pkname, ".pk") ;
  788.    
  789.    if (--argc < 1) pm_usage(usage) ;
  790.    strcpy(tfmname, *++argv) ;
  791.    pbmtopk_add_suffix(tfmname, ".tfm") ;
  792.    
  793.    if (--argc < 1) pm_usage(usage) ;
  794.    resolution = atoi(*++argv) ;
  795.    if (resolution < 1 || resolution > 32767)
  796.       pm_error("unlikely resolution %d dpi", resolution);
  797.    
  798.    car = flags = hesc = vesc = xoff = yoff = tfwid = 0;
  799.    while (++argv, --argc) {
  800.       if (argv[0][0] == '-' && argv[0][1]) {
  801.      char c, *p;
  802.      c = argv[0][1] ;
  803.      if (argv[0][2]) p = *argv + 2 ;    /* set argument pointer */
  804.      else if (++argv, --argc) p = *argv ;
  805.      else pm_usage(usage) ;
  806.      switch (c) {
  807.      case 'C':
  808.         codingscheme = p;
  809.         break ;
  810.      case 'F':
  811.         familyname = p;
  812.         break ;
  813.      case 'c':
  814.         car = atoi(p) ;
  815.         break ;
  816.      case 's':
  817.         designsize = fixword(atof(p));
  818.         if (designsize < 1048576)
  819.            pm_error("design size %f out of range", unfixword(designsize));
  820.      case 'h':
  821.         hesc = atoi(p) ;
  822.         flags |= HORZESC ;
  823.         break ;
  824.      case 'v':
  825.         vesc = atoi(p) ;
  826.         flags |= VERTESC ;
  827.         break ;
  828.      case 'x':
  829.         xoff = atoi(p) ;
  830.         flags |= XOFFSET ;
  831.         break ;
  832.      case 'y':
  833.         yoff = atoi(p) ;
  834.         flags |= YOFFSET ;
  835.         break ;
  836.      case 'W':
  837.         tfwid = fixword(atof(p)) ;
  838.         flags |= TFMWIDTH ;
  839.         break ;
  840.      case 'H':
  841.         tfhgt = fixword(atof(p)) ;
  842.         flags |= TFMHEIGHT ;
  843.         break ;
  844.      case 'D':
  845.         tfdep = fixword(atof(p)) ;
  846.         flags |= TFMDEPTH ;
  847.         break ;
  848.      case 'I':
  849.         tfital = fixword(atof(p)) ;
  850.         flags |= TFMITALIC ;
  851.         break ;
  852.      case 'f':
  853.         optionfile(p) ;
  854.         break ;
  855.      case 'p':
  856.         numparam = atoi(p);
  857.         if (numparam < 1 || numparam > MAXPARAMS)
  858.            pm_error("parameter count %d out of range", numparam);
  859.         for (i=0; i<numparam; i++)
  860.            if (++argv,--argc)
  861.           parameters[i] = fixword(atof(*argv)) ;
  862.            else
  863.           pm_error("not enough parameters (-p)");
  864.         break ;
  865.      default:
  866.         pm_usage(usage) ;
  867.      }
  868.       } else  {
  869.      checkchar() ;
  870.      if (flags & TFMWIDTH)
  871.         tfmindex[car] = add_tfmwidth(tfwid);
  872.      if (flags & TFMDEPTH)
  873.         depindex[car] = add_tfmdepth(tfdep);
  874.      if (flags & TFMHEIGHT)
  875.         hgtindex[car] = add_tfmheight(tfhgt);
  876.      if (flags & TFMITALIC)
  877.         italindex[car] = add_tfmitalic(tfital);
  878.      horzesc[car] = hesc ;
  879.      vertesc[car] = vesc ;
  880.      xoffset[car] = xoff ;
  881.      yoffset[car] = yoff ;
  882.      filename[car] = *argv ;
  883.      charflags[car] = flags ;
  884.      car++ ;
  885.      flags = 0;
  886.       }
  887.    }
  888.    hppp = round((resolution<<16) / 72.27) ;
  889.    pkfile = pm_openw(pkname);
  890.    tfmfile = pm_openw(tfmname);
  891.    writepreamble() ;
  892.    for (car = 0 ; car < MAXPKCHAR ; car++)
  893.       if (filename[car]) {
  894.      readcharacter() ;
  895.      shipcharacter() ;
  896.       }
  897.    writepostamble() ;
  898.    writetfmfile() ;
  899.    pm_close(pkfile) ;
  900.    pm_close(tfmfile) ;
  901.    exit(0);
  902. }
  903.  
  904.