koblas@mips.COM (David Koblas) (01/16/89)
Since this is probably of general interest to more than one or two people, I'm posting this. For a description of what RLE is and what the Utah Raster Toolkit is I'll point you at a previous posting with included the BLURB.UTAH file. If you find any bugs or have any great ideas on how to improve this I'd be greatly interested...etc, and so forth. One word of warning, many GIF images that I've found do not fully conform to the GIF standard. They are lacking a NULL byte at the end if the compressed data stream. -- name : David Koblas uucp : {ames,decwrl}!mips!koblas place: MIPS Computers Systems domain: koblas@mips.com quote: I haven't lost my mind -- it's backed up on tape somewhere. ------CUT------HERE---------CUT------HERE----------CUT------HERE------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: giftorle.1 giftorle.c Makefile # Wrapped by koblas@giant on Sun Jan 15 23:22:19 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'giftorle.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'giftorle.1'\" else echo shar: Extracting \"'giftorle.1'\" \(833 characters\) sed "s/^X//" >'giftorle.1' <<'END_OF_FILE' X.\" Copyright (c) 1989, David Koblas X.TH GIFTORLE 1 X.UC 4 X.SH NAME giftorle \- Convert GIF images to RLE format X.SH SYNOPSIS X.B giftorle X[ X.B \-o X.I outfile X] X[ X.B \-c X] X[ X.I infile X] X.SH DESCRIPTION X.I Giftorle converts a file from Graphics Interchange Format (GIF) format into RLE format. Images converted with X.I giftorle will need to be fliped with X.IR rleflip -v for correct presentation. If no input file is specified, the data is read from stdin. The following options are available: X.TP X.B -c Preserve the colormap that the GIF image contains, otherwise the colormap is applied to input image. X.TP X.B -o Use X.I outputfile as output instead of X.I stdout. X X.LP X.SH MISC GIF and Graphics Interchange Format are both trademarks of CompuServe Incorporated. X X.SH AUTHOR David Koblas (koblas@mips.com or koblas@cs.uoregon.edu) END_OF_FILE if test 833 -ne `wc -c <'giftorle.1'`; then echo shar: \"'giftorle.1'\" unpacked with wrong size! fi # end of 'giftorle.1' fi if test -f 'giftorle.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'giftorle.c'\" else echo shar: Extracting \"'giftorle.c'\" \(12206 characters\) sed "s/^X//" >'giftorle.c' <<'END_OF_FILE' X/* +------------------------------------------------------------------+ */ X/* | Copyright 1989, David Koblas. | */ X/* | You may copy this file in whole or in part as long as you | */ X/* | don't try to make money off it, or pretend that you wrote it. | */ X/* +------------------------------------------------------------------+ */ X X#include <stdio.h> X#include <sys/file.h> X#include "svfb_global.h" X X#ifndef lint static char *rcsid = "$Header: giftorle.c,v 1.4 89/01/15 22:23:08 koblas Exp $"; X#endif X X#define MAXCOLORMAPSIZE 256 X X#define TRUE 1 X#define FALSE 0 X X#define CM_RED 0 X#define CM_GREEN 1 X#define CM_BLUE 2 X X#define MAX_LWZ_BITS 12 X X#define ReadOK(file,buffer,len) (fread(buffer,len,1,file)!=0) X#define EasyFail(str,status) while(1){fprintf(stderr,str);return(status);} X#define HardFail(str,status) while(1){fprintf(stderr,str);exit (status);} X X#define LM_to_uint(a,b) (((b)<<8)|(a)) X X#define MY_NAME "giftorle" X struct { X unsigned int Width; X unsigned int Height; X unsigned char ColorMap[3][MAXCOLORMAPSIZE]; X unsigned int BitPixel; X unsigned int ColorResolution; X unsigned int Background; X} Screen; X static int output_colormap = FALSE; X main(argc,argv) int argc; char **argv; X{ X int c; X extern int optind; X extern char *optarg; X X while ((c=getopt(argc,argv,"co:"))!=EOF) { X switch (c) { X case 'c': X output_colormap = TRUE; X break; X case 'o': X if (freopen(optarg,"w",stdout)==NULL) { X fprintf(stderr,"Unable to open %s for output\n",optarg); X exit(1); X } X break; X default : X fprintf(stderr,"Usage: %s [-o filename] [file]\n",MY_NAME); X exit(1); X } X } X X if (argc < (optind-1)) { X fprintf(stderr,"Usage: %s [-o filename] [file]\n",MY_NAME); X exit(1); X } X X if (argc == optind) X ReadGIF(NULL); X X while (optind!=argc) { X ReadGIF(argv[optind]); X optind++; X } X} X ReadGIF(filename) char *filename; X{ X unsigned char buf[16]; X unsigned char c; X unsigned char LocalColorMap[3][MAXCOLORMAPSIZE]; X FILE *fd; X int use_global_colormap; X int bit_pixel; X int count=0; X X if (filename==NULL) X fd=stdin ; X else X if ((fd=fopen(filename,"r"))==NULL) { X fprintf(stderr,"Couldn't open file %s for input\n",filename); X return ; X } X X if (! ReadOK(fd,buf,6)) X EasyFail("error reading magic number\n",TRUE); X if (strncmp(buf,"GIF87a",6)!=0) X EasyFail("bad magic number (version mismatch?)\n",TRUE); X if (! ReadOK(fd,buf,7)) X EasyFail("error reading screen descriptor\n",TRUE); X Screen.Width = LM_to_uint(buf[0],buf[1]); X Screen.Height = LM_to_uint(buf[2],buf[3]); X Screen.BitPixel = 2<<(buf[4]&0x07); X Screen.ColorResolution = (((buf[4]&0x70)>>3)+1); X Screen.Background = buf[5]; X if ((buf[4]&0x80)==0x80) { X if (ReadColorMap(fd,Screen.BitPixel,Screen.ColorMap)) X return (TRUE); X } X X while (1) { X if (! ReadOK(fd,&c,1)) X EasyFail("No image data -- EOF\n",TRUE); X if (c == ';') X return FALSE; X if (c == '!') { X if (! ReadOK(fd,&c,1)) X EasyFail("No extention function code -- EOF\n",TRUE); X if (IgnoreExtention(fd)) X return(TRUE); X } X if (c != ',') { X fprintf(stderr,"Bogus character ignoring '%c'\n",c); X continue; X } X if (count == 1) X HardFail("This file contains more than one image! FAILING\n",1); X count++; X X if (! ReadOK(fd,buf,9)) X EasyFail("Couldn't read left/top/width/height\n",TRUE); X if ((buf[8]&0x80)==0x80) X use_global_colormap = FALSE ; X else X use_global_colormap = TRUE ; X X bit_pixel = 1<<((buf[8]&0x07)+1); X X if (! use_global_colormap) { X if (ReadColorMap(fd,bit_pixel,LocalColorMap)) X return TRUE; X } X X if ((buf[8]&0x40)==0x40) { X if (ReadInterlaced(fd,LM_to_uint(buf[4],buf[5]), X LM_to_uint(buf[6],buf[7]), X use_global_colormap?Screen.ColorMap:LocalColorMap)) X return TRUE; X } else { X if (ReadRaster(fd,LM_to_uint(buf[4],buf[5]), X LM_to_uint(buf[6],buf[7]), X use_global_colormap?Screen.ColorMap:LocalColorMap)) X return TRUE; X } X } X} X ReadColorMap(fd,number,buffer) XFILE *fd; int number; unsigned char buffer[3][MAXCOLORMAPSIZE]; X{ X int i; X unsigned char rgb[3]; X X for (i=0;i<number;i++) { X if (! ReadOK(fd,rgb,sizeof(rgb))) X EasyFail("Bogus colormap\n",TRUE); X buffer[CM_RED][i] = rgb[0] ; X buffer[CM_GREEN][i] = rgb[1] ; X buffer[CM_BLUE][i] = rgb[2] ; X } X return FALSE; X} X IgnoreExtention(fd) XFILE *fd; X{ X static char buf[256]; X unsigned char c; X X while (1) { X if (! ReadOK(fd,&c,1)) X EasyFail("EOF in extention\n",TRUE); X if (c == 0) X return FALSE; X if (read(fd,buf,(int) c)!=(int) c) X EasyFail("EOF in extention\n",TRUE); X } X} X GetCode(fd, code_size, flag) XFILE *fd; int code_size; int flag; X{ X static unsigned char buf[280]; X static int curbit,lastbit,done,last_byte; X int i, j, k, ret; X unsigned char count; X X if (flag) { X curbit = 0; X lastbit = 0; X done = FALSE; X return 0; X } X X if ( (curbit+code_size) >= lastbit) { X if (done) { X if (curbit>=lastbit) X EasyFail("Ran off the end of my bits\n",-1); X } X buf[0] = buf[last_byte-2]; X buf[1] = buf[last_byte-1]; X if (! ReadOK(fd,&count,1)) { X EasyFail("Error in getting buffer size\n",-1); X } X if (count == 0) { X done = TRUE; X } else if (! ReadOK(fd,&buf[2],count)) X EasyFail("Error in getting buffer\n",-1); X last_byte = 2 + count; X curbit = (curbit - lastbit) + 16; X lastbit = (2+count)*8 ; X } X X ret = 0; X for( i = curbit, j = 0; j < code_size; i++, j++ ) X ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; X X curbit += code_size; X X return ret; X} X LWZReadByte(fd,flag,input_code_size) XFILE *fd; int flag; int input_code_size; X{ X static int fresh=FALSE; X int code,incode; X static int code_size,set_code_size; X static int max_code,max_code_size; X static int firstcode,oldcode; X static int clear_code,end_code; X static int table[2][(1<< MAX_LWZ_BITS)]; X static int stack[(1<<(MAX_LWZ_BITS))*2],*sp; X register int i; X X if (flag) { X set_code_size = input_code_size; X code_size = set_code_size+1; X clear_code = 1 << set_code_size ; X end_code = clear_code + 1; X max_code_size = 2*clear_code; X max_code = clear_code+2; X X GetCode(fd,NULL,NULL,NULL,TRUE); X X fresh=TRUE; X X for (i=0;i<clear_code;i++) { X table[0][i] = 0; X table[1][i] = i; X } X for (;i<(1<<MAX_LWZ_BITS);i++) X table[0][i] = table[1][0] = 0; X X sp=stack; X X return 0; X } else if (fresh) { X fresh = FALSE; X do { X firstcode=oldcode= X GetCode(fd, code_size, FALSE); X } while (firstcode == clear_code); X return firstcode; X } X X if (sp > stack) X return *--sp; X X while ((code=GetCode(fd,code_size,FALSE))>=0) { X if (code == clear_code) { X for (i=0;i<clear_code;i++) { X table[0][i] = 0; X table[1][i] = i; X } X for (;i<(1<<MAX_LWZ_BITS);i++) X table[0][i] = table[1][i] = 0; X code_size = set_code_size+1; X max_code_size = 2*clear_code; X max_code = clear_code+2; X sp=stack; X firstcode=oldcode= X GetCode(fd,code_size,FALSE); X return firstcode; X } else if (code == end_code) { X unsigned char count; X unsigned char junk; X X while (ReadOK(fd,&count,1) && (count!=0)) X while (count-->0 && ReadOK(fd,&junk,1)); X if (count!=0) X EasyFail("missing EOD in data stream (common occurance)\n",-3); X return -2; X } X X incode = code; X X if (code >= max_code) { X *sp++ = firstcode; X code = oldcode; X } X X while (code >= clear_code) { X *sp++ = table[1][code]; X if (code == table[0][code]) X EasyFail("Circular table entry BIG ERROR\n",-1); X code = table[0][code]; X } X X *sp++ = firstcode = table[1][code]; X X if ((code=max_code)<(1<<MAX_LWZ_BITS)) { X table[0][code] = oldcode; X table[1][code] = firstcode; X max_code++; X if ((max_code >= max_code_size) && X (max_code_size < (1<<MAX_LWZ_BITS))) { X max_code_size *= 2; X code_size++; X } X } X X oldcode = incode; X X if (sp > stack) X return *--sp; X } X return code; X} X ReadInterlaced(fd,len,height,cmap) XFILE *fd; int len,height; char cmap[3][MAXCOLORMAPSIZE]; X{ X unsigned char c; X int v; X int xpos=0; X rle_pixel **scanline[3]; X rle_pixel *ptr[3] ; X struct sv_globals global ; X int i,j; X int ypos=0,pass=0; X static rle_map out_map[3*(1<<8)]; X X X for (j=0;j<(output_colormap?1:3);j++) { X if ((scanline[j]=(rle_pixel **) X malloc(height*sizeof(rle_pixel *)))==NULL) X EasyFail("Unable to malloc space for pixels #1\n",1); X for (i=0;i<height;i++) { X if ((scanline[j][i]=(rle_pixel *) X malloc(len*sizeof(rle_pixel)))==NULL) { X for (;j>=0;j--) X for (;i>=0;i--) X if (scanline[j][i]!=NULL) free(scanline[i]); X EasyFail("Unable to malloc space for pixels #2\n",1); X } X } X } X X global = sv_globals; X X if (output_colormap) { X global.sv_ncolors = 1; X global.sv_ncmap = 3; X global.sv_cmaplen = 8; X global.sv_cmap = out_map; X for (i=0;i<(1<<8);i++) { X out_map[i+(0<<8)] = cmap[CM_RED][i] << 8; X out_map[i+(1<<8)] = cmap[CM_GREEN][i] << 8; X out_map[i+(2<<8)] = cmap[CM_BLUE][i] << 8; X } X } else { X SV_SET_BIT(global, SV_RED); X SV_SET_BIT(global, SV_GREEN); X SV_SET_BIT(global, SV_BLUE); X global.sv_ncolors = 3; X } X global.svfb_fd = stdout ; X global.sv_xmax = len - 1; X global.sv_ymax = height - 1; X X sv_setup(RUN_DISPATCH, &global); X X if (! ReadOK(fd,&c,1)) X EasyFail("Bogus image data -- EOF\n",TRUE); X if (LWZReadByte(fd,TRUE,c)<0) X return TRUE; X X while ((v=LWZReadByte(fd,FALSE,c))>=0) { X if (output_colormap) { X scanline[SV_RED][ypos][xpos] = v ; X } else { X scanline[SV_RED][ypos][xpos] = cmap[CM_RED][v] ; X scanline[SV_GREEN][ypos][xpos] = cmap[CM_GREEN][v] ; X scanline[SV_BLUE][ypos][xpos] = cmap[CM_BLUE][v] ; X } X xpos++; X if (xpos==len) { X xpos = 0; X switch (pass) { X case 0: X case 1: X ypos += 8; break; X case 2: X ypos += 4; break; X case 3: X ypos += 2; break; X } X if (ypos >= height) { X pass++; X switch (pass) { X case 1: X ypos = 4; break; X case 2: X ypos = 2; break; X case 3: X ypos = 1; break; X } X } X } X } X X for (i=0;i<height;i++) { X ptr[0] = scanline[SV_RED][i] ; X if (! output_colormap) { X ptr[1] = scanline[SV_GREEN][i] ; X ptr[2] = scanline[SV_BLUE][i] ; X } X sv_putrow(ptr,len,&global); X } X X sv_puteof(&global); X X for (i=0;i<height;i++) { X if (scanline[0][i]!=NULL) free(scanline[0][i]); X if (output_colormap) continue; X X if (scanline[1][i]!=NULL) free(scanline[1][i]); X if (scanline[2][i]!=NULL) free(scanline[2][i]); X } X free(scanline[0]); X if (! output_colormap) { X free(scanline[1]); X free(scanline[2]); X } X X if (v==(-2)) X return FALSE; X return TRUE; X} X ReadRaster(fd,len,height,cmap) XFILE *fd; int len,height; char cmap[3][MAXCOLORMAPSIZE]; X{ X unsigned char c; X int v; X int xpos=0; X rle_pixel *scanline[3]; X struct sv_globals global ; X int i; X static rle_map out_map[3*(1<<8)]; X X if (((scanline[0]=(rle_pixel *)malloc(len*sizeof(rle_pixel)))==NULL) || X ((scanline[1]=(rle_pixel *)malloc(len*sizeof(rle_pixel)))==NULL) || X ((scanline[2]=(rle_pixel *)malloc(len*sizeof(rle_pixel)))==NULL)) X EasyFail("Unable to malloc space for pixels\n",1); X X global = sv_globals; X X if (output_colormap) { X global.sv_ncolors = 1; X global.sv_ncmap = 3; X global.sv_cmaplen = 8; X global.sv_cmap = out_map; X for (i=0;i<(1<<8);i++) { X out_map[i+(0<<8)] = cmap[CM_RED][i] << 8; X out_map[i+(1<<8)] = cmap[CM_GREEN][i] << 8; X out_map[i+(2<<8)] = cmap[CM_BLUE][i] << 8; X } X } else { X SV_SET_BIT(global, SV_RED); X SV_SET_BIT(global, SV_GREEN); X SV_SET_BIT(global, SV_BLUE); X global.sv_ncolors = 3; X } X global.svfb_fd = stdout ; X global.sv_xmax = len - 1; X global.sv_ymax = height - 1; X X sv_setup(RUN_DISPATCH, &global); X X if (! ReadOK(fd,&c,1)) X EasyFail("Bogus image data -- EOF\n",TRUE); X if (LWZReadByte(fd,TRUE,c)<0) X return TRUE; X X while ((v=LWZReadByte(fd,FALSE,c))>=0) { X if (output_colormap) { X scanline[SV_RED][xpos] = v ; X } else { X scanline[SV_RED][xpos] = cmap[CM_RED][v] ; X scanline[SV_GREEN][xpos] = cmap[CM_GREEN][v] ; X scanline[SV_BLUE][xpos] = cmap[CM_BLUE][v] ; X } X xpos++; X if (xpos==len) { X sv_putrow(scanline,len,&global); X xpos=0; X } X } X X if (xpos!=0) X sv_putrow(scanline,xpos,&global); X X sv_puteof(&global); X X free(scanline[0]); X free(scanline[1]); X free(scanline[2]); X X if (v==(-2)) X return FALSE; X return TRUE; X} END_OF_FILE if test 12206 -ne `wc -c <'giftorle.c'`; then echo shar: \"'giftorle.c'\" unpacked with wrong size! fi # end of 'giftorle.c' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(237 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' RLELIB = ../lib/librle.a X CFLAGS = -g -I../utah/include X SHAR = /user/koblas/bin/shar X CSRC = giftorle.c MAN = giftorle.1 X giftorle : giftorle.o X $(CC) $(CFLAGS) -o $@ giftorle.o $(RLELIB) X shar: X $(SHAR) $(MAN) $(CSRC) Makefile > Shar END_OF_FILE if test 237 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi echo shar: End of shell archive. exit 0 -- name : David Koblas uucp : {ames,decwrl}!mips!koblas place: MIPS Computers Systems domain: koblas@mips.com quote: I haven't lost my mind -- it's backed up on tape somewhere.