This is GifToTiff.m in view mode; [Download] [Up]
// Tabs:3 Indent:3 /* * GifToTiff.m, GIF to TIFF converter. * Author: Michael McCulloch * Written for 3.1, June 14, 1993. * * You may freely copy, distribute and reuse the code in this example. * Michael McCulloch disclaims any warranty of any kind, expressed or * implied, as to its fitness for any particular use. */ #import <appkit/appkit.h> #import <libc.h> #import <string.h> #import <stdio.h> long int imagePos; // image position in stream long int imageNextPos; // position of end of image int loadError; // loading error flag u_int pixWide; // pixel width u_int pixHigh; // pixel height u_long rasterSize; // width * height u_int rasterTop; // top raster row float aspectRatio; // aspect ratio BOOL isGlobalMap; // Is there a global color map? int colorMapCount; // Number of global colors u_char colorMap[256][3]; // RGB values for global color map u_char gamtab[256]; // gamma correction table u_char *imageRaster; // raster buffer #define IMAX ((1<<8)-1) /* max intensity value */ // error codes & descriptions #define errNONE 0 #define errTABLE_OVERFLOW 1 #define errRASTER_SIZE 2 #define errNO_COLORMAP 3 #define errINVALID_FILE 4 #define errBAD_BLOCK 5 #define errCANT_LOAD 6 #define errEND_OF_FILE 7 #define errNO_IMAGE 8 static char *errDesc[] = { "none", "code table overflow", "raster has the wrong size", "no colormap present for image", "invalid GIF file", "illegal GIF block type", "unable to load file (unknown reason)", "reached premature end-of-file" "no image found in file", 0 }; const char *errorDesc(int x) { return errDesc[x]; } static unsigned char getByte (NXStream *stream) { return (unsigned char)NXGetc(stream); } static void getBytes (NXStream *stream, u_char *buf, int count) { NXRead(stream, buf, count); } /* check file type */ static BOOL validImageType(NXStream *stream) { char buf[16]; getBytes(stream, buf, 6); return strncasecmp(buf,"GIF87a", 6) && strncasecmp(buf,"GIF89a", 6)? NO : YES; } static int readRaster(NXStream *imageStream) { u_char *ch, buf[260], *fill; u_int count, datm; int i, err, code, bits, thisCode; int codeTable[4096][2]; // LZW compression code data int stack[4096 * 2], *sp; int _datasize, _codesize, _maxsize; int _clear, _avail, _oldcode, _firstcode; /* initialize */ err = errNONE; fill = imageRaster; _datasize = getByte(imageStream); _clear = 1 << _datasize; _codesize = _datasize + 1; _avail = _clear + 2; _maxsize = _clear * 2; _oldcode = -1; _firstcode = -1; bits = 0; datm = 0; sp = stack; /* prefill table */ for(i = 0; i < 4096; i++){ codeTable[i][0] = 0; codeTable[i][1] = (i < _clear)? i : 0; } /* decode raster */ for(count = getByte(imageStream); count > 0; count = getByte(imageStream)){ /* read block */ getBytes(imageStream, buf, count); /* process block */ for(ch = buf; count-- > 0; ch++){ datm += (u_int)(*ch) << bits; bits += 8; while(bits >= _codesize){ /* get code */ code = datm & ((1 << _codesize) - 1); datm >>= _codesize; bits -= _codesize; /* clear table */ if(code == _clear){ _codesize = _datasize + 1; _maxsize = _clear * 2; _avail = _clear + 2; _oldcode = -1; _firstcode = -1; sp = stack; for(i = 0; i < 4096; i++){ codeTable[i][0] = 0; codeTable[i][1] = (i < _clear)? i : 0; } continue; } /* end of decompression */ if(code == _clear + 1) goto EXITLOOP; /* for non-standard GIF files */ /* save first code */ if(_firstcode == -1){ _firstcode = _oldcode = code; *fill++ = code; continue; } /* save this code */ thisCode = code; /* code check */ if(code >= _avail){ *sp++ = _firstcode; code = _oldcode; } /* place codes on stack */ while(code >= _clear){ *sp++ = codeTable[code][1]; if(code == codeTable[code][0]){ err = errTABLE_OVERFLOW; goto EXITLOOP; } code = codeTable[code][0]; } *sp++ = _firstcode = codeTable[code][1]; /* save in table */ code = _avail; if(code < 4096){ codeTable[code][0] = _oldcode; codeTable[code][1] = _firstcode; _avail++; if((_avail >= _maxsize) && (_maxsize < 4096)){ _maxsize *= 2; _codesize++; } } /* save old code */ _oldcode = thisCode; /* flush stack */ while(sp > stack) *fill++ = *--sp; } } } EXITLOOP: if(err == errEND_OF_FILE){ err = errNONE; NXLogError("GIF premature end of file"); } if(!err && (fill != imageRaster + rasterSize)) err = errRASTER_SIZE; return err; } static int loadImage(NXStream *imageStream) { u_char buf[10]; BOOL local, interleaved; int err, left; /* set file position */ if(imagePos) NXSeek(imageStream, imagePos, NX_FROMSTART); else imagePos = NXTell(imageStream); /* read image information */ getBytes(imageStream, buf, 9); left = buf[0] + (buf[1] << 8); rasterTop = buf[2] + (buf[3] << 8); pixWide = buf[4] + (buf[5] << 8); pixHigh = buf[6] + (buf[7] << 8); local = (buf[8] & 0x80)? YES : NO; interleaved = (buf[8] & 0x40)? YES : NO; rasterSize = (u_long)pixWide * (u_long)pixHigh; /* convert color map */ if(local){ colorMapCount = 1 << ((buf[8] & 0x7) + 1); getBytes(imageStream, &colorMap[0][0], 3*colorMapCount); } else{ if(!isGlobalMap) return errNO_COLORMAP; } /* read image raster */ if(!imageRaster) memset((imageRaster=(u_char*)malloc(rasterSize)), 0, rasterSize); if((err = readRaster(imageStream)) && (err != errRASTER_SIZE)) return err; /* remove any interleave */ if(interleaved){ int i, r=0; u_char *temp = (u_char*)malloc(rasterSize); u_short *tbl = (u_short*)malloc(pixHigh * sizeof(u_short)); for(i = rasterTop; i < (int)(rasterTop + pixHigh); i+=8) tbl[i] = r++; for(i = rasterTop + 4; i < (int)(rasterTop + pixHigh); i+=8) tbl[i] = r++; for(i = rasterTop + 2; i < (int)(rasterTop + pixHigh); i+=4) tbl[i] = r++; for(i = rasterTop + 1; i < (int)(rasterTop + pixHigh); i += 2) tbl[i] = r++; for(i = 0, r = rasterTop; r < (int)(rasterTop + pixHigh); i++, r++) memcpy(&temp[i * pixWide], &imageRaster[tbl[r] * pixWide], pixWide); free(tbl); free(imageRaster); imageRaster = temp; rasterTop = 0; } /* return successful */ return errNONE; } /* read GIF header info */ static int readGIFHeader(NXStream *imageStream, BOOL showMessage, const char *imageFile) { u_int screenWidth,screenHeight; // screen dimensions u_int background; u_char buf[256]; /* rewind file pointer */ NXSeek(imageStream, 0, NX_FROMSTART); /* check gif signiture type */ if(!validImageType(imageStream)) return errINVALID_FILE; /* read global information */ getBytes(imageStream, buf, 7); screenWidth = buf[0] + (buf[1] << 8); screenHeight = buf[2] + (buf[3] << 8); isGlobalMap = (buf[4] & 0x80)? YES : NO; // global color map? background = buf[5]; // not used aspectRatio = (buf[6])? ((float)buf[6] + 15.0) / 64.0 : 1.0; // aspect ratio if(showMessage) fprintf(stderr, "McFilter:GIFFilter converting %s: %d x %d\n", (strrchr(imageFile,'/')+1), screenWidth, screenHeight); /* load global colormap */ if(isGlobalMap){ colorMapCount = 1 << ((buf[4] & 0x07) + 1); getBytes(imageStream, &colorMap[0][0], 3*colorMapCount); } return errNONE; } /* initialize from stream */ static int readImage(NXStream *imageStream, BOOL showMessage, const char *imageFile) { int err; /* read gif header info */ if(err = readGIFHeader(imageStream, showMessage, imageFile)) return err; // /* set file position override */ // if(overridePos) // NXSeek(imageStream, 0, NX_FROMSTART); /* loop through file */ for(;;){ int err; u_char buf[256]; u_char ch = getByte(imageStream); switch(ch){ case ',' : if (err = loadImage(imageStream)) return err; imageNextPos = NXTell(imageStream); return errNONE; case '!' : // skip extension for(ch=getByte(imageStream); ch=getByte(imageStream);) getBytes(imageStream, buf, ch); break; case '\0': break; /* non-standard files */ case ';' : return imageNextPos? errNONE: errNO_IMAGE; default : return errBAD_BLOCK; } } /* return any error */ return errNONE; } /* init from file stream */ NXBitmapImageRep *convertGIFToTIFF(NXStream *imageStream,float gammaFactor, BOOL showMessage, const char *imageFile) { NXSize pSize; NXBitmapImageRep *tiff = nil; /* image data storage */ int i, j, r, c, bpr; u_char *p; u_char *bitmap[5] = { 0, 0, 0, 0, 0 }; /* local var init */ imageRaster = (u_char*)nil; pixWide = 0; pixHigh = 0; rasterSize = 0L; isGlobalMap = NO; colorMapCount = 0; imagePos = 0L; imageNextPos = 0L; // overridePos = 0L; /* initialize */ loadError = readImage(imageStream,showMessage,imageFile); if (loadError == errNO_IMAGE) return (id)nil; if(!loadError && (!pixWide || !pixHigh)) loadError = errCANT_LOAD; if(loadError){ NXLogError("GIF stream error: %s", errDesc[loadError]); return (id)nil; } /* init size (check aspect ratio) */ pSize.width = (float)pixWide; pSize.height = (float)pixHigh; if (aspectRatio < 1.0) pSize.width *= 1.0 / aspectRatio; else if (aspectRatio > 1.0) pSize.height *= aspectRatio; /* create gamma table */ for(i=0; i<256; i++) gamtab[i] = (IMAX*pow(i/255.0,gammaFactor)+0.5); /* modify colorMap */ for(i=0; i<256; i++) for(j=0; j<3; j++) colorMap[i][j] = gamtab[(int)colorMap[i][j]]; /* build image bitmap */ bitmap[0] = p = (u_char*)malloc(3L * rasterSize); for(r = rasterTop; r < (int)(rasterTop + pixHigh); r++){ u_char *s = &imageRaster[r * pixWide]; for (c = 0; c < (int)pixWide; c++, p+=3) memcpy(p, colorMap[s[c]], 3); } /* render bitmap */ bpr = (7 + pixWide * 8 * 3) / 8; tiff = [[NXBitmapImageRep alloc] initDataPlanes:bitmap pixelsWide:pixWide pixelsHigh:pixHigh bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO colorSpace:NX_RGBColorSpace bytesPerRow:bpr bitsPerPixel:(8*3)]; /* init bitmap image rep */ [tiff setSize:&pSize]; free(imageRaster); return tiff; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.