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