/********************************************* * GIFtoPS Converter * * * * May 16, 1988 by Scott Hemphill * * * * I wrote this program, and hereby place it * * in the public domain, i.e. there are no * * copying restrictions of any kind. * * * * Command line processing, EPSF support, * * and image positioning by Mic Kaczmarczik, * * modeled after James Frew's ``suntops'' * * * * All ints were assumed 32 bits, changed to * * work with 16 bit ints with mwc on Atari ST* * The routine below provides the getopt() * * routine unavailable with mwc. * * A GEM version for the Atari ST may be * * appearing soon in the Atari SIG. * * Mark Storkamp 3/24/90. * * * * Converted to compile under Turbo C 2.0 * * Changed "raster","fill", and "scanline" * * to HUGE pointers and compiled using * * "compact" memory model. Also stripped out * * the getopt() function (for troubleshooting* * purposes). Turbo C includes getopt() if * * you want it. Atof() were substituted for * * sscanf() in the command line parser (for * * getting imageheight and imagewidth values,* * I was unable to get atof to work with my * * compiler). * * Craig Moore 4/13/90 * *********************************************/ #include #include #include #include #define FALSE 0 #define TRUE 1 typedef int bool; typedef struct codestruct { struct codestruct *prefix; unsigned char first,suffix; } codetype; FILE *infile; unsigned int screenwidth; /* The dimensions of the screen */ unsigned int screenheight; /* (not those of the image) */ bool global; /* Is there a global color map? */ int globalbits; /* Number of bits of global colors */ unsigned char globalmap[256][3]; /* RGB values for global color map */ char colortable[256][3]; /* Hex intensity strings for an image */ char huge *raster; /* Decoded image data */ codetype codetable[4096]; /* LZW compression code data */ int datasize,codesize,codemask; /* Decoder working variables */ int clear,eoi; /* Special code values */ #define INCH 72.0 int EPSF = FALSE; /* should we generate EPSF? */ int screen = FALSE; /* use alternate halftone screen? */ int landscape = FALSE; /* display image in landscape mode? */ int copies = 1; /* number of copies to create */ double pagewidth; double pageheight; double imagewidth; double imageheight; void usage() { fprintf(stderr, "usage: giftops [-els] [-c{copies}] [-w{width}] [-h{height}] [file]\n"); exit(-1); } void fatal(s) char *s; { fprintf(stderr,"giftops: %s\n",s); exit(-1); } void checksignature() { char buf[6]; fread(buf,1,6,infile); if (strncmp(buf,"GIF",3)) fatal("file is not a GIF file"); if (strncmp(&buf[3],"87a",3)) fatal("unknown GIF version number"); } /* Get information which is global to all the images stored in the file */ void readscreen() { unsigned char buf[7]; fread(buf,1,7,infile); screenwidth = buf[0] + (buf[1] << 8); screenheight = buf[2] + (buf[3] << 8); global = buf[4] & 0x80; if (global) { globalbits = (buf[4] & 0x07) + 1; fread(globalmap,3,1<>= 8; colortable[i][0] = hextab[color >> 4]; colortable[i][1] = hextab[color & 15]; colortable[i][2] = '\0'; } } /* Write a postscript header to the standard output. * * imagewidth and imageheight always represent the width/height of the * bounding box in the standard PostScript coordinate system, even when * the image rotated 90 degrees. */ void writeheader(left,top,width,height) unsigned left,top,width,height; { double aspect, xorg, yorg; /* * using imagewidth and imageheight as maxima, figure out how * tall and wide the image will be on the PostScript page. */ aspect = ((double) width) / ((double) height); if (landscape) { if (aspect >= imageheight / imagewidth) imagewidth = imageheight / aspect; else imageheight = imagewidth * aspect; } else { if (aspect >= imagewidth / imageheight) imageheight = imagewidth / aspect; else imagewidth = imageheight * aspect; } /* * For simplicity's sake, EPSF files have origin (0, 0). */ if (EPSF) { xorg = yorg = 0.0; printf("%%!PS-Adobe-2.0 EPSF-1.2\n"); /* magic number */ } else { xorg = (pagewidth - imagewidth) / 2.0; yorg = (pageheight - imageheight) / 2.0; printf("%%!\n"); } printf("%%%%BoundingBox: %.3f %.3f %.3f %.3f\n", xorg, yorg, xorg + imagewidth, yorg + imageheight); printf("%%%%Creator: GIFtoPS\n"); printf("%%%%EndComments\n"); /* * setting # of copies doesn't make sense if creating EPSF file */ if (!EPSF) printf("/#copies %d def\n", copies); printf("gsave\n"); printf("/alternatehalftone %s def\n", screen ? "true" : "false"); printf("alternatehalftone {\n"); printf(" currentscreen\n"); printf(" /proc exch def /angle exch def /frequency exch def\n"); printf(" /angle 90 def /frequency 60 def\n"); printf(" frequency angle /proc load setscreen\n"); printf("} if\n"); printf("/picstr %d string def\n",width); printf("/screen {\n"); printf(" %d %d 8 [%d 0 0 -%d 0 %d]\n", width, height, width, height, height); printf(" {currentfile picstr readhexstring pop} image} def\n"); printf("%.3f %.3f translate\n", xorg, yorg); if (landscape) { printf("%.3f 0 translate 90 rotate %.3f %.3f scale\n", imagewidth, imageheight, imagewidth); } else { printf("%.3f %.3f scale\n", imagewidth, imageheight); } printf("screen\n"); } /* Output the bytes associated with a code to the raster array */ void outcode(p,fill) register codetype *p; register unsigned char (huge **fill); { if (p->prefix) outcode(p->prefix,fill); *(*fill)++ = p->suffix; } /* Process a compression code. "clear" resets the code table. Otherwise make a new code table entry, and output the bytes associated with the code. */ void process(code,fill) register code; unsigned char (huge **fill); { static avail,oldcode; register codetype *p; if (code == clear) { codesize = datasize + 1; codemask = (1 << codesize) - 1; avail = clear + 2; oldcode = -1; } else if (code < avail) { outcode(&codetable[code],fill); if (oldcode != -1) { p = &codetable[avail++]; p->prefix = &codetable[oldcode]; p->first = p->prefix->first; p->suffix = codetable[code].first; if ((avail & codemask) == 0 && avail < 4096) { codesize++; codemask += avail; } } oldcode = code; } else if (code == avail && oldcode != -1) { p = &codetable[avail++]; p->prefix = &codetable[oldcode]; p->first = p->prefix->first; p->suffix = p->first; outcode(p,fill); if ((avail & codemask) == 0 && avail < 4096) { codesize++; codemask += avail; } oldcode = code; } else { fatal("illegal code in raster data"); } } /* Decode a raster image */ void readraster(width,height) unsigned width,height; { unsigned char huge *fill = raster; unsigned char buf[255]; register bits=0; register unsigned count; register unsigned long datum=0L; register unsigned char *ch; register int code; datasize = getc(infile); clear = 1 << datasize; eoi = clear+1; codesize = datasize + 1; codemask = (1 << codesize) - 1; for (code = 0; code < clear; code++) { codetable[code].prefix = (codetype*)0; codetable[code].first = code; codetable[code].suffix = code; } for (count = getc(infile); count > 0; count = getc(infile)) { fread(buf,1,count,infile); for (ch=buf; count-- > 0; ch++) { datum += (long)*ch << bits; bits += 8; while (bits >= codesize) { code = datum & codemask; datum >>= codesize; bits -= codesize; if (code == eoi) goto exitloop; /* This kludge put in because some GIF files aren't standard */ process(code,&fill); } } } exitloop: if (fill != raster + (long)width*height) fatal("raster has the wrong size"); } /* Read a row out of the raster image and write it to the output file */ void rasterize(row,width) int row,width; { unsigned char (huge *scanline); register i; scanline = raster + (long)row*width; for (i = 0; i < width; i++) { if (i % 40 == 0) printf("\n"); /* break line every 80 chars */ fputs(colortable[*scanline++],stdout); } printf("\n"); } /* write image trailer to standard output */ void writetrailer() { printf("\n\ngrestore\n"); if (!EPSF) printf("showpage\n"); } /* Read image information (position, size, local color map, etc.) and convert to postscript. */ void readimage() { unsigned char buf[9]; unsigned left,top,width,height; unsigned long lwidth, lheight; bool local,interleaved; char localmap[256][3]; int localbits; int *interleavetable; register row; register i; fread(buf,1,9,infile); left = buf[0] + (buf[1] << 8); top = buf[2] + (buf[3] << 8); lwidth = width = buf[4] + (buf[5] << 8); lheight = height = buf[6] + (buf[7] << 8); local = buf[8] & 0x80; interleaved = buf[8] & 0x40; if (local) { localbits = (buf[8] & 0x7) + 1; fread(localmap,3,1< 2) strcpy(optarg, argv[posn]+2); switch (opt) { case 'c': if ((copies = atoi(optarg)) <= 0) fatal("#copies must be > 0"); break; case 'e': EPSF = TRUE; break; case 'l': landscape = TRUE; break; case 's': screen = TRUE; break; case 'w': sscanf(optarg,"%lf",&imagewidth); imagewidth *= INCH; if (imagewidth <= 0.0) fatal("negative image width"); break; case 'h': sscanf(optarg,"%lf",&imageheight); imageheight *= INCH; if (imageheight <= 0.0) fatal("negative image height"); break; default: usage(); break; } } strcpy(gifname, argv[posn]); infile = fopen(gifname,"rb"); if (infile == NULL) { perror("giftops"); exit(-1); } checksignature(); readscreen(); do { ch = getc(infile); switch (ch) { case '\0': break; /* this kludge for non-standard files */ case ',': readimage(); break; case ';': quit = TRUE; break; case '!': readextension(); break; default: fatal("illegal GIF block type"); break; } } while (!quit); }