Thread View: comp.sources.mac
1 messages
1 total messages
Started by Reed Rector
Sat, 13 May 1989 09:00
GIF Image Decompression
Author: Reed Rector
Date: Sat, 13 May 1989 09:00
Date: Sat, 13 May 1989 09:00
500 lines
17080 bytes
17080 bytes
[GIF Image Decompression]
As promised weeks ago, here is some 'C' source code that will read and
decompress a GIF image file. (This program converts it to a Sun Raster
image, but it is no great problem converting for use in other programs)
Any problems or questions, just let me know
-Reed
SXWRR@ALASKA (Bitnet)
SXWRR@acad3.fai.alaska.edu (internet)
---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#
# gif2ras.c
#
# This archive created: Fri May 12 20:22:24 1989
# By: Roger L. Long (bytebug@dhw68k.cts.com)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'gif2ras.c'" '(14611 characters)'
if test -f 'gif2ras.c'
then
echo shar: will not over-write existing file "'gif2ras.c'"
else
sed 's/^X//' << \SHAR_EOF > 'gif2ras.c'
X/*
X * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
X *
X * Copyright (c) 1988 by Patrick J. Naughton
X *
X * Author: Patrick J. Naughton
X * naughton@wind.sun.com
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation.
X *
X * This file is provided AS IS with no warranties of any kind. The author
X * shall have no liability with respect to the infringement of copyrights,
X * trade secrets or any patents by this file or any part thereof. In no
X * event will the author be liable for any lost revenue or profits or
X * other special, indirect and consequential damages.
X *
X * Comments and additions should be sent to the author:
X *
X * Patrick J. Naughton
X * Sun Microsystems, Inc.
X * 2550 Garcia Ave, MS 14-40
X * Mountain View, CA 94043
X * (415) 336-1080
X *
X * Revision History:
X * 28-Aug-88: Modified by Jef Poskanzer to output PBM instead of Sun raster.
X * 27-Jul-88: Updated to use libpixrect to fix 386i byteswapping problems.
X * 11-Apr-88: Converted to C and changed to write Sun rasterfiles.
X * 19-Jan-88: GIFSLOW.PAS posted to comp.graphics by Jim Briebel,
X * a Turbo Pascal 4.0 program to painfully slowly display
X * GIF images on an EGA equipped IBM-PC.
X *
X * Description:
X * This program takes a Compuserve "Graphics Interchange Format" or "GIF"
X * file as input and writes a file known as a Sun rasterfile. This datafile
X * can be loaded by the NeWS "readcanvas" operator and is of the same format
X * as the files in /usr/NeWS/smi/*. Under X11R2 there is a program called
X * xraster to display these files.
X *
X * Portability:
X * To make this program convert to some image format other than PBM
X * format simply seach for the tag "PBMS:" in the source and
X * replace these simple mechanisms with the appropriate ones for the
X * other output format. I have marked all (six) PBM Specific pieces
X * of code with this comment.
X *
X * SS: compile with "cc -o gif2ras -O gif2ras.c -lpixrect"
X * PBMS: compile with "cc -o giftopbm -O giftopbm.c libpbm.a
X */
X
X#include <stdio.h>
X#ifdef notdefSS
X#include <pixrect/pixrect_hs.h> /* SS: main Pixrect header file */
X#endif notdefSS
X#include <sys/types.h>
X#include "pbm.h" /* PBMS: main PBM header file */
X
Xtypedef int boolean;
X#define True (1)
X#define False (0)
X
X#define NEXTSHORT (*ptr++ + (0x100 * *ptr++))
X#define NEXTBYTE (*ptr++)
X#define IMAGESEP 0x2c
X#define INTERLACEMASK 0x40
X#define COLORMAPMASK 0x80
X
Xint BitOffset = 0, /* Bit Offset of next code */
X XC = 0, YC = 0, /* Output X and Y coords of current pixel */
X Pass = 0, /* Used by output routine if interlaced pic */
X OutCount = 0, /* Decompressor output 'stack count' */
X RWidth, RHeight, /* screen dimensions */
X Width, Height, /* image dimensions */
X LeftOfs, TopOfs, /* image offset */
X BitsPerPixel, /* Bits per pixel, read from GIF header */
X ColorMapSize, /* number of colors */
X CodeSize, /* Code size, read from GIF header */
X InitCodeSize, /* Starting code size, used during Clear */
X Code, /* Value returned by ReadCode */
X MaxCode, /* limiting value for current code size */
X ClearCode, /* GIF clear code */
X EOFCode, /* GIF end-of-information code */
X CurCode, OldCode, InCode, /* Decompressor variables */
X FirstFree, /* First free code, generated per GIF spec */
X FreeCode, /* Decompressor, next free slot in hash table */
X FinChar, /* Decompressor variable */
X BitMask, /* AND mask for data size */
X ReadMask; /* Code AND mask for current code size */
X
Xboolean Interlace, HasColormap;
X
X#ifdef notdefSS
X/* SS: defined in pixrect/pixrect_hs.h */
XPixrect *Output; /* The Sun Pixrect */
Xcolormap_t Colormap; /* The Pixrect Colormap */
Xu_char *Image; /* The result array */
X#endif notdefSS
X/* PBMS: defined in pbm.h */
Xbit **bits; /* The PBM bit array */
X
Xu_char *RawGIF; /* The heap array to hold it, raw */
Xu_char *Raster; /* The raster data stream, unblocked */
X
X /* The hash table used by the decompressor */
Xint Prefix[4096];
Xint Suffix[4096];
X
X /* An output array used by the decompressor */
Xint OutCode[1025];
X
X /* The color map, read from the GIF header */
Xu_char Red[256], Green[256], Blue[256];
X
Xchar *id = "GIF87a";
X
Xchar *pname; /* program name (used for error messages) */
X
Xvoid
Xerror(s1, s2)
Xchar *s1, *s2;
X{
X fprintf(stderr, s1, pname, s2);
X exit(1);
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
XFILE *fp;
Xchar *infname = argv[1];
Xchar *outfname = argv[2];
Xint filesize;
Xregister u_char ch, ch1;
Xregister u_char *ptr, *ptr1;
Xregister int i;
X
X setbuf(stderr, NULL);
X pname = argv[0];
X
X if (argc < 3)
X error("usage: %s GIFfile rasterfile\n", NULL);
X
X if (!(fp = fopen(infname, "r")))
X error("%s: %s not found.\n", infname);
X
X /* find the size of the file */
X
X fseek(fp, 0L, 2);
X filesize = ftell(fp);
X fseek(fp, 0L, 0);
X
X if (!(ptr = RawGIF = (u_char *) malloc(filesize)))
X error("%s: not enough memory to read gif file.\n", NULL);
X
X if (!(Raster = (u_char *) malloc(filesize)))
X error("%s: not enough memory to read gif file.\n", NULL);
X
X fread(ptr, filesize, 1, fp);
X
X if (strncmp(ptr, id, 6))
X error("%s: %s is not a GIF file.\n", infname);
X ptr += 6;
X
X/* Get variables from the GIF screen descriptor */
X
X RWidth = NEXTSHORT; /* screen dimensions... not used. */
X RHeight = NEXTSHORT;
X
X ch = NEXTBYTE;
X HasColormap = ((ch & COLORMAPMASK) ? True : False);
X
X BitsPerPixel = (ch & 7) + 1;
X ColorMapSize = 1 << BitsPerPixel;
X BitMask = ColorMapSize - 1;
X
X ch = NEXTBYTE; /* background color... not used. */
X
X if (NEXTBYTE) /* supposed to be NULL */
X error("%s: %s is a corrupt GIF file.\n", infname);
X
X/* Read in global colormap. */
X
X if (HasColormap) {
X fprintf(stderr, "%s is %d bits per pixel, (%d colors).\n",
X infname, BitsPerPixel, ColorMapSize);
X for (i = 0; i < ColorMapSize; i++) {
X Red[i] = NEXTBYTE;
X Green[i] = NEXTBYTE;
X Blue[i] = NEXTBYTE;
X }
X
X#ifdef notdefSS
X/* SS: Fill in the Pixrect colormap struct */
X Colormap.type = RMT_EQUAL_RGB;
X Colormap.length = ColorMapSize;
X Colormap.map[0] = Red;
X Colormap.map[1] = Green;
X Colormap.map[2] = Blue;
X#endif notdefSS
X /* PBMS: PBM only handles bitmaps. Reject any pixmaps here. */
X if (BitsPerPixel != 1)
X error("%s: %s has more than one bit per pixel - it's not a bitmap.\n
X", infname);
X }
X else error("%s: %s does not have a colormap.\n", infname);
X
X
X/* Check for image seperator */
X
X if (NEXTBYTE != IMAGESEP)
X error("%s: %s is a corrupt GIF file.\n", infname);
X
X/* Now read in values from the image descriptor */
X
X LeftOfs = NEXTSHORT;
X TopOfs = NEXTSHORT;
X Width = NEXTSHORT;
X Height = NEXTSHORT;
X Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
X
X fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
X Width, Height, (Interlace) ? "" : "non-");
X
X
X/* Note that I ignore the possible existence of a local color map.
X * I'm told there aren't many files around that use them, and the spec
X * says it's defined for future use. This could lead to an error
X * reading some files.
X */
X
X/* Start reading the raster data. First we get the intial code size
X * and compute decompressor constant values, based on this code size.
X */
X
X CodeSize = NEXTBYTE;
X ClearCode = (1 << CodeSize);
X EOFCode = ClearCode + 1;
X FreeCode = FirstFree = ClearCode + 2;
X
X/* The GIF spec has it that the code size is the code size used to
X * compute the above values is the code size given in the file, but the
X * code size used in compression/decompression is the code size given in
X * the file plus one. (thus the ++).
X */
X
X CodeSize++;
X InitCodeSize = CodeSize;
X MaxCode = (1 << CodeSize);
X ReadMask = MaxCode - 1;
X
X/* Read the raster data. Here we just transpose it from the GIF array
X * to the Raster array, turning it from a series of blocks into one long
X * data stream, which makes life much easier for ReadCode().
X */
X
X ptr1 = Raster;
X do {
X ch = ch1 = NEXTBYTE;
X while (ch--) *ptr1++ = NEXTBYTE;
X } while(ch1);
X
X free(RawGIF); /* We're done with the raw data now... */
X
X fprintf(stderr, "done.\n");
X fprintf(stderr, "Decompressing...");
X
X
X#ifdef notdefSS
X/* SS: Allocate the Sun Pixrect and make "Image" point to the image data. */
X Output = mem_create(Width, Height, 8);
X if (Output == (Pixrect *) NULL)
X error("%s: not enough memory for output data.\n", NULL);
X Image = (u_char *) mpr_d(Output)->md_image;
X#endif notdefSS
X/* PBMS: Allocate the PBM bit array. */
X bits = pbm_allocarray(Width, Height);
X
X
X/* Decompress the file, continuing until you see the GIF EOF code.
X * One obvious enhancement is to add checking for corrupt files here.
X */
X
X Code = ReadCode();
X while (Code != EOFCode) {
X
X/* Clear code sets everything back to its initial value, then reads the
X * immediately subsequent code as uncompressed data.
X */
X
X if (Code == ClearCode) {
X CodeSize = InitCodeSize;
X MaxCode = (1 << CodeSize);
X ReadMask = MaxCode - 1;
X FreeCode = FirstFree;
X CurCode = OldCode = Code = ReadCode();
X FinChar = CurCode & BitMask;
X AddToPixel(FinChar);
X }
X else {
X
X/* If not a clear code, then must be data: save same as CurCode and InCode */
X
X CurCode = InCode = Code;
X
X/* If greater or equal to FreeCode, not in the hash table yet;
X * repeat the last character decoded
X */
X
X if (CurCode >= FreeCode) {
X CurCode = OldCode;
X OutCode[OutCount++] = FinChar;
X }
X
X/* Unless this code is raw data, pursue the chain pointed to by CurCode
X * through the hash table to its end; each code in the chain puts its
X * associated output code on the output queue.
X */
X
X while (CurCode > BitMask) {
X OutCode[OutCount++] = Suffix[CurCode];
X CurCode = Prefix[CurCode];
X }
X
X/* The last code in the chain is treated as raw data. */
X
X FinChar = CurCode & BitMask;
X OutCode[OutCount++] = FinChar;
X
X/* Now we put the data out to the Output routine.
X * It's been stacked LIFO, so deal with it that way...
X */
X
X for (i = OutCount - 1; i >= 0; i--)
X AddToPixel(OutCode[i]);
X OutCount = 0;
X
X/* Build the hash table on-the-fly. No table is stored in the file. */
X
X Prefix[FreeCode] = OldCode;
X Suffix[FreeCode] = FinChar;
X OldCode = InCode;
X
X/* Point to the next slot in the table. If we exceed the current
X * MaxCode value, increment the code size unless it's already 12. If it
X * is, do nothing: the next code decompressed better be CLEAR
X */
X
X FreeCode++;
X if (FreeCode >= MaxCode) {
X if (CodeSize < 12) {
X CodeSize++;
X MaxCode *= 2;
X ReadMask = (1 << CodeSize) - 1;
X }
X }
X }
X Code = ReadCode();
X }
X
X free(Raster);
X
X fprintf(stderr, "done.\n");
X
X if (!(fp = fopen(outfname, "w")))
X error("%s: can't create %s.\n", outfname);
X
X#ifdef notdefSS
X/* SS: Pixrect Rasterfile output code. */
X fprintf(stderr, "Writing Sun Rasterfile: %s...", outfname);
X if (pr_dump(Output, fp, &Colormap, RT_STANDARD, 0) == PIX_ERR)
X error("%s: error writing Sun Rasterfile: %s\n", outfname);
X#endif notdefSS
X/* PBMS: PBM output code. */
X pbm_writepbm(stdout, bits, Width, Height);
X
X fclose(fp);
X
X fprintf(stderr, "done.\n");
X}
X
X
X/* Fetch the next code from the raster data stream. The codes can be
X * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
X * maintain our location in the Raster array as a BIT Offset. We compute
X * the byte Offset into the raster array by dividing this by 8, pick up
X * three bytes, compute the bit Offset into our 24-bit chunk, shift to
X * bring the desired code to the bottom, then mask it off and return it.
X */
XReadCode()
X{
Xint RawCode, ByteOffset;
X
X ByteOffset = BitOffset / 8;
X RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
X if (CodeSize >= 8)
X RawCode += (0x10000 * Raster[ByteOffset + 2]);
X RawCode >>= (BitOffset % 8);
X BitOffset += CodeSize;
X return(RawCode & ReadMask);
X}
X
X
XAddToPixel(Index)
Xu_char Index;
X{
X#ifdef notdefSS
X *(Image + YC * Width + XC) = Index;
X#endif notdefSS
X/* PBMS: Store a pixel. */
X bits[YC][XC] = Index;
X
X/* Update the X-coordinate, and if it overflows, update the Y-coordinate */
X
X if (++XC == Width) {
X
X/* If a non-interlaced picture, just increment YC to the next scan line.
X * If it's interlaced, deal with the interlace as described in the GIF
X * spec. Put the decoded scan line out to the screen if we haven't gone
X * past the bottom of it
X */
X
X XC = 0;
X if (!Interlace) YC++;
X else {
X switch (Pass) {
X case 0:
X YC += 8;
X if (YC >= Height) {
X Pass++;
X YC = 4;
X }
X break;
X case 1:
X YC += 8;
X if (YC >= Height) {
X Pass++;
X YC = 2;
X }
X break;
X case 2:
X YC += 4;
X if (YC >= Height) {
X Pass++;
X YC = 1;
X }
X break;
X case 3:
X YC += 2;
X break;
X default:
X break;
X }
X }
X }
X}
SHAR_EOF
if test 14611 -ne "`wc -c < 'gif2ras.c'`"
then
echo shar: error transmitting "'gif2ras.c'" '(should have been 14611 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
---
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads