home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / d / dvips549.zip / DVIPS / EMSPECIA.C < prev    next >
C/C++ Source or Header  |  1992-10-14  |  33KB  |  1,348 lines

  1. /*
  2.  *   emspecial.c
  3.  *   This routine handles the emTeX special commands.
  4.  */
  5. #include "structures.h" /* The copyright notice in that file is included too! */
  6.  
  7. #include <ctype.h>
  8. extern int atoi();
  9. /*
  10.  *   These are the external routines called:
  11.  */
  12. /**/
  13. extern void hvpos() ;
  14. extern void cmdout() ;
  15. extern void numout() ;
  16. extern void error() ;
  17. extern void specerror() ;
  18. extern FILE *search();
  19. extern char errbuf[] ;
  20. extern shalfword linepos;
  21. extern FILE *bitfile;
  22. extern int actualdpi ;
  23. extern int vactualdpi ;
  24. extern integer hh, vv;
  25. extern char *figpath ;
  26. extern int prettycolumn ;
  27. extern Boolean disablecomments ;
  28.  
  29. #ifdef DEBUG
  30. extern integer debug_flag;
  31. #endif
  32.  
  33.  
  34. #ifdef EMTEX
  35. /* emtex specials */
  36.  
  37. #define EMMAX 1613 /* maximum number of emtex special points */
  38. #define TRUE 1
  39. #define FALSE 0
  40.  
  41. struct empt {
  42.    shalfword point;
  43.    integer x, y;
  44. };
  45.  
  46. struct empt *empoints = NULL;
  47. boolean emused = FALSE;  /* true if em points used on this page */
  48. integer emx, emy;
  49.  
  50. struct emunit {
  51.    char *unit;
  52.    float factor;
  53. };
  54. struct emunit emtable[] = {
  55.   {"pt",72.27},
  56.   {"pc",72.27/12},
  57.   {"in",1.0},
  58.   {"bp",72.0},
  59.   {"cm",2.54},
  60.   {"mm",25.4},
  61.   {"dd",72.27/(1238/1157)},
  62.   {"cc",72.27/12/(1238/1157)},
  63.   {"sp",72.27*65536},
  64.   {"",0.0}
  65. };
  66.  
  67.  
  68. /* clear the empoints array if necessary */
  69. void
  70. emclear()
  71. {
  72. int i;
  73.    if (emused && empoints)
  74.       for (i=0; i<EMMAX; i++)
  75.          empoints[i].point = 0;
  76.    emused = FALSE ;
  77. }
  78.  
  79. /* put an empoint into the empoints array */
  80. struct empt *emptput(point, x, y)
  81. shalfword point;
  82. integer x, y;
  83. {
  84. int i, start;
  85.  
  86.    emused = TRUE;
  87.    start = point % EMMAX;
  88.    i = start;
  89.    while ( empoints[i].point != 0 ) {
  90.       if ( empoints[i].point == point )
  91.          break;
  92.       i++;
  93.       if (i >= EMMAX)
  94.          i = 0;
  95.       if (i == start) {
  96.      sprintf(errbuf,"!Too many em: special points");
  97.      specerror(errbuf);
  98.       }
  99.    }
  100.  
  101.    empoints[i].point = point;
  102.    empoints[i].x = x;
  103.    empoints[i].y = y;
  104.    return(&empoints[i]);
  105. }
  106.  
  107. /* get an empoint from the empoints array */
  108. struct empt *emptget(point)
  109. shalfword point;
  110. {
  111. int i, start;
  112.  
  113.    start = point % EMMAX;
  114.    i = start;
  115.    if (emused == TRUE)
  116.       while ( empoints[i].point != 0 ) {
  117.          if (empoints[i].point == point)
  118.             return(&empoints[i]);
  119.          i++;
  120.          if (i >= EMMAX)
  121.             i = 0;
  122.          if (i == start)
  123.             break;
  124.       }
  125.    sprintf(errbuf,"!em: point %d not defined",point);
  126.    specerror(errbuf);
  127.    return(NULL); /* never returns due to error */
  128. }
  129.  
  130.  
  131. /* convert width into dpi units */
  132. float emunits(width,unit)
  133. float width;
  134. char *unit;
  135. {
  136. struct emunit *p;
  137.     for (p=emtable; *(p->unit)!='\0'; p++) {
  138.        if (strcmp(p->unit,unit)==0)
  139.         return( width * actualdpi / p->factor );
  140.     }
  141.     return (-1.0); /* invalid unit */
  142. }
  143.  
  144. /* specials for emtex, added by rjl */
  145. /* the line cut parameter is not supported (and is ignored)
  146.  * em:graph supports PCX, MSP1, MSP2 and uncompressed BMP files
  147.  */
  148.  
  149. void emspecial(p)
  150. char *p ;
  151. {
  152. float emwidth, emheight;
  153. shalfword empoint1, empoint2;
  154. struct empt *empoint;
  155. char emunit[3];
  156. char emstr[80];
  157. char *emp;
  158. void emgraph();
  159.  
  160.         hvpos() ;
  161.     for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
  162.     if (strncmp(emp, "linewidth", 9) == 0) {
  163.        /* code for linewidth */
  164.        for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
  165.        sscanf(emp, "%f%2s", &emwidth, emunit);
  166.        emwidth = emunits(emwidth,emunit);
  167.        if (emwidth!=-1.0) {
  168.           sprintf(emstr,"%.1f setlinewidth", emwidth);
  169.           cmdout(emstr);
  170. #ifdef DEBUG
  171.    if (dd(D_SPECIAL))
  172.       (void)fprintf(stderr, "em special: Linewidth set to %.1f dots\n", 
  173.         emwidth) ;
  174. #endif
  175.        } else {
  176.           sprintf(errbuf,"Unknown em: special width");
  177.           specerror(errbuf);
  178.        }
  179.     }
  180.         else if (strncmp(emp, "moveto", 6) == 0) {
  181. #ifdef DEBUG
  182.    if (dd(D_SPECIAL))
  183. #ifdef SHORTINT
  184.       (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
  185. #else
  186.       (void)fprintf(stderr, "em special: moveto %d,%d\n", hh, vv);
  187. #endif
  188. #endif
  189.            emx = hh;
  190.            emy = vv;
  191.         }
  192.         else if (strncmp(emp, "lineto", 6) == 0) {
  193. #ifdef DEBUG
  194.    if (dd(D_SPECIAL))
  195. #ifdef SHORTINT
  196.       (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
  197. #else
  198.       (void)fprintf(stderr, "em special: lineto %d,%d\n", hh, vv);
  199. #endif
  200. #endif
  201.        cmdout("np");
  202.        numout(emx);
  203.        numout(emy);
  204.        cmdout("a");
  205.        numout(hh);
  206.        numout(vv);
  207.        cmdout("li");
  208.        cmdout("st");
  209.            emx = hh;
  210.            emy = vv;
  211.         }
  212.     else if (strncmp(emp, "point", 5) == 0) {
  213.            if (empoints == NULL) {
  214.               empoints = 
  215.               (struct empt *)mymalloc((integer)EMMAX * sizeof(struct empt)) ;
  216.               emused = TRUE;
  217.               emclear();
  218.            }
  219.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  220.            empoint1 = (shalfword)atoi(emp);
  221.            empoint = emptput(empoint1,hh,vv);
  222. #ifdef DEBUG
  223.    if (dd(D_SPECIAL))
  224. #ifdef SHORTINT
  225.       (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
  226. #else
  227.       (void)fprintf(stderr, "em special: Point %d is %d,%d\n",
  228. #endif
  229.         empoint->point, empoint->x, empoint->y) ;
  230. #endif
  231.     }
  232.     else if (strncmp(emp, "line", 4) == 0) {
  233.        for (emp = emp+4; *emp && isspace(*emp); emp++); /* skip blanks */
  234.            empoint1 = (shalfword)atoi(emp);
  235.        for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
  236.        if ( *emp && strchr("hvp",*emp)!=0 )
  237.           emp++;  /* skip line cut */
  238.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  239.        if ( *emp && (*emp==',') )
  240.           emp++; /*  skip comma separator */
  241.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  242.            empoint2 = (shalfword)atoi(emp);
  243.        for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
  244.        if ( *emp && strchr("hvp",*emp)!=0 )
  245.           emp++;  /* skip line cut */
  246.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  247.        if ( *emp && (*emp==',') )
  248.           emp++; /*  skip comma separator */
  249.        emwidth = -1.0;
  250.        emunit[0]='\0';
  251.        sscanf(emp, "%f%2s", &emwidth, emunit);
  252.        emwidth = emunits(emwidth,emunit);
  253. #ifdef DEBUG
  254.    if (dd(D_SPECIAL))
  255.       (void)fprintf(stderr, "em special: Line from point %d to point %d\n",
  256.         empoint1, empoint2) ;
  257. #endif
  258.        cmdout("np");
  259.        if (emwidth!=-1.0) {
  260. #ifdef DEBUG
  261.    if (dd(D_SPECIAL))
  262.    (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n", 
  263.         emwidth) ;
  264. #endif
  265.            strcpy(emstr,"currentlinewidth");
  266.            cmdout(emstr);
  267.             sprintf(emstr,"%.1f setlinewidth", emwidth);
  268.             cmdout(emstr);
  269.        }
  270.            empoint = emptget(empoint1);
  271.        numout(empoint->x);
  272.        numout(empoint->y);
  273.        cmdout("a");
  274.            empoint = emptget(empoint2);
  275.        numout(empoint->x);
  276.        numout(empoint->y);
  277.        cmdout("li");
  278.        cmdout("st");
  279.        if (emwidth!=-1.0) {
  280.            strcpy(emstr,"setlinewidth");
  281.            cmdout(emstr);
  282.        }
  283.     }
  284.     else if (strncmp(emp, "message", 7) == 0) {
  285.            (void)fprintf(stderr, "em message: %s\n", emp+7) ;
  286.     }
  287.     else if (strncmp(emp, "graph", 5) == 0) {
  288.        int i;
  289.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  290.        for (i=0; *emp && !isspace(*emp) && !(*emp==',') ; emp++)
  291.           emstr[i++] = *emp; /* copy filename */
  292.        emstr[i] = '\0';
  293.        /* now get optional width and height */
  294.        emwidth = emheight = -1.0;    /* no dimension is <= 0 */
  295.        for (; *emp && ( isspace(*emp) || (*emp==',') ); emp++)
  296.           ;  /* skip blanks and comma */
  297.        if (*emp) {
  298.           sscanf(emp, "%f%2s", &emwidth, emunit); /* read width */
  299.           emwidth = emunits(emwidth,emunit); /* convert to pixels */
  300.           for (; *emp && ( isdigit(*emp) || isalpha(*emp) ); emp++)
  301.              ; /* skip width dimension */
  302.           for (; *emp && ( isspace(*emp) || (*emp==',') ); emp++)
  303.              ;  /* skip blanks and comma */
  304.           if (*emp) {
  305.              sscanf(emp, "%f%2s", &emheight, emunit); /* read height */
  306.              emheight = emunits(emheight,emunit)*vactualdpi/actualdpi;
  307.           }
  308.        }
  309.        if (emstr[0]) {
  310.           emgraph(emstr,emwidth,emheight);
  311.        }
  312.        else {
  313.               (void)fprintf(stderr, "em graph: no file given\n") ;
  314.        }
  315.     }
  316.     else {
  317.            sprintf(errbuf, 
  318.           "Unknown em: command (%s) in \\special will be ignored", p);
  319.            specerror(errbuf) ;
  320.     }
  321.     return;
  322.    }
  323.  
  324.  
  325. /* em:graph routines */
  326.  
  327. /* The graphics routines currently decode 3 types of IBM-PC based graphics    */
  328. /* files: .pcx, .bmp, .msp. The information on the formats has occasionally   */
  329. /* been sketchy, and subject to interpretation. I have attempted to implement */
  330. /* these routines to correctly decode the graphics file types mentioned.      */
  331. /* please note that .bmp file type does not support compressed .bmp files     */
  332. /* this was caused by an inability to locate an example of a complete         */
  333. /* compressed file. 
  334. /*                                                                            */
  335. /* The method of reading in the headers of the binary files is ungainly, but  */
  336. /* portable. Failure to use a byte by byte read and convert method will       */
  337. /* result in portability problems. Specifically there is no requirement that  */
  338. /* elements of a C structure be contiguous, only that they have an ascending  */
  339. /* order of addresses.                                                        */
  340. /*                                                                            */
  341. /* The current implementations of the graphics format to postscript           */
  342. /* conversion are not the most efficient possible. Specifically: color        */
  343. /* formats are converted to RGB ratios prior to using a simple thresholding   */
  344. /* method to determine if the postscript bit is to be set. The thresholding   */
  345. /* method is compabible with that used in emtex's drivers. The RGB            */
  346. /* intermediate value is retained to allow easy conversion to color or grey   */
  347. /* scale operation in the future, should emtex's drivers be rewritten to      */
  348. /* support these modes.                                                       */
  349. /*                                                                            */
  350. /* Please send bug reports relating to the em:graph routines to:              */
  351. /*                maurice@bruce.cs.monash.edu.au                              */
  352. /*                                                                            */
  353. /* My thanks to Russell Lang for his assistance with the implementation of    */
  354. /* these routines in a manner compatible with dvips and for the optimization  */
  355. /* of some routines.                                                          */
  356. /*                                                                            */
  357. /*                                                   Maurice Castro           */
  358. /*                                                   8 Oct 92                 */
  359.  
  360. /* Routines to read binary numbers from IBM PC file types */
  361. integer readinteger(f)
  362. FILE *f;
  363. {
  364.     union {
  365.         integer i;
  366.         unsigned char ip[4];
  367.         } inv;
  368.     int r;
  369.  
  370.     for (r = 0; r < 4; r++)
  371.     {
  372.         inv.ip[r] = ((unsigned char) fgetc(f)) & 0xff;
  373.     }
  374.     return(inv.i);
  375. }
  376.  
  377. halfword readhalfword(f)
  378. FILE *f;
  379. {
  380.     union {
  381.         halfword i;
  382.         unsigned char ip[2];
  383.         } inv;
  384.     int r;
  385.  
  386.     for (r = 0; r < 2; r++)
  387.     {
  388.         inv.ip[r] = ((unsigned char) fgetc(f)) & 0xff;
  389.     }
  390.     return(inv.i);
  391. }
  392.  
  393. quarterword readquarterword(f)
  394. FILE *f;
  395. {
  396.     return(((unsigned char)fgetc(f)) & 0xff);
  397. }
  398.  
  399. #define tobyte(x) ((x/8) + (x%8 ? 1 : 0))
  400.  
  401. /* These routines will decode PCX files produced by Microsoft 
  402.  * Windows Paint.  Other programs may not produce files which
  403.  * will be successfully decoded, most notably version 1.xx of
  404.  * PC Paint. */
  405.  
  406. /*
  407.  *   Type declarations.  integer must be a 32-bit signed; shalfword must
  408.  *   be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
  409.  *   quarterword must be an eight-bit unsigned.
  410.  */
  411. typedef struct 
  412. {
  413.     quarterword man;
  414.     quarterword ver;
  415.     quarterword enc;
  416.     quarterword bitperpix;
  417.     halfword xmin;
  418.     halfword ymin;
  419.     halfword xmax;
  420.     halfword ymax;
  421.     halfword hres;
  422.     halfword vres;
  423.     quarterword pal[48];
  424.     quarterword reserved;
  425.     quarterword colorplanes;
  426.     halfword byteperline;
  427.     halfword paltype;
  428.     quarterword fill[58];
  429. } PCXHEAD; 
  430.  
  431. int PCXreadhead(pcxf, pcxh)
  432. FILE *pcxf;
  433. PCXHEAD *pcxh;
  434. {
  435.     pcxh->man = readquarterword(pcxf);
  436.     pcxh->ver = readquarterword(pcxf);
  437.     pcxh->enc = readquarterword(pcxf);
  438.     pcxh->bitperpix = readquarterword(pcxf);
  439.     pcxh->xmin = readhalfword(pcxf);
  440.     pcxh->ymin = readhalfword(pcxf);
  441.     pcxh->xmax = readhalfword(pcxf);
  442.     pcxh->ymax = readhalfword(pcxf);
  443.     pcxh->hres = readhalfword(pcxf);
  444.     pcxh->vres = readhalfword(pcxf);
  445.     fread(pcxh->pal, 1, 48, pcxf);
  446.     pcxh->reserved = readquarterword(pcxf);
  447.     pcxh->colorplanes = readquarterword(pcxf);
  448.     pcxh->byteperline = readhalfword(pcxf);
  449.     pcxh->paltype = readhalfword(pcxf);
  450.     fread(pcxh->fill, 1, 58, pcxf);
  451.  
  452.     if (feof(pcxf))
  453.         return(0);                /* fail */
  454.     if (pcxh->man != 0x0a)
  455.         return(0);                /* fail */
  456.     if (pcxh->enc != 0x1)
  457.         return(0);                /* fail */
  458.     return(1);                    /* success */
  459.     }
  460.  
  461. int PCXreadline(pcxf, pcxbuf, byteperline)
  462. FILE *pcxf;
  463. unsigned char *pcxbuf;
  464. unsigned int byteperline;
  465. {
  466.     int n;
  467.     int c;
  468.     int i;
  469.  
  470.     n = 0;
  471.     memset(pcxbuf,0,byteperline);
  472.     do {
  473.         c = fgetc(pcxf) & 0xff;
  474.         if ((c & 0xc0) == 0xc0) {
  475.             i = c & 0x3f;
  476.             c = fgetc(pcxf);
  477.             while ((i--) && (n < byteperline)) pcxbuf[n++] = c;
  478.         }
  479.         else {
  480.             pcxbuf[n++] = c;
  481.         }
  482.     } while (n < byteperline);
  483.     if (c==EOF) n=0;
  484.     return(n);
  485. }
  486.  
  487. void PCXgetpalette(pcxf, pcxh, r, g, b)
  488. FILE *pcxf;
  489. PCXHEAD *pcxh;
  490. unsigned char r[256];
  491. unsigned char g[256];
  492. unsigned char b[256];
  493. {
  494.     int i;
  495.  
  496.     /* clear palette */
  497.     for (i=0; i < 256; i++) {
  498.         r[i] = 0;
  499.         g[i] = 0;
  500.         b[i] = 0;
  501.     }
  502.  
  503.     switch (pcxh->ver) {
  504.         case 0:
  505.             /* version 2.5 of PC Paint Brush */
  506.             for (i=0; i < 16; i++) {
  507.                 r[i] = pcxh->pal[i*3];
  508.                 g[i] = pcxh->pal[i*3+1];
  509.                 b[i] = pcxh->pal[i*3+2];
  510.             }
  511.             break;
  512.         case 2:
  513.             /* version 2.8 of PC Paint Brush with valid Palette */
  514.             for (i=0; i < 16; i++) {
  515.                 r[i] = pcxh->pal[i*3];
  516.                 g[i] = pcxh->pal[i*3+1];
  517.                 b[i] = pcxh->pal[i*3+2];
  518.             }
  519.             break;
  520.         case 3:
  521.             /* version 2.8 of PC Paint Brush with no valid Palette */
  522.             /* either mono or default */
  523.  
  524.             if (pcxh->colorplanes != 1) {
  525.                 /* Color default palette - should be checked */
  526.                 r[0] = 0x00;        g[0] = 0x00;        b[0] = 0x00;
  527.                 r[1] = 0x80;        g[1] = 0x00;         b[1] = 0x00;
  528.                 r[2] = 0x00;         g[2] = 0x80;         b[2] = 0x00;
  529.                 r[3] = 0x80;        g[3] = 0x80;         b[3] = 0x00;
  530.                 r[4] = 0x00;        g[4] = 0x00;         b[4] = 0x80;
  531.                 r[5] = 0x80;        g[5] = 0x00;         b[5] = 0x80;
  532.                 r[6] = 0x00;        g[6] = 0x80;         b[6] = 0x80;
  533.                 r[7] = 0x80;        g[7] = 0x80;         b[7] = 0x80;
  534.                 r[8] = 0xc0;        g[8] = 0xc0;        b[8] = 0xc0;
  535.                 r[9] = 0xff;        g[9] = 0x00;         b[9] = 0x00;
  536.                 r[10] = 0x00;         g[10] = 0xff;         b[10] = 0x00;
  537.                 r[11] = 0xff;         g[11] = 0xff;         b[11] = 0x00;
  538.                 r[12] = 0x00;         g[12] = 0x00;         b[12] = 0xff;
  539.                 r[13] = 0xff;         g[13] = 0x00;         b[13] = 0xff;
  540.                 r[14] = 0x00;         g[14] = 0xff;         b[14] = 0xff;
  541.                 r[15] = 0xff;         g[15] = 0xff;         b[15] = 0xff;
  542.             }
  543.             else {
  544.                 /* mono palette */
  545.                 r[0] = 0x00;        g[0] = 0x00;        b[0] = 0x00;
  546.                 r[1] = 0xff;        g[1] = 0xff;         b[1] = 0xff;
  547.             }
  548.             break;
  549.         case 5:
  550.         default:
  551.             /* version 3.0 of PC Paint Brush or Better */
  552.             fseek(pcxf, -769L, SEEK_END);
  553.             /* if signature byte is correct then read the palette */
  554.             /* otherwise copy the existing palette */
  555.             if (fgetc(pcxf) == 12) {
  556.                 for (i=0; i < 256; i++) {
  557.                     r[i] = fgetc(pcxf);
  558.                     g[i] = fgetc(pcxf);
  559.                     b[i] = fgetc(pcxf);
  560.                 }
  561.             }
  562.             else {
  563.                 for (i=0; i < 16; i++) {
  564.                     r[i] = pcxh->pal[i*3];
  565.                     g[i] = pcxh->pal[i*3+1];
  566.                     b[i] = pcxh->pal[i*3+2];
  567.                 }
  568.             }
  569.             break;
  570.     }
  571. }
  572.  
  573. extern void mhexout() ;
  574.  
  575. void showpicture(pcxf, wide, high, bytes, cp, bp, r, g, b)
  576. FILE *pcxf;
  577. int wide;
  578. int high;
  579. int bytes;
  580. int cp;
  581. int bp;
  582. unsigned char r[256];
  583. unsigned char g[256];
  584. unsigned char b[256];
  585. {
  586.     int x;
  587.     int y;
  588.     int c;
  589.     unsigned char *rowa[4];                /* row array */
  590.     unsigned char *row;
  591.     int a;
  592.     int p;
  593.     int ra;
  594.     int ga;
  595.     int ba;
  596.     unsigned char *pshexa;
  597.     int cbp;
  598.     int xdiv, xmod, xbit;
  599.     int width;
  600.  
  601.     width = tobyte(wide) * 8;
  602.  
  603.     /* output the postscript image size preamble */
  604.     cmdout("/picstr ");
  605.     numout((integer)tobyte(wide));
  606.     cmdout("string def");
  607.  
  608.     numout((integer)width);
  609.     numout((integer)high);
  610.     numout((integer)1);
  611.  
  612.     cmdout("[");
  613.     numout((integer)width);
  614.     numout((integer)0);
  615.     numout((integer)0);
  616.     numout((integer)-high);
  617.     numout((integer)0);
  618.     numout((integer)0);
  619.     cmdout("]");
  620.  
  621.     cmdout("{currentfile picstr readhexstring pop} ");
  622.     cmdout("image ");
  623.  
  624.     /* allocate the postscript hex output array */
  625.     pshexa = (unsigned char *) malloc(tobyte(wide));
  626.  
  627.     /* make sure that you start at the right point in the file */
  628.     fseek(pcxf, (long) sizeof(PCXHEAD), SEEK_SET);
  629.  
  630.     /* malloc the lines */
  631.     for (c = 0; c < cp; c++)
  632.         rowa[c] = (unsigned char *) malloc(bytes);
  633.  
  634.     for (y = 0; y < high; y++) {
  635.         /* clear the postscript hex array */
  636.         memset(pshexa,0xff,bytes);
  637.  
  638.         /* read in all the color planes for a row of pixels */
  639.         for (c = 0; c < cp; c++)
  640.             PCXreadline(pcxf, rowa[c], bytes);
  641.         /* process each pixel */
  642.         for (x = 0; x < wide; x++) {
  643.             /* build up the pixel value from color plane entries */
  644.             p = 0;
  645.             xdiv = x>>3;
  646.             xmod = 7 - (x&7);
  647.             xbit = 1 << xmod;
  648.             switch(bp) {
  649.                 case 1: 
  650.                     for (c = 0; c < cp; c++) {
  651.                         row = rowa[c];
  652.                         p |= ( (unsigned)(row[xdiv] & xbit) >> xmod ) << c;
  653.                     }
  654.                     ra = r[p];    /* red actual */
  655.                     ga = g[p];    /* green actual */
  656.                     ba = b[p];    /* blue actual */
  657.                     if ((ra < 0xff) || (ga < 0xff) || (ba < 0xff))
  658.                         pshexa[xdiv] &= (~xbit);
  659.                     else
  660.                         pshexa[xdiv] |= xbit;
  661.                     break;
  662.                 case 8:
  663.                     for (c = 0, cbp = 0; c < cp; c++, cbp += bp) {
  664.                         row = rowa[c];
  665.                         a = (unsigned) (row[x]);
  666.                         p |= a << (cbp);
  667.                     }
  668.                     ra = r[p];    /* red actual */
  669.                     ga = g[p];    /* green actual */
  670.                     ba = b[p];    /* blue actual */
  671.                     if ((ra < 0xff) || (ga < 0xff) || (ba < 0xff))
  672.                         pshexa[xdiv] &= (~xbit);
  673.                     else
  674.                         pshexa[xdiv] |= xbit;
  675.                     break;
  676.                 default: 
  677.                     fprintf(stderr, "em graph: Unable to Decode this PCX file\n");
  678.                     return;
  679.             }
  680.         }
  681.         mhexout(pshexa,(long)tobyte(wide));
  682.     }
  683. }
  684.  
  685. void imagehead(filename,wide,high,emwidth,emheight)
  686. char filename[];
  687. int wide, high;
  688. float emwidth, emheight;    /* dimension in pixels */
  689. {
  690.     (void)fprintf(stderr,"<%s",filename);
  691.     (void)fflush(stderr);
  692.     hvpos();
  693.     cmdout("@beginspecial") ;
  694.     cmdout("@setspecial") ;
  695.     if (linepos != 0)
  696.         (void)putc('\n', bitfile) ;
  697.     linepos = 0;
  698.     if (! disablecomments)
  699.         (void)fprintf(bitfile, "%%%%BeginDocument: %s_via_em:graph\n", filename) ;
  700.  
  701.     cmdout("gsave");
  702.     /* set the image size */
  703.     if (emwidth <= 0.0)  emwidth = (float)wide;
  704.     if (emheight <= 0.0)  emheight = (float)high;
  705.     numout(((integer)emwidth)*72/actualdpi);
  706.     numout(((integer)emheight)*72/vactualdpi);
  707.     cmdout("scale");
  708. #ifdef DEBUG
  709.     if (dd(D_SPECIAL)) {
  710.       (void)fprintf(stderr, 
  711.         "\nem graph: %s width  %d pixels scaled to %.1f pixels\n",
  712.         filename, wide, emwidth);
  713.       (void)fprintf(stderr, 
  714.         "em graph: %s height %d pixels scaled to %.1f pixels\n",
  715.         filename, high, emheight);
  716.        }
  717. #endif
  718. }
  719.  
  720. void imagetail(filename)
  721. char filename[];
  722. {
  723.     cmdout("grestore");
  724.     if (linepos != 0)
  725.         (void)putc('\n', bitfile) ;
  726.     linepos = 0;
  727.     if (!disablecomments) {
  728.         (void)fprintf(bitfile, "%%%%EndDocument\n") ;
  729.         linepos = 0;
  730.     }
  731.     cmdout("\n@endspecial") ;
  732.     (void)fprintf(stderr,">");
  733.     (void)fflush(stderr);
  734.     prettycolumn += 2+strlen(filename);
  735. }
  736.  
  737. void pcxgraph(filename,emwidth,emheight)
  738. char filename[];
  739. float emwidth, emheight;    /* dimension in pixels */
  740. {
  741.     PCXHEAD pcxh;
  742.     FILE *pcxf;
  743.     unsigned char red[256];
  744.     unsigned char green[256];
  745.     unsigned char blue[256];
  746.     int wide;
  747.     int high;
  748.     int bytes;
  749.     int cp;
  750.     int bpp;
  751.  
  752.     pcxf = search(figpath, filename, READBIN);
  753.     if (pcxf == NULL) {
  754.         fprintf(stderr, "em graph: Unable to Open File %s\n", filename);
  755.         return;
  756.     }
  757.     if (!PCXreadhead(pcxf, &pcxh)) {
  758.         fprintf(stderr, "em graph: Unable to Read Valid PCX Header\n");
  759.         return;
  760.     }
  761.     PCXgetpalette(pcxf, &pcxh, red, green, blue);
  762.  
  763.     /* picture size calculation */
  764.     wide = (pcxh.xmax - pcxh.xmin) + 1;
  765.     high = (pcxh.ymax - pcxh.ymin) + 1;
  766.     bytes = pcxh.byteperline;
  767.     cp = pcxh.colorplanes;
  768.     bpp = pcxh.bitperpix;
  769.  
  770.     imagehead(filename,wide,high,emwidth,emheight);
  771.     showpicture(pcxf, wide, high, bytes, cp, bpp, red, green, blue);
  772.     imagetail(filename);
  773. }
  774.  
  775. struct wpnt_1 {
  776.     quarterword id[4];
  777.     halfword width;
  778.     halfword high;
  779.     halfword x_asp;
  780.     halfword y_asp;
  781.     halfword x_asp_prn;
  782.     halfword y_asp_prn;
  783.     halfword width_prn;
  784.     halfword high_prn;
  785.     integer chk_sum;
  786.     halfword chk_head;
  787. };
  788.  
  789. #define WPAINT_1 1
  790. #define WPAINT_2 2
  791.  
  792. void MSP_2_ps(f, wide, high)
  793. FILE *f;
  794. int wide;
  795. int high;
  796. {
  797.     char *line;
  798.     char *l;
  799.     int i;
  800.     int j;
  801.     char a, b, c;
  802.     int d;
  803.     int width;
  804.     halfword *linelen;
  805.  
  806.     /* an undocumented format - based on a type of run length encoding    */
  807.     /* the format is made up of a list of line lengths, followed by a set */
  808.     /* of lines. Each line is made up of 2 types of entries:              */
  809.     /*     1) A 3 term entry (0 a b): the byte b is repeated a times     */
  810.     /*    2) A variable length entry (a xxxx....xxxx): a bytes are read */
  811.     /*       from the file.                                             */
  812.     /* These entries are combined to build up a line                      */
  813.  
  814.     width = tobyte(wide)*8;
  815.  
  816.     /* output the postscript image size preamble */
  817.     cmdout("/picstr ");
  818.     numout((integer)tobyte(wide));
  819.     cmdout("string def");
  820.  
  821.     numout((integer)width);
  822.     numout((integer)high);
  823.     numout((integer)1);
  824.  
  825.     cmdout("[");
  826.     numout((integer)width);
  827.     numout((integer)0);
  828.     numout((integer)0);
  829.     numout((integer)-high);
  830.     numout((integer)0);
  831.     numout((integer)0);
  832.     cmdout("]");
  833.  
  834.     cmdout("{currentfile picstr readhexstring pop} ");
  835.     cmdout("image ");
  836.  
  837.     fseek(f, 32, SEEK_SET);
  838.  
  839.     /* read in the table of line lengths */    
  840.     linelen = (halfword *) malloc(sizeof(halfword) * high);
  841.     for (i = 0; i < high; i++) {
  842.         linelen[i] = readhalfword(f);
  843.         if (feof(f))
  844.             return;
  845.     }
  846.  
  847.     line = (char *) malloc(tobyte(wide));
  848.     for (i = 0; i < high; i++) {
  849.         memset(line, 0xff, tobyte(wide));
  850.         l = line;
  851.         if (linelen[i] != 0) {
  852.             d = linelen[i];
  853.             while (d) {
  854.                 a = fgetc(f);
  855.                 d--;
  856.                 if (a == 0) {
  857.                     b = fgetc(f);
  858.                     c = fgetc(f);
  859.                     d -= 2;
  860.                     for (j = 0; j < b; j++)
  861.                         *l++ = c;
  862.                 }
  863.                 else {
  864.                     for (j = 0; j < a; j++)
  865.                         *l++ = fgetc(f);
  866.                     d -= j;
  867.                 }
  868.             }
  869.         }
  870.         mhexout(line,(long)tobyte(wide));
  871.     }
  872. }
  873.  
  874. void MSP_1_ps(f, wide, high)
  875. FILE *f;
  876. int wide;
  877. int high;
  878. {
  879.     char *line;
  880.     int i;
  881.     int width;
  882.  
  883.     width = tobyte(wide)*8;
  884.     /* an partly documented format - see The PC Sourcebook                */
  885.     /* the format is made up of a simple bitmap.                          */
  886.  
  887.     /* output the postscript image size preamble */
  888.     cmdout("/picstr ");
  889.     numout((integer)tobyte(wide));
  890.     cmdout("string def");
  891.  
  892.     numout((integer)width);
  893.     numout((integer)high);
  894.     numout((integer)1);
  895.  
  896.     cmdout("[");
  897.     numout((integer)width);
  898.     numout((integer)0);
  899.     numout((integer)0);
  900.     numout((integer)-high);
  901.     numout((integer)0);
  902.     numout((integer)0);
  903.     cmdout("]");
  904.  
  905.     cmdout("{currentfile picstr readhexstring pop} ");
  906.     cmdout("image ");
  907.  
  908.     fseek(f, 32, SEEK_SET);
  909.  
  910.     line = (char *) malloc(tobyte(wide));
  911.     for (i = 0; i < high; i++) {
  912.         fread(line, 1, tobyte(wide), f);
  913.         mhexout(line,(long)tobyte(wide));
  914.     }
  915. }
  916.  
  917.  
  918. void mspgraph(filename,emwidth,emheight)
  919. char filename[];
  920. float emwidth, emheight;    /* dimension in pixels */
  921. {
  922.     struct wpnt_1 head;
  923.     int paint_type;
  924.     FILE *f;
  925.  
  926.     paint_type = 0;
  927.     f = search(figpath, filename, READBIN);
  928.     if (f == NULL) {
  929.         fprintf(stderr, "em graph: Unable to Open File %s\n", filename);
  930.         return;
  931.     }
  932.  
  933.         /* read the header of the file and figure out what it is */
  934.     fread(head.id, 1, 4, f);
  935.     head.width = readhalfword(f); 
  936.     head.high = readhalfword(f); 
  937.     head.x_asp = readhalfword(f); 
  938.     head.y_asp = readhalfword(f); 
  939.     head.x_asp_prn = readhalfword(f); 
  940.     head.y_asp_prn = readhalfword(f); 
  941.     head.width_prn = readhalfword(f); 
  942.     head.high_prn = readhalfword(f); 
  943.     head.chk_sum = readinteger(f); 
  944.     head.chk_head = readhalfword(f); 
  945.  
  946.     if (feof(f)) {
  947.         fprintf(stderr, "em graph: Unable to Read Valid MSP Header\n");
  948.         return;
  949.     }
  950.         
  951.         /* check the id bytes */
  952.     if (!memcmp(head.id, "DanM", 4))
  953.             paint_type = WPAINT_1;
  954.     if (!memcmp(head.id, "LinS", 4))
  955.         paint_type = WPAINT_2;
  956.  
  957.  
  958.     imagehead(filename,head.width,head.high,emwidth,emheight);
  959.     switch (paint_type) {
  960.         case WPAINT_1:
  961.                     MSP_1_ps(f, head.width, head.high);
  962.             fclose(f);
  963.             break;
  964.                 case WPAINT_2:
  965.                     MSP_2_ps(f, head.width, head.high);
  966.             fclose(f);
  967.             break;
  968.         default:
  969.             fprintf(stderr, "em graph: Unknown File Type\n");
  970.             return;
  971.     }
  972.     imagetail(filename);
  973. }
  974.  
  975. /* ------------------------------------------------------------------------ */
  976. /* .BMP file structures */
  977. struct rgbquad
  978. {
  979.     char blue;
  980.     char green;
  981.     char red;
  982.     char res;
  983.     };
  984.  
  985. struct bitmapinfoheader
  986. {
  987.     integer size;
  988.     integer width;
  989.     integer height;
  990.     halfword planes;            /* must be set to 1 */
  991.     halfword bitcount;            /* 1, 4, 8 or 24 */
  992.     integer compression;
  993.     integer sizeimage;
  994.     integer xpelspermeter;
  995.     integer ypelspermeter;
  996.     integer clrused;
  997.     integer clrimportant;
  998.     };
  999.  
  1000. /* constants for the compression field */
  1001. #define RGB 0L
  1002. #define RLE8 1L
  1003. #define RLE4 2L
  1004.  
  1005. struct bitmapfileheader
  1006. {
  1007.     char type[2];
  1008.     integer size;
  1009.     halfword reserved1;
  1010.     halfword reserved2;
  1011.     integer offbits;
  1012.     };
  1013.  
  1014. void rgbread(f, w, b, s)
  1015. FILE *f;
  1016. int b;
  1017. int w;
  1018. char *s;
  1019. {
  1020.     int i;
  1021.  
  1022.     /* set the line to white */
  1023.     memset(s, 0xff, ((w*b)/8)+1); 
  1024.  
  1025.     /* read in all the full bytes */
  1026.     for (i = 0; i < (w * b) / 8; i++)
  1027.         *s++ = fgetc(f);
  1028.  
  1029.     /* read in a partly filled byte */
  1030.     if ((w * b) % 8)
  1031.     {
  1032.         i++;
  1033.         *s++ = fgetc(f);
  1034.         }
  1035.  
  1036.     /* check that we are on a 32 bit boundary; otherwise align */
  1037.     while (i % 4 != 0)
  1038.     {
  1039.         fgetc(f);
  1040.         i++;
  1041.         }
  1042.     }
  1043.  
  1044. void bmpgraph(filename,emwidth,emheight)
  1045. char filename[];
  1046. float emwidth, emheight;    /* dimension in pixels */
  1047. {
  1048.     FILE *f;
  1049.     struct bitmapfileheader bmfh;
  1050.     struct bitmapinfoheader bmih;
  1051.     unsigned char r[256];
  1052.     unsigned char g[256];
  1053.     unsigned char b[256];
  1054.  
  1055.     unsigned char rr;
  1056.     unsigned char gg;
  1057.     unsigned char bb;
  1058.     unsigned char c;
  1059.  
  1060.     char *line;
  1061.     char *pshexa;
  1062.  
  1063.     int clrtablesize;
  1064.     int i;
  1065.     int j;
  1066.  
  1067.     unsigned char imask;
  1068.     unsigned char omask;
  1069.     int iroll;
  1070.     int oroll;
  1071.  
  1072.     f = search(figpath, filename, READBIN);
  1073.     if (f == NULL) {
  1074.         fprintf(stderr, "em graph: Unable to Open File %s\n", filename);
  1075.         return;
  1076.     }
  1077.  
  1078.         /* read the header of the file */
  1079.     fread(bmfh.type, 1, 2, f);
  1080.     bmfh.size = readinteger(f);
  1081.     bmfh.reserved1 = readhalfword(f);
  1082.     bmfh.reserved2 = readhalfword(f);
  1083.     bmfh.offbits = readinteger(f);
  1084.     if (feof(f))
  1085.     {
  1086.         fprintf(stderr, "em graph: Unable to Read Valid BMP Header\n");
  1087.         return;
  1088.                 }
  1089.  
  1090.     bmih.size = readinteger(f);
  1091.     bmih.width = readinteger(f);
  1092.     bmih.height = readinteger(f);
  1093.     bmih.planes = readhalfword(f);
  1094.     bmih.bitcount = readhalfword(f);
  1095.     bmih.compression = readinteger(f);
  1096.     bmih.sizeimage = readinteger(f);
  1097.     bmih.xpelspermeter = readinteger(f);
  1098.     bmih.ypelspermeter = readinteger(f);
  1099.     bmih.clrused = readinteger(f);
  1100.     bmih.clrimportant = readinteger(f);
  1101.  
  1102.     if (feof(f))
  1103.     {
  1104.         fprintf(stderr, "em graph: Unable to Read Valid BMP Info\n");
  1105.         return;
  1106.         }
  1107.  
  1108.     if (!memcmp(bmfh.type, "bm", 2))
  1109.     {
  1110.         fprintf(stderr, "em graph: Unknown File Type\n");
  1111.         return;
  1112.         }
  1113.  
  1114.     imagehead(filename,(int)bmih.width,(int)bmih.height,emwidth,emheight);
  1115.  
  1116.     /* determine the size of the color table to read */
  1117.     clrtablesize = 0;
  1118.     if (bmih.clrused == 0)
  1119.     {
  1120.         switch (bmih.bitcount)
  1121.         {
  1122.             case 1:
  1123.                 clrtablesize = 2;
  1124.                 break;
  1125.             case 4:
  1126.                 clrtablesize = 16;
  1127.                 break;
  1128.             case 8:
  1129.                 clrtablesize = 256;
  1130.                 break;
  1131.             case 24:
  1132.                 break;
  1133.             }
  1134.         }
  1135.     else
  1136.         clrtablesize = bmih.clrused;
  1137.  
  1138.     /* read in the color table */
  1139.     for (i = 0; i < clrtablesize; i++)
  1140.     {
  1141.         b[i] = fgetc(f);
  1142.         g[i] = fgetc(f);
  1143.         r[i] = fgetc(f);
  1144.         (void) fgetc(f);
  1145.         }
  1146.  
  1147.     line = (char *) malloc(((bmih.width * bmih.bitcount) / 8) + 1);
  1148.     pshexa = (char *) malloc(tobyte(bmih.width));
  1149.  
  1150.     /* output the postscript image size preamble */
  1151.     cmdout("/picstr ");
  1152.     numout((integer)tobyte(bmih.width));
  1153.     cmdout("string def");
  1154.  
  1155.     numout((integer)bmih.width);
  1156.     numout((integer)bmih.height);
  1157.     numout((integer)1);
  1158.  
  1159.     cmdout("[");
  1160.     numout((integer)bmih.width);
  1161.     numout((integer)0);
  1162.     numout((integer)0);
  1163.     numout((integer)bmih.height);
  1164.     numout((integer)0);
  1165.     numout((integer)bmih.height);
  1166.     cmdout("]");
  1167.  
  1168.     cmdout("{currentfile picstr readhexstring pop} ");
  1169.     cmdout("image ");
  1170.  
  1171.     switch (bmih.compression)
  1172.     {
  1173.         case RGB:
  1174.             /* read in all the lines of the file */
  1175.             for (i = 0; i < bmih.height; i++)
  1176.             {
  1177.                 memset(pshexa,0xff,tobyte(bmih.width));
  1178.                 rgbread(f, (int) bmih.width, (int) bmih.bitcount, line);
  1179.  
  1180.                 switch (bmih.bitcount)
  1181.                 {
  1182.                     case 1:
  1183.                         imask = 0x80;
  1184.                         iroll = 7;
  1185.                         break;
  1186.                     case 4:
  1187.                         imask = 0xf0;
  1188.                         iroll = 4;
  1189.                         break;
  1190.                     }
  1191.                 omask = 0x80;
  1192.                 oroll = 7;
  1193.  
  1194.                 for (j = 0; j < bmih.width - 1; j++)
  1195.                 {
  1196.                     /* performance in this section of code */
  1197.                     /* can easily be improved through the */
  1198.                     /* use of techniques used in pcx */
  1199.                     /* Postscript generation routines */
  1200.                     switch (bmih.bitcount)
  1201.                     {
  1202.                         case 1:
  1203.                             c = line[j/8];
  1204.                             c &= imask;
  1205.                             c >>= iroll;
  1206.  
  1207.                             rr = r[c];
  1208.                             gg = g[c];
  1209.                             bb = b[c];
  1210.  
  1211.                             iroll--;
  1212.                             imask >>= 1;
  1213.     
  1214.                             if (iroll < 0)
  1215.                             {
  1216.                                 imask = 0x80;
  1217.                                 iroll = 7;
  1218.                                 }
  1219.                             break;
  1220.                         case 4:
  1221.                             c = line[j/2];
  1222.                             c &= imask;
  1223.                             c >>= iroll;
  1224.  
  1225.                             rr = r[c];
  1226.                             gg = g[c];
  1227.                             bb = b[c];
  1228.  
  1229.                             iroll-=4;
  1230.                             imask >>= 4;
  1231.     
  1232.                             if (iroll < 0)
  1233.                             {
  1234.                                 imask = 0xf0;
  1235.                                 iroll = 4;
  1236.                                 }
  1237.                             break;
  1238.                         case 8:
  1239.                             c = line[j];
  1240.                             rr = r[c];
  1241.                             gg = g[c];
  1242.                             bb = b[c];
  1243.                             break;
  1244.                         case 24:
  1245.                             rr = r[j*3];
  1246.                             gg = g[j*3+1];
  1247.                             bb = b[j*3+2];
  1248.                             break;
  1249.                         }
  1250.                     if ((rr < 0xff) || (gg < 0xff) || (bb < 0xff))
  1251.                         pshexa[j/8] &= ~omask;
  1252.                     else
  1253.                         pshexa[j/8] |= omask;
  1254.                     oroll--;
  1255.                     omask >>= 1;
  1256.                     if (oroll < 0)
  1257.                     {
  1258.                         omask = 0x80;
  1259.                         oroll = 7;
  1260.                         }
  1261.  
  1262.                     }
  1263.                 mhexout(pshexa,(long)tobyte(bmih.width));
  1264.                 }
  1265.             fclose(f);
  1266.             break;
  1267.         case RLE8:
  1268.             fprintf(stderr, "em graph: BMP Compressed Files Not Implemented\n");
  1269.             return;
  1270.         case RLE4:
  1271.             fprintf(stderr, "em graph: BMP Compressed Files Not Implemented\n");
  1272.             return;
  1273.         }
  1274.     imagetail(filename);
  1275. }
  1276. /* ------------------------------------------------------------------------ */
  1277.  
  1278. char *extarr[]=
  1279. { ".pcx", ".msp", ".bmp", NULL };
  1280.  
  1281. void emgraph(filename,emwidth,emheight)
  1282. char filename[];
  1283. float emwidth, emheight;    /* dimension in pixels */
  1284. {
  1285.     int l;
  1286.     char fname[80];
  1287.     char *ext;
  1288.     int idx;
  1289.     int filetype;
  1290.     FILE *f;
  1291.  
  1292.     strcpy(fname, filename);
  1293.  
  1294.     /* identify file type by extension */
  1295.     l = strlen(fname);
  1296.     filetype = -1;
  1297.     if (l  > 4) {
  1298.         ext = fname+(l-4);
  1299.         idx = 0;
  1300.         while (extarr[idx] != NULL) {
  1301.             if (!strcmp(ext, extarr[idx]))
  1302.                 filetype = idx;
  1303.             idx++;
  1304.         }
  1305.     }
  1306.  
  1307.     if (filetype == -1) {
  1308.         /* try various file types */
  1309.         ext = fname + l;
  1310.         idx = 0;
  1311.         while (extarr[idx] != NULL) {
  1312.             strcpy(ext, extarr[idx]);
  1313.             f = search(figpath, fname, READBIN);
  1314.             if (f != NULL) {
  1315.                 filetype = idx;
  1316.                 fclose(f);
  1317.                 break;
  1318.             }
  1319.             idx++;
  1320.         }
  1321.     }
  1322.  
  1323.     switch (filetype) {
  1324.         case 0:
  1325.             pcxgraph(fname, emwidth, emheight);
  1326.             break;
  1327.         case 1:
  1328.             mspgraph(fname, emwidth, emheight);
  1329.             break;
  1330.         case 2:
  1331.             bmpgraph(fname, emwidth, emheight);
  1332.             break;
  1333.         default:
  1334.             sprintf(fname,"em graph: %s: File not found", filename);
  1335.             error(fname);
  1336.     }
  1337. }
  1338.  
  1339. #else
  1340. void emspecial(p)
  1341. char *p ;
  1342. {
  1343.     sprintf(errbuf,"emTeX specials not compiled in this version");
  1344.     specerror(errbuf);
  1345. }
  1346. #endif EMTEX
  1347.  
  1348.