summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipsk/emspecial.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvipsk/emspecial.c')
-rw-r--r--Build/source/texk/dvipsk/emspecial.c1469
1 files changed, 1469 insertions, 0 deletions
diff --git a/Build/source/texk/dvipsk/emspecial.c b/Build/source/texk/dvipsk/emspecial.c
new file mode 100644
index 00000000000..38e450d050e
--- /dev/null
+++ b/Build/source/texk/dvipsk/emspecial.c
@@ -0,0 +1,1469 @@
+/* $Id$
+ * emspecial.c
+ * This routine handles the emTeX special commands.
+ */
+#include "dvips.h" /* The copyright notice in that file is included too!*/
+
+#include <ctype.h>
+#include <stdlib.h>
+/*
+ * The external declarations:
+ */
+#include "protos.h"
+
+#ifdef EMTEX
+/* emtex specials, added by rjl */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+static long emmax = 161;
+
+/*
+ * We define these seek constants if they don't have their
+ * values already defined.
+ */
+#ifndef SEEK_SET
+#define SEEK_SET (0)
+#endif
+#ifndef SEEK_END
+#define SEEK_END (2)
+#endif
+
+struct empt {
+ struct empt *next;
+ shalfword point;
+ integer x, y;
+};
+
+static struct empt **empoints = NULL;
+boolean emused = FALSE; /* true if em points used on this page */
+integer emx, emy;
+
+struct emunit {
+ const char *unit;
+ float factor;
+};
+struct emunit emtable[] = {
+ {"pt",72.27},
+ {"pc",72.27/12},
+ {"in",1.0},
+ {"bp",72.0},
+ {"cm",2.54},
+ {"mm",25.4},
+ {"dd",72.27/(1238.0/1157)},
+ {"cc",72.27/12/(1238.0/1157)},
+ {"sp",72.27*65536},
+ {0,0.0}
+};
+
+static void emgraph(char *filename, float emwidth, float emheight);
+
+/* clear the empoints array if necessary */
+void
+emclear(void)
+{
+ int i;
+ if (emused && empoints)
+ for (i=0; i<emmax; i++)
+ empoints[i] = 0;
+ emused = FALSE;
+}
+
+/* put an empoint into the empoints array */
+static struct empt *
+emptput(shalfword point, integer x, integer y)
+{
+ struct empt *p;
+ int start;
+
+ emused = TRUE;
+ start = point % emmax;
+ p = empoints[start];
+ while ( p ) {
+ if ( p->point == point )
+ break;
+ p = p->next;
+ }
+ if (p == 0) {
+ p = (struct empt *)mymalloc(sizeof(struct empt));
+ p->next = empoints[start];
+ empoints[start] = p;
+ }
+ p->point = point;
+ p->x = x;
+ p->y = y;
+ return(p);
+}
+
+/* get an empoint from the empoints array */
+static struct empt *
+emptget(shalfword point)
+{
+ struct empt *p;
+ int start;
+
+ start = point % emmax;
+ if (emused == TRUE) {
+ p = empoints[start];
+ while (p) {
+ if (p->point == point)
+ return p;
+ p = p->next;
+ }
+ }
+ sprintf(errbuf,"!em: point %d not defined",point);
+ specerror(errbuf);
+ return(NULL); /* never returns due to error */
+}
+
+
+/* convert width into dpi units */
+static float
+emunits(float width, char *unit)
+{
+struct emunit *p;
+ for (p=emtable; p->unit; p++) {
+ if (strcmp(p->unit,unit)==0)
+ return( width * actualdpi / p->factor );
+ }
+ return (-1.0); /* invalid unit */
+}
+
+/* The main routine for \special{em:graph ...} called from dospecial.c */
+/* the line cut parameter is not supported (and is ignored) */
+
+void
+emspecial(char *p)
+{
+float emwidth, emheight;
+shalfword empoint1, empoint2;
+struct empt *empoint;
+char emunit[30];
+char emstr[500];
+char *emp;
+
+ hvpos();
+ for (emp = p+3; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ if (strncmp(emp, "linewidth", 9) == 0) {
+ /* code for linewidth */
+ for (emp = emp+9; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ sscanf(emp, "%f%2s", &emwidth, emunit);
+ emwidth = emunits(emwidth,emunit);
+ if (emwidth!=-1.0) {
+ snprintf(emstr, sizeof(emstr), "%.1f setlinewidth", emwidth);
+ cmdout(emstr);
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+ fprintf(stderr, "em special: Linewidth set to %.1f dots\n",
+ emwidth);
+#endif
+ } else {
+ sprintf(errbuf,"Unknown em: special width");
+ specerror(errbuf);
+ }
+ }
+ else if (strncmp(emp, "moveto", 6) == 0) {
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+#ifdef SHORTINT
+ fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
+#else
+ fprintf(stderr, "em special: moveto %d,%d\n", hh, vv);
+#endif
+#endif
+ emx = hh;
+ emy = vv;
+ }
+ else if (strncmp(emp, "lineto", 6) == 0) {
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+#ifdef SHORTINT
+ fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
+#else
+ fprintf(stderr, "em special: lineto %d,%d\n", hh, vv);
+#endif
+#endif
+ cmdout("np");
+ numout(emx);
+ numout(emy);
+ cmdout("a");
+ numout(hh);
+ numout(vv);
+ cmdout("li");
+ cmdout("st");
+ emx = hh;
+ emy = vv;
+ }
+ else if (strncmp(emp, "point", 5) == 0) {
+ if (empoints == NULL) {
+ empoints =
+ (struct empt **)mymalloc((integer)emmax * sizeof(struct empt *));
+ emused = TRUE;
+ emclear();
+ }
+ for (emp = emp+5; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ empoint1 = (shalfword)atoi(emp);
+ empoint = emptput(empoint1,hh,vv);
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+#ifdef SHORTINT
+ fprintf(stderr, "em special: Point %d is %ld,%ld\n",
+#else
+ fprintf(stderr, "em special: Point %d is %d,%d\n",
+#endif
+ empoint->point, empoint->x, empoint->y);
+#endif
+ }
+ else if (strncmp(emp, "line", 4) == 0) {
+ for (emp = emp+4; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ empoint1 = (shalfword)atoi(emp);
+ for (; *emp && isdigit((unsigned char)*emp); emp++); /* skip point 1 */
+ if ( *emp && strchr("hvp",*emp)!=0 )
+ emp++; /* skip line cut */
+ for (; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ if ( *emp && (*emp==',') )
+ emp++; /* skip comma separator */
+ for (; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ empoint2 = (shalfword)atoi(emp);
+ for (; *emp && isdigit((unsigned char)*emp); emp++); /* skip point 2 */
+ if ( *emp && strchr("hvp",*emp)!=0 )
+ emp++; /* skip line cut */
+ for (; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ if ( *emp && (*emp==',') )
+ emp++; /* skip comma separator */
+ emwidth = -1.0;
+ emunit[0]='\0';
+ sscanf(emp, "%f%2s", &emwidth, emunit);
+ emwidth = emunits(emwidth,emunit);
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+ fprintf(stderr, "em special: Line from point %d to point %d\n",
+ empoint1, empoint2);
+#endif
+ cmdout("np");
+ if (emwidth!=-1.0) {
+#ifdef DEBUG
+ if (dd(D_SPECIAL))
+ fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n",
+ emwidth);
+#endif
+ strcpy(emstr,"currentlinewidth");
+ cmdout(emstr);
+ snprintf(emstr, sizeof(emstr), "%.1f setlinewidth", emwidth);
+ cmdout(emstr);
+ }
+ empoint = emptget(empoint1);
+ numout(empoint->x);
+ numout(empoint->y);
+ cmdout("a");
+ empoint = emptget(empoint2);
+ numout(empoint->x);
+ numout(empoint->y);
+ cmdout("li");
+ cmdout("st");
+ if (emwidth!=-1.0) {
+ strcpy(emstr,"setlinewidth");
+ cmdout(emstr);
+ }
+ }
+ else if (strncmp(emp, "message", 7) == 0) {
+ fprintf_str(stderr, "em message: %s\n", emp+7);
+ }
+ else if (strncmp(emp, "graph", 5) == 0) {
+ int i;
+ for (emp = emp+5; *emp && isspace((unsigned char)*emp); emp++); /* skip blanks */
+ for (i=0; *emp && !isspace((unsigned char)*emp) && !(*emp==','); emp++) {
+ if (i > (int)sizeof(emstr) - 2) {
+ fprintf(stderr, "em:graph: special too long, truncating\n");
+ break;
+ }
+ emstr[i++] = *emp; /* copy filename */
+ }
+ emstr[i] = '\0';
+ /* now get optional width and height */
+ emwidth = emheight = -1.0; /* no dimension is <= 0 */
+ for (; *emp && ( isspace((unsigned char)*emp) || (*emp==',') ); emp++)
+ ; /* skip blanks and comma */
+ if (*emp) {
+ sscanf(emp, "%f%2s", &emwidth, emunit); /* read width */
+ emwidth = emunits(emwidth,emunit); /* convert to pixels */
+ for (; *emp && (*emp=='.'||isdigit((unsigned char)*emp)||isalpha((unsigned char)*emp)); emp++)
+ ; /* skip width dimension */
+ for (; *emp && ( isspace((unsigned char)*emp) || (*emp==',') ); emp++)
+ ; /* skip blanks and comma */
+ if (*emp) {
+ sscanf(emp, "%f%2s", &emheight, emunit); /* read height */
+ emheight = emunits(emheight,emunit)*vactualdpi/actualdpi;
+ }
+ }
+ if (emstr[0]) {
+ emgraph(emstr,emwidth,emheight);
+ }
+ else {
+ fprintf(stderr, "em:graph: no file given\n");
+ }
+ }
+ else {
+ sprintf(errbuf,
+ "Unknown em: command (%s) in \\special will be ignored", p);
+ specerror(errbuf);
+ }
+ return;
+ }
+
+
+/* em:graph routines */
+
+/* The graphics routines currently decode 3 types of IBM-PC based graphics */
+/* files: .pcx, .bmp, .msp. The information on the formats has occasionally */
+/* been sketchy, and subject to interpretation. I have attempted to implement*/
+/* these routines to correctly decode the graphics file types mentioned. */
+/* The compressed .bmp file type has not been tested fully due to a lack of */
+/* test files. */
+/* */
+/* The method of reading in the headers of the binary files is ungainly, but */
+/* portable. Failure to use a byte by byte read and convert method will */
+/* result in portability problems. Specifically there is no requirement that */
+/* elements of a C structure be contiguous, only that they have an ascending */
+/* order of addresses. */
+/* */
+/* The current implementations of the graphics format to postscript */
+/* conversion are not the most efficient possible. Specifically: color */
+/* formats are converted to RGB ratios prior to using a simple thresholding */
+/* method to determine if the postscript bit is to be set. The thresholding */
+/* method is compabible with that used in emtex's drivers. */
+/* */
+/* Please send bug reports relating to the em:graph routines to: */
+/* maurice@bruce.cs.monash.edu.au */
+/* */
+/* My thanks to Russell Lang for his assistance with the implementation of */
+/* these routines in a manner compatible with dvips and for the optimization */
+/* of some routines. */
+/* */
+/* Maurice Castro */
+/* 8 Oct 92 */
+
+/* Routines to read binary numbers from IBM PC file types */
+static integer
+readinteger(FILE *f)
+{
+ integer i;
+ int r;
+
+ i = 0;
+ for (r = 0; r < 4; r++)
+ {
+ i = i | ( ((integer) fgetc(f)) << (8*r) );
+ }
+ return(i);
+}
+
+static halfword
+readhalfword(FILE *f)
+{
+ halfword i;
+ int r;
+
+ i = 0;
+ for (r = 0; r < 2; r++)
+ {
+ i = i | ( ((halfword) fgetc(f)) << (8*r) );
+ }
+ return(i);
+}
+
+#define readquarterword(f) ((unsigned char)fgetc(f))
+#define tobyte(x) ((x/8) + (x%8 ? 1 : 0))
+
+/* These routines will decode PCX files produced by Microsoft
+ * Windows Paint. Other programs may not produce files which
+ * will be successfully decoded, most notably version 1.xx of
+ * PC Paint. */
+
+/*
+ * Type declarations. integer must be a 32-bit signed; shalfword must
+ * be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
+ * quarterword must be an eight-bit unsigned.
+ */
+typedef struct
+{
+ quarterword man;
+ quarterword ver;
+ quarterword enc;
+ quarterword bitperpix;
+ halfword xmin;
+ halfword ymin;
+ halfword xmax;
+ halfword ymax;
+ halfword hres;
+ halfword vres;
+ quarterword pal[48];
+ quarterword reserved;
+ quarterword colorplanes;
+ halfword byteperline;
+ halfword paltype;
+ quarterword fill[58];
+} PCXHEAD;
+
+static int
+PCXreadhead(FILE *pcxf, PCXHEAD *pcxh)
+{
+ pcxh->man = readquarterword(pcxf);
+ pcxh->ver = readquarterword(pcxf);
+ pcxh->enc = readquarterword(pcxf);
+ pcxh->bitperpix = readquarterword(pcxf);
+ pcxh->xmin = readhalfword(pcxf);
+ pcxh->ymin = readhalfword(pcxf);
+ pcxh->xmax = readhalfword(pcxf);
+ pcxh->ymax = readhalfword(pcxf);
+ pcxh->hres = readhalfword(pcxf);
+ pcxh->vres = readhalfword(pcxf);
+ fread(pcxh->pal, 1, 48, pcxf);
+ pcxh->reserved = readquarterword(pcxf);
+ pcxh->colorplanes = readquarterword(pcxf);
+ pcxh->byteperline = readhalfword(pcxf);
+ pcxh->paltype = readhalfword(pcxf);
+ fread(pcxh->fill, 1, 58, pcxf);
+
+ if (feof(pcxf))
+ return(0); /* fail */
+ if (pcxh->man != 0x0a)
+ return(0); /* fail */
+ if (pcxh->enc != 0x1)
+ return(0); /* fail */
+ return(1); /* success */
+ }
+
+static int
+PCXreadline(FILE *pcxf,
+ unsigned char *pcxbuf,
+ unsigned int byteperline)
+{
+ int n;
+ int c;
+ int i;
+
+ n = 0;
+ memset(pcxbuf,0,byteperline);
+ do {
+ c = fgetc(pcxf);
+ if ((c & 0xc0) == 0xc0) {
+ i = c & 0x3f;
+ c = fgetc(pcxf) & 0xff;
+ while ((i--) && (n < byteperline)) pcxbuf[n++] = c;
+ }
+ else {
+ pcxbuf[n++] = c & 0xff;
+ }
+ } while (n < byteperline);
+ if (c==EOF) n=0;
+ return(n);
+}
+
+static void
+PCXgetpalette(FILE *pcxf, PCXHEAD *pcxh,
+ unsigned char *r,
+ unsigned char *g,
+ unsigned char *b)
+{
+ int i;
+
+ /* clear palette */
+ for (i=0; i < 256; i++) {
+ r[i] = 0;
+ g[i] = 0;
+ b[i] = 0;
+ }
+
+ switch (pcxh->ver) {
+ case 0:
+ /* version 2.5 of PC Paint Brush */
+ for (i=0; i < 16; i++) {
+ r[i] = pcxh->pal[i*3];
+ g[i] = pcxh->pal[i*3+1];
+ b[i] = pcxh->pal[i*3+2];
+ }
+ break;
+ case 2:
+ if (pcxh->colorplanes != 1) {
+ /* version 2.8 of PC Paint Brush with valid Palette */
+ for (i=0; i < 16; i++) {
+ r[i] = pcxh->pal[i*3];
+ g[i] = pcxh->pal[i*3+1];
+ b[i] = pcxh->pal[i*3+2];
+ }
+ }
+ else { /* not sure if this is correct - rjl */
+ /* mono palette */
+ r[0] = 0x00; g[0] = 0x00; b[0] = 0x00;
+ r[1] = 0xff; g[1] = 0xff; b[1] = 0xff;
+ }
+ break;
+ case 3:
+ /* version 2.8 of PC Paint Brush with no valid Palette */
+ /* either mono or default */
+
+ if (pcxh->colorplanes != 1) {
+ /* Color default palette - should be checked */
+ r[0] = 0x00; g[0] = 0x00; b[0] = 0x00;
+ r[1] = 0x80; g[1] = 0x00; b[1] = 0x00;
+ r[2] = 0x00; g[2] = 0x80; b[2] = 0x00;
+ r[3] = 0x80; g[3] = 0x80; b[3] = 0x00;
+ r[4] = 0x00; g[4] = 0x00; b[4] = 0x80;
+ r[5] = 0x80; g[5] = 0x00; b[5] = 0x80;
+ r[6] = 0x00; g[6] = 0x80; b[6] = 0x80;
+ r[7] = 0x80; g[7] = 0x80; b[7] = 0x80;
+ r[8] = 0xc0; g[8] = 0xc0; b[8] = 0xc0;
+ r[9] = 0xff; g[9] = 0x00; b[9] = 0x00;
+ r[10] = 0x00; g[10] = 0xff; b[10] = 0x00;
+ r[11] = 0xff; g[11] = 0xff; b[11] = 0x00;
+ r[12] = 0x00; g[12] = 0x00; b[12] = 0xff;
+ r[13] = 0xff; g[13] = 0x00; b[13] = 0xff;
+ r[14] = 0x00; g[14] = 0xff; b[14] = 0xff;
+ r[15] = 0xff; g[15] = 0xff; b[15] = 0xff;
+ }
+ else {
+ /* mono palette */
+ r[0] = 0x00; g[0] = 0x00; b[0] = 0x00;
+ r[1] = 0xff; g[1] = 0xff; b[1] = 0xff;
+ }
+ break;
+ case 5:
+ default:
+ /* version 3.0 of PC Paint Brush or Better */
+ fseek(pcxf, -769L, SEEK_END);
+ /* if signature byte is correct then read the palette */
+ /* otherwise copy the existing palette */
+ if (fgetc(pcxf) == 12) {
+ for (i=0; i < 256; i++) {
+ r[i] = fgetc(pcxf);
+ g[i] = fgetc(pcxf);
+ b[i] = fgetc(pcxf);
+ }
+ }
+ else {
+ for (i=0; i < 16; i++) {
+ r[i] = pcxh->pal[i*3];
+ g[i] = pcxh->pal[i*3+1];
+ b[i] = pcxh->pal[i*3+2];
+ }
+ }
+ break;
+ }
+}
+
+static void
+PCXshowpicture(FILE *pcxf, int wide, int high, int bytes,
+ int cp, int bp, unsigned char *r,
+ unsigned char *g, unsigned char *b)
+{
+ int x;
+ int y;
+ int c;
+ unsigned char *rowa[4]; /* row array */
+ unsigned char *row;
+ int p;
+ unsigned char *pshexa;
+ int xdiv, xmod, xbit;
+ int width;
+ int bytewidth;
+
+ bytewidth = tobyte(wide);
+ width = bytewidth * 8;
+
+ /* output the postscript image size preamble */
+ cmdout("/picstr ");
+ numout((integer)tobyte(wide));
+ cmdout("string def");
+
+ numout((integer)width);
+ numout((integer)high);
+ numout((integer)1);
+ newline();
+
+ cmdout("[");
+ numout((integer)width);
+ numout((integer)0);
+ numout((integer)0);
+ numout((integer)-high);
+ numout((integer)0);
+ numout((integer)0);
+ cmdout("]");
+
+ nlcmdout("{currentfile picstr readhexstring pop} image");
+
+ /* allocate the postscript hex output array */
+ pshexa = (unsigned char *) mymalloc((integer)bytewidth);
+
+ /* make sure that you start at the right point in the file */
+ fseek(pcxf, (long) sizeof(PCXHEAD), SEEK_SET);
+
+ /* malloc the lines */
+ row = (unsigned char *) mymalloc((integer)bytes * cp);
+ for (c = 0; c < cp; c++)
+ rowa[c] = row + bytes*c;
+
+ for (y = 0; y < high; y++) {
+ /* clear the postscript hex array */
+ memset(pshexa,0xff,bytewidth);
+
+ /* read in all the color planes for a row of pixels */
+ PCXreadline(pcxf, rowa[0], bytes*cp);
+
+ /* process each pixel */
+ for (x = 0; x < wide; x++) {
+ /* build up the pixel value from color plane entries */
+ p = 0;
+ xdiv = x>>3;
+ xmod = 7 - (x&7);
+ xbit = 1 << xmod;
+ switch(bp) {
+ case 1:
+ for (c = 0; c < cp; c++) {
+ row = rowa[c];
+ p |= ( (unsigned)(row[xdiv] & xbit) >> xmod ) << c;
+ }
+ break;
+ case 4: /* untested - most programs use 1 bit/pixel, 4 planes */
+ row = rowa[0]; /* assume single plane */
+ p = ( x & 1 ? row[xdiv] : row[xdiv]>>4 ) & 0x0f;
+ break;
+ case 8:
+ row = rowa[0]; /* assume single plane */
+ p = (unsigned) (row[x]);
+ break;
+ default:
+ fprintf(stderr, "em:graph: Unable to Decode this PCX file\n");
+ return;
+ }
+ if ((r[p] < 0xff) || (g[p] < 0xff) || (b[p] < 0xff))
+ pshexa[xdiv] &= (~xbit);
+ else
+ pshexa[xdiv] |= xbit;
+ }
+ newline();
+ mhexout(pshexa,(long)bytewidth);
+ }
+ free(pshexa);
+ free(rowa[0]);
+}
+
+static void
+imagehead(char *filename, int wide, int high,
+ float emwidth, float emheight)
+{
+ char *fullname = NULL, *name;
+ if (!quiet) {
+#ifdef KPATHSEA
+ fullname = (char *)kpse_find_file (filename, pictpath, 0);
+#endif
+ if (!fullname)
+ name = filename;
+ else
+ name = fullname;
+ if (strlen(name) + prettycolumn > STDOUTSIZE) {
+ fprintf(stderr,"\n");
+ prettycolumn = 0;
+ }
+ fprintf_str(stderr,"<%s",name);
+ fflush(stderr);
+ prettycolumn += 2+strlen(name);
+ if (fullname) free (fullname);
+ }
+ hvpos();
+ nlcmdout("@beginspecial @setspecial");
+ if (!disablecomments) {
+ cmdout("%%BeginDocument: em:graph");
+ cmdout(filename);
+ newline();
+ }
+ /* set the image size */
+ if (emwidth <= 0.0) emwidth = (float)wide;
+ if (emheight <= 0.0) emheight = (float)high;
+ floatout(emwidth*72/actualdpi);
+ floatout(emheight*72/vactualdpi);
+ newline();
+ cmdout("scale");
+#ifdef DEBUG
+ if (dd(D_SPECIAL)) {
+ fprintf(stderr,
+ "\nem:graph: %s width %d pixels scaled to %.1f pixels\n",
+ filename, wide, emwidth);
+ fprintf_str(stderr,
+ "em:graph: %s height %d pixels scaled to %.1f pixels\n",
+ filename, high, emheight);
+ }
+#endif
+}
+
+static void
+imagetail(void)
+{
+ if (!disablecomments) {
+ fprintf(bitfile, "\n%%%%EndDocument\n");
+ linepos = 0;
+ }
+ nlcmdout("@endspecial");
+ if (!quiet) {
+ fprintf(stderr,">");
+ fflush(stderr);
+ }
+}
+
+static void
+pcxgraph(FILE *pcxf, char *filename,
+ float emwidth, float emheight /* dimension in pixels */ )
+{
+ PCXHEAD pcxh;
+ unsigned char red[256];
+ unsigned char green[256];
+ unsigned char blue[256];
+ int wide;
+ int high;
+ int bytes;
+ int cp;
+ int bpp;
+
+ if (!PCXreadhead(pcxf, &pcxh)) {
+ sprintf(errbuf,"em:graph: Unable to Read Valid PCX Header");
+ specerror(errbuf);
+ }
+ PCXgetpalette(pcxf, &pcxh, red, green, blue);
+
+ /* picture size calculation */
+ wide = (pcxh.xmax - pcxh.xmin) + 1;
+ high = (pcxh.ymax - pcxh.ymin) + 1;
+ bytes = pcxh.byteperline;
+ cp = pcxh.colorplanes;
+ bpp = pcxh.bitperpix;
+
+ imagehead(filename,wide,high,emwidth,emheight);
+ PCXshowpicture(pcxf, wide, high, bytes, cp, bpp, red, green, blue);
+ imagetail();
+}
+
+/* Microsoft Paint routines */
+struct wpnt_1 {
+ quarterword id[4];
+ halfword width;
+ halfword high;
+ halfword x_asp;
+ halfword y_asp;
+ halfword x_asp_prn;
+ halfword y_asp_prn;
+ halfword width_prn;
+ halfword high_prn;
+ integer chk_sum;
+ halfword chk_head;
+};
+
+#define WPAINT_1 1
+#define WPAINT_2 2
+
+static void
+MSP_2_ps(FILE *f, int wide, int high)
+{
+ char *line;
+ char *l;
+ int i;
+ int j;
+ unsigned char a, b, c;
+ int d;
+ int width;
+ halfword *linelen;
+
+ /* an undocumented format - based on a type of run length encoding */
+ /* the format is made up of a list of line lengths, followed by a set */
+ /* of lines. Each line is made up of 2 types of entries: */
+ /* 1) A 3 term entry (0 a b): the byte b is repeated a times */
+ /* 2) A variable length entry (a xxxx....xxxx): a bytes are read */
+ /* from the file. */
+ /* These entries are combined to build up a line */
+
+ width = tobyte(wide)*8;
+
+ /* output the postscript image size preamble */
+ cmdout("/picstr");
+ numout((integer)tobyte(wide));
+ cmdout("string def");
+
+ numout((integer)width);
+ numout((integer)high);
+ numout((integer)1);
+
+ cmdout("[");
+ numout((integer)width);
+ numout((integer)0);
+ numout((integer)0);
+ numout((integer)-high);
+ numout((integer)0);
+ numout((integer)0);
+ cmdout("]");
+
+ nlcmdout("{currentfile picstr readhexstring pop} image");
+
+ fseek(f, 32, SEEK_SET);
+
+ /* read in the table of line lengths */
+ linelen = (halfword *) mymalloc((integer)sizeof(halfword) * high);
+ for (i = 0; i < high; i++) {
+ linelen[i] = readhalfword(f);
+ if (feof(f))
+ return;
+ }
+
+ line = (char *) mymalloc((integer)tobyte(wide));
+ for (i = 0; i < high; i++) {
+ memset(line, 0xff, tobyte(wide));
+ l = line;
+ if (linelen[i] != 0) {
+ d = linelen[i];
+ while (d) {
+ a = fgetc(f);
+ d--;
+ if (a == 0) {
+ b = fgetc(f);
+ c = fgetc(f);
+ d -= 2;
+ for (j = 0; j < b; j++)
+ *l++ = c;
+ }
+ else {
+ for (j = 0; j < a; j++)
+ *l++ = fgetc(f);
+ d -= j;
+ }
+ }
+ }
+ newline();
+ mhexout((unsigned char *) line,(long)tobyte(wide));
+ }
+ free(linelen);
+ free(line);
+}
+
+static void
+MSP_1_ps(FILE *f, int wide, int high)
+{
+ char *line;
+ int i;
+ int width;
+
+ width = tobyte(wide)*8;
+ /* an partly documented format - see The PC Sourcebook */
+ /* the format is made up of a simple bitmap. */
+
+ /* output the postscript image size preamble */
+ cmdout("/picstr");
+ numout((integer)tobyte(wide));
+ cmdout("string def");
+
+ numout((integer)width);
+ numout((integer)high);
+ numout((integer)1);
+
+ cmdout("[");
+ numout((integer)width);
+ numout((integer)0);
+ numout((integer)0);
+ numout((integer)-high);
+ numout((integer)0);
+ numout((integer)0);
+ cmdout("]");
+
+ nlcmdout("{currentfile picstr readhexstring pop} image");
+
+ fseek(f, 32, SEEK_SET);
+
+ line = (char *) mymalloc((integer)tobyte(wide));
+ for (i = 0; i < high; i++) {
+ fread(line, 1, tobyte(wide), f);
+ newline();
+ mhexout((unsigned char *) line,(long)tobyte(wide));
+ }
+ free(line);
+}
+
+
+static void
+mspgraph(FILE *f, char *filename, float emwidth, float emheight)
+{
+ struct wpnt_1 head;
+ int paint_type = 0;
+
+ /* read the header of the file and figure out what it is */
+ fread(head.id, 1, 4, f);
+ head.width = readhalfword(f);
+ head.high = readhalfword(f);
+ head.x_asp = readhalfword(f);
+ head.y_asp = readhalfword(f);
+ head.x_asp_prn = readhalfword(f);
+ head.y_asp_prn = readhalfword(f);
+ head.width_prn = readhalfword(f);
+ head.high_prn = readhalfword(f);
+ head.chk_sum = readinteger(f);
+ head.chk_head = readhalfword(f);
+
+ if (feof(f)) {
+ fprintf(stderr, "em:graph: Unable to Read Valid MSP Header\n");
+ return;
+ }
+
+ /* check the id bytes */
+ if (!memcmp(head.id, "DanM", 4))
+ paint_type = WPAINT_1;
+ if (!memcmp(head.id, "LinS", 4))
+ paint_type = WPAINT_2;
+
+
+ imagehead(filename,head.width,head.high,emwidth,emheight);
+ switch (paint_type) {
+ case WPAINT_1:
+ MSP_1_ps(f, head.width, head.high);
+ break;
+ case WPAINT_2:
+ MSP_2_ps(f, head.width, head.high);
+ break;
+ default:
+ sprintf(errbuf, "em:graph: Unknown MSP File Type");
+ specerror(errbuf);
+ }
+ imagetail();
+}
+
+/* ------------------------------------------------------------------------ */
+/* .BMP file structures */
+struct rgbquad {
+ char blue;
+ char green;
+ char red;
+ char res;
+};
+
+struct bitmapinfoheader {
+ integer size;
+ integer width;
+ integer height;
+ halfword planes; /* must be set to 1 */
+ halfword bitcount; /* 1, 4, 8 or 24 */
+ integer compression;
+ integer sizeimage;
+ integer xpelspermeter;
+ integer ypelspermeter;
+ integer clrused;
+ integer clrimportant;
+};
+
+#ifdef WIN32
+#undef RGB
+#endif
+
+/* constants for the compression field */
+#define RGB 0L
+#define RLE8 1L
+#define RLE4 2L
+
+struct bitmapfileheader {
+ char type[2];
+ integer size;
+ halfword reserved1;
+ halfword reserved2;
+ integer offbits;
+};
+
+static void
+rgbread(FILE *f, int w, int b, char *s)
+{
+ int i;
+
+ /* set the line to white */
+ memset(s, 0xff, ((w*b)/8)+1);
+
+ /* read in all the full bytes */
+ for (i = 0; i < (w * b) / 8; i++)
+ *s++ = fgetc(f);
+
+ /* read in a partly filled byte */
+ if ((w * b) % 8) {
+ i++;
+ *s++ = fgetc(f);
+ }
+
+ /* check that we are on a 32 bit boundary; otherwise align */
+ while (i % 4 != 0) {
+ fgetc(f);
+ i++;
+ }
+}
+
+unsigned rle_dx = 0; /* delta command horizontal offset */
+unsigned rle_dy = 0; /* delta command vertical offset */
+
+/* checked against output from Borland Resource Workshop */
+static void
+rle4read(FILE *f, int w, int b, char *s)
+{
+ int i;
+ int limit;
+ int ch;
+ unsigned cnt;
+ int hi;
+
+ limit = (w*b)/8;
+ i = 0;
+ hi = TRUE;
+ /* set the line to white */
+ memset(s, 0xff, limit+1);
+
+ if (rle_dy) {
+ rle_dy--;
+ return;
+ }
+
+ if (rle_dx) {
+ for (; rle_dx>1; rle_dx-=2) {
+ s++;
+ i++;
+ }
+ if (rle_dx)
+ hi = FALSE;
+ }
+
+ while (i<=limit) {
+ cnt = fgetc(f);
+ ch = fgetc(f);
+ if (cnt == 0) { /* special operation */
+ switch(ch) {
+ case 0: /* EOL */
+ return; /* this is our way out */
+ case 1: /* End of Bitmap */
+ return;
+ case 2: /* Delta */ /* untested */
+ rle_dx = fgetc(f) + i*2 + (hi ? 1 : 0);
+ rle_dy = fgetc(f);
+ return;
+ default: /* next cnt bytes are absolute */
+ /* must be aligned on word boundary */
+ if (!hi)
+ fprintf(stderr,"em:graph: RLE4 absolute is not byte aligned\n");
+ for (cnt = ch; cnt>0 && i<=limit; cnt-=2) {
+ i++;
+ *s++ = fgetc(f);
+ }
+ if (ch % 4) /* word align file */
+ fgetc(f);
+ }
+ }
+ else { /* cnt is repeat count */
+ if (!hi) { /* we are about to place the low 4 bits */
+ ch = ((ch>>4)&0x0f) | ((ch<<4)&0xf0); /* swap order */
+ i++;
+ *s = (*s & 0xf0) | (ch & 0x0f);
+ s++;
+ hi = TRUE;
+ cnt--;
+ }
+ /* we are about to place the high 4 bits */
+ for (; cnt>1 && i<=limit; cnt-=2) { /* place the whole bytes */
+ i++;
+ *s++ = ch;
+ }
+ if (cnt) { /* place the partial byte */
+ *s = (*s & 0x0f) | (ch & 0xf0);
+ hi = FALSE;
+ }
+ }
+ }
+}
+
+/* untested */
+static void
+rle8read(FILE *f, int w, int b, char *s)
+{
+ int i;
+ int limit;
+ int ch;
+ unsigned cnt;
+
+ limit = (w*b)/8;
+ i = 0;
+ /* set the line to white */
+ memset(s, 0xff, limit+1);
+
+ if (rle_dy) {
+ rle_dy--;
+ return;
+ }
+
+ if (rle_dx) {
+ for (; rle_dx > 0; rle_dx--) {
+ s++;
+ i++;
+ }
+ }
+
+ while (i<=limit) {
+ cnt = fgetc(f);
+ ch = fgetc(f);
+ if (cnt == 0) { /* special operation */
+ switch(ch) {
+ case 0: /* EOL */
+ return; /* this is our way out */
+ case 1: /* End of Bitmap */
+ return;
+ case 2: /* Delta */ /* untested */
+ rle_dx = fgetc(f) + i;
+ rle_dy = fgetc(f);
+ return;
+ default: /* next cnt bytes are absolute */
+ for (cnt = ch; cnt>0 && i<=limit; cnt--) {
+ i++;
+ *s++ = fgetc(f);
+ }
+ if (ch % 2) /* word align file */
+ fgetc(f);
+ }
+ }
+ else { /* cnt is repeat count */
+ for (; cnt>0 && i<=limit; cnt--) {
+ i++;
+ *s++ = ch;
+ }
+ }
+ }
+}
+
+static void
+bmpgraph(FILE *f, char *filename, float emwidth, float emheight)
+{
+ struct bitmapfileheader bmfh;
+ struct bitmapinfoheader bmih;
+
+ #define ISBLACKSIZ 256
+ unsigned char isblack[ISBLACKSIZ];
+ unsigned char rr;
+ unsigned char gg;
+ unsigned char bb;
+ unsigned char c = 0;
+
+ char *line;
+ char *pshexa;
+
+ int clrtablesize;
+ int i;
+ int j;
+
+ unsigned char omask;
+ int oroll;
+
+ unsigned char emask = 0;
+ integer ewidth = 0;
+ int isOS2;
+
+ /* read the header of the file */
+ fread(bmfh.type, 1, 2, f);
+ bmfh.size = readinteger(f);
+ bmfh.reserved1 = readhalfword(f);
+ bmfh.reserved2 = readhalfword(f);
+ bmfh.offbits = readinteger(f);
+ if (feof(f)) {
+ sprintf(errbuf, "em:graph: Unable to Read Valid BMP Header\n");
+ specerror(errbuf);
+ return;
+ }
+
+ bmih.size = readinteger(f);
+ if (bmih.size == 12) { /* OS2 bitmap */
+ isOS2 = TRUE;
+ bmih.width = readhalfword(f);
+ bmih.height = readhalfword(f);
+ bmih.planes = readhalfword(f);
+ bmih.bitcount = readhalfword(f);
+ /* the following don't exist in OS2 format so fill with 0's */
+ bmih.compression = RGB;
+ bmih.sizeimage = 0;
+ bmih.xpelspermeter = 0;
+ bmih.ypelspermeter = 0;
+ bmih.clrused = 0;
+ bmih.clrimportant = 0;
+ }
+ else { /* Windows bitmap */
+ isOS2 = FALSE;
+ bmih.width = readinteger(f);
+ bmih.height = readinteger(f);
+ bmih.planes = readhalfword(f);
+ bmih.bitcount = readhalfword(f);
+ bmih.compression = readinteger(f);
+ bmih.sizeimage = readinteger(f);
+ bmih.xpelspermeter = readinteger(f);
+ bmih.ypelspermeter = readinteger(f);
+ bmih.clrused = readinteger(f);
+ bmih.clrimportant = readinteger(f);
+ }
+
+ if (feof(f)) {
+ sprintf(errbuf, "em:graph: Unable to Read Valid BMP Info");
+ specerror(errbuf);
+ return;
+ }
+
+ if (memcmp(bmfh.type, "BM", 2)) {
+ sprintf(errbuf, "em:graph: Unknown BMP File Type");
+ specerror(errbuf);
+ return;
+ }
+
+ if ((bmih.compression == RLE4) && (bmih.bitcount != 4)) {
+ sprintf(errbuf, "em:graph: Can't do BMP RLE4 with %d bits per pixel",
+ bmih.bitcount);
+ specerror(errbuf);
+ return;
+ }
+
+ if ((bmih.compression == RLE8) && (bmih.bitcount != 8)) {
+ sprintf(errbuf, "em:graph: Can't do BMP RLE8 with %d bits per pixel\n",
+ bmih.bitcount);
+ specerror(errbuf);
+ return;
+ }
+
+ imagehead(filename,(int)bmih.width,(int)bmih.height,emwidth,emheight);
+
+ /* determine the size of the color table to read */
+ clrtablesize = 0;
+ if (bmih.clrused == 0) {
+ switch (bmih.bitcount) {
+ case 1:
+ clrtablesize = 2;
+ break;
+ case 4:
+ clrtablesize = 16;
+ break;
+ case 8:
+ clrtablesize = 256;
+ break;
+ case 24:
+ break;
+ }
+ }
+ else
+ clrtablesize = bmih.clrused;
+
+ if (clrtablesize > ISBLACKSIZ) {
+ /* This is wrong, since we won't read the whole file below.
+ But we can't give correct output without more work,
+ and it's unlikely these specials are still in use. */
+ sprintf(errbuf,
+ "em color table size (%d) larger than %d; output incorrect",
+ clrtablesize, ISBLACKSIZ);
+ specerror(errbuf);
+ clrtablesize = ISBLACKSIZ;
+ }
+
+ /* read in the color table */
+ for (i = 0; i < clrtablesize; i++) {
+ bb = fgetc(f);
+ gg = fgetc(f);
+ rr = fgetc(f);
+ isblack[i] = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
+ if (!isOS2)
+ (void) fgetc(f);
+ }
+
+ line = (char *) mymalloc((integer)((bmih.width * bmih.bitcount) / 8) + 1);
+ pshexa = (char *) mymalloc((integer)tobyte(bmih.width));
+
+ /* output the postscript image size preamble */
+ cmdout("/picstr");
+ numout((integer)tobyte(bmih.width));
+ cmdout("string def");
+
+ numout((integer)bmih.width);
+ numout((integer)bmih.height);
+ numout((integer)1);
+
+ cmdout("[");
+ numout((integer)bmih.width);
+ numout((integer)0);
+ numout((integer)0);
+ numout((integer)bmih.height);
+ numout((integer)0);
+ numout((integer)bmih.height);
+ cmdout("]");
+
+ nlcmdout("{currentfile picstr readhexstring pop} image");
+
+ if (bmih.bitcount == 1) {
+ if (bmih.width%8)
+ emask = (1<<(8-(bmih.width%8)))-1; /* mask for edge of bitmap */
+ else
+ emask = 0;
+ ewidth = tobyte(bmih.width);
+ }
+
+ /* read in all the lines of the file */
+ for (i = 0; i < bmih.height; i++) {
+ memset(pshexa,0xff,tobyte(bmih.width));
+ switch (bmih.compression) {
+ case RGB:
+ rgbread(f, (int) bmih.width, (int) bmih.bitcount, line);
+ break;
+ case RLE4:
+ rle4read(f, (int) bmih.width, (int) bmih.bitcount, line);
+ break;
+ case RLE8:
+ rle8read(f, (int) bmih.width, (int) bmih.bitcount, line);
+ break;
+ default:
+ sprintf(errbuf,"em:graph: Unknown BMP compression\n");
+ specerror(errbuf);
+ return;
+ }
+
+ omask = 0x80;
+ oroll = 7;
+
+ if (bmih.bitcount == 1) {
+ if (isblack[0])
+ for (j = 0; j < ewidth; j++)
+ pshexa[j] = line[j];
+ else
+ for (j = 0; j < ewidth; j++)
+ pshexa[j] = ~line[j];
+ pshexa[ewidth-1] |= emask;
+ }
+ else {
+ for (j = 0; j < bmih.width; j++) {
+ switch (bmih.bitcount) {
+ case 4:
+ c = line[j>>1];
+ if (!(j&1))
+ c >>= 4;
+ c = isblack[ c & 0x0f ];
+ break;
+ case 8:
+ c = isblack[ (int)(line[j]) ];
+ break;
+ case 24:
+ rr = line[j*3];
+ gg = line[j*3+1];
+ bb = line[j*3+2];
+ c = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
+ break;
+ }
+ if (c)
+ pshexa[j/8] &= ~omask;
+ else
+ pshexa[j/8] |= omask;
+ oroll--;
+ omask >>= 1;
+ if (oroll < 0) {
+ omask = 0x80;
+ oroll = 7;
+ }
+ }
+ }
+ newline();
+ mhexout((unsigned char *) pshexa,(long)tobyte(bmih.width));
+ }
+ imagetail();
+ free(pshexa);
+ free(line);
+}
+/* ------------------------------------------------------------------------ */
+
+#define PCX 0
+#define MSP 1
+#define BMP 2
+const char *extarr[]=
+{ ".pcx", ".msp", ".bmp", NULL };
+
+static void
+emgraph(char *filename, float emwidth, float emheight)
+{
+ char fname[500];
+ int filetype;
+ FILE *f;
+ char *env;
+ char id[4];
+ int i;
+
+ strcpy(fname, filename);
+
+ /* find the file */
+ f = search(figpath, fname, READBIN);
+ if (f == (FILE *)NULL) {
+ if ( (env = getenv("DVIDRVGRAPH")) != NULL )
+#ifdef KPATHSEA
+ f = search((kpse_file_format_type)env,filename,READBIN);
+#else
+ f = search(env,filename,READBIN);
+#endif
+ }
+ /* if still haven't found it try adding extensions */
+ if (f == (FILE *)NULL) {
+ i = 0;
+ while (extarr[i] != NULL) {
+ strcpy(fname, filename);
+ strcat(fname, extarr[i]);
+ f = search(figpath, fname, READBIN);
+ if (f == (FILE *)NULL) {
+ if ( (env = getenv("DVIDRVGRAPH")) != NULL )
+#ifdef KPATHSEA
+ f = search((kpse_file_format_type)env,filename,READBIN);
+#else
+ f = search(env,filename,READBIN);
+#endif
+ }
+ if (f != (FILE *)NULL)
+ break;
+ i++;
+ }
+ }
+
+ filetype = -1;
+ if (f != (FILE *)NULL) {
+ for (i=0; i<4; i++) {
+ id[i] = readquarterword(f);
+ }
+ if ( (id[0] == 0x0a) && (id[2] == 0x01) )
+ filetype = PCX;
+ if (!memcmp(id, "DanM", 4))
+ filetype = MSP;
+ if (!memcmp(id, "LinS", 4))
+ filetype = MSP;
+ if (!memcmp(id, "BM", 2))
+ filetype = BMP;
+ fseek(f, 0L, SEEK_SET);
+ }
+
+ switch (filetype) {
+ case PCX:
+ pcxgraph(f, fname, emwidth, emheight);
+ break;
+ case MSP:
+ mspgraph(f, fname, emwidth, emheight);
+ break;
+ case BMP:
+ bmpgraph(f, fname, emwidth, emheight);
+ break;
+ default:
+ snprintf(fname, sizeof(fname),
+ "em:graph: %s: File not found", filename);
+ error(fname);
+ }
+ if (f != (FILE *)NULL)
+ close_file(f);
+}
+
+#else
+void
+emspecial(char *p)
+{
+ sprintf(errbuf,"emTeX specials not compiled in this version");
+ specerror(errbuf);
+}
+#endif /* EMTEX */