home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 3.3J / os33j.iso / NextLibrary / TeX / tex / src / dvips / emspecial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-27  |  34.3 KB  |  1,491 lines

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