Blender V2.61 - r43446

imbuf_cocoa.m

Go to the documentation of this file.
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 }