mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-11-26 21:40:44 +00:00
711 lines
22 KiB
Objective-C
711 lines
22 KiB
Objective-C
/* Copyright (c) 2006-2007 Christopher J. W. Lloyd
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
#import <Foundation/NSDebug.h>
|
|
#import <Onyx2D/O2Decoder_TIFF.h>
|
|
#import <Onyx2D/O2ImageSource.h>
|
|
#import <Onyx2D/O2LZW.h>
|
|
#import <Onyx2D/O2TIFFImageDirectory.h>
|
|
|
|
#import <Onyx2D/O2Defines_libtiff.h>
|
|
|
|
#if LIBTIFF_PRESENT
|
|
#define uint64 tiff_uint64
|
|
#import <tiffio.h>
|
|
#undef uint64
|
|
|
|
// TIFF Reader from NSData memory
|
|
@interface O2TIFFReader : NSObject {
|
|
NSData *_data;
|
|
toff_t _currentOffset;
|
|
}
|
|
|
|
- (id) initWithData: (NSData *) data;
|
|
|
|
// Data access methods for libtiff
|
|
- (int) write: (tdata_t) data size: (tsize_t) size;
|
|
- (int) read: (tdata_t) data size: (tsize_t) size;
|
|
- (toff_t) seek: (tsize_t) offset whence: (int) whence;
|
|
- (int) map: (tdata_t *) data size: (toff_t *) size;
|
|
- (void) unmap: (tdata_t) data size: (toff_t) size;
|
|
- (toff_t) size;
|
|
- (int) close;
|
|
|
|
@end
|
|
|
|
static tsize_t sTIFFWriteProc(thandle_t userData, tdata_t data, tsize_t size) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
return [reader write: data size: size];
|
|
}
|
|
|
|
static tsize_t sTIFFReadProc(thandle_t userData, tdata_t data, tsize_t size) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
return [reader read: data size: size];
|
|
}
|
|
|
|
static toff_t sTIFFSeekProc(thandle_t userData, toff_t offset, int whence) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
return [reader seek: offset whence: whence];
|
|
}
|
|
|
|
static int sTIFFCloseProc(thandle_t userData) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
return [reader close];
|
|
}
|
|
|
|
static toff_t sTIFFSizeProc(thandle_t userData) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
return [reader size];
|
|
}
|
|
|
|
static int sTIFFMapFileProc(thandle_t userData, tdata_t *data, toff_t *size) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
return [reader map: data size: size];
|
|
}
|
|
|
|
static void sTIFFUnmapFileProc(thandle_t userData, tdata_t data, toff_t size) {
|
|
O2TIFFReader *reader = (O2TIFFReader *) userData;
|
|
[reader unmap: data size: size];
|
|
}
|
|
|
|
@implementation O2TIFFReader
|
|
- (id) initWithData: (NSData *) data {
|
|
if ((self = [super init])) {
|
|
_data = [data retain];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc {
|
|
[_data release];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (int) write: (tdata_t) data size: (tsize_t) size {
|
|
return 0;
|
|
}
|
|
|
|
- (int) read: (tdata_t) data size: (tsize_t) size {
|
|
int bytesCount = MIN(size, [_data length] - _currentOffset);
|
|
memcpy(data, [_data bytes] + _currentOffset, bytesCount);
|
|
_currentOffset += bytesCount;
|
|
return bytesCount;
|
|
}
|
|
|
|
- (toff_t) seek: (tsize_t) offset whence: (int) whence {
|
|
/*
|
|
If whence is SEEK_SET, the offset is set to offset bytes.
|
|
If whence is SEEK_CUR, the offset is set to its current location plus offset
|
|
bytes. If whence is SEEK_END, the offset is set to the size of the file plus
|
|
offset bytes.
|
|
*/
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
_currentOffset = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
_currentOffset += offset;
|
|
break;
|
|
case SEEK_END:
|
|
_currentOffset = [_data length] + offset - 1;
|
|
break;
|
|
}
|
|
if (_currentOffset > [_data length]) {
|
|
_currentOffset = -1;
|
|
}
|
|
|
|
return _currentOffset;
|
|
}
|
|
|
|
- (int) map: (tdata_t *) data size: (toff_t *) size {
|
|
*data = (tdata_t)[_data bytes];
|
|
*size = [_data length];
|
|
return 0;
|
|
}
|
|
|
|
- (void) unmap: (tdata_t) data size: (toff_t) size {
|
|
}
|
|
|
|
- (toff_t) size {
|
|
return [_data length];
|
|
}
|
|
|
|
- (int) close {
|
|
return 0;
|
|
}
|
|
|
|
- (void) readImage: (void *) pixelBytes directory: (int) directory {
|
|
const char *data = [_data bytes];
|
|
|
|
// Temporary disable warnings - we're getting too many at app launch
|
|
// and with a lot of tiff files
|
|
TIFFErrorHandler prevHandler = TIFFSetWarningHandler(NULL);
|
|
TIFF *tif = TIFFClientOpen([NSStringFromClass([self class]) UTF8String],
|
|
"r", self, sTIFFReadProc, sTIFFWriteProc,
|
|
sTIFFSeekProc, sTIFFCloseProc, sTIFFSizeProc,
|
|
sTIFFMapFileProc, sTIFFUnmapFileProc);
|
|
|
|
uint32 width = 0;
|
|
uint32 height = 0;
|
|
TIFFSetDirectory(tif, directory);
|
|
if (TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) != 0 &&
|
|
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height) != 0) {
|
|
// We want top-left orientation - libtiff default is bottom-left, which
|
|
// is giving flipped bitmaps libtiff is giving us pixels in the same
|
|
// order we need - so we can just fill the pixels using libtiff and no
|
|
// post-processing is needed
|
|
if (TIFFReadRGBAImageOriented(tif, width, height, pixelBytes,
|
|
ORIENTATION_TOPLEFT, 1) == 0) {
|
|
NSLog(@"Couldn't not decode TIFF Image at index %d", directory);
|
|
}
|
|
} else {
|
|
NSLog(@"Couldn't not read TIFF Image dimensions at index %d",
|
|
directory);
|
|
}
|
|
TIFFClose(tif);
|
|
|
|
TIFFSetWarningHandler(prevHandler);
|
|
}
|
|
@end
|
|
|
|
#endif
|
|
|
|
@implementation O2TIFFImageDirectory
|
|
|
|
- initWithTIFFReader: (O2Decoder_TIFF *) reader {
|
|
unsigned i, numberOfEntries = O2DecoderNextUnsigned16_TIFF(reader);
|
|
|
|
#if LIBTIFF_PRESENT
|
|
// Save the index for the current directory object
|
|
_idx = [[reader imageFileDirectory] count];
|
|
#endif
|
|
_xPosition = 0;
|
|
_xResolution = 72.0;
|
|
_yPosition = 0;
|
|
_yResolution = 72.0;
|
|
|
|
for (i = 0; i < numberOfEntries; i++) {
|
|
unsigned offset = [reader currentOffset];
|
|
unsigned tag = O2DecoderNextUnsigned16_TIFF(reader);
|
|
|
|
switch (tag) {
|
|
|
|
case NSTIFFTagArtist:
|
|
_artist = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagBitsPerSample:
|
|
[reader expectArrayOfUnsigned16: &_bitsPerSample
|
|
count: &_sizeOfBitsPerSample];
|
|
break;
|
|
|
|
case NSTIFFTagCellLength:
|
|
_cellLength = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagCellWidth:
|
|
_cellWidth = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagColorMap:
|
|
[reader expectArrayOfUnsigned16: &_colorMap
|
|
count: &_sizeOfColorMap];
|
|
break;
|
|
|
|
case NSTIFFTagCompression:
|
|
_compression = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagCopyright:
|
|
_copyright = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagDateTime:
|
|
_dateTime = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagDocumentName:
|
|
_documentName = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagExtraSamples:
|
|
[reader expectArrayOfUnsigned16: &_extraSamples
|
|
count: &_sizeOfExtraSamples];
|
|
break;
|
|
|
|
case NSTIFFTagFillOrder:
|
|
_fillOrder = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagFreeByteCounts:
|
|
_freeByteCounts = [reader expectUnsigned32];
|
|
break;
|
|
|
|
case NSTIFFTagFreeOffsets:
|
|
_freeByteCounts = [reader expectUnsigned32];
|
|
break;
|
|
|
|
case NSTIFFTagGrayResponseCurve:
|
|
[reader expectArrayOfUnsigned16: &_grayResponseCurve
|
|
count: &_sizeOfGrayResponseCurve];
|
|
break;
|
|
|
|
case NSTIFFTagGrayResponseUnit:
|
|
_grayResponseUnit = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagHostComputer:
|
|
_hostComputer = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagImageDescription:
|
|
_imageDescription = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagImageLength:
|
|
_imageLength = [reader expectUnsigned16OrUnsigned32];
|
|
break;
|
|
|
|
case NSTIFFTagImageWidth:
|
|
_imageWidth = [reader expectUnsigned16OrUnsigned32];
|
|
break;
|
|
|
|
case NSTIFFTagMake:
|
|
_make = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagMaxSampleValue:
|
|
[reader expectArrayOfUnsigned16: &_maxSampleValue
|
|
count: &_sizeOfMaxSampleValue];
|
|
break;
|
|
|
|
case NSTIFFTagMinSampleValue:
|
|
[reader expectArrayOfUnsigned16: &_minSampleValue
|
|
count: &_sizeOfMinSampleValue];
|
|
break;
|
|
|
|
case NSTIFFTagModel:
|
|
_model = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagNewSubfileType:
|
|
_newSubfileType = [reader expectUnsigned32];
|
|
break;
|
|
|
|
case NSTIFFTagOrientation:
|
|
_orientation = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagPageName:
|
|
_pageName = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagPageNumber:
|
|
[reader expectArrayOfUnsigned16: &_pageNumbers
|
|
count: &_sizeOfPageNumbers];
|
|
break;
|
|
|
|
case NSTIFFTagPhotometricInterpretation:
|
|
_photometricInterpretation = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagPlanarConfiguration:
|
|
_planarConfiguration = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagResolutionUnit:
|
|
_resolutionUnit = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagRowsPerStrip:
|
|
_rowsPerStrip = [reader expectUnsigned16OrUnsigned32];
|
|
break;
|
|
|
|
case NSTIFFTagSampleFormat:
|
|
[reader expectArrayOfUnsigned16: &_sampleFormats
|
|
count: &_sizeOfSampleFormats];
|
|
break;
|
|
|
|
case NSTIFFTagSamplesPerPixel:
|
|
_samplesPerPixel = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagSoftware:
|
|
_software = [[reader expectASCII] copy];
|
|
break;
|
|
|
|
case NSTIFFTagStripByteCounts:
|
|
[reader expectArrayOfUnsigned16OrUnsigned32: &_stripByteCounts
|
|
count: &
|
|
_sizeOfStripByteCounts];
|
|
break;
|
|
|
|
case NSTIFFTagStripOffsets:
|
|
[reader expectArrayOfUnsigned16OrUnsigned32: &_stripOffsets
|
|
count: &_sizeOfStripOffsets];
|
|
break;
|
|
|
|
case NSTIFFTagSubfileType:
|
|
_subfileType = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagThreshholding:
|
|
_threshholding = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagXMP:
|
|
[reader expectArrayOfUnsigned8: &_xmp count: &_sizeOfXMP];
|
|
break;
|
|
|
|
case NSTIFFTagXPosition:
|
|
_xPosition = [reader expectRational];
|
|
break;
|
|
|
|
case NSTIFFTagXResolution:
|
|
_xResolution = [reader expectRational];
|
|
break;
|
|
|
|
case NSTIFFTagYPosition:
|
|
_yPosition = [reader expectRational];
|
|
break;
|
|
|
|
case NSTIFFTagYResolution:
|
|
_yResolution = [reader expectRational];
|
|
break;
|
|
|
|
case NSTIFFTagPredictor:
|
|
_predictor = [reader expectUnsigned16];
|
|
break;
|
|
|
|
case NSTIFFTagPhotoshopPrivate1:
|
|
case NSTIFFTagPhotoshopPrivate2:
|
|
// ignore
|
|
break;
|
|
|
|
case NSTIFFTagExifIFD:
|
|
break;
|
|
|
|
case NSTIFFTagGPSIFD:
|
|
break;
|
|
|
|
default:
|
|
if (NSDebugEnabled)
|
|
NSLog(@"TIFF trace: unknown tag=%d", tag);
|
|
break;
|
|
}
|
|
[reader seekToOffset: offset + 12];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc {
|
|
[_artist release];
|
|
if (_bitsPerSample != NULL)
|
|
NSZoneFree([self zone], _bitsPerSample);
|
|
if (_colorMap != NULL)
|
|
NSZoneFree([self zone], _colorMap);
|
|
[_copyright release];
|
|
[_dateTime release];
|
|
[_documentName release];
|
|
if (_extraSamples != NULL)
|
|
NSZoneFree([self zone], _extraSamples);
|
|
if (_grayResponseCurve != NULL)
|
|
NSZoneFree([self zone], _grayResponseCurve);
|
|
[_hostComputer release];
|
|
[_imageDescription release];
|
|
[_make release];
|
|
if (_maxSampleValue != NULL)
|
|
NSZoneFree([self zone], _maxSampleValue);
|
|
if (_minSampleValue != NULL)
|
|
NSZoneFree([self zone], _minSampleValue);
|
|
[_model release];
|
|
[_pageName release];
|
|
if (_pageNumbers != NULL)
|
|
NSZoneFree([self zone], _pageNumbers);
|
|
if (_sampleFormats != NULL)
|
|
NSZoneFree([self zone], _sampleFormats);
|
|
[_software release];
|
|
if (_stripByteCounts != NULL)
|
|
NSZoneFree([self zone], _stripByteCounts);
|
|
if (_stripOffsets != NULL)
|
|
NSZoneFree([self zone], _stripOffsets);
|
|
if (_xmp != NULL)
|
|
NSZoneFree([self zone], _xmp);
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
- (int) imageLength {
|
|
return _imageLength;
|
|
}
|
|
|
|
- (int) imageWidth {
|
|
return _imageWidth;
|
|
}
|
|
|
|
#if !LIBTIFF_PRESENT
|
|
static void decode_R8_G8_B8_A8(const unsigned char *stripBytes,
|
|
unsigned byteCount, unsigned char *pixelBytes,
|
|
int bytesPerRow, int *pixelBytesRowp, int height)
|
|
{
|
|
int pixelBytesRow = *pixelBytesRowp;
|
|
int pixelBytesCol = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < byteCount; i++) {
|
|
pixelBytes[pixelBytesRow * bytesPerRow + pixelBytesCol] = stripBytes[i];
|
|
pixelBytesCol++;
|
|
|
|
if (pixelBytesCol >= bytesPerRow) {
|
|
pixelBytesCol = 0;
|
|
pixelBytesRow++;
|
|
if (pixelBytesRow >= height)
|
|
break;
|
|
}
|
|
}
|
|
|
|
*pixelBytesRowp = pixelBytesRow;
|
|
}
|
|
|
|
static void decode_R8_G8_B8_Afill(const unsigned char *stripBytes,
|
|
unsigned byteCount, unsigned char *pixelBytes,
|
|
int bytesPerRow, int *pixelBytesRowp,
|
|
int height)
|
|
{
|
|
int pixelBytesRow = *pixelBytesRowp;
|
|
int pixelBytesCol = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < byteCount; i++) {
|
|
pixelBytes[pixelBytesRow * bytesPerRow + pixelBytesCol] = stripBytes[i];
|
|
pixelBytesCol++;
|
|
|
|
if (((pixelBytesCol + 1) % 4) == 0) {
|
|
pixelBytes[pixelBytesRow * bytesPerRow + pixelBytesCol] = 0xFF;
|
|
pixelBytesCol++;
|
|
}
|
|
|
|
if (pixelBytesCol >= bytesPerRow) {
|
|
pixelBytesCol = 0;
|
|
pixelBytesRow++;
|
|
if (pixelBytesRow >= height)
|
|
break;
|
|
}
|
|
}
|
|
|
|
*pixelBytesRowp = pixelBytesRow;
|
|
}
|
|
|
|
void depredict_R8G8B8A8(uint8_t *pixelBytes, unsigned bytesPerRow,
|
|
unsigned height)
|
|
{
|
|
int y;
|
|
|
|
for (y = 0; y < height; y++) {
|
|
int i;
|
|
|
|
for (i = 4; i < bytesPerRow;) {
|
|
pixelBytes[i] += pixelBytes[i - 4];
|
|
i++;
|
|
pixelBytes[i] += pixelBytes[i - 4];
|
|
i++;
|
|
pixelBytes[i] += pixelBytes[i - 4];
|
|
i++;
|
|
pixelBytes[i] += pixelBytes[i - 4];
|
|
i++;
|
|
}
|
|
pixelBytes += bytesPerRow;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
- (BOOL) getRGBAImageBytes: (unsigned char *) pixelBytes data: (NSData *) data {
|
|
#if LIBTIFF_PRESENT
|
|
// Note: it would be much more efficient to use LIBTIFF for all of the TIFF
|
|
// processing but we're doing minimal changes to the non-libtiff version -
|
|
// so we're just using LIBTIFF to do the image decoding for an image
|
|
// directory object (in order to support more image codecs than the one
|
|
// supported natively by cocotron)
|
|
O2TIFFReader *tiffReader = [[O2TIFFReader alloc] initWithData: data];
|
|
[tiffReader readImage: pixelBytes directory: _idx];
|
|
[tiffReader release];
|
|
#else
|
|
const unsigned char *bytes = [data bytes];
|
|
unsigned length = [data length];
|
|
unsigned strip, i;
|
|
int bitsPerPixel, bytesPerRow, pixelBytesRow;
|
|
|
|
// general checks
|
|
if (_imageLength == 0) {
|
|
NSLog(@"TIFF general failure, imageLength=0");
|
|
return NO;
|
|
}
|
|
|
|
if (_imageWidth == 0) {
|
|
NSLog(@"TIFF rastering error, imageWidth=0");
|
|
return NO;
|
|
}
|
|
|
|
if (_sizeOfStripByteCounts != _sizeOfStripOffsets) {
|
|
NSLog(@"TIFF strip error, # of StripOffsets (%d) ! = # of "
|
|
@"StripByteCounts (%d)",
|
|
_sizeOfStripOffsets, _sizeOfStripByteCounts);
|
|
return NO;
|
|
}
|
|
|
|
if (_sizeOfBitsPerSample != _samplesPerPixel) {
|
|
NSLog(@"TIFF data error, size of bitsPerSample array (%d) != "
|
|
@"samplesPerPixel (%d)",
|
|
_sizeOfBitsPerSample, _samplesPerPixel);
|
|
return NO;
|
|
}
|
|
|
|
// specific checks for unimplemented features
|
|
|
|
if (_compression != NSTIFFCompression_none &&
|
|
_compression != NSTIFFCompression_LZW) {
|
|
NSLog(@"TIFF unsupported, compression %d", _compression);
|
|
return NO;
|
|
}
|
|
|
|
if (_samplesPerPixel != 4 && _samplesPerPixel != 3) {
|
|
NSLog(@"TIFF unsupported, samplesPerPixel!=4 or 3, got %d",
|
|
_samplesPerPixel);
|
|
return NO;
|
|
}
|
|
|
|
if (_sampleFormats != NULL) {
|
|
for (i = 0; i < _sizeOfSampleFormats; i++)
|
|
if (_sampleFormats[i] != NSTIFFSampleFormat_UINT) {
|
|
NSLog(@"TIFF unsupported, sampleFormats[%d]!=1, got %d", i,
|
|
_sampleFormats[i]);
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
bitsPerPixel = 0;
|
|
for (i = 0; i < _sizeOfBitsPerSample; i++) {
|
|
bitsPerPixel += _bitsPerSample[i];
|
|
if (_bitsPerSample[i] != 8) {
|
|
NSLog(@"TIFF unsupported, bitsPerSample[%d]!=8, got %d", i,
|
|
_bitsPerSample[i]);
|
|
return NO;
|
|
}
|
|
}
|
|
bytesPerRow = _imageWidth * (bitsPerPixel / 8);
|
|
pixelBytesRow = 0;
|
|
|
|
if (_compression == NSTIFFCompression_LZW) {
|
|
|
|
for (strip = 0; strip < _sizeOfStripOffsets; strip++) {
|
|
unsigned offset = _stripOffsets[strip];
|
|
unsigned byteCount = _stripByteCounts[strip];
|
|
|
|
if (offset + byteCount > length) {
|
|
NSLog(@"TIFF strip error, offset (%d) + byteCount (%d) > "
|
|
@"length (%d)",
|
|
offset, byteCount, length);
|
|
return NO;
|
|
}
|
|
NSData *data = [NSData dataWithBytes: bytes + offset
|
|
length: byteCount];
|
|
|
|
int stripLength = _rowsPerStrip;
|
|
|
|
if (pixelBytesRow + stripLength > _imageLength)
|
|
stripLength = _imageLength - pixelBytesRow;
|
|
|
|
stripLength *= bytesPerRow;
|
|
|
|
data = LZWDecodeWithExpectedResultLength(data, stripLength);
|
|
|
|
if (_samplesPerPixel == 4)
|
|
decode_R8_G8_B8_A8([data bytes], stripLength, pixelBytes,
|
|
_imageWidth * 4, &pixelBytesRow,
|
|
_imageLength);
|
|
else
|
|
decode_R8_G8_B8_Afill([data bytes], stripLength, pixelBytes,
|
|
_imageWidth * 4, &pixelBytesRow,
|
|
_imageLength);
|
|
}
|
|
|
|
} else {
|
|
for (strip = 0; strip < _sizeOfStripOffsets; strip++) {
|
|
unsigned offset = _stripOffsets[strip];
|
|
unsigned byteCount = _stripByteCounts[strip];
|
|
|
|
if (offset + byteCount > length) {
|
|
NSLog(@"TIFF strip error, offset (%d) + byteCount (%d) > "
|
|
@"length (%d)",
|
|
offset, byteCount, length);
|
|
return NO;
|
|
}
|
|
if (_samplesPerPixel == 4)
|
|
decode_R8_G8_B8_A8(bytes + offset, byteCount, pixelBytes,
|
|
_imageWidth * 4, &pixelBytesRow,
|
|
_imageLength);
|
|
else
|
|
decode_R8_G8_B8_Afill(bytes + offset, byteCount, pixelBytes,
|
|
_imageWidth * 4, &pixelBytesRow,
|
|
_imageLength);
|
|
}
|
|
}
|
|
|
|
switch (_predictor) {
|
|
case NSTIFFTagPredictor_none:
|
|
break;
|
|
|
|
case NSTIFFTagPredictor_horizontal:
|
|
if (_samplesPerPixel == 4)
|
|
depredict_R8G8B8A8(pixelBytes, bytesPerRow, _imageLength);
|
|
else
|
|
NSLog(@"TIFF predictor error, horizontal unsupported for samples "
|
|
@"per pixel=%d",
|
|
_samplesPerPixel);
|
|
break;
|
|
|
|
case NSTIFFTagPredictor_floatingPoint:
|
|
NSLog(@"TIFF predictor error, floating point unsupported");
|
|
break;
|
|
}
|
|
#endif
|
|
return YES;
|
|
}
|
|
|
|
- (NSDictionary *) properties {
|
|
NSMutableDictionary *result = [NSMutableDictionary new];
|
|
|
|
if (_imageLength) {
|
|
[result setObject: [NSNumber numberWithUnsignedInt: _imageLength]
|
|
forKey: kO2ImagePropertyPixelHeight];
|
|
}
|
|
if (_imageWidth) {
|
|
[result setObject: [NSNumber numberWithUnsignedInt: _imageWidth]
|
|
forKey: kO2ImagePropertyPixelWidth];
|
|
}
|
|
[result setObject: [NSNumber numberWithDouble: _xResolution]
|
|
forKey: kO2ImagePropertyDPIWidth];
|
|
[result setObject: [NSNumber numberWithDouble: _yResolution]
|
|
forKey: kO2ImagePropertyDPIHeight];
|
|
|
|
return result;
|
|
}
|
|
|
|
@end
|