/* NSBitmapImageRep+PNG.m Methods for loading .png images. Copyright (C) 2003-2011 Free Software Foundation, Inc. Written by: Alexander Malmberg Date: 2003-12-07 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, see or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #import "config.h" /* we include PNG stuff only if required and before the resto to avoid header and redeclaration problems (setjmp, etc) */ #ifdef HAVE_LIBPNG #include #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 #endif /* HAVE_LIBPNG */ /* we import all the standard headers to allow compilation without PNG */ #import #import #import #import #import #import "AppKit/NSGraphics.h" #import "NSBitmapImageRep+PNG.h" #ifdef HAVE_LIBPNG @implementation NSBitmapImageRep (PNG) + (BOOL) _bitmapIsPNG: (NSData *)imageData { if (![imageData length]) return NO; if (!png_sig_cmp((png_bytep)[imageData bytes], 0, [imageData length])) return YES; return NO; } typedef struct { NSData *data; unsigned int offset; } reader_struct_t; static void reader_func(png_structp png_struct, png_bytep data, png_size_t length) { reader_struct_t *r = png_get_io_ptr(png_struct); if (r->offset + length > [r->data length]) { png_error(png_struct, "end of buffer"); return; } memcpy(data, [r->data bytes] + r->offset, length); r->offset += length; } - (id) _initBitmapFromPNG: (NSData *)imageData { png_structp png_struct; png_infop png_info, png_end_info; int width,height; unsigned char *buf; int bytes_per_row; int type,channels,depth; BOOL alpha; int bpp; NSString *colorspace; reader_struct_t reader; if (!(self = [super init])) return nil; png_struct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_struct) { RELEASE(self); return nil; } png_info = png_create_info_struct(png_struct); if (!png_info) { png_destroy_read_struct(&png_struct, NULL, NULL); RELEASE(self); return nil; } png_end_info = png_create_info_struct(png_struct); if (!png_end_info) { png_destroy_read_struct(&png_struct, &png_info, NULL); RELEASE(self); return nil; } if (setjmp(png_jmpbuf(png_struct))) { png_destroy_read_struct(&png_struct, &png_info, &png_end_info); RELEASE(self); return nil; } reader.data = imageData; reader.offset = 0; png_set_read_fn(png_struct, &reader, reader_func); png_read_info(png_struct, png_info); width = png_get_image_width(png_struct, png_info); height = png_get_image_height(png_struct, png_info); bytes_per_row = png_get_rowbytes(png_struct, png_info); type = png_get_color_type(png_struct, png_info); channels = png_get_channels(png_struct, png_info); depth = png_get_bit_depth(png_struct, png_info); switch (type) { case PNG_COLOR_TYPE_GRAY: colorspace = NSCalibratedWhiteColorSpace; alpha = NO; NSAssert(channels == 1, @"unexpected channel/color_type combination"); bpp = depth; break; case PNG_COLOR_TYPE_GRAY_ALPHA: colorspace = NSCalibratedWhiteColorSpace; alpha = YES; NSAssert(channels == 2, @"unexpected channel/color_type combination"); bpp = depth * 2; break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_struct); channels = 3; depth = 8; alpha = NO; if (png_get_valid(png_struct, png_info, PNG_INFO_tRNS)) { alpha = YES; channels++; png_set_tRNS_to_alpha(png_struct); } bpp = channels * 8; bytes_per_row = channels * width; colorspace = NSCalibratedRGBColorSpace; break; case PNG_COLOR_TYPE_RGB: colorspace = NSCalibratedRGBColorSpace; alpha = NO; bpp = channels * depth; /* channels might be 4 if there's a filler */ channels = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: colorspace = NSCalibratedRGBColorSpace; alpha = YES; NSAssert(channels == 4, @"unexpected channel/color_type combination"); bpp = 4 * depth; break; default: NSLog(@"NSBitmapImageRep+PNG: unknown color type %i", type); RELEASE(self); return nil; } buf = NSZoneMalloc([self zone], bytes_per_row * height); { unsigned char *row_pointers[height]; int i; for (i=0;i