Blender  V2.59
imbuf_cocoa.m
Go to the documentation of this file.
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 }