This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/imbuf/intern/imbuf_cocoa.m
Campbell Barton 7bbf4b7831 style cleanup
- spelling - turns out we had tessellation spelt wrong all over.
- use \directive for doxy (not @directive)
- remove BLI_sparsemap.h - was from bmesh merge IIRC but entire file commented and not used.
2012-03-02 16:05:54 +00:00

387 lines
12 KiB
Objective-C

/*
* imbuf_coca.m
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Damien Plisson 10/2009
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* Provides image file loading and saving for Blender, via Cocoa.
*
*/
#include <stdint.h>
#include <string.h>
#import <Cocoa/Cocoa.h>
#include "imbuf.h"
#include "IMB_cocoa.h"
#include "BKE_global.h"
#include "BKE_colortools.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_allocimbuf.h"
#pragma mark load/save functions
/**
* Loads an image from the supplied buffer
*
* Loads any Core Graphics supported type
* Currently is : TIFF, BMP, JPEG, GIF, PNG, DIB, ICO, and various RAW formats
*
* \param mem: Memory containing the bitmap image
* \param size: Size of the mem buffer.
* \param flags: If flags has IB_test set then the file is not actually loaded,
* but all other operations take place.
*
* \return: A newly allocated ImBuf structure if successful, otherwise NULL.
*/
struct ImBuf *imb_cocoaLoadImage(unsigned char *mem, int size, int flags)
{
struct ImBuf *ibuf = NULL;
NSSize bitmapSize;
uchar *rasterRGB = NULL;
uchar *rasterRGBA = NULL;
uchar *toIBuf = NULL;
int x, y, to_i, from_i;
NSData *data;
NSBitmapImageRep *bitmapImage;
NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA;
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
data = [NSData dataWithBytes:mem length:size];
bitmapImage = [[NSBitmapImageRep alloc] initWithData:data];
if (!bitmapImage) {
fprintf(stderr, "imb_cocoaLoadImage: error loading image\n");
[pool drain];
return NULL;
}
bitmapSize.width = [bitmapImage pixelsWide];
bitmapSize.height = [bitmapImage pixelsHigh];
/* Tell cocoa image resolution is same as current system one */
[bitmapImage setSize:bitmapSize];
/* allocate the image buffer */
ibuf = IMB_allocImBuf(bitmapSize.width, bitmapSize.height, 32/*RGBA*/, 0);
if (!ibuf) {
fprintf(stderr,
"imb_cocoaLoadImage: could not allocate memory for the " \
"image.\n");
[bitmapImage release];
[pool drain];
return NULL;
}
/* read in the image data */
if (!(flags & IB_test)) {
/* allocate memory for the ibuf->rect */
imb_addrectImBuf(ibuf);
/* Convert the image in a RGBA 32bit format */
/* As Core Graphics does not support contextes with non premutliplied alpha,
we need to get alpha key values in a separate batch */
/* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:bitmapSize.width
pixelsHigh:bitmapSize.height
bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:0
bytesPerRow:4*bitmapSize.width
bitsPerPixel:32/*RGB format padded to 32bits*/];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
[bitmapImage draw];
[NSGraphicsContext restoreGraphicsState];
rasterRGB = (uchar*)[blBitmapFormatImageRGB bitmapData];
if (rasterRGB == NULL) {
[bitmapImage release];
[blBitmapFormatImageRGB release];
[pool drain];
return NULL;
}
/* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */
blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:bitmapSize.width
pixelsHigh:bitmapSize.height
bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:0
bytesPerRow:4*bitmapSize.width
bitsPerPixel:32/* RGBA */];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
[bitmapImage draw];
[NSGraphicsContext restoreGraphicsState];
rasterRGBA = (uchar*)[blBitmapFormatImageRGBA bitmapData];
if (rasterRGBA == NULL) {
[bitmapImage release];
[blBitmapFormatImageRGB release];
[blBitmapFormatImageRGBA release];
[pool drain];
return NULL;
}
/*Copy the image to ibuf, flipping it vertically*/
toIBuf = (uchar*)ibuf->rect;
for (x = 0; x < bitmapSize.width; x++) {
for (y = 0; y < bitmapSize.height; y++) {
to_i = (bitmapSize.height-y-1)*bitmapSize.width + x;
from_i = y*bitmapSize.width + x;
toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */
toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */
toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */
toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */
}
}
[blBitmapFormatImageRGB release];
[blBitmapFormatImageRGBA release];
}
/* release the cocoa objects */
[bitmapImage release];
[pool drain];
if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
ibuf->ftype = TIF;
ibuf->profile = IB_PROFILE_SRGB;
/* return successfully */
return (ibuf);
}
/**
* Saves an image to a file.
*
* ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
* respectively) are accepted, and interpreted correctly.
*
* Accepted formats: TIFF, GIF, BMP, PNG, JPEG, JPEG2000
*
* \param ibuf: Image buffer.
* \param name: Name of the image file to create.
* \param flags: Currently largely ignored.
*
* \return: 1 if the function is successful, 0 on failure.
*/
#define FTOUSHORT(val) ((val >= 1.0f-0.5f/65535)? 65535: (val <= 0.0f)? 0: (unsigned short)(val*65535.0f + 0.5f))
short imb_cocoaSaveImage(struct ImBuf *ibuf, char *name, int flags)
{
uint16_t samplesperpixel, bitspersample;
unsigned char *from = NULL, *to = NULL;
unsigned short *to16 = NULL;
float *fromf = NULL;
int x, y, from_i, to_i, i;
int success;
BOOL hasAlpha;
NSString* colorSpace;
NSBitmapImageRep *blBitmapFormatImage;
NSData *dataToWrite;
NSDictionary *imageProperties;
NSAutoreleasePool *pool;
if (!ibuf) return FALSE;
if (!name) return FALSE;
/* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
* to gray, RGB, RGBA respectively. */
samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
switch (samplesperpixel) {
case 4: /*RGBA type*/
hasAlpha = YES;
colorSpace = NSCalibratedRGBColorSpace;
break;
case 3: /*RGB type*/
hasAlpha = NO;
colorSpace = NSCalibratedRGBColorSpace;
break;
case 1:
hasAlpha = NO;
colorSpace = NSCalibratedWhiteColorSpace;
break;
default:
fprintf(stderr,
"imb_cocoaSaveImage: unsupported number of bytes per "
"pixel: %d\n", samplesperpixel);
return (0);
}
if((ibuf->ftype & TIF_16BIT) && ibuf->rect_float)
bitspersample = 16;
else
bitspersample = 8;
pool = [[NSAutoreleasePool alloc] init];
/* Create bitmap image rep in blender format */
blBitmapFormatImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:ibuf->x
pixelsHigh:ibuf->y
bitsPerSample:bitspersample samplesPerPixel:samplesperpixel hasAlpha:hasAlpha isPlanar:NO
colorSpaceName:colorSpace
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
bytesPerRow:(ibuf->x*bitspersample*samplesperpixel/8)
bitsPerPixel:(bitspersample*samplesperpixel)];
if (!blBitmapFormatImage) {
[pool drain];
return FALSE;
}
/* setup pointers */
if(bitspersample == 16) {
fromf = ibuf->rect_float;
to16 = (unsigned short*)[blBitmapFormatImage bitmapData];
}
else {
from = (unsigned char*)ibuf->rect;
to = (unsigned char*)[blBitmapFormatImage bitmapData];
}
/* copy pixel data. While copying, we flip the image vertically. */
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
from_i = 4*(y*ibuf->x+x);
to_i = samplesperpixel*((ibuf->y-y-1)*ibuf->x+x);
if(bitspersample == 16) {
if (ibuf->profile == IB_PROFILE_SRGB) {
switch (samplesperpixel) {
case 4 /*RGBA*/:
to16[to_i] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i]));
to16[to_i+1] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+1]));
to16[to_i+2] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+2]));
to16[to_i+3] = FTOUSHORT(fromf[from_i+3]);
break;
case 3 /*RGB*/:
to16[to_i] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i]));
to16[to_i+1] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+1]));
to16[to_i+2] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i+2]));
break;
case 1 /*BW*/:
to16[to_i] = FTOUSHORT(linearrgb_to_srgb(fromf[from_i]));
break;
}
}
else {
for (i = 0; i < samplesperpixel; i++, to_i++, from_i++)
to16[to_i] = FTOUSHORT(fromf[from_i]);
}
}
else {
/* 8bits per sample*/
for (i = 0; i < samplesperpixel; i++, to_i++, from_i++)
to[to_i] = from[from_i];
}
}
}
/* generate file data */
if (IS_tiff(ibuf)) {
dataToWrite = [blBitmapFormatImage TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0];
}
else if (IS_png(ibuf)) {
imageProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:false], NSImageInterlaced,
nil];
dataToWrite = [blBitmapFormatImage representationUsingType:NSPNGFileType properties:imageProperties];
}
else if (IS_bmp(ibuf)) {
dataToWrite = [blBitmapFormatImage representationUsingType:NSBMPFileType properties:nil];
}
else {/* JPEG by default */
int quality;
quality = ibuf->ftype & 0xff;
if (quality <= 0) quality = 90; /* Standard quality if wrong supplied*/
if (quality > 100) quality = 100;
imageProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithFloat:quality], NSImageCompressionFactor,
[NSNumber numberWithBool:true], NSImageProgressive,
nil];
dataToWrite = [blBitmapFormatImage representationUsingType:NSJPEGFileType properties:imageProperties];
}
/* Write the file */
success = [dataToWrite writeToFile:[NSString stringWithCString:name encoding:NSISOLatin1StringEncoding]
atomically:YES];
[blBitmapFormatImage release];
[pool drain];
return success;
}
#pragma mark format checking functions
/* Currently, only tiff format is handled, so need to include here function that was previously in tiff.c */
/**
* Checks whether a given memory buffer contains a TIFF file.
*
* FIXME: Possible memory leak if mem is less than IMB_TIFF_NCB bytes long.
* However, changing this will require up-stream modifications.
*
* This method uses the format identifiers from:
* http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-9.html
* The first four bytes of big-endian and little-endian TIFF files
* respectively are (hex):
* 4d 4d 00 2a
* 49 49 2a 00
* Note that TIFF files on *any* platform can be either big- or little-endian;
* it's not platform-specific.
*
* AFAICT, libtiff doesn't provide a method to do this automatically, and
* hence my manual comparison. - Jonathan Merritt (lancelet) 4th Sept 2005.
*/
#define IMB_TIFF_NCB 4 /* number of comparison bytes used */
int imb_is_a_tiff(void *mem)
{
char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a };
char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 };
return ( (memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) ||
(memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) );
}