This is MiscPNGDecoder.m in view mode; [Download] [Up]
/* MiscPNGDecoder.m Copyright 1996 Uwe Hoffmann. This notice may not be removed from this source code. The use and distribution of this software is governed by the terms of the MiscKit license agreement. Refer to the license document included with the MiscKit distribution for the terms. */ #import <AppKit/AppKit.h> #import "MiscPNGDecoder.h" #ifdef VERBOSE #undef VERBOSE #undef METHOD #undef METHODnl #endif #define VERBOSE if(_SDFlags.verboseMode) #define METHOD NSLog(@"[%@ %s%@] ", \ [[self class] description], \ (self == (id)[self class]) ? "+" : "-", \ NSStringFromSelector(_cmd)) #define METHODnl NSLog(@"[%@ %s%@]\n", \ [[self class] description], \ (self == (id)[self class]) ? "+" : "-", \ NSStringFromSelector(_cmd)) void misc_read_png_data(png_structp png_ptr, png_bytep data, png_uint_32 length) { NSRange range; unsigned int nbytes; MiscPNGSource *src_ptr; src_ptr = (MiscPNGSource *)png_get_io_ptr(png_ptr); if(src_ptr->bytesRead < src_ptr->infileLength){ nbytes = MIN(length, src_ptr->infileLength - src_ptr->bytesRead); range = NSMakeRange(src_ptr->bytesRead, nbytes); [src_ptr->infile getBytes:data range:range]; } else nbytes = 0; src_ptr->bytesRead += nbytes; } void misc_png_error_fn(png_structp png_ptr, png_const_charp error_msg) { MiscPNGError *error; error = (MiscPNGError *)png_get_error_ptr(png_ptr); [error->decoder setLastImageCorrupt:YES]; [error->decoder spewMessage:[NSString stringWithCString:error_msg] withSeverity:MiscDecoderSeverityFailure]; longjmp(error->setjmp_buffer, 1); // bounce to setjmp() point } void misc_png_warning_fn(png_structp png_ptr, png_const_charp warning_msg) { MiscPNGError *error; error = (MiscPNGError *)png_get_error_ptr(png_ptr); [error->decoder spewMessage:[NSString stringWithCString:warning_msg] withSeverity:MiscDecoderSeverityNotice]; } @implementation MiscPNGDecoder /*" This class implements the internals of the PNG decoder. It basically provides an interface between the #{MiscDecoder} API and the libpng API. "*/ + sharedInstance { static id sharedInstance = nil; if(!sharedInstance) sharedInstance = [[self alloc] init]; return sharedInstance; } + (NSArray *)imageUnfilteredFileTypes; { return [NSArray arrayWithObjects: @"png", @"PNG", nil]; } + (BOOL)canInitWithData:(NSData *)data { unsigned char header[8]; NSParameterAssert(data); if([data length] < 8) return NO; [data getBytes:header length:8]; return png_check_sig(header,8); } - init { [super init]; error.decoder = self; rows = NULL; png_ptr = NULL; info_ptr = NULL; end_info = NULL; return self; } - (NSBitmapImageRep *)_internalDecodeImage { NSBitmapImageRep *imageRep; char *data; int i; VERBOSE { METHODnl; } if(info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && info_ptr->bit_depth < 8) || (info_ptr->valid & PNG_INFO_tRNS)){ png_set_expand(png_ptr); png_read_update_info(png_ptr, info_ptr); } if(info_ptr->bit_depth == 16){ png_set_strip_16(png_ptr); png_read_update_info(png_ptr, info_ptr); } VERBOSE { NSLog(@"pixelsWide:%d",info_ptr->width); NSLog(@"pixelsHigh:%d",info_ptr->height); NSLog(@"bitsPerSample:%d",info_ptr->bit_depth); NSLog(@"samplesPerPixel:%d",info_ptr->channels); if(info_ptr->color_type & PNG_COLOR_MASK_ALPHA) NSLog(@"hasAlpha:YES"); else NSLog(@"hasAlpha:NO"); if(info_ptr->color_type & PNG_COLOR_MASK_COLOR) NSLog(@"colorSpaceName:NSCalibratedRGBColorSpace"); else NSLog(@"colorSpaceName:NSCalibratedWhiteColorSpace"); NSLog(@"bytesPerRow:%d",info_ptr->rowbytes); NSLog(@"bitsPerPixel:%d",info_ptr->pixel_depth); } imageRep = [[[NSBitmapImageRep allocWithZone:[self zone]] initWithBitmapDataPlanes:NULL pixelsWide:info_ptr->width pixelsHigh:info_ptr->height bitsPerSample:info_ptr->bit_depth samplesPerPixel:info_ptr->channels hasAlpha: (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) ? YES:NO isPlanar:NO colorSpaceName: (info_ptr->color_type & PNG_COLOR_MASK_COLOR) ? NSCalibratedRGBColorSpace:NSCalibratedWhiteColorSpace bytesPerRow:info_ptr->rowbytes bitsPerPixel:info_ptr->pixel_depth] autorelease]; if(!imageRep) { VERBOSE { METHOD; NSLog(@"Failed to allocate imageRep.\n"); } return nil; } data = [imageRep bitmapData]; rows = (char **)NSZoneMalloc([self zone], info_ptr->height * sizeof(char *)); for(i = 0; i < info_ptr->height; i++) rows[i] = (char *)(data + info_ptr->rowbytes * i); png_read_image(png_ptr, (png_bytep *)rows); NSZoneFree([self zone], rows); rows = NULL; return imageRep; } - (NSBitmapImageRep *)decodeFromData:(NSData *)data { NSBitmapImageRep *pngRep; _SDFlags.lastCorrupt = NO; if(![[self class] canInitWithData:data]) { VERBOSE { METHOD; NSLog(@"+canInitWithData: returned NO"); } _SDFlags.lastCorrupt = YES; return nil; } else VERBOSE { METHOD; NSLog(@"Data validated"); } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void *)&error, misc_png_error_fn, misc_png_warning_fn); if(!png_ptr) return nil; info_ptr = png_create_info_struct(png_ptr); if(!info_ptr){ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return nil; } end_info = png_create_info_struct(png_ptr); if(!end_info){ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return nil; } png_set_read_fn(png_ptr, (void *)&source, misc_read_png_data); source.infile = data; source.bytesRead = 0; source.infileLength = [data length]; if(setjmp(error.setjmp_buffer)){ _SDFlags.lastCorrupt = YES; if(rows) NSZoneFree([self zone], rows); return nil; } png_read_info(png_ptr, info_ptr); // decode image pngRep = [self _internalDecodeImage]; png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); VERBOSE { METHOD; NSLog(@"Image was %s corrupted.", _SDFlags.lastCorrupt ? "" : "not"); } return pngRep; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.