diff options
Diffstat (limited to 'Build/source/texk/dvipsk/emspecial.c')
-rw-r--r-- | Build/source/texk/dvipsk/emspecial.c | 1469 |
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 */ |