Logo Search packages:      
Sourcecode: texfam version File versions  Download package

emspecial.c

/*
 *   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>
/*
 *   These are the external routines called:
 */
#include "protos.h"

extern char errbuf[] ;
extern shalfword linepos;
extern FILE *bitfile;
extern int actualdpi ;
extern int vactualdpi ;
extern integer hh, vv;
#ifndef KPATHSEA
extern char *figpath ;
#endif
extern int prettycolumn ;
extern int quiet;
extern Boolean disablecomments ;

#ifdef DEBUG
extern integer debug_flag;
#endif


#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 {
   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}
};


/* clear the empoints array if necessary */
void
emclear P1H(void)
{
   int i;
   if (emused && empoints)
      for (i=0; i<emmax; i++)
         empoints[i] = 0 ;
   emused = FALSE ;
}

/* put an empoint into the empoints array */
struct empt *emptput P3C(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 */
struct empt *emptget P1C(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 */
float emunits P2C(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 P1C(char *, p)
{
float emwidth, emheight;
shalfword empoint1, empoint2;
struct empt *empoint;
char emunit[3];
char emstr[80];
char *emp;
#ifndef KPATHSEA
void emgraph();
#endif

        hvpos() ;
      for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
      if (strncmp(emp, "linewidth", 9) == 0) {
         /* code for linewidth */
         for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
         sscanf(emp, "%f%2s", &emwidth, emunit);
         emwidth = emunits(emwidth,emunit);
         if (emwidth!=-1.0) {
            sprintf(emstr,"%.1f setlinewidth", emwidth);
            cmdout(emstr);
#ifdef DEBUG
   if (dd(D_SPECIAL))
      (void)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
      (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
#else
      (void)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
      (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
#else
      (void)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(*emp); emp++); /* skip blanks */
           empoint1 = (shalfword)atoi(emp);
           empoint = emptput(empoint1,hh,vv);
#ifdef DEBUG
   if (dd(D_SPECIAL))
#ifdef SHORTINT
      (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
#else
      (void)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(*emp); emp++); /* skip blanks */
           empoint1 = (shalfword)atoi(emp);
         for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
         if ( *emp && strchr("hvp",*emp)!=0 )
            emp++;  /* skip line cut */
         for (; *emp && isspace(*emp); emp++); /* skip blanks */
         if ( *emp && (*emp==',') )
            emp++; /*  skip comma separator */
         for (; *emp && isspace(*emp); emp++); /* skip blanks */
           empoint2 = (shalfword)atoi(emp);
         for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
         if ( *emp && strchr("hvp",*emp)!=0 )
            emp++;  /* skip line cut */
         for (; *emp && isspace(*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))
      (void)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))
   (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n", 
            emwidth) ;
#endif
            strcpy(emstr,"currentlinewidth");
            cmdout(emstr);
              sprintf(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) {
           (void)fprintf(stderr, "em message: %s\n", emp+7) ;
      }
      else if (strncmp(emp, "graph", 5) == 0) {
         int i;
         for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
         for (i=0; *emp && !isspace(*emp) && !(*emp==',') ; emp++)
            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(*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(*emp)||isalpha(*emp)); emp++)
               ; /* skip width dimension */
            for (; *emp && ( isspace(*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 {
              (void)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 */
integer readinteger P1C(FILE *, f)
{
   integer i;
   int r;

   i = 0;
   for (r = 0; r < 4; r++)
   {
      i = i |  ( ((integer) fgetc(f)) << (8*r) );
   }
   return(i);
}

halfword readhalfword P1C(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; 

int PCXreadhead P2C(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 */
      }

int PCXreadline P3C(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);
}

void PCXgetpalette P5C( 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;
      }
}

void PCXshowpicture P9C(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]);
}

void imagehead P5C(char *, filename, int, wide, int, high, 
               float, emwidth, float, emheight)
{
      if (!quiet) {
          if (strlen(filename) + prettycolumn > STDOUTSIZE) {
            fprintf(stderr,"\n");
            prettycolumn = 0;
          }
          (void)fprintf(stderr,"<%s",filename);
          (void)fflush(stderr);
          prettycolumn += 2+strlen(filename);
      }
      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)) {
        (void)fprintf(stderr, 
          "\nem:graph: %s width  %d pixels scaled to %.1f pixels\n",
          filename, wide, emwidth);
        (void)fprintf(stderr, 
          "em:graph: %s height %d pixels scaled to %.1f pixels\n",
          filename, high, emheight);
      }
#endif
}

void imagetail P1H(void)
{
      if (!disablecomments) {
          (void)fprintf(bitfile, "\n%%%%EndDocument\n") ;
          linepos = 0;
      }
      nlcmdout("@endspecial") ;
      if (!quiet) {
          (void)fprintf(stderr,">");
          (void)fflush(stderr);
      }
}

void pcxgraph P4C(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

void MSP_2_ps P3C(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(line,(long)tobyte(wide));
      }
      free(linelen);
      free(line);
}

void MSP_1_ps P3C(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(line,(long)tobyte(wide));
      }
      free(line);
}


void mspgraph P4C(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;
};

void rgbread P4C(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 */
void rle4read P4C(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 */
                      (void)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);
                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 */
void rle8read P4C(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 */
                      (void)fgetc(f);
            }
          }
          else { /* cnt is repeat count */
            for ( ; cnt>0 && i<=limit; cnt--) {
                i++;
                *s++ = ch;
            }
          }
      }
}

void bmpgraph P4C(FILE *, f, char *, filename, float, emwidth, float, emheight)
{
      struct bitmapfileheader bmfh;
      struct bitmapinfoheader bmih;

      unsigned char isblack[256];
      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;

      /* 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(pshexa,(long)tobyte(bmih.width));
      }
      imagetail() ;
      free(pshexa);
      free(line);
}
/* ------------------------------------------------------------------------ */

#define PCX 0
#define MSP 1
#define BMP 2
char *extarr[]=
{ ".pcx", ".msp", ".bmp", NULL };

void emgraph P3C(char *, filename, float, emwidth, float, emheight)
{
      char fname[80];
      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:
                  sprintf(fname,"em:graph: %s: File not found", filename);
                  error(fname);
      }
      if (f != (FILE *)NULL)
          close_file(f);
}

#else
void emspecial P1C(char *, p)
{
      sprintf(errbuf,"emTeX specials not compiled in this version");
      specerror(errbuf);
}
#endif /* EMTEX */

Generated by  Doxygen 1.6.0   Back to index