|
Blender
V2.59
|
00001 /* 00002 * imbuf_coca.m 00003 * 00004 * $Id: imbuf_cocoa.m 32541 2010-10-17 18:56:36Z jesterking $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * Contributor(s): Damien Plisson 10/2009 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 */ 00026 00032 #include <stdint.h> 00033 #include <string.h> 00034 #import <Cocoa/Cocoa.h> 00035 00036 #include "imbuf.h" 00037 00038 #include "IMB_cocoa.h" 00039 00040 #include "BKE_global.h" 00041 #include "BKE_colortools.h" 00042 00043 #include "IMB_imbuf_types.h" 00044 #include "IMB_imbuf.h" 00045 00046 #include "IMB_allocimbuf.h" 00047 00048 00049 00050 #pragma mark load/save functions 00051 00065 struct ImBuf *imb_cocoaLoadImage(unsigned char *mem, int size, int flags) 00066 { 00067 struct ImBuf *ibuf = NULL; 00068 NSSize bitmapSize; 00069 uchar *rasterRGB = NULL; 00070 uchar *rasterRGBA = NULL; 00071 uchar *toIBuf = NULL; 00072 int x, y, to_i, from_i; 00073 NSData *data; 00074 NSBitmapImageRep *bitmapImage; 00075 NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA; 00076 NSAutoreleasePool *pool; 00077 00078 pool = [[NSAutoreleasePool alloc] init]; 00079 00080 data = [NSData dataWithBytes:mem length:size]; 00081 bitmapImage = [[NSBitmapImageRep alloc] initWithData:data]; 00082 00083 if (!bitmapImage) { 00084 fprintf(stderr, "imb_cocoaLoadImage: error loading image\n"); 00085 [pool drain]; 00086 return NULL; 00087 } 00088 00089 bitmapSize.width = [bitmapImage pixelsWide]; 00090 bitmapSize.height = [bitmapImage pixelsHigh]; 00091 00092 /* Tell cocoa image resolution is same as current system one */ 00093 [bitmapImage setSize:bitmapSize]; 00094 00095 /* allocate the image buffer */ 00096 ibuf = IMB_allocImBuf(bitmapSize.width, bitmapSize.height, 32/*RGBA*/, 0); 00097 if (!ibuf) { 00098 fprintf(stderr, 00099 "imb_cocoaLoadImage: could not allocate memory for the " \ 00100 "image.\n"); 00101 [bitmapImage release]; 00102 [pool drain]; 00103 return NULL; 00104 } 00105 00106 /* read in the image data */ 00107 if (!(flags & IB_test)) { 00108 00109 /* allocate memory for the ibuf->rect */ 00110 imb_addrectImBuf(ibuf); 00111 00112 /* Convert the image in a RGBA 32bit format */ 00113 /* As Core Graphics does not support contextes with non premutliplied alpha, 00114 we need to get alpha key values in a separate batch */ 00115 00116 /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */ 00117 blBitmapFormatImageRGB = /*RGB format padded to 32bits*/[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 00118 pixelsWide:bitmapSize.width 00119 pixelsHigh:bitmapSize.height 00120 bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO 00121 colorSpaceName:NSCalibratedRGBColorSpace 00122 bitmapFormat:0 00123 bytesPerRow:4*bitmapSize.width 00124 bitsPerPixel:32]; 00125 00126 [NSGraphicsContext saveGraphicsState]; 00127 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]]; 00128 [bitmapImage draw]; 00129 [NSGraphicsContext restoreGraphicsState]; 00130 00131 rasterRGB = (uchar*)[blBitmapFormatImageRGB bitmapData]; 00132 if (rasterRGB == NULL) { 00133 [bitmapImage release]; 00134 [blBitmapFormatImageRGB release]; 00135 [pool drain]; 00136 return NULL; 00137 } 00138 00139 /* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */ 00140 blBitmapFormatImageRGBA = /* RGBA */[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 00141 pixelsWide:bitmapSize.width 00142 pixelsHigh:bitmapSize.height 00143 bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO 00144 colorSpaceName:NSCalibratedRGBColorSpace 00145 bitmapFormat:0 00146 bytesPerRow:4*bitmapSize.width 00147 bitsPerPixel:32]; 00148 00149 [NSGraphicsContext saveGraphicsState]; 00150 [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]]; 00151 [bitmapImage draw]; 00152 [NSGraphicsContext restoreGraphicsState]; 00153 00154 rasterRGBA = (uchar*)[blBitmapFormatImageRGBA bitmapData]; 00155 if (rasterRGBA == NULL) { 00156 [bitmapImage release]; 00157 [blBitmapFormatImageRGB release]; 00158 [blBitmapFormatImageRGBA release]; 00159 [pool drain]; 00160 return NULL; 00161 } 00162 00163 /*Copy the image to ibuf, flipping it vertically*/ 00164 toIBuf = (uchar*)ibuf->rect; 00165 for (x = 0; x < bitmapSize.width; x++) { 00166 for (y = 0; y < bitmapSize.height; y++) { 00167 to_i = (bitmapSize.height-y-1)*bitmapSize.width + x; 00168 from_i = y*bitmapSize.width + x; 00169 00170 toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */ 00171 toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */ 00172 toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */ 00173 toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */ 00174 } 00175 } 00176 00177 [blBitmapFormatImageRGB release]; 00178 [blBitmapFormatImageRGBA release]; 00179 } 00180 00181 /* release the cocoa objects */ 00182 [bitmapImage release]; 00183 [pool drain]; 00184 00185 if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); 00186 00187 ibuf->ftype = TIF; 00188 ibuf->profile = IB_PROFILE_SRGB; 00189 00190 /* return successfully */ 00191 return (ibuf); 00192 } 00193 00209 #define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f)) 00210 00211 short imb_cocoaSaveImage(struct ImBuf *ibuf, char *name, int flags) 00212 { 00213 uint16_t samplesperpixel, bitspersample; 00214 unsigned char *from = NULL, *to = NULL; 00215 unsigned short *to16 = NULL; 00216 float *fromf = NULL; 00217 int x, y, from_i, to_i, i; 00218 int success; 00219 BOOL hasAlpha; 00220 NSString* colorSpace; 00221 NSBitmapImageRep *blBitmapFormatImage; 00222 NSData *dataToWrite; 00223 NSDictionary *imageProperties; 00224 00225 NSAutoreleasePool *pool; 00226 00227 if (!ibuf) return FALSE; 00228 if (!name) return FALSE; 00229 00230 /* check for a valid number of bytes per pixel. Like the PNG writer, 00231 * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding 00232 * to gray, RGB, RGBA respectively. */ 00233 samplesperpixel = (uint16_t)((ibuf->depth + 7) >> 3); 00234 switch (samplesperpixel) { 00235 case 4: /*RGBA type*/ 00236 hasAlpha = YES; 00237 colorSpace = NSCalibratedRGBColorSpace; 00238 break; 00239 case 3: /*RGB type*/ 00240 hasAlpha = NO; 00241 colorSpace = NSCalibratedRGBColorSpace; 00242 break; 00243 case 1: 00244 hasAlpha = NO; 00245 colorSpace = NSCalibratedWhiteColorSpace; 00246 break; 00247 default: 00248 fprintf(stderr, 00249 "imb_cocoaSaveImage: unsupported number of bytes per " 00250 "pixel: %d\n", samplesperpixel); 00251 return (0); 00252 } 00253 00254 if((ibuf->ftype & TIF_16BIT) && ibuf->rect_float) 00255 bitspersample = 16; 00256 else 00257 bitspersample = 8; 00258 00259 pool = [[NSAutoreleasePool alloc] init]; 00260 00261 /* Create bitmap image rep in blender format */ 00262 blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 00263 pixelsWide:ibuf->x 00264 pixelsHigh:ibuf->y 00265 bitsPerSample:bitspersample samplesPerPixel:samplesperpixel hasAlpha:hasAlpha isPlanar:NO 00266 colorSpaceName:colorSpace 00267 bitmapFormat:NSAlphaNonpremultipliedBitmapFormat 00268 bytesPerRow:(ibuf->x*bitspersample*samplesperpixel/8) 00269 bitsPerPixel:(bitspersample*samplesperpixel)]; 00270 if (!blBitmapFormatImage) { 00271 [pool drain]; 00272 return FALSE; 00273 } 00274 00275 /* setup pointers */ 00276 if(bitspersample == 16) { 00277 fromf = ibuf->rect_float; 00278 to16 = (unsigned short*)[blBitmapFormatImage bitmapData]; 00279 } 00280 else { 00281 from = (unsigned char*)ibuf->rect; 00282 to = (unsigned char*)[blBitmapFormatImage bitmapData]; 00283 } 00284 00285 /* copy pixel data. While copying, we flip the image vertically. */ 00286 for (x = 0; x < ibuf->x; x++) { 00287 for (y = 0; y < ibuf->y; y++) { 00288 from_i = 4*(y*ibuf->x+x); 00289 to_i = samplesperpixel*((ibuf->y-y-1)*ibuf->x+x); 00290 00291 if(bitspersample == 16) { 00292 if (ibuf->profile == IB_PROFILE_SRGB) { 00293 switch (samplesperpixel) { 00294 case 4 /*RGBA*/: 00295 to16[to_i] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i])); 00296 to16[to_i+1] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+1])); 00297 to16[to_i+2] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+2])); 00298 to16[to_i+3] = FTOUSHORT(fromf[from_i+3]); 00299 break; 00300 case 3 /*RGB*/: 00301 to16[to_i] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i])); 00302 to16[to_i+1] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+1])); 00303 to16[to_i+2] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+2])); 00304 break; 00305 case 1 /*BW*/: 00306 to16[to_i] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i])); 00307 break; 00308 } 00309 } 00310 else { 00311 for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) 00312 to16[to_i] = FTOUSHORT(fromf[from_i]); 00313 } 00314 } 00315 else { 00316 /* 8bits per sample*/ 00317 for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) 00318 to[to_i] = from[from_i]; 00319 } 00320 } 00321 } 00322 00323 /* generate file data */ 00324 if (IS_tiff(ibuf)) { 00325 dataToWrite = [blBitmapFormatImage TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0]; 00326 } 00327 else if (IS_png(ibuf)) { 00328 imageProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:false], NSImageInterlaced, 00329 nil]; 00330 dataToWrite = [blBitmapFormatImage representationUsingType:NSPNGFileType properties:imageProperties]; 00331 } 00332 else if (IS_bmp(ibuf)) { 00333 dataToWrite = [blBitmapFormatImage representationUsingType:NSBMPFileType properties:nil]; 00334 } 00335 else {/* JPEG by default */ 00336 int quality; 00337 00338 quality = ibuf->ftype & 0xff; 00339 if (quality <= 0) quality = 90; /* Standard quality if wrong supplied*/ 00340 if (quality > 100) quality = 100; 00341 00342 imageProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithFloat:quality], NSImageCompressionFactor, 00343 [NSNumber numberWithBool:true], NSImageProgressive, 00344 nil]; 00345 dataToWrite = [blBitmapFormatImage representationUsingType:NSJPEGFileType properties:imageProperties]; 00346 } 00347 00348 /* Write the file */ 00349 success = [dataToWrite writeToFile:[NSString stringWithCString:name encoding:NSISOLatin1StringEncoding] 00350 atomically:YES]; 00351 00352 [blBitmapFormatImage release]; 00353 [pool drain]; 00354 00355 return success; 00356 } 00357 00358 #pragma mark format checking functions 00359 00360 /* Currently, only tiff format is handled, so need to include here function that was previously in tiff.c */ 00361 00380 #define IMB_TIFF_NCB 4 /* number of comparison bytes used */ 00381 int imb_is_a_tiff(void *mem) 00382 { 00383 char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a }; 00384 char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 }; 00385 00386 return ( (memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) || 00387 (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) ); 00388 }