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.