home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989 by Ken C.M. Lau.
- ** Permission to use, copy, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted.
- **
- ** Author : Ken Lau. June 89
- ** Purpose : Convert GIF file to IFF ham file
- ** Compiler : Aztec C 4.3a
- ** cc hamsharp.c
- ** cc hamsharp2.c
- ** cc hamsharp3.c
- ** cc hamsharp4.c
- ** ln hamsharp.o hamsharp2.o hamsharp3.o hamsharp4.o -lc -lm
- */
-
- #include <stdio.h>
-
- struct rgb {int r, g, b;};
- struct remapelement {int pal, dist;};
-
- long colorerr [256]; /* Histogram of errors */
- long imageerr = 0L; /* Total error */
- int colors; /* Colors in source */
- int pals; /* Number of palette colors currently defined */
- int planes; /* Planes in destination */
- int hamflag; /* Set if picture requires HAM */
- int picstep; /* Horizontal source pixels per dest pixel */
- int picwidth; /* Destination pixels per line */
- int scanstep = 2; /* Increase for faster processing */
- int hamonly = 0; /* Set to process skip processing non-HAM */
- int compression = -1; /* Set to 0 to switch off IFF compression */
- int filenote = 0; /* Set to -1 to note error */
- int edge = 1; /* Set to 0 for edge smoothing algorithm */
- int update = 0; /* Set to 1 for skip existing files */
- short iffbufsize = 16384; /* Default output file buffer size */
- struct rgb palette [32]; /* Destination palette */
- unsigned char **pic = NULL; /* Pointer to decompressed image in RAM */
- struct remapelement remap [256]; /* Closest palette color to given color */
- char gifname [80], iffname [80]; /* Source and destination files */
- FILE *gif, *iff;
- char *iffbuf = NULL; /* Pointer to output buffer */
-
- /* GIF header info */
- char signature [6];
- struct {
- unsigned width;
- unsigned height;
- unsigned char pixel;
- unsigned char background;
- unsigned char reserved;
- } screen;
- struct rgb cmap [256];
- struct {
- unsigned char seperator;
- unsigned left;
- unsigned top;
- unsigned width;
- unsigned height;
- unsigned char pixel;
- } image;
-
- /* Main. Source and destination filenames may be specified in command line */
- main(argc, argv)
- char *argv[];
- {
- int bestcolor;
-
- getargs(argc, argv); /* Set filenames */
- initvars(); /* Allocate and initialize tables and variables */
- while (getlist(gifname, iffname)) {
- printf("Converting %s-->%s\n", gifname, iffname);
- if (!readgif()) /* Decompress file into RAM pointed by pic */
- goto nextfile;
- palette [0] = cmap [0]; /* Background color is always assigned */
- if (hamflag) {
- if (edge) {
- for (pals = 1; pals < 16; pals++) {
- calcremap(); /* Calculate closest palette colors to remap to */
- scanpic(); /* Scan pic and set colorerr [] */
- bestcolor = findbest(); /* Pick a color to assign to palette */
- palette [pals] = cmap [bestcolor];
- printf("Palette %2d = colour %3d\x0D", pals, bestcolor);
- printf("\x1B[40CImageErr = %7ld\n\x1BM", imageerr);
- }
- printf("\x1B[80K");
- }
- else
- setpalette();
- }
- else {
- for (pals = 1; pals < colors; pals++)
- palette [pals] = cmap [pals];
- }
- calcremap();
- if (!writeiff()) /* Use palette [] and remap [] */
- goto nextfile;
- printf("\x1B[1F\x1B[40K"); /* Erase image size stats */
- printf("\x1BM\x1B[56C");
- printf("ImageErr=%ld\n", imageerr);
- nextfile:
- freepic(); /* Free memory if required */
- }
- freevars();
- }
-
- /* Allocate and initialize tables and variables */
- initvars()
- {
- char *calloc();
-
- /* Allocate memory for file buffers */
- iffbuf = calloc(iffbufsize, sizeof(char));
- if (iffbuf == NULL)
- fatalerr("Out of memory");
- initrgberr();
- }
-
- /* Free memory for lookup tables */
- freevars ()
- {
- if (iffbuf != NULL) {
- free (iffbuf);
- iffbuf = NULL;
- }
- freergberr ();
- }
-
- /* Print title page, get arguments from user if required */
- getargs (argc, argv)
- char *argv [];
- {
- int i;
-
- printf ("\n");
- printf (" HAMSHARP 1.5, GIF to IFF HAM converter, KL\n");
- printf (" ------------------------------------------\n");
- printf ("\n");
-
- initlist ();
- gifname[0] = iffname[0] = '\0';
- for (i = 1; i < argc; i++)
- if (argv[i][0] == '-') {
- switch (tolower (argv[i][1])) {
- case 's':
- sscanf (argv[i], "%*c%*c%d", &scanstep);
- break;
- case 'h':
- hamonly = -1;
- break;
- case 'c':
- compression = 0;
- break;
- case 'b':
- sscanf (argv [i], "%*c%*c%d", &iffbufsize);
- break;
- case 'f':
- filenote = -1;
- break;
- case 'd':
- edge = 0;
- break;
- case 'e':
- edge = -1;
- break;
- case 'u':
- update = -1;
- break;
- default:
- fatalerr ("Illegal option");
- break;
- }
- }
- else {
- if (gifname[0] == '\0') strcpy (gifname, argv[i]);
- else if (iffname [0] == '\0') strcpy (iffname, argv[i]);
- }
- printf ("Source GIF filespec? ");
- if (gifname [0] == '\0')
- scanf ("%s", gifname);
- else
- printf ("%s\n", gifname);
-
- printf ("Destn IFF filespec? ");
- if (iffname [0] == '\0')
- scanf ("%s", iffname);
- else
- printf ("%s\n", iffname);
-
- if (scanstep <= 0)
- fatalerr ("Scan step must be greater than 0");
-
- getwild (); /* Read filenames matching wildcard from disk */
- /* and add to list */
- printf ("\n");
- }
-
- /* Decompress GIF file into RAM. Return error status */
- readgif ()
- {
- if ((gif = fopen (gifname, "r")) == NULL) {
- printf ("GIF file not found\n");
- return (0);
- }
-
- if (!readheader ())
- return (0);
- if (hamonly && !hamflag) {
- fclose (gif);
- printf ("\x1BM\x1B[40K\x1BM\x1B[56C");
- printf ("Not HAM\n");
- return (0);
- }
- readpic ();
- fclose (gif);
- return (-1);
- }
-
- /* Print error message and halt */
- fatalerr (s)
- char *s;
- {
- printf (s);
- printf ("\n");
- freepic ();
- freelist ();
- freevars ();
- exit (20);
- }
-
- /* Read header. Return error status */
- readheader ()
- {
- int color;
-
- fread (signature, 1, 6, gif);
- if (strncmp (signature, "GIF87a", 6) != 0) {
- printf ("Not GIF file\n");
- return (0);
- }
-
- screen.width = readint ();
- screen.height = readint ();
- screen.pixel = getc (gif);
- screen.background = getc (gif);
- screen.reserved = getc (gif);
-
- colors = 1 << ((screen.pixel & 0x07) + 1);
- for (color = 0; color < colors; color++) {
- cmap [color].r = getc (gif) >> 4;
- cmap [color].g = getc (gif) >> 4;
- cmap [color].b = getc (gif) >> 4;
- }
-
- image.seperator = getc (gif);
- image.left = readint ();
- image.top = readint ();
- image.width = readint ();
- image.height = readint ();
- image.pixel = getc (gif);
-
- if (image.seperator != ',') {
- printf ("Missing seperator\n");
- return (0);
- }
- if ((image.pixel & 0x80) != 0) {
- printf ("Cannot handle local color map\n");
- return (0);
- }
- printf ("%ux%ux%u\n", image.width, image.height, colors);
-
- picstep = 1;
- picwidth = image.width;
- hamflag = (colors > 32) || ((colors > 16) && (image.width > 320));
- if (hamflag && (image.width > 320)) {
- picstep = 2;
- picwidth = image.width / picstep;
- }
- planes = hamflag ? 6 : (screen.pixel & 7) + 1;
- return (-1);
- }
-
- /* Read 16 bit quantity from GIF file, low byte first */
- readint ()
- {
- int temp;
-
- temp = getc (gif);
- temp |= getc (gif) << 8;
- return (temp);
- }
-
- unsigned char codesize; /* Used by readpic() and readcode() */
-
- /* Read from gif file and write to iff file */
- readpic()
- {
- int i;
- int code, maxcode, clearcode, eofcode, curcode, oldcode, incode;
- int freecode, firstfree;
- unsigned char initcodesize, finchar, bitmask, *outptr;
- static int prefix [4096];
- static unsigned char suffix [4096], outcode [1025];
-
- openadd ();
- openreadcode ();
-
- outptr = outcode;
- bitmask = (1 << ((screen.pixel & 7) + 1)) - 1;
-
- codesize = getc (gif);
- clearcode = (1 << codesize);
- eofcode = clearcode + 1;
- freecode = firstfree = clearcode + 2;
-
- codesize++;
- initcodesize = codesize;
- maxcode = (1 << codesize);
-
- code = readcode ();
- while (code != eofcode)
- {
- if (code == clearcode)
- {
- codesize = initcodesize;
- maxcode = (1 << codesize);
- freecode = firstfree;
- curcode = oldcode = code = readcode ();
- finchar = curcode;
- addpixel (finchar);
- }
- else
- {
- curcode = incode = code;
-
- if (curcode >= freecode)
- {
- curcode = oldcode;
- *outptr++ = finchar;
- }
-
- while (curcode > bitmask)
- {
- #ifdef CHECK
- if (outptr > outcode + 1024)
- fatalerr ("Corrupt GIF file");
- #endif
- *outptr++ = suffix [curcode];
- curcode = prefix [curcode];
- }
-
- finchar = curcode;
- addpixel (finchar);
-
- while (outptr != outcode)
- addpixel (*--outptr);
-
- prefix [freecode] = oldcode;
- suffix [freecode] = finchar;
- oldcode = incode;
-
- if (++freecode >= maxcode)
- {
- #ifdef CHECK
- if (codesize < 12)
- {
- #endif
- codesize ++;
- maxcode <<= 1;
- #ifdef CHECK
- }
- #endif
- }
- }
- code = readcode ();
- }
-
- if (getc (gif) != 0)
- printf ("Warning: unaligned packet\n");
-
- closereadcode ();
- closeadd ();
- }
-
- static unsigned char bitmask = 0x00;
- static int bytecount = 0;
-
- /* Prepare to call readcode */
- openreadcode ()
- {
- bytecount = bitmask = 0;
- }
-
- /* Fetch the next few bit from the source gif file */
- readcode ()
- {
- static unsigned dsttbl [13] =
- {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
- 0x0100, 0x0200, 0x0400, 0x0800, 0x1000 };
- static unsigned dstmasked = 0x0800;
- static unsigned dstmask = 0x0001;
- static int bytebuf = 0;
- static unsigned temp;
-
- temp = 0;
- dstmasked = dsttbl [codesize];
- for (dstmask = 0x0001; dstmask != dstmasked; dstmask <<= 1)
- {
- if (!bitmask)
- {
- bitmask = 0x01;
- if (bytecount == 0)
- bytecount = getc (gif);
- bytebuf = getc (gif);
- bytecount--;
- }
- if (bytebuf & bitmask)
- temp |= dstmask;
- bitmask <<= 1;
- }
- return (temp);
- }
-
- /* Finish reading code */
- closereadcode ()
- {
- }
-
- int xpic, ypic, xstate, leavepass;
- unsigned char *linestart;
-
- /* Prepare to add pixels to pic */
- openadd ()
- {
- char *calloc ();
- int y;
-
- xpic = ypic = xstate = leavepass = 0;
- if (image.pixel & 0x40)
- leavepass = 2; /* GIF interleaved */
- /* Allocate memory for the whole picture */
- pic = (unsigned char **) calloc (image.height, sizeof (unsigned char *));
- if (pic == NULL)
- fatalerr ("Out of memory");
- for (y = 0; y < image.height; y++) {
- pic [y] = (unsigned char *) calloc (picwidth, sizeof (unsigned char));
- if (pic [y] == NULL)
- fatalerr ("Out of memory");
- }
- linestart = pic [0];
- printf ("Decompressing line\n");
- }
-
- /* Add pixels to pic in RAM */
- addpixel (pix)
- {
- static step [8] = {1, 0, 8, 8, 4, 2, 0}; /* GIF interleaved consts */
- static first [8] = {0, 0, 0, 4, 2, 1, 0};
-
- if (!xstate) {
- xstate = picstep;
- *linestart++ = pix;
- }
- xstate--;
- xpic++;
- if (xpic >= image.width) {
- printf ("%3d\n\x1BM", ypic);
- xpic = 0;
- ypic += step [leavepass];
- if (ypic >= image.height)
- ypic = first [++leavepass];
- linestart = pic [ypic];
- }
- }
-
- /* Stop add pixels to RAM */
- closeadd ()
- {
- printf (" \x1B[1F\x1B[40K\n\x1BM");
- }
-
- /* Free memory for picture */
- freepic ()
- {
- int y;
-
- if (pic == NULL)
- return;
- for (y = 0; y < image.height; y++)
- free (pic [y]);
- free (pic);
- pic = NULL;
- }
-
- /* Calculate nearest palette color to given color */
- calcremap ()
- {
- int color, pal, minpal, mindistance, distance, r, g, b;
- int maxdistance = rgberr (0, 0, 0, 15, 15, 15);
- struct rgb *c, *p;
-
- for (color = 0; color < colors; color++) {
- r = (c = & cmap [color]) -> r;
- g = c->g;
- b = c->b;
- minpal = 0;
- mindistance = maxdistance;
- for (pal = 0; pal < pals; pal++) {
- p = & palette [pal];
- distance = rgberr (r, g, b, p->r, p->g, p->b);
- if (distance < mindistance) {
- mindistance = distance;
- minpal = pal;
- }
- }
- remap [color].pal = minpal;
- remap [color].dist = mindistance;
- }
- }
-
- /* Accumulate the error due to each color in the source image */
- scanpic ()
- {
- unsigned char *linestart, *lineend;
- int color, y, pix, select, gunerr, gunerr2, gunerr3;
- struct rgb gun, want;
- struct remapelement *remapp;
-
- for (color = 0; color < colors; color++)
- colorerr [color] = 0L;
- for (y = 0; y < image.height; y += scanstep) {
- gun = palette [0];
- lineend = (linestart = pic [y]) + picwidth;
- while (linestart != lineend) {
- pix = *linestart++;
- if (! (remapp = & remap [pix]) -> dist)
- gun = palette [remapp->pal];
- else {
- want = cmap [pix];
- gunerr = rgberr (want.r, gun.g, gun.b, want.r, want.g, want.b);
- gunerr2 = rgberr (gun.r, want.g, gun.b, want.r, want.g, want.b);
- gunerr3 = rgberr (gun.r, gun.g, want.b, want.r, want.g, want.b);
- select = 0;
- if (gunerr2 < gunerr) {
- gunerr = gunerr2;
- select = 1;
- }
- if (gunerr3 < gunerr) {
- gunerr = gunerr3;
- select = 2;
- }
- *(&gun.r + select) = *(&want.r + select);
-
- if (remapp->dist < gunerr) {
- gunerr = remapp->dist;
- gun = palette [remapp->pal];
- }
- colorerr [pix] += gunerr;
- }
- }
- }
- }
-
- /* Select colour to assign to palette given colorerr [] */
- findbest ()
- {
- int bestcolor = 0;
- long besterror = 0L;
- int color;
-
- imageerr = 0L; /* Estimated */
- for (color = 0; color < colors; color++) {
- if (colorerr [color] >= besterror) {
- besterror = colorerr [color];
- bestcolor = color;
- }
- imageerr += colorerr [color];
- }
- imageerr = (imageerr - besterror) * scanstep;
- return (bestcolor);
- }
-
- /* Write IFF file from image in RAM given pic and remap [] */
- /* Return error status */
- writeiff ()
- {
- static char noteline [120];
-
- if ((iff = fopen (iffname, "w")) == NULL) {
- printf ("Cannot write to IFF file\n");
- return (0);
- }
-
- /* Set up buffer for output */
- if (iff->_buff)
- fatalerr ("IFF buffer already allocated"); /* Should never occur */
- iff->_buff = iffbuf;
- iff->_buflen = iffbufsize;
-
- writeheader ();
- writepic (); /* with optional compression */
- fixupheader (); /* body and form lengths fixups */
- fclose (iff);
-
- sprintf (noteline, "Err=%ld", imageerr);
- if (filenote)
- SetComment (iffname, noteline);
- return (-1);
- }
-
- long formlenpsn, bodylenpsn;
-
- /* Write header to IFF file */
- writeheader ()
- {
- long ftell ();
- int pal;
-
- fputs ("FORM", iff); formlenpsn = ftell (iff); writelong (0L);
- fputs ("ILBM", iff);
-
- fputs ("BMHD", iff); writelong (20L);
- writeint (picwidth); writeint (image.height); /* w, h */
- writeint (image.left / picstep); /* x, y */
- writeint (image.top);
- putc (planes, iff); /* bitplanes */
- putc (0, iff); /* masking */
- putc (compression ? 1 : 0, iff); /* compression */
- putc (0, iff); /* pad1 */
- writeint (0); /* transparent color */
- putc (10, iff); putc (11, iff); /* xAspect, yAspect */
- writeint (screen.width / picstep); /* pagewidth, pageheight */
- writeint (screen.height);
-
- if (hamflag) {
- fputs ("CAMG", iff); writelong (4L);
- writelong (screen.height > 200 ? 0x4804L : 0x4800L);
- }
-
- fputs ("CMAP", iff); writelong ((long)(pals * 3));
- for (pal = 0; pal < pals; pal++) {
- putc (palette [pal].r << 4, iff);
- putc (palette [pal].g << 4, iff);
- putc (palette [pal].b << 4, iff);
- }
- fputs ("BODY", iff); bodylenpsn = ftell (iff); writelong (0L);
- }
-
- /* Write long integer to IFF file, high byte first */
- writelong (a)
- long a;
- {
- writeint ((unsigned) (a >> 16));
- writeint ((unsigned) a);
- }
-
- /* Write unsigned integer to IFF file, high byte first */
- writeint (a)
- unsigned a;
- {
- putc (a >> 8, iff);
- putc (a & 0xFF, iff);
- }
-
- /* Fixup IFF header */
- fixupheader ()
- {
- long ftell ();
- long bodylen = ftell (iff) - bodylenpsn - 4L;
- long formlen = ftell (iff) - formlenpsn - 4L;
-
- fseek (iff, bodylenpsn, 0); writelong (bodylen);
- fseek (iff, formlenpsn, 0); writelong (formlen);
- fseek (iff, 0L, 2);
- }
-
- /* Write out body of IFF file with optional compression */
- writepic ()
- {
- long ftell ();
- unsigned char *linestart, *lineend;
- int y, pix, select, gunerr, gunerr2, gunerr3, colmask, planemask;
- struct rgb gun, want;
- struct remapelement *remapp;
- int cols = (picwidth + 7) / 8;
- static char pl[6][256];
- static bitpsn, col, plane;
- static compbuf [128];
- static compbufi, compbufi1, compbufi2, state, disp, data;
- static hambit [3] = {0x20, 0x30, 0x10};
-
- imageerr = 0L;
- printf ("Writing line\n");
- for (y = 0; y < image.height; y++) {
- printf ("%3d\n\x1BM", y);
- col = 0;
- colmask = 0x80;
- gun = palette [0];
- lineend = (linestart = pic [y]) + picwidth;
- while (linestart != lineend) {
- pix = *linestart++;
- if (! (remapp = & remap [pix]) -> dist)
- gun = palette [data = remapp->pal];
- else {
- want = cmap [pix];
- gunerr = rgberr (want.r, gun.g, gun.b, want.r, want.g, want.b);
- gunerr2 = rgberr (gun.r, want.g, gun.b, want.r, want.g, want.b);
- gunerr3 = rgberr (gun.r, gun.g, want.b, want.r, want.g, want.b);
- select = 0;
- if (gunerr2 < gunerr) {
- gunerr = gunerr2;
- select = 1;
- }
- if (gunerr3 < gunerr) {
- gunerr = gunerr3;
- select = 2;
- }
- data = hambit [select]
- | (*(&gun.r + select) = *(&want.r + select));
- if (remapp->dist < gunerr) {
- gunerr = remapp->dist;
- gun = palette [data = remapp->pal];
- }
- imageerr += gunerr;
- }
- planemask = 0x01;
- for (plane = 0; plane < planes; plane++) {
- if (data & planemask)
- pl [plane][col] |= colmask;
- planemask <<= 1;
- }
- if (colmask == 0x01) {
- colmask = 0x80;
- col++;
- }
- else
- colmask >>= 1;
- }
-
- if (!compression) {
- for (plane = 0; plane < planes; plane++) {
- for (col = 0; col < cols; col++) {
- putc (pl [plane][col], iff);
- pl [plane][col] = 0;
- }
- if (ftell (iff) & 1L)
- putc (0, iff);
- }
- goto nextline;
- }
- for (plane = 0; plane < planes; plane ++) {
- compbufi = 0;
- state = 0;
- data = pl[plane][0];
- for (col = 1; col < cols; col ++)
- switch (state) {
- case 0:
- if (data == pl[plane][col]) {
- state = 1;
- compbuf [compbufi] = col - 2 - compbufi;
- compbufi = col - 1;
- }
- else
- data = pl[plane][col];
- break;
- case 1:
- if (data != pl[plane][col]) {
- state = 0;
- compbuf [compbufi] = compbufi - col + 1;
- compbufi = col;
- data = pl[plane][col];
- }
- break;
- }
- compbuf [compbufi] =
- (state==0) ? cols-compbufi-1 : compbufi-cols+1;
- state = 0;
- compbufi = 0;
- while (compbufi < cols) {
- disp = compbuf [compbufi];
- switch (state) {
- case 0:
- if (disp >= 0) {
- state = 1;
- compbufi1 = compbufi;
- }
- break;
- case 1:
- if (disp < 0) {
- state = 2;
- compbufi2 = compbufi;
- }
- else
- compbufi1 = compbufi;
- break;
- case 2:
- if (disp >= 0) {
- state = 1;
- if (compbuf [compbufi2] == -1) {
- compbuf [compbufi1] += 3 + disp;
- compbuf [compbufi2] = 0;
- compbuf [compbufi] = 0;
- }
- else
- compbufi1 = compbufi;
- }
- else
- state = 0;
- break;
- }
- compbufi += (disp >= 0) ? disp + 1 : -disp + 1;
- }
- compbufi = 0;
- while (compbufi < cols) {
- disp = compbuf [compbufi];
- putc (disp, iff);
- if (disp < 0) {
- putc (pl [plane][compbufi], iff);
- for (col = compbufi; col <= (compbufi - disp); col++)
- pl [plane][col] = 0;
- }
- else
- for (col = compbufi; col <= (compbufi + disp); col++) {
- putc (pl [plane][col], iff);
- pl [plane][col] = 0;
- }
- compbufi += (disp >= 0) ? disp + 1 : -disp + 1;
- }
- }
- nextline:;
- }
- if (ftell (iff) & 1L)
- putc (0, iff); /* Pad to word boundary */
- printf (" \x1B[1F\x1B[40K\n\x1BM");
- }
-
-