This is NXBitmapImageRep.m in view mode; [Download] [Up]
/* NXBitmapImageRep - image representation for bitmapped images Copyright (C) 1993, Adam Fedor. */ #include <stdlib.h> #include <math.h> #include "stdmacros.h" #include "NXBitmapImageRep.h" #include "appkit/tiff.h" #include <objc/hashtable.h> #define DATA_OWNER 1 #define DATA_NOTOWNER 2 /* Maximum number of planes */ #define PLANES 5 extern const char *NXBitmapImageRepInstanceName(void); @interface NXBitmapImageRep(ToolKit) - (BOOL)_displayDrawIn:(const NXRect *)rect; - (BOOL)_displayDraw; @end @implementation NXBitmapImageRep /* Used by newListFromFile: and newListFromStream: to tell the imageRep which image it is supposed to be using. */ - _setImageNumber:(int)number { _imageNumber = number; return self; } /* Used by newListFromFile: to tell the imageRep which image file it is supposed to be using. */ - _setFileName:(const char *)fileName { _fileName = NXCopyStringBuffer(fileName); return self; } - _dataFromImage:(TIFF *)image { unsigned char *newdata; [self data]; newdata = NXReadTiff(_imageNumber, image, NULL, *_data); if (!newdata) return nil; *_data = newdata; if (_moreRepFlags.isPlanar) { int i; for (i=1; i < _repFlags.numColors; i++) _data[i] = _data[0] + i*_bytesPerRow * _pixelsHigh; } return self; } /* Given a TIFF image (from the libtiff library), load the image information into our data structure. Reads the default or current image from the stream. This is done by passing a -1 as the imageNumber to NXGetTiffInfo. */ - _initFromImage:(TIFF *)image { id ok; #ifdef HAVE_LIBTIFF NXColorSpace colorSpace; #endif NXTiffInfo *info; info = NXGetTiffInfo(-1, image); if (!info) { [self free]; return nil; } /* 8-bit RGB will be converted to 24-bit by the tiff routines, so account for this. */ #ifdef HAVE_LIBTIFF switch(info->photoInterp) { case PHOTOMETRIC_MINISBLACK: colorSpace = NX_OneIsWhiteColorSpace; break; case PHOTOMETRIC_MINISWHITE: colorSpace = NX_OneIsBlackColorSpace; break; case PHOTOMETRIC_RGB: colorSpace = NX_RGBColorSpace; break; case PHOTOMETRIC_PALETTE: colorSpace = NX_RGBColorSpace; info->samplesPerPixel = 3; break; default: break; } ok = [self initData:NULL pixelsWide:info->width pixelsHigh:info->height bitsPerSample:info->bitsPerSample samplesPerPixel:info->samplesPerPixel hasAlpha:(info->samplesPerPixel > 3) isPlanar:(info->planarConfig == PLANARCONFIG_SEPARATE) colorSpace:colorSpace bytesPerRow:0 bitsPerPixel:0]; compression = info->compression; #endif return ok; } - initFromFile:(const char *)fileName { id ok; TIFF *image; _fileName = NXCopyStringBuffer(fileName); /* Open the file just to read image info */ image = NXOpenTiffFile(fileName, NX_READONLY); if (!image) { [self free]; return nil; } ok = [self _initFromImage:image]; NXCloseTiff(image); return ok; } /* Loads only the default (first) image from the TIFF image contained in the stream. */ - initFromStream:(NXStream *)stream { id ok; TIFF *image; image = NXOpenTiffStream(stream, NX_READONLY); if (!image) return nil; ok = [self _initFromImage:image]; if (!ok) { [self free]; return nil; } _imageNumber = 0; [self _dataFromImage:image]; NXCloseTiff(image); return ok; } - initData: (void *)data pixelsWide:(int)width pixelsHigh:(int)height bitsPerSample:(int)bps samplesPerPixel:(int)spp hasAlpha:(BOOL)alpha isPlanar:(BOOL)isPlanar colorSpace:(int)colorSpace bytesPerRow:(int)rBytes bitsPerPixel:(int)pBits { unsigned char **planes = NULL; if (data) { if (isPlanar) { NX_MALLOC(planes, unsigned char *, PLANES); planes[0] = data; planes[1] = NULL; } else { NX_MALLOC(planes, unsigned char *, 1); planes[0] = data; } } return [self initDataPlanes:planes pixelsWide:width pixelsHigh:height bitsPerSample:bps samplesPerPixel:spp hasAlpha:alpha isPlanar:isPlanar colorSpace:colorSpace bytesPerRow:rBytes bitsPerPixel:pBits]; } - initDataPlanes:(unsigned char **)planes pixelsWide:(int)width pixelsHigh:(int)height bitsPerSample:(int)bps samplesPerPixel:(int)spp hasAlpha:(BOOL)alpha isPlanar:(BOOL)isPlanar colorSpace:(int)colorSpace bytesPerRow:(int)rBytes bitsPerPixel:(int)pBits { const char *instance_name; instance_name = NXBitmapImageRepInstanceName(); if (!bps || !spp || !width || !height) { [self free]; return nil; } _pixelsWide = width; _pixelsHigh = height; size.width = width; size.height = height; _repFlags.bitsPerSample = bps; _repFlags.numColors = spp; _moreRepFlags.isPlanar = isPlanar; _colorSpace = colorSpace; if (!pBits) pBits = bps * ((isPlanar) ? 1 : spp); bitsPerPixel = pBits; if (!rBytes) rBytes = ceil((float)width * bitsPerPixel / 8); _bytesPerRow = rBytes; if (!planes || planes[0] == NULL) { _repFlags.dataSource = DATA_OWNER; _repFlags.dataLoaded = 0; _data = NULL; } else { _repFlags.dataSource = DATA_NOTOWNER; _repFlags.dataLoaded = 1; _data = planes; if (spp > 1 && _data[1] == NULL) { // data came from initData:... and we need to set the other planes int i; for (i=1; i < spp; i++) _data[i] = (_data[0] + i*rBytes*height); for (i=spp; i < PLANES; i++) _data[i] = NULL; } } return self; } + (List *)newListFromFile:(const char *)fileName { NXTiffInfo *info; int images; TIFF *image; List *aList; id imageRep; if (!fileName) return nil; // We need to open the file and find out how many images there are image = NXOpenTiffFile(fileName, NX_READONLY); if (!image) return nil; images = 0; aList = [[List alloc] init]; while ((info = NXGetTiffInfo(images, image))) { NX_FREE(info); imageRep = [[[self class] alloc] _initFromImage:image]; if (imageRep) { [imageRep _setImageNumber:images]; [imageRep _setFileName:fileName]; [aList addObject:imageRep]; } images++; } NXCloseTiff(image); if (images == 0) { [aList free]; return nil; } return aList; } + (List *)newListFromStream:(NXStream *)stream { NXTiffInfo *info; int images; TIFF *image; List *aList; id imageRep; image = NXOpenTiffStream(stream, NX_READONLY); if (!image) return nil; images = 0; aList = [[List alloc] init]; while ((info = NXGetTiffInfo(images, image))) { NX_FREE(info); imageRep = [[[self class] alloc] _initFromImage:image]; if (imageRep) { [imageRep _setImageNumber:images]; [aList addObject:imageRep]; } [imageRep _dataFromImage:image]; images++; } NXCloseTiff(image); if (images == 0) { [aList free]; return nil; } return aList; } + (const char *const *)imageUnfilteredFileTypes { static const char *const types[] = {"tiff", "tif", NULL}; return types; } + (const NXAtom *)imageUnfilteredPasteboardTypes { static NXAtom tiffTypes[1] = {NULL}; return (const NXAtom *)tiffTypes; } + (BOOL) canLoadFromStream:(NXStream *)stream { TIFF *image = NULL; #ifdef HAVE_LIBTIFF int pos = NXTell(stream); image = NXOpenTiffStream(stream, NX_READONLY); NXCloseTiff(image); NXSeek(stream, pos, NX_FROMSTART); #endif return (image) ? YES : NO; } - (unsigned char *)data { unsigned char *planes[5]; if (!_data) [self getDataPlanes:planes]; return *_data; } - getDataPlanes:(unsigned char **)data { int i; /* Make sure data is loaded */ if (!_repFlags.dataLoaded) { if (_moreRepFlags.isPlanar) { NX_MALLOC(_data, unsigned char *, PLANES); NX_MALLOC(_data[0], unsigned char, _bytesPerRow*_pixelsHigh * _repFlags.numColors); for (i=1; i < _repFlags.numColors; i++) _data[i] = _data[0] + i*_bytesPerRow * _pixelsHigh; for (i= _repFlags.numColors; i < PLANES; i++) _data[i] = NULL; } else { NX_MALLOC(_data, unsigned char *, 1); NX_MALLOC(_data[0], unsigned char, _bytesPerRow*_pixelsHigh); } if (_fileName) { TIFF *image; image = NXOpenTiffFile(_fileName, NX_READONLY); [self _dataFromImage:image]; NXCloseTiff(image); } _repFlags.dataLoaded = 1; } if (!data) return nil; for (i=0; i < _repFlags.numColors; i++) data[i] = _data[i]; return self; } - (BOOL)isPlanar { return _moreRepFlags.isPlanar; } - (int)samplesPerPixel { return _repFlags.numColors; } - (int)bitsPerPixel { return bitsPerPixel; } - (int)bytesPerRow { return _bytesPerRow; } - (int)bytesPerPlane { return _bytesPerRow*_pixelsHigh; } - (int)numPlanes { return (_moreRepFlags.isPlanar) ? _repFlags.numColors : 1; } - (int)colorSpace { return _colorSpace; } - (BOOL)drawIn:(const NXRect *)rect { if (!_repFlags.dataLoaded) [self data]; return [self _displayDrawIn:rect]; } - (BOOL)draw { if (!_repFlags.dataLoaded) [self data]; return [self _displayDraw]; } - free { if (_repFlags.dataSource == DATA_OWNER && _repFlags.dataLoaded) { if (_moreRepFlags.isPlanar) { int i; for (i=0; i < _repFlags.numColors; i++) NX_FREE(_data[i]); } else NX_FREE(_data[0]); NX_FREE(_data); } return [super free]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.