mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 02:04:20 +00:00
Change Log
Mon. 20-Nov-2006 Mark Tracy <tracy454 at concentric dot net> Many changes related to bitmap images 1. NSBitmapImateRep attribute global strings were not defined Fix: add definitions to externs.h, and declarations to NSBitmapImageRep.h Comment: Two strings defined in Cocoa were commented out: NSImageColorSyncData is proprietary to Apple, and NSImageEXIFData has no support elsewhere in GNUstep. I propose adding GSImageICCProfileData if and when color management is added to GNUstep. 2. LZW compression in TIFF was disabled for lack of a test of its availability Fix: Implement NSTiffIsCodecConfigured(codec) in tiff.m Comment: As of libtiff-3.7.0, there is a function call in the API to test availability at runtime. For libtiff-3.6.0 (earlier?) there are macros #defined in tiffconf.h. The implementation check the library version at compile time, and uses one of the two methods. I have not tested the second method for lack of an installation of an old libtiff. 3. -canCompressUsing: relied on a static list of capabilities Fix: Use the new NSTiffIsCodecConfigured(codec) in NSBitmapImageRep.m Comment: The static list could be wrong, as it was on my system. Also eliminate the supports_lzw_compression flag. 4. +getTIFFCompressionTypes:count: relied on a static list of compressors. Fix: Use the new NSTiffIsCodecConfigured(codec) in NSBitmapImageRep.m Comment: Compares GNUstep supported compressors against actual availability. Also change the private instance methods _localFromCompressionType and _compressionTypeFromLocal to private class methods so that they can be used in -initWithTIFFImage:number: and -TIFFRepresentationUsingCompression:factor: and +getTIFFCompressionTypes:count: This is probably a clumsy implementation but it works. 5. -setProperty:toValue: and -valueForProperty: were not implemented Fix: Add a new instance variable NSMutableDictionary * _properties to NSBitmapImageRep.h and implemented accessors in NSBitmapImageRep.m. Patch -_initFromTIFFImage to set compression type and factor in _properties. Comment: This feature is used to pass options to and from JPEG, PNG, TIFF, and GIF in Cocoa, although the docs are kind of vague. In one case the Cocoa docs said the properties were set when reading a TIFF, but the implementation didn't; I chose to implement the docs. Cocoa does use properties when exporting bitmaps, so I implemented that. 6. Checked and updated NSBitmapImageFileType in NSBitmapImageRep.h Fix: confirmed the enumeration values against Cocoa, and added NSJPEG2000FileType = 5 Comment: JPEG-2000 is not implemented, just reserved a space for it. 7. -representationUsingType:properties: was not implemented Fix: Implement export of TIFF, JPEG, GIF and PNG in NSBitmapImage.m Comment: See the change notes for JPEG, GIF, and PNG for more. BMP and JPEG-2000 are not implemented; they just log a message to that effect. As apparently Cocoa does it this way, if you pass nil for properties, it falls back to the internal _properties, and if that is empty, there are some safe defaults. 8. +representationfOfImageRepsInArray:UsingType:properties: was not implemented Fix: Partially implement in NSBitmapImageRep.m Comment: I just stole the incomplete code from +TIFFRepresentationOfImageRepsInArray: since I have yet to find an explanation of how this really ought to work. 9. JPEG export didn't handle alpha channel, properties or errors. Fix: Add -_JPEGRepresentationWithProperties:errorMessage: to NSBitmapImageRep+JPEG.h and greatly rework Nicolas Roard's code in NSBitmapImageRep+JPEG.m. Patch -_initBitmapFromJPEG:errorMessage to write properties. Comment: Major rewrite of Nicolas Roard's JPEG export code. To do: Support for planar bitmaps and support for colorspaces other than RGB(A). 10. PNG export not implemented Fix: Add -_PNGRepresentationWithProperties: to NSBitmapImageRep+PNG.h and implement NSBitmapImageRep+PNG.m Comment: No support yet for planar bitmaps. Only supports NS*WhiteColorSpace and NS*RGBColorSpace. Does support alpha. Support for reading and writing NSImageGamma is experimental. In keeping with Cocoa, the property NSImageGamma ranges from 0.0 to 1.0; representing the range of minimum supported gamma to maximum supported gamma, in this case 1.0 to 2.5. This is in contrast to GNUstep where by convention the property would range from 0.0 to 255.0. To do: proper error message support 11. GIF export not implemented Fix: Add -_GIFRepresentationWithPropterties:errorMessage: to NSBitmapImageRep+GIF.h and implement in NSBitmapImageRep+GIF.m Comments: Supports only RGB(A) colorspaces, but ignores alpha. Supports planar or interleaved bitmaps. Supports properties NSImageRGBColorTable. 12. -_initBitmapFromGIF:errorMessage: did not support transparency Fix: Don't ignore control blocks in NSBitmapImageRep+GIF.m; check for transparency. Comment: If a transparent color is found, it adds an alpha channel to the bitmap. Also, save the color table in properties. 13. -_initBitmapFromGIF:errorMessage: would show the last image in a multi-image GIF file Fix: Break the parsing loop after the first image in NSBitmapImageRep+GIF.m Comment: Also check for frame duration, and set that property. There is not yet any support for animated GIF. This will require some additional infrastructure, and I won't do it unless asked. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@24140 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
abfea70cf8
commit
9f633f60f6
11 changed files with 669 additions and 84 deletions
|
@ -32,6 +32,7 @@
|
|||
#import <GNUstepBase/GSVersionMacros.h>
|
||||
|
||||
#include <AppKit/NSImageRep.h>
|
||||
#include <Foundation/NSDictionary.h>
|
||||
|
||||
@class NSArray;
|
||||
@class NSString;
|
||||
|
@ -44,21 +45,37 @@ typedef enum _NSTIFFCompression {
|
|||
NSTIFFCompressionCCITTFAX3,
|
||||
NSTIFFCompressionCCITTFAX4,
|
||||
NSTIFFCompressionLZW,
|
||||
NSTIFFCompressionOldJPEG,
|
||||
NSTIFFCompressionJPEG,
|
||||
NSTIFFCompressionNEXT,
|
||||
NSTIFFCompressionPackBits,
|
||||
NSTIFFCompressionOldJPEG
|
||||
NSTIFFCompressionPackBits
|
||||
} NSTIFFCompression;
|
||||
|
||||
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
|
||||
// FIXME: This is probably wrong
|
||||
typedef enum _NSBitmapImageFileType {
|
||||
NSTIFFFileType = 0,
|
||||
NSBMPFileType = 1,
|
||||
NSGIFFileType = 2,
|
||||
NSJPEGFileType = 3,
|
||||
NSPNGFileType = 4
|
||||
NSPNGFileType = 4,
|
||||
NSJPEG2000FileType = 5 // available in Mac OS X v10.4
|
||||
} NSBitmapImageFileType;
|
||||
|
||||
APPKIT_EXPORT NSString *NSImageCompressionMethod; // NSNumber; only for TIFF files
|
||||
APPKIT_EXPORT NSString *NSImageCompressionFactor; // NSNumber 0.0 to 255.0; only for JPEG files (GNUstep extension: JPEG-compressed TIFFs too)
|
||||
APPKIT_EXPORT NSString *NSImageDitherTranparency; // NSNumber boolean; only for writing GIF files
|
||||
APPKIT_EXPORT NSString *NSImageRGBColorTable; // NSData; only for reading & writing GIF files
|
||||
APPKIT_EXPORT NSString *NSImageInterlaced; // NSNumber boolean; only for writing PNG files
|
||||
//APPKIT_EXPORT NSString *NSImageColorSyncProfileData; // Mac OX X only
|
||||
//APPKIT_EXPORT NSString *GSImageICCProfileData; // if & when color management comes to GNUstep
|
||||
APPKIT_EXPORT NSString *NSImageFrameCount; // NSNumber integer; only for reading animated GIF files
|
||||
APPKIT_EXPORT NSString *NSImageCurrentFrame; // NSNumber integer; only for animated GIF files
|
||||
APPKIT_EXPORT NSString *NSImageCurrentFrameDuration; // NSNumber float; only for reading animated GIF files
|
||||
APPKIT_EXPORT NSString *NSImageLoopCount; // NSNumber integer; only for reading animated GIF files
|
||||
APPKIT_EXPORT NSString *NSImageGamma; // NSNumber 0.0 to 1.0; only for reading & writing PNG files
|
||||
APPKIT_EXPORT NSString *NSImageProgressive; // NSNumber boolean; only for reading & writing JPEG files
|
||||
//APPKIT_EXPORT NSString *NSImageEXIFData; // No GNUstep support yet; for reading & writing JPEG
|
||||
|
||||
#endif
|
||||
|
||||
@interface NSBitmapImageRep : NSImageRep
|
||||
|
@ -67,8 +84,9 @@ typedef enum _NSBitmapImageFileType {
|
|||
unsigned int _bytesPerRow;
|
||||
unsigned int _numColors;
|
||||
unsigned int _bitsPerPixel;
|
||||
unsigned short _compression;
|
||||
unsigned short _compression;
|
||||
float _comp_factor;
|
||||
NSMutableDictionary *_properties;
|
||||
BOOL _isPlanar;
|
||||
unsigned char **_imagePlanes;
|
||||
NSMutableData *_imageData;
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
+ (BOOL) _bitmapIsGIF: (NSData *)imageData;
|
||||
- (id) _initBitmapFromGIF: (NSData *)imageData
|
||||
errorMessage: (NSString **)errorMsg;
|
||||
- (NSData *) _GIFRepresentationWithProperties: (NSDictionary *) properties
|
||||
errorMessage: (NSString **)errorMsg;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
Written by: Stefan Kleine Stegemann <stefan@wms-network.de>
|
||||
Date: Nov 2003
|
||||
|
||||
GIF writing, properties and transparency: Mark Tracy <tracy454@concentric.net>
|
||||
Date: Nov 2006
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
|
@ -42,6 +45,7 @@ objective-c headers.
|
|||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include "AppKit/NSGraphics.h"
|
||||
|
||||
|
||||
|
@ -105,6 +109,15 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
src->pos = 0;
|
||||
}
|
||||
|
||||
/* Function to write GIF to buffer */
|
||||
static int gs_gif_output(GifFileType *file, const GifByteType *buffer, int len)
|
||||
{
|
||||
if (len <= 0) return 0;
|
||||
|
||||
NSMutableData * nsData = file->UserData;
|
||||
[nsData appendBytes: buffer length: len];
|
||||
return len;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
The gif loading part of NSBitmapImageRep
|
||||
|
@ -143,7 +156,10 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
{\
|
||||
*errorMsg = msg; \
|
||||
}\
|
||||
NSLog(msg);
|
||||
else \
|
||||
{\
|
||||
NSLog(msg);\
|
||||
}
|
||||
|
||||
#define GIF_CREATE_ERROR(msg) \
|
||||
SET_ERROR_MSG(msg); \
|
||||
|
@ -177,16 +193,21 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
GifByteType *extension;
|
||||
GifPixelType *imgBuffer = NULL;
|
||||
GifPixelType *imgBufferPos; /* a position inside imgBuffer */
|
||||
unsigned char *rgbBuffer; /* image convertet to rgb */
|
||||
unsigned char *rgbBuffer; /* image converted to rgb */
|
||||
unsigned rgbBufferPos;
|
||||
unsigned rgbBufferSize;
|
||||
ColorMapObject *colorMap;
|
||||
GifColorType *color;
|
||||
unsigned char colorIndex;
|
||||
unsigned pixelSize, rowSize;
|
||||
int extCode;
|
||||
int gifrc; /* required by CALL_CHECKED */
|
||||
int i, j; /* counters */
|
||||
int imgHeight = 0, imgWidth = 0, imgRow = 0, imgCol = 0;
|
||||
BOOL hasAlpha = NO;
|
||||
unsigned char transparentColor = 0;
|
||||
int sPP = 3; /* samples per pixel */
|
||||
unsigned short duration = 0;
|
||||
|
||||
/* open the image */
|
||||
gs_gif_init_input_source(&src, imageData);
|
||||
|
@ -216,7 +237,9 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
memset(imgBuffer, file->SBackGroundColor, file->SHeight * rowSize);
|
||||
|
||||
|
||||
/* read the image */
|
||||
/* read the image
|
||||
* this delivers the first image in a multi-image gif
|
||||
*/
|
||||
do
|
||||
{
|
||||
CALL_CHECKED(DGifGetRecordType(file, &recordType), @"GetRecordType");
|
||||
|
@ -267,12 +290,19 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
{
|
||||
/* ignore extensions */
|
||||
/* transparency support */
|
||||
CALL_CHECKED(DGifGetExtension(file, &extCode, &extension), @"GetExtension");
|
||||
if (extCode == GRAPHICS_EXT_FUNC_CODE)
|
||||
{
|
||||
hasAlpha = (extension[1] & 0x01);
|
||||
transparentColor = extension[4];
|
||||
duration = extension[3];
|
||||
duration = (duration << 8) + extension[2];
|
||||
}
|
||||
while (extension != NULL)
|
||||
{
|
||||
CALL_CHECKED(DGifGetExtensionNext(file, &extension), @"GetExtensionNext");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -282,11 +312,13 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
} while (recordType != TERMINATE_RECORD_TYPE);
|
||||
} while ((recordType != IMAGE_DESC_RECORD_TYPE)
|
||||
&& (recordType != TERMINATE_RECORD_TYPE));
|
||||
|
||||
|
||||
/* convert the image to rgb */
|
||||
rgbBufferSize = file->SHeight * (file->SWidth * sizeof(unsigned char) * 3);
|
||||
sPP = hasAlpha? 4 : 3;
|
||||
rgbBufferSize = file->SHeight * (file->SWidth * sizeof(unsigned char) * sPP);
|
||||
rgbBuffer = NSZoneMalloc([self zone], rgbBufferSize);
|
||||
if (rgbBuffer == NULL)
|
||||
{
|
||||
|
@ -302,10 +334,13 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
imgBufferPos = imgBuffer + (i * rowSize);
|
||||
for (j = 0; j < file->SWidth; j++)
|
||||
{
|
||||
color = &colorMap->Colors[*(imgBufferPos + (j * pixelSize))];
|
||||
colorIndex = *(imgBufferPos + j*pixelSize);
|
||||
color = &colorMap->Colors[colorIndex];
|
||||
rgbBuffer[rgbBufferPos++] = color->Red;
|
||||
rgbBuffer[rgbBufferPos++] = color->Green;
|
||||
rgbBuffer[rgbBufferPos++] = color->Blue;
|
||||
if (hasAlpha)
|
||||
rgbBuffer[rgbBufferPos++] = (transparentColor == colorIndex)? 0 : 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,16 +352,25 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
pixelsWide: file->SWidth
|
||||
pixelsHigh: file->SHeight
|
||||
bitsPerSample: 8
|
||||
samplesPerPixel: 3
|
||||
hasAlpha: NO
|
||||
samplesPerPixel: sPP
|
||||
hasAlpha: hasAlpha
|
||||
isPlanar: NO
|
||||
colorSpaceName: NSCalibratedRGBColorSpace
|
||||
bytesPerRow: file->SWidth * 3
|
||||
bitsPerPixel: 8 * 3];
|
||||
bytesPerRow: file->SWidth * sPP
|
||||
bitsPerPixel: 8 * sPP];
|
||||
|
||||
_imageData = [[NSData alloc] initWithBytesNoCopy: rgbBuffer
|
||||
length: rgbBufferSize];
|
||||
|
||||
[self setProperty: NSImageRGBColorTable
|
||||
withValue: [NSData dataWithBytes: colorMap->Colors
|
||||
length: sizeof(GifColorType)*colorMap->ColorCount]];
|
||||
if (duration > 0)
|
||||
{
|
||||
[self setProperty: NSImageCurrentFrameDuration
|
||||
withValue: [NSNumber numberWithFloat: (100.0 * duration)]];
|
||||
}
|
||||
[self setProperty: NSImageCurrentFrame
|
||||
withValue: [NSNumber numberWithInt: 0]];
|
||||
|
||||
/* don't forget to close the gif */
|
||||
DGifCloseFile(file);
|
||||
|
@ -334,6 +378,161 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
return self;
|
||||
}
|
||||
|
||||
- (NSData *) _GIFRepresentationWithProperties: (NSDictionary *) properties
|
||||
errorMessage: (NSString **)errorMsg
|
||||
{
|
||||
NSMutableData * GIFRep = nil; // our return value
|
||||
GifFileType * GIFFile = NULL;
|
||||
GifByteType * rgbPlanes = NULL; // giflib needs planar RGB
|
||||
GifByteType * redPlane = NULL;
|
||||
GifByteType * greenPlane = NULL;
|
||||
GifByteType * bluePlane = NULL;
|
||||
int width, height;
|
||||
GifByteType * GIFImage = NULL; // intermediate image storage
|
||||
GifByteType * GIFImageP = NULL;
|
||||
int h; // general-purpose loop counter
|
||||
ColorMapObject * GIFColorMap = NULL;
|
||||
int colorMapSize = 256;
|
||||
int status; // return status for giflib calls
|
||||
NSString * colorSpaceName;
|
||||
BOOL isRGB, hasAlpha;
|
||||
unsigned char * bitmapData = NULL;
|
||||
unsigned char * planes[5]; // MAX_PLANES = 5
|
||||
NSData * colorTable = NULL; // passed in from properties
|
||||
|
||||
NSLog(@"GIF representation is experimental");
|
||||
|
||||
width = [self pixelsWide];
|
||||
height = [self pixelsHigh];
|
||||
if ( !width || !height )
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation: image is zero size");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Giflib wants planar RGB so convert as necessary
|
||||
colorSpaceName = [self colorSpaceName];
|
||||
isRGB = ([colorSpaceName isEqualToString: NSDeviceRGBColorSpace] ||
|
||||
[colorSpaceName isEqualToString: NSCalibratedRGBColorSpace]);
|
||||
if ( !isRGB )
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation: Only RGB is supported at this time.");
|
||||
return nil;
|
||||
}
|
||||
hasAlpha = [self hasAlpha];
|
||||
if ([self isPlanar])
|
||||
{
|
||||
[self getBitmapDataPlanes: planes];
|
||||
redPlane = planes[0];
|
||||
greenPlane = planes[1];
|
||||
bluePlane = planes[2];
|
||||
}
|
||||
else // interleaved RGB or RGBA
|
||||
{
|
||||
OBJC_MALLOC(rgbPlanes, GifByteType, width*height*3);
|
||||
if ( !rgbPlanes )
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation: malloc out of memory.");
|
||||
return nil;
|
||||
}
|
||||
redPlane = rgbPlanes;
|
||||
greenPlane = redPlane + width*height;
|
||||
bluePlane = greenPlane + width*height;
|
||||
bitmapData = [self bitmapData];
|
||||
for (h = 0; h < width*height; h++)
|
||||
{
|
||||
*redPlane++ = *bitmapData++;
|
||||
*greenPlane++ = *bitmapData++;
|
||||
*bluePlane++ = *bitmapData++;
|
||||
if (hasAlpha) bitmapData++; // ignore alpha channel
|
||||
}
|
||||
redPlane = rgbPlanes;
|
||||
greenPlane = redPlane + width*height;
|
||||
bluePlane = greenPlane + width*height;
|
||||
}
|
||||
|
||||
// If you have a color table, you must be certain that it is GIF format
|
||||
colorTable = [self valueForProperty: NSImageRGBColorTable]; // nil is OK
|
||||
colorMapSize = (colorTable)? [colorTable length]/sizeof(GifColorType) : 256;
|
||||
GIFColorMap = MakeMapObject(colorMapSize, [colorTable bytes]);
|
||||
if ( !GIFColorMap )
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation (giflib): MakeMapObject() failed.");
|
||||
OBJC_FREE(rgbPlanes);
|
||||
return nil;
|
||||
}
|
||||
|
||||
OBJC_MALLOC(GIFImage, GifByteType, height*width);
|
||||
if ( !GIFImage )
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation: malloc out of memory.");
|
||||
OBJC_FREE(rgbPlanes);
|
||||
}
|
||||
status = QuantizeBuffer(width, height, &colorMapSize,
|
||||
redPlane, greenPlane, bluePlane,
|
||||
GIFImage, GIFColorMap->Colors);
|
||||
if (status == GIF_ERROR)
|
||||
{
|
||||
OBJC_FREE(GIFImage);
|
||||
OBJC_FREE(rgbPlanes);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// QuantizeBuffer returns an optimized colorMapSize,
|
||||
// but we must round up to nearest power of 2
|
||||
// otherwise MakeColorMap() fails
|
||||
for (h = 0; h < 8; h++)
|
||||
if ((1<<h) >= colorMapSize) break;
|
||||
colorMapSize = 1<<h;
|
||||
GIFColorMap->ColorCount = colorMapSize;
|
||||
GIFColorMap->BitsPerPixel = h;
|
||||
|
||||
if ( ![self isPlanar] ) OBJC_FREE(rgbPlanes);
|
||||
|
||||
// Write the converted image out to the NSData
|
||||
GIFRep = [NSMutableData dataWithLength: 0];
|
||||
if ( !GIFRep )
|
||||
{
|
||||
OBJC_FREE(GIFImage);
|
||||
return nil;
|
||||
}
|
||||
GIFFile = EGifOpen(GIFRep, gs_gif_output);
|
||||
status = EGifPutScreenDesc(GIFFile, width, height, 8, 0, NULL);
|
||||
if (status == GIF_ERROR)
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation (giflib): EGifPutScreenDesc() failed.");
|
||||
OBJC_FREE(GIFImage);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// note we are not supporting interlaced mode
|
||||
status = EGifPutImageDesc(GIFFile, 0, 0, width, height, FALSE, GIFColorMap);
|
||||
if (status == GIF_ERROR)
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation (giflib): EGifPutImageDesc() failed.");
|
||||
OBJC_FREE(GIFImage);
|
||||
return nil;
|
||||
}
|
||||
|
||||
GIFImageP = GIFImage;
|
||||
for (h = 0; h < height ; h++)
|
||||
{
|
||||
status = EGifPutLine(GIFFile, GIFImageP, width);
|
||||
if (status == GIF_ERROR)
|
||||
{
|
||||
SET_ERROR_MSG(@"GIFRepresentation (giflib): EGifPutLine() failed.");
|
||||
OBJC_FREE(GIFImage);
|
||||
return nil;
|
||||
}
|
||||
GIFImageP += width;
|
||||
}
|
||||
status = EGifCloseFile(GIFFile);
|
||||
|
||||
OBJC_FREE(GIFImage);
|
||||
|
||||
return GIFRep;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else /* !HAVE_LIBUNGIF || !HAVE_LIBGIF */
|
||||
|
@ -349,6 +548,13 @@ static void gs_gif_init_input_source(gs_gif_input_src *src, NSData *data)
|
|||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *) _GIFRepresentationWithProperties: (NSDictionary *) properties
|
||||
errorMessage: (NSString **)errorMsg
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* !HAVE_LIBUNGIF || !HAVE_LIBGIF */
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
+ (BOOL) _bitmapIsJPEG: (NSData *)imageData;
|
||||
- (id) _initBitmapFromJPEG: (NSData *)imageData
|
||||
errorMessage: (NSString **)errorMsg;
|
||||
|
||||
- (NSData *) _JPEGRepresentationWithProperties: (NSDictionary *) properties
|
||||
errorMessage: (NSString **)errorMsg;
|
||||
@end
|
||||
|
||||
#endif // _NSBitmapImageRep_JPEG_H_include
|
||||
|
|
|
@ -382,6 +382,7 @@ static void gs_jpeg_memory_dest_destroy (j_compress_ptr cinfo)
|
|||
JDIMENSION sclcount, samplesPerRow, i, j, rowSize;
|
||||
JSAMPARRAY sclbuffer = NULL;
|
||||
unsigned char *imgbuffer = NULL;
|
||||
BOOL isProgressive;
|
||||
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
@ -417,7 +418,7 @@ static void gs_jpeg_memory_dest_destroy (j_compress_ptr cinfo)
|
|||
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
/* we use RGB as target color space */
|
||||
/* we use RGB as target color space; others are not yet supported */
|
||||
cinfo.out_color_space = JCS_RGB;
|
||||
|
||||
/* decompress */
|
||||
|
@ -459,6 +460,8 @@ static void gs_jpeg_memory_dest_destroy (j_compress_ptr cinfo)
|
|||
}
|
||||
}
|
||||
|
||||
isProgressive = cinfo.progressive_mode;
|
||||
|
||||
/* done */
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
||||
|
@ -484,6 +487,9 @@ static void gs_jpeg_memory_dest_destroy (j_compress_ptr cinfo)
|
|||
bytesPerRow: rowSize
|
||||
bitsPerPixel: BITS_IN_JSAMPLE * cinfo.output_components];
|
||||
|
||||
[self setProperty: NSImageProgressive
|
||||
withValue: [NSNumber numberWithBool: isProgressive]];
|
||||
|
||||
_imageData = [[NSData alloc]
|
||||
initWithBytesNoCopy: imgbuffer
|
||||
length: (rowSize * cinfo.output_height)];
|
||||
|
@ -491,90 +497,143 @@ static void gs_jpeg_memory_dest_destroy (j_compress_ptr cinfo)
|
|||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
The jpeg writing part of NSBitmapImageRep
|
||||
----------------------------------------------------------- */
|
||||
|
||||
@implementation NSBitmapImageRep (JPEGWriting)
|
||||
|
||||
- (NSData*) representationUsingType: (NSBitmapImageFileType) storageType
|
||||
properties: (NSDictionary*) properties
|
||||
- (NSData*) _JPEGRepresentationWithProperties: (NSDictionary*) properties
|
||||
errorMessage: (NSString **)errorMsg
|
||||
{
|
||||
NSData *ret;
|
||||
unsigned char *imageSource = [self bitmapData];
|
||||
int sPP = [self samplesPerPixel];
|
||||
int width = [self size].width;
|
||||
int height = [self size].height;
|
||||
int row_stride = width * sPP;
|
||||
unsigned char *imageSource;
|
||||
int sPP;
|
||||
int width;
|
||||
int height;
|
||||
int row_stride;
|
||||
int quality = 90;
|
||||
NSNumber *qualityNumber = nil;
|
||||
NSNumber *progressiveNumber = nil;
|
||||
NSString *colorSpace = nil;
|
||||
BOOL isRGB;
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
struct gs_jpeg_error_mgr jerrMgr;
|
||||
JSAMPROW row_pointer[1]; // pointer to a single row
|
||||
|
||||
cinfo.err = jpeg_std_error (&jerr);
|
||||
jpeg_create_compress (&cinfo);
|
||||
|
||||
// TODO: handles planar images
|
||||
|
||||
if ([self isPlanar])
|
||||
{
|
||||
NSLog (@"Planar Image, not handled yet !");
|
||||
NSString * em = @"JPEG image rep: Planar Image, not handled yet !";
|
||||
if (errorMsg != NULL)
|
||||
*errorMsg = em;
|
||||
else
|
||||
NSLog (em);
|
||||
return nil;
|
||||
}
|
||||
|
||||
imageSource = [self bitmapData];
|
||||
sPP = [self samplesPerPixel];
|
||||
width = [self size].width;
|
||||
height = [self size].height;
|
||||
row_stride = width * sPP;
|
||||
|
||||
/* Establish the our custom error handler */
|
||||
gs_jpeg_error_mgr_init(&jerrMgr);
|
||||
cinfo.err = jpeg_std_error(&jerrMgr.parent);
|
||||
jerrMgr.parent.error_exit = gs_jpeg_error_exit;
|
||||
jerrMgr.parent.output_message = gs_jpeg_output_message;
|
||||
|
||||
// establish return context for error handling
|
||||
if (setjmp(jerrMgr.setjmpBuffer))
|
||||
{
|
||||
/* assign the description of possible occured error to errorMsg */
|
||||
if (errorMsg)
|
||||
*errorMsg = (jerrMgr.error ? (id)jerrMgr.error : (id)nil);
|
||||
gs_jpeg_memory_dest_destroy(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// initialize libjpeg for compression
|
||||
|
||||
jpeg_create_compress (&cinfo);
|
||||
|
||||
// specify the destination for the compressed data..
|
||||
|
||||
gs_jpeg_memory_dest_create (&cinfo, &ret);
|
||||
|
||||
// set parameters
|
||||
|
||||
colorSpace = [self colorSpaceName];
|
||||
isRGB = ([colorSpace isEqualToString: NSDeviceRGBColorSpace]
|
||||
|| [colorSpace isEqualToString: NSCalibratedRGBColorSpace]);
|
||||
cinfo.image_width = width;
|
||||
cinfo.image_height = height;
|
||||
cinfo.input_components = sPP;
|
||||
// note we will strip alpha from RGBA
|
||||
cinfo.input_components = (isRGB && [self hasAlpha])? 3 : sPP;
|
||||
cinfo.in_color_space = JCS_UNKNOWN;
|
||||
if (isRGB) cinfo.in_color_space = JCS_RGB;
|
||||
if (sPP == 1) cinfo.in_color_space = JCS_GRAYSCALE;
|
||||
if ([colorSpace isEqualToString: NSDeviceCMYKColorSpace])
|
||||
cinfo.in_color_space = JCS_CMYK;
|
||||
if (cinfo.in_color_space == JCS_UNKNOWN)
|
||||
NSLog(@"JPEG image rep: Using unknown color space with unpredictable results");
|
||||
|
||||
// TODO: use the image infos to choose the proper color space
|
||||
//cinfo.in_color_space = JCS_GRAYSCALE;
|
||||
|
||||
colorSpace = [self colorSpaceName];
|
||||
|
||||
if ([colorSpace isEqualToString: @"NSCalibratedRGBColorSpace"]
|
||||
|| [colorSpace isEqualToString: @"NSDeviceRGBColorSpace"])
|
||||
{
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog (@"Image Color Space: %@ not handled yet !", colorSpace);
|
||||
return nil;
|
||||
}
|
||||
jpeg_set_defaults (&cinfo);
|
||||
|
||||
// set quality
|
||||
|
||||
qualityNumber = [properties objectForKey: @"NSImageCompressionFactor"];
|
||||
qualityNumber = [properties objectForKey: NSImageCompressionFactor];
|
||||
if (qualityNumber != nil)
|
||||
{
|
||||
quality = (int) ([qualityNumber floatValue] * 100);
|
||||
quality = (int) ((1-[qualityNumber floatValue] / 255.0) * 100.0);
|
||||
}
|
||||
|
||||
// set progressive mode
|
||||
progressiveNumber = [properties objectForKey: NSImageProgressive];
|
||||
if (progressiveNumber != nil)
|
||||
{
|
||||
cinfo.progressive_mode = [progressiveNumber boolValue];
|
||||
}
|
||||
|
||||
jpeg_set_defaults (&cinfo);
|
||||
|
||||
// compress the image
|
||||
|
||||
jpeg_set_quality (&cinfo, quality, TRUE);
|
||||
jpeg_start_compress (&cinfo, TRUE);
|
||||
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height)
|
||||
if (isRGB && [self hasAlpha]) // strip alpha channel before encoding
|
||||
{
|
||||
unsigned char * RGB, * pRGB, * pRGBA;
|
||||
unsigned int iRGB, iRGBA;
|
||||
OBJC_MALLOC(RGB, unsigned char, 3*width);
|
||||
while (cinfo.next_scanline < cinfo.image_height)
|
||||
{
|
||||
iRGBA = cinfo.next_scanline * row_stride;
|
||||
pRGBA = &imageSource[iRGBA];
|
||||
pRGB = RGB;
|
||||
for (iRGB = 0; iRGB < 3*width; iRGB += 3)
|
||||
{
|
||||
memcpy(pRGB, pRGBA, 3);
|
||||
pRGB +=3;
|
||||
pRGBA +=4;
|
||||
}
|
||||
row_pointer[0] = RGB;
|
||||
jpeg_write_scanlines (&cinfo, row_pointer, 1);
|
||||
}
|
||||
OBJC_FREE(RGB);
|
||||
}
|
||||
else // no alpha channel
|
||||
{
|
||||
while (cinfo.next_scanline < cinfo.image_height)
|
||||
{
|
||||
int index = cinfo.next_scanline * row_stride;
|
||||
|
||||
row_pointer[0] = &imageSource[index];
|
||||
jpeg_write_scanlines (&cinfo, row_pointer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
|
@ -601,6 +660,11 @@ static void gs_jpeg_memory_dest_destroy (j_compress_ptr cinfo)
|
|||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
- (NSData *) _JPEGRepresentationWithProperties: (NSDictionary *) properties
|
||||
errorMessage: (NSString **)errorMsg
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
@end
|
||||
|
||||
#endif /* !HAVE_LIBJPEG */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
@interface NSBitmapImageRep (PNG)
|
||||
+ (BOOL) _bitmapIsPNG: (NSData *)imageData;
|
||||
- (id) _initBitmapFromPNG: (NSData *)imageData;
|
||||
- (NSData *) _PNGRepresentationWithProperties: (NSDictionary *) properties;
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,8 +35,19 @@
|
|||
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSValue.h>
|
||||
#include "AppKit/NSGraphics.h"
|
||||
|
||||
#if defined(PNG_FLOATING_POINT_SUPPORT)
|
||||
# define PNG_FLOATING_POINT 1
|
||||
#else
|
||||
# define PNG_FLOATING_POINT 0
|
||||
#endif
|
||||
#if defined(PNG_gAMA_SUPPORT)
|
||||
# define PNG_gAMA 1
|
||||
#else
|
||||
# define PNG_gAMA 0
|
||||
#endif
|
||||
|
||||
@implementation NSBitmapImageRep (PNG)
|
||||
|
||||
|
@ -212,11 +223,141 @@ static void reader_func(png_structp png_struct, png_bytep data,
|
|||
initWithBytesNoCopy: buf
|
||||
length: bytes_per_row * height];
|
||||
|
||||
if (PNG_INFO_gAMA & png_info->valid)
|
||||
{
|
||||
double file_gamma = 2.2;
|
||||
if (PNG_FLOATING_POINT)
|
||||
{
|
||||
png_get_gAMA(png_struct, png_info, &file_gamma);
|
||||
// remap file_gamma [1.0, 2.5] to property [0.0, 1.0]
|
||||
file_gamma = (file_gamma - 1.0)/1.5;
|
||||
}
|
||||
else // fixed point
|
||||
{
|
||||
png_fixed_point int_gamma = 220000;
|
||||
png_get_gAMA_fixed(png_struct, png_info, &int_gamma);
|
||||
// remap gamma [0.0, 1.0] to [100000, 250000]
|
||||
file_gamma = ((double)int_gamma - 100000.0)/150000.0;
|
||||
}
|
||||
[self setProperty: NSImageGamma
|
||||
withValue: [NSNumber numberWithDouble: file_gamma]];
|
||||
//NSLog(@"PNG file gamma: %f", file_gamma);
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&png_struct, &png_info, &png_end_info);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/***** PNG writing support ******/
|
||||
static void writer_func(png_structp png_struct, png_bytep data,
|
||||
png_size_t length)
|
||||
{
|
||||
NSMutableData * PNGRep = png_get_io_ptr(png_struct);
|
||||
[PNGRep appendBytes: data length: length];
|
||||
}
|
||||
|
||||
- (NSData *) _PNGRepresentationWithProperties: (NSDictionary *) properties
|
||||
{
|
||||
png_structp png_struct;
|
||||
png_infop png_info;
|
||||
|
||||
int width, height, depth;
|
||||
unsigned char * bitmapData;
|
||||
int bytes_per_row;
|
||||
NSString * colorspace;
|
||||
NSMutableData * PNGRep = nil;
|
||||
int type = -1; // illegal value
|
||||
int interlace = PNG_INTERLACE_NONE;
|
||||
int transforms = PNG_TRANSFORM_IDENTITY; // no transformations
|
||||
NSNumber * gammaNumber = nil;
|
||||
double gamma = 0.0;
|
||||
|
||||
if ([self isPlanar]) // don't handle planar yet
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
// get the image parameters
|
||||
width = [self pixelsWide];
|
||||
height = [self pixelsHigh];
|
||||
bytes_per_row = [self bytesPerRow];
|
||||
colorspace = [self colorSpaceName];
|
||||
depth = [self bitsPerSample];
|
||||
gammaNumber = [properties objectForKey: NSImageGamma];
|
||||
gamma = [gammaNumber doubleValue];
|
||||
if ([[properties objectForKey: NSImageInterlaced] boolValue])
|
||||
interlace = PNG_INTERLACE_ADAM7;
|
||||
|
||||
if ([colorspace isEqualToString: NSCalibratedWhiteColorSpace] ||
|
||||
[colorspace isEqualToString: NSDeviceWhiteColorSpace])
|
||||
type = PNG_COLOR_TYPE_GRAY;
|
||||
if ([colorspace isEqualToString: NSCalibratedRGBColorSpace] ||
|
||||
[colorspace isEqualToString: NSDeviceRGBColorSpace])
|
||||
type = PNG_COLOR_TYPE_RGB;
|
||||
if ([self hasAlpha]) type = type | PNG_COLOR_MASK_ALPHA;
|
||||
|
||||
// make the PNG structures
|
||||
// ignore errors until I write the handlers
|
||||
png_struct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_struct)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
png_info = png_create_info_struct(png_struct);
|
||||
if (!png_info)
|
||||
{
|
||||
png_destroy_write_struct(&png_struct, NULL);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_struct)))
|
||||
{
|
||||
png_destroy_write_struct(&png_struct, &png_info);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// init structures
|
||||
PNGRep = [NSMutableData dataWithLength: 0];
|
||||
png_info_init_3(&png_info, png_sizeof(png_info));
|
||||
png_set_write_fn(png_struct, PNGRep, writer_func, NULL);
|
||||
png_set_IHDR(png_struct, png_info, width, height, depth,
|
||||
type, interlace, PNG_COMPRESSION_TYPE_BASE,
|
||||
PNG_FILTER_TYPE_BASE);
|
||||
|
||||
if (gammaNumber)
|
||||
{
|
||||
NSLog(@"PNGRepresentation: gamma support is experimental");
|
||||
if (PNG_FLOATING_POINT)
|
||||
{
|
||||
// remap gamma [0.0, 1.0] to [1.0, 2.5]
|
||||
png_set_gAMA(png_struct, png_info, (gamma * 1.5 + 1.0));
|
||||
}
|
||||
else // fixed point
|
||||
{
|
||||
// remap gamma [0.0, 1.0] to [100000, 250000]
|
||||
int int_gamma = (int)(gamma * 150000.0 + 100000.0);
|
||||
png_set_gAMA_fixed(png_struct, png_info, int_gamma);
|
||||
}
|
||||
}
|
||||
|
||||
// get rgb data and row pointers and
|
||||
// write PNG out to NSMutableData
|
||||
bitmapData = [self bitmapData];
|
||||
{
|
||||
unsigned char *row_pointers[height];
|
||||
int i;
|
||||
for (i = 0 ; i < height ; i++)
|
||||
row_pointers[i] = bitmapData + i * bytes_per_row;
|
||||
png_set_rows(png_struct, png_info, row_pointers);
|
||||
|
||||
png_write_png(png_struct, png_info, transforms, NULL);
|
||||
}
|
||||
|
||||
NSLog(@"PNG representation is experimental: %i bytes written", [PNGRep length]);
|
||||
png_destroy_write_struct(&png_struct, &png_info);
|
||||
return PNGRep;
|
||||
}
|
||||
@end
|
||||
|
||||
#else /* !HAVE_LIBPNG */
|
||||
|
@ -231,6 +372,10 @@ static void reader_func(png_structp png_struct, png_bytep data,
|
|||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
- (NSData *) _PNGRepresentationWithProperties: (NSDictionary *) properties
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
@end
|
||||
|
||||
#endif /* !HAVE_LIBPNG */
|
||||
|
|
|
@ -55,19 +55,14 @@
|
|||
/* Maximum number of planes */
|
||||
#define MAX_PLANES 5
|
||||
|
||||
/* FIXME: By default the libtiff library (v3.5.7 and less at least) do
|
||||
not support LZW compression, but it's not possible to find out if it
|
||||
does or not until after we've already written an image :-(. */
|
||||
static BOOL supports_lzw_compression = NO;
|
||||
|
||||
/* Backend methods (optional) */
|
||||
@interface NSBitmapImageRep (GSPrivate)
|
||||
// GNUstep extension
|
||||
- _initFromTIFFImage: (TIFF *)image number: (int)imageNumber;
|
||||
|
||||
// Internal
|
||||
- (int) _localFromCompressionType: (NSTIFFCompression)type;
|
||||
- (NSTIFFCompression) _compressionTypeFromLocal: (int)type;
|
||||
+ (int) _localFromCompressionType: (NSTIFFCompression)type;
|
||||
+ (NSTIFFCompression) _compressionTypeFromLocal: (int)type;
|
||||
@end
|
||||
|
||||
/**
|
||||
|
@ -526,6 +521,7 @@ static BOOL supports_lzw_compression = NO;
|
|||
{
|
||||
[self setOpaque: YES];
|
||||
}
|
||||
_properties = [[NSMutableDictionary alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -555,6 +551,7 @@ static BOOL supports_lzw_compression = NO;
|
|||
{
|
||||
NSZoneFree([self zone],_imagePlanes);
|
||||
RELEASE(_imageData);
|
||||
RELEASE(_properties);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -763,7 +760,7 @@ static BOOL supports_lzw_compression = NO;
|
|||
}
|
||||
|
||||
info.extraSamples = (_hasAlpha) ? 1 : 0;
|
||||
info.compression = [self _localFromCompressionType: type];
|
||||
info.compression = [NSBitmapImageRep _localFromCompressionType: type];
|
||||
if (factor < 0)
|
||||
factor = 0;
|
||||
if (factor > 255)
|
||||
|
@ -790,23 +787,81 @@ static BOOL supports_lzw_compression = NO;
|
|||
usingType:(NSBitmapImageFileType)storageType
|
||||
properties:(NSDictionary *)properties
|
||||
{
|
||||
// TODO
|
||||
// Partial implementation only returns data for the first imageRep in the array
|
||||
// and only works for NSBitmapImageRep or subclasses thereof.
|
||||
//FIXME: This only outputs one of the ImageReps
|
||||
NSEnumerator *enumerator = [imageReps objectEnumerator];
|
||||
NSImageRep *rep;
|
||||
|
||||
while ((rep = [enumerator nextObject]) != nil)
|
||||
{
|
||||
if ([rep isKindOfClass: self])
|
||||
{
|
||||
return [(NSBitmapImageRep*)rep representationUsingType: storageType
|
||||
properties: properties];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)representationUsingType:(NSBitmapImageFileType)storageType
|
||||
properties:(NSDictionary *)properties
|
||||
{
|
||||
// TODO
|
||||
// if it exists, the passed in properties takes precedence over the internal _properties
|
||||
NSDictionary * __properties;
|
||||
__properties = (properties)? properties : (NSDictionary *)_properties;
|
||||
|
||||
switch (storageType)
|
||||
{
|
||||
case NSTIFFFileType:
|
||||
{
|
||||
NSNumber * property;
|
||||
float factor = _comp_factor;
|
||||
NSTIFFCompression compression = _compression;
|
||||
if ((property = [__properties objectForKey: NSImageCompressionMethod]))
|
||||
compression = [property unsignedShortValue];
|
||||
if ((property = [__properties objectForKey: NSImageCompressionFactor]))
|
||||
factor = [property floatValue];
|
||||
if ([self canBeCompressedUsing: compression] == NO)
|
||||
{
|
||||
factor = 0.0;
|
||||
compression = NSTIFFCompressionNone;
|
||||
}
|
||||
return [self TIFFRepresentationUsingCompression: compression factor: factor];
|
||||
}
|
||||
|
||||
case NSBMPFileType:
|
||||
NSLog(@"BMP representation is not yet implemented");
|
||||
return nil;
|
||||
|
||||
case NSGIFFileType:
|
||||
return [self _GIFRepresentationWithProperties: __properties
|
||||
errorMessage: NULL];
|
||||
|
||||
case NSJPEGFileType:
|
||||
return [self _JPEGRepresentationWithProperties: __properties
|
||||
errorMessage: NULL];
|
||||
|
||||
case NSPNGFileType:
|
||||
return [self _PNGRepresentationWithProperties: __properties];
|
||||
|
||||
case NSJPEG2000FileType:
|
||||
NSLog(@"JPEG2000 representation is not yet implemented");
|
||||
return nil;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
// Setting and Checking Compression Types
|
||||
//
|
||||
/** Returns a C-array of available TIFF compression types.
|
||||
*/
|
||||
+ (void) getTIFFCompressionTypes: (const NSTIFFCompression **)list
|
||||
count: (int *)numTypes
|
||||
{
|
||||
// the GNUstep supported types
|
||||
static NSTIFFCompression types[] = {
|
||||
NSTIFFCompressionNone,
|
||||
NSTIFFCompressionCCITTFAX3,
|
||||
|
@ -817,11 +872,22 @@ static BOOL supports_lzw_compression = NO;
|
|||
NSTIFFCompressionPackBits,
|
||||
NSTIFFCompressionOldJPEG
|
||||
};
|
||||
|
||||
|
||||
// check with libtiff to see what is really available
|
||||
int i, j;
|
||||
static NSTIFFCompression checkedTypes[8];
|
||||
for (i = 0, j = 0; i < 8; i++)
|
||||
{
|
||||
if (NSTiffIsCodecConfigured([NSBitmapImageRep _localFromCompressionType: types[i]]))
|
||||
{
|
||||
checkedTypes[j] = types[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (list)
|
||||
*list = types;
|
||||
*list = checkedTypes;
|
||||
if (numTypes)
|
||||
*numTypes = sizeof(types)/sizeof(*types);
|
||||
*numTypes = j;
|
||||
}
|
||||
|
||||
+ (NSString*) localizedNameForTIFFCompressionType: (NSTIFFCompression)type
|
||||
|
@ -845,30 +911,26 @@ static BOOL supports_lzw_compression = NO;
|
|||
- (BOOL) canBeCompressedUsing: (NSTIFFCompression)compression
|
||||
{
|
||||
BOOL does;
|
||||
int codecConf =
|
||||
NSTiffIsCodecConfigured([NSBitmapImageRep _localFromCompressionType: compression]);
|
||||
switch (compression)
|
||||
{
|
||||
case NSTIFFCompressionCCITTFAX3:
|
||||
case NSTIFFCompressionCCITTFAX4:
|
||||
if (_numColors == 1 && _bitsPerSample == 1)
|
||||
if (_numColors == 1 && _bitsPerSample == 1 && codecConf != 0)
|
||||
does = YES;
|
||||
else
|
||||
does = NO;
|
||||
break;
|
||||
|
||||
case NSTIFFCompressionLZW:
|
||||
does = supports_lzw_compression;
|
||||
break;
|
||||
|
||||
case NSTIFFCompressionNone:
|
||||
case NSTIFFCompressionJPEG:
|
||||
case NSTIFFCompressionJPEG: // this is a GNUstep extension; Cocoa does not support
|
||||
case NSTIFFCompressionPackBits:
|
||||
case NSTIFFCompressionOldJPEG:
|
||||
does = YES;
|
||||
break;
|
||||
|
||||
case NSTIFFCompressionNEXT:
|
||||
default:
|
||||
does = NO;
|
||||
does = (codecConf != 0);
|
||||
}
|
||||
return does;
|
||||
}
|
||||
|
@ -894,13 +956,19 @@ static BOOL supports_lzw_compression = NO;
|
|||
|
||||
- (void)setProperty:(NSString *)property withValue:(id)value
|
||||
{
|
||||
// TODO
|
||||
if (value)
|
||||
{
|
||||
[_properties setObject: value forKey: property];
|
||||
}
|
||||
else // clear the property
|
||||
{
|
||||
[_properties removeObjectForKey: property];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)valueForProperty:(NSString *)property
|
||||
{
|
||||
// TODO
|
||||
return nil;
|
||||
return [_properties objectForKey: property];
|
||||
}
|
||||
|
||||
// NSCopying protocol
|
||||
|
@ -978,7 +1046,7 @@ static BOOL supports_lzw_compression = NO;
|
|||
|
||||
@implementation NSBitmapImageRep (GSPrivate)
|
||||
|
||||
- (int) _localFromCompressionType: (NSTIFFCompression)type
|
||||
+ (int) _localFromCompressionType: (NSTIFFCompression)type
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -996,7 +1064,7 @@ static BOOL supports_lzw_compression = NO;
|
|||
return COMPRESSION_NONE;
|
||||
}
|
||||
|
||||
- (NSTIFFCompression) _compressionTypeFromLocal: (int)type
|
||||
+ (NSTIFFCompression) _compressionTypeFromLocal: (int)type
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -1057,9 +1125,15 @@ static BOOL supports_lzw_compression = NO;
|
|||
colorSpaceName: space
|
||||
bytesPerRow: 0
|
||||
bitsPerPixel: 0];
|
||||
_compression = [self _compressionTypeFromLocal: info->compression];
|
||||
_compression = [NSBitmapImageRep _compressionTypeFromLocal: info->compression];
|
||||
_comp_factor = 255 * (1 - ((float)info->quality)/100.0);
|
||||
|
||||
// Note that Cocoa does not do this, even though the docs say it should
|
||||
[_properties setObject: [NSNumber numberWithUnsignedShort: _compression]
|
||||
forKey: NSImageCompressionMethod];
|
||||
[_properties setObject: [NSNumber numberWithFloat: _comp_factor]
|
||||
forKey: NSImageCompressionFactor];
|
||||
|
||||
if (NSTiffRead(image, info, [self bitmapData]))
|
||||
{
|
||||
OBJC_FREE(info);
|
||||
|
|
|
@ -96,6 +96,22 @@ NSString *NSApplicationWillResignActiveNotification
|
|||
NSString *NSApplicationWillUnhideNotification = @"ApplicationWillUnhide";
|
||||
NSString *NSApplicationWillUpdateNotification = @"ApplicationWillUpdate";
|
||||
|
||||
// NSBitmapImageRep Global strings
|
||||
NSString *NSImageCompressionMethod = @"NSImageCompressionMethod";
|
||||
NSString *NSImageCompressionFactor = @"NSImageCompressionFactor";
|
||||
NSString *NSImageDitherTransparency = @"NSImageDitherTransparency";
|
||||
NSString *NSImageRGBColorTable = @"NSImageRGBColorTable";
|
||||
NSString *NSImageInterlaced = @"NSImageInterlaced";
|
||||
//NSString *NSImageColorSyncProfileData = @"NSImageColorSyncProfileData"; // Mac OS X only
|
||||
//NSString *GSImageICCProfileData = @"GSImageICCProfileData"; // if & when GNUstep supports color management
|
||||
NSString *NSImageFrameCount = @"NSImageFrameCount";
|
||||
NSString *NSImageCurrentFrame = @"NSImageCurrentFrame";
|
||||
NSString *NSImageCurrentFrameDuration = @"NSImageCurrentFrameDuration";
|
||||
NSString *NSImageLoopCount = @"NSImageLoopCount";
|
||||
NSString *NSImageGamma = @"NSImageGamma";
|
||||
NSString *NSImageProgressive = @"NSImageProgressive";
|
||||
//NSString *NSImageEXIFData = @"NSImageEXIFData"; // No support yet in GNUstep
|
||||
|
||||
// NSColor Global strings
|
||||
NSString *NSCalibratedWhiteColorSpace = @"NSCalibratedWhiteColorSpace";
|
||||
NSString *NSCalibratedBlackColorSpace = @"NSCalibratedBlackColorSpace";
|
||||
|
|
|
@ -75,5 +75,7 @@ extern NSTiffInfo* NSTiffGetInfo(int imageNumber, TIFF* image);
|
|||
|
||||
extern NSTiffColormap* NSTiffGetColormap(TIFF* image);
|
||||
|
||||
extern int NSTiffIsCodecConfigured(unsigned int codec);
|
||||
|
||||
#endif // _GNUstep_H_tiff
|
||||
|
||||
|
|
|
@ -585,4 +585,60 @@ NSTiffGetColormap(TIFF* image)
|
|||
return map;
|
||||
}
|
||||
|
||||
int NSTiffIsCodecConfigured(unsigned int codec)
|
||||
{
|
||||
#if (TIFFLIB_VERSION >= 20041016)
|
||||
// starting with version 3.7.0 we can ask libtiff what it is configured to do
|
||||
return TIFFIsCODECConfigured(codec);
|
||||
#else
|
||||
// we check the tiffconf.h
|
||||
#include <tiffconf.h>
|
||||
#ifndef CCITT_SUPPORT
|
||||
# define CCITT_SUPPORT 0
|
||||
#else
|
||||
# define CCITT_SUPPORT 1
|
||||
#endif
|
||||
#ifndef PACKBITS_SUPPORT
|
||||
# define PACKBITS_SUPPORT 0
|
||||
#else
|
||||
# define PACKBITS_SUPPORT 1
|
||||
#endif
|
||||
#ifndef OJPEG_SUPPORT
|
||||
# define OJPEG_SUPPORT 0
|
||||
#else
|
||||
# define OJPEG_SUPPORT 1
|
||||
#endif
|
||||
#ifndef LZW_SUPPORT
|
||||
# define LZW_SUPPORT 0
|
||||
#else
|
||||
# define LZW_SUPPORT 1
|
||||
#endif
|
||||
#ifndef NEXT_SUPPORT
|
||||
# define NEXT_SUPPORT 0
|
||||
#else
|
||||
# define NEXT_SUPPORT 1
|
||||
#endif
|
||||
#ifndef JPEG_SUPPORT
|
||||
# define JPEG_SUPPORT 0
|
||||
#else
|
||||
# define JPEG_SUPPORT 1
|
||||
#endif
|
||||
/* If this fails, your libtiff is obsolete! Come to think of it
|
||||
* if you even are compiling this part your libtiff is obsolete. */
|
||||
switch (codec)
|
||||
{
|
||||
case COMPRESSION_NONE: return 1;
|
||||
case COMPRESSION_CCITTFAX3: return CCITT_SUPPORT;
|
||||
case COMPRESSION_CCITTFAX4: return CCITT_SUPPORT;
|
||||
case COMPRESSION_JPEG: return JPEG_SUPPORT;
|
||||
case COMPRESSION_PACKBITS: return PACKBITS_SUPPORT;
|
||||
case COMPRESSION_OJPEG: return OJPEG_SUPPORT;
|
||||
case COMPRESSION_LZW: return LZW_SUPPORT;
|
||||
case COMPRESSION_NEXT: return NEXT_SUPPORT;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue