Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!hellgate.utah.edu!cs.utah.edu!thomson From: thomson@cs.utah.edu (Rich Thomson) Newsgroups: comp.graphics Subject: gif2rle.shar (was Re: GIF encoders, decoders, and viewers source) Summary: GIF to Utah Raster Toolkit RLE format converter Keywords: source, Utah Raster Toolkit Message-ID: <1989Sep19.191351.6540@hellgate.utah.edu> Date: 20 Sep 89 01:13:51 GMT References: <12677@s.ms.uky.edu> <610002@hpcll21.HP.COM> Distribution: usa Organization: Oasis Technologies Lines: 592 For those of you that have the Utah Raster Toolkit, here's a little format converter I hacked up from xgif. It could be alot smarter, but it's only a hack. -- Rich -=-=-=-=-=-=--==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- : Run this shell script with "sh" not "csh" PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH export PATH all=false if [ x$1 = x-a ]; then all=true fi echo Extracting Makefile sed 's/^X//' <<'//go.sysin dd *' >Makefile X# You must edit the CFLAGS and LIBS macros to tell the compiler where to X# find the Raster Toolkit include files and library. XOBJS = gifload.o gif2rle.o X XCFLAGS = -g -I/u/alpha1/urt/include XLIBS = /u/alpha1/urt/lib/librle.a X Xgif2rle: $(OBJS) X $(CC) -o gif2rle $(OBJS) $(LIBS) X X$(OBJS): gif2rle.h X Xclean: X rm -rf $(OBJS) gif2rle //go.sysin dd * if [ `wc -c < Makefile` != 328 ]; then made=false echo error transmitting Makefile -- echo length should be 328, not `wc -c < Makefile` else made=true fi if $made; then chmod 644 Makefile echo -n ' '; ls -ld Makefile fi echo Extracting gif2rle.c sed 's/^X//' <<'//go.sysin dd *' >gif2rle.c X/* X * gif.c - displays GIF pictures on an X11 display X * X * Author: John Bradley, University of Pennsylvania X * (bradley@cis.upenn.edu) X */ X X#define MAIN X#include "gif2rle.h" X#include "svfb_global.h" X X X/*******************************************/ Xmain(argc, argv) X int argc; X char *argv[]; X/*******************************************/ X{ X int i; X char *fname; X X cmd = argv[0]; X fname = NULL; X X if (argc > 2) X Syntax(); X else if (argc == 2) X fname = argv[1]; X else X fname = "-"; X X /****************** Open/Read the File *****************/ X LoadGIF(fname); X X DumpRLE(); X} X X#define GET_INDEX(x,y) *(Image + (y)*BytesPerScanline + (x)) X XDumpRLE() X { X rle_pixel *rows[3]; X int i, x, y; X byte *ptr; X X sv_globals.svfb_fd = stdout; X sv_globals.sv_xmin = 0; X sv_globals.sv_ymin = 0; X sv_globals.sv_xmax = Width-1; X sv_globals.sv_ymax = Height-1; X sv_globals.sv_ncolors = 3; X sv_globals.sv_alpha = 0; X sv_setup(RUN_DISPATCH, &sv_globals); X X for (i = 0; i < 3; i++) X if ((rows[i] = (rle_pixel *) malloc(Width*sizeof(rle_pixel))) == NULL) X FatalError("couldn't allocate RLE row!"); X X for (y = 0; y < Height; y++) X { X for (x = 0; x < Width; x++) X { X i = (int) GET_INDEX(x, (Height-1)-y); X rows[0][x] = (rle_pixel) Red[i]; X rows[1][x] = (rle_pixel) Green[i]; X rows[2][x] = (rle_pixel) Blue[i]; X } X X sv_putrow(rows, Width, &sv_globals); X } X X sv_puteof(&sv_globals); X } X X/***********************************/ XSyntax() X{ X printf("Usage: %s [filename]\n",cmd); X exit(1); X} X X X/***********************************/ XFatalError (identifier) X char *identifier; X{ X fprintf(stderr, "%s: %s\n",cmd, identifier); X exit(-1); X} //go.sysin dd * if [ `wc -c < gif2rle.c` != 1777 ]; then made=false echo error transmitting gif2rle.c -- echo length should be 1777, not `wc -c < gif2rle.c` else made=true fi if $made; then chmod 644 gif2rle.c echo -n ' '; ls -ld gif2rle.c fi echo Extracting gif2rle.h sed 's/^X//' <<'//go.sysin dd *' >gif2rle.h X/* X * xgif.h - header file for xgif, but you probably already knew as much X */ X X X#define REVDATE "Rev: 2/13/89" X#define MAXEXPAND 16 X X/* include files */ X#include X#include X#include X X#ifndef MAIN X#define WHERE extern X#else X#define WHERE X#endif X X#define False 0 X#define True 1 X Xtypedef unsigned char byte; X X#define CENTERX(f,x,str) ((x)-XTextWidth(f,str,strlen(str))/2) X#define CENTERY(f,y) ((y)-((f->ascent+f->descent)/2)+f->ascent) X X X/* global vars */ Xextern int Width, Height, BytesPerScanline; Xextern byte *Image; Xextern byte Red[], Green[], Blue[]; XWHERE char *cmd; //go.sysin dd * if [ `wc -c < gif2rle.h` != 612 ]; then made=false echo error transmitting gif2rle.h -- echo length should be 612, not `wc -c < gif2rle.h` else made=true fi if $made; then chmod 644 gif2rle.h echo -n ' '; ls -ld gif2rle.h fi echo Extracting gifload.c sed 's/^X//' <<'//go.sysin dd *' >gifload.c X/* X * gifload.c is based strongly on... X * X * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image. X * X * Copyright (c) 1988, 1989 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 */ X X#include "gif2rle.h" X Xtypedef int boolean; X X#define NEXTBYTE (*ptr++) X#define IMAGESEP 0x2c X#define INTERLACEMASK 0x40 X#define COLORMAPMASK 0x80 X XFILE *fp; 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 BytesPerScanline, /* bytes per scanline in output raster */ X ColorMapSize, /* number of colors */ X Background, /* background color */ 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 Xbyte *Image; /* The result array */ Xbyte *RawGIF; /* The heap array to hold it, raw */ Xbyte *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 */ Xbyte Red[256], Green[256], Blue[256], used[256]; Xint numused; X Xchar *id = "GIF87a"; X X X X/*****************************/ XLoadGIF(fname) X char *fname; X/*****************************/ X{ X int filesize; X register byte ch, ch1; X register byte *ptr, *ptr1; X register int i; X X if (strcmp(fname,"-")==0) { fp = stdin; fname = ""; } X else fp = fopen(fname,"r"); X X if (!fp) FatalError("file not found"); X X /* find the size of the file */ X fseek(fp, 0L, 2); X filesize = ftell(fp); X fseek(fp, 0L, 0); X X if (!(ptr = RawGIF = (byte *) malloc(filesize))) X FatalError("not enough memory to read gif file"); X X if (!(Raster = (byte *) malloc(filesize))) X FatalError("not enough memory to read gif file"); X X if (fread(ptr, filesize, 1, fp) != 1) X FatalError("GIF data read failed"); X X if (strncmp(ptr, id, 6)) X FatalError("not a GIF file"); X X ptr += 6; X X/* Get variables from the GIF screen descriptor */ X X ch = NEXTBYTE; X RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */ X ch = NEXTBYTE; X RHeight = ch + 0x100 * NEXTBYTE; X 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 Background = NEXTBYTE; /* background color... not used. */ X X if (NEXTBYTE) /* supposed to be NULL */ X FatalError("corrupt GIF file (bad screen descriptor)"); X X X/* Read in global colormap. */ X X if (HasColormap) X { X for (i = 0; i < ColorMapSize; i++) X { X Red[i] = NEXTBYTE; X Green[i] = NEXTBYTE; X Blue[i] = NEXTBYTE; X used[i] = 0; X } X X numused = 0; X } X X/* Check for image seperator */ X X if (NEXTBYTE != IMAGESEP) X FatalError("corrupt GIF file (no image separator)"); X X/* Now read in values from the image descriptor */ X X ch = NEXTBYTE; X LeftOfs = ch + 0x100 * NEXTBYTE; X ch = NEXTBYTE; X TopOfs = ch + 0x100 * NEXTBYTE; X ch = NEXTBYTE; X Width = ch + 0x100 * NEXTBYTE; X ch = NEXTBYTE; X Height = ch + 0x100 * NEXTBYTE; X Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False); 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 if ((Raster - ptr1) > filesize) X FatalError("corrupt GIF file (unblock)"); X } while(ch1); X X free(RawGIF); /* We're done with the raw data now... */ X X X /* Allocate the Image */ X Image = (byte *) malloc(Width*Height); X if (!Image) FatalError("not enough memory for Image"); X X BytesPerScanline = Width; 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 if (OutCount > 1024) { X FatalError("Corrupt GIF file (OutCount)!"); X } 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 if (fp != stdin) X fclose(fp); 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) Xbyte Index; X{ 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} //go.sysin dd * if [ `wc -c < gifload.c` != 10222 ]; then made=false echo error transmitting gifload.c -- echo length should be 10222, not `wc -c < gifload.c` else made=true fi if $made; then chmod 644 gifload.c echo -n ' '; ls -ld gifload.c fi Rich Thomson thomson@cs.utah.edu {bellcore,hplabs,uunet}!utah-cs!thomson "Tyranny, like hell, is not easily conquered; yet we have this consolation with us, that the harder the conflict, the more glorious the triumph. What we obtain too cheap, we esteem too lightly." Thomas Paine, _The Crisis_, Dec. 23rd, 1776