mirror of
https://github.com/darlinghq/darling-coregraphics.git
synced 2024-11-23 04:09:42 +00:00
Opal: work in progress on color management.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/opal/trunk@31052 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
b8237df007
commit
843c77be59
2
Resources/LICENSE
Normal file
2
Resources/LICENSE
Normal file
@ -0,0 +1,2 @@
|
||||
coated_FOGRA39L_argl.icc:
|
||||
Copyright (c) 2008 Kai-Uwe Behrmann - http://www.opensource.org/licenses/zlib-license.php
|
BIN
Resources/coated_FOGRA39L_argl.icc
Normal file
BIN
Resources/coated_FOGRA39L_argl.icc
Normal file
Binary file not shown.
40
Source/CGColor-private.h
Normal file
40
Source/CGColor-private.h
Normal file
@ -0,0 +1,40 @@
|
||||
/** <title>CGColor</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2006 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
Date: 2006
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CoreGraphics/CGColor.h"
|
||||
|
||||
@interface CGColor : NSObject
|
||||
{
|
||||
@public
|
||||
CGColorSpaceRef cspace;
|
||||
CGFloat *comps;
|
||||
CGPatternRef pattern;
|
||||
}
|
||||
|
||||
- (CGColor*) transformToColorSpace: (CGColorSpaceRef)space withRenderingIntent: (CGColorRenderingIntent)intent;
|
||||
|
||||
@end
|
||||
|
||||
CGColorRef OPColorGetTransformedToSpace(CGColorRef clr, CGColorSpaceRef space, CGColorRenderingIntent intent);
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include "CoreGraphics/CGContext.h"
|
||||
#include "CoreGraphics/CGColor.h"
|
||||
|
||||
#import "CGColor-private.h"
|
||||
#import "CGColorSpace-private.h"
|
||||
#import "OPImageConversion.h"
|
||||
|
||||
const CFStringRef kCGColorWhite = @"kCGColorWhite";
|
||||
const CFStringRef kCGColorBlack = @"kCGColorBlack";
|
||||
const CFStringRef kCGColorClear = @"kCGColorClear";
|
||||
@ -34,15 +38,6 @@ static CGColorRef _blackColor;
|
||||
static CGColorRef _clearColor;
|
||||
|
||||
|
||||
@interface CGColor : NSObject
|
||||
{
|
||||
@public
|
||||
CGColorSpaceRef cspace;
|
||||
CGFloat *comps;
|
||||
CGPatternRef pattern;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CGColor
|
||||
|
||||
- (id) initWithColorSpace: (CGColorSpaceRef)cs components: (const CGFloat*)components
|
||||
@ -52,6 +47,7 @@ static CGColorRef _clearColor;
|
||||
|
||||
size_t nc, i;
|
||||
nc = CGColorSpaceGetNumberOfComponents(cs);
|
||||
NSLog(@"Create color with %d comps", nc);
|
||||
self->comps = malloc((nc+1)*sizeof(CGFloat));
|
||||
if (NULL == self->comps) {
|
||||
NSLog(@"malloc failed");
|
||||
@ -90,6 +86,57 @@ static CGColorRef _clearColor;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGColor*) transformToColorSpace: (CGColorSpaceRef)destSpace withRenderingIntent: (CGColorRenderingIntent)intent
|
||||
{
|
||||
CGColorSpaceRef sourceSpace = CGColorGetColorSpace(self);
|
||||
|
||||
// FIXME: this is ugly because CGColor uses CGFloats, but OPColorTransform only accepts
|
||||
// 32-bit float components.
|
||||
|
||||
float originalComps[CGColorSpaceGetNumberOfComponents(sourceSpace) + 1];
|
||||
float tranformedComps[CGColorSpaceGetNumberOfComponents(destSpace) + 1];
|
||||
|
||||
for (size_t i=0; i < CGColorSpaceGetNumberOfComponents(sourceSpace) + 1; i++)
|
||||
{
|
||||
originalComps[i] = comps[i];
|
||||
}
|
||||
|
||||
OPImageFormat sourceFormat;
|
||||
sourceFormat.compFormat = kOPComponentFormatFloat32bpc;
|
||||
sourceFormat.colorComponents = CGColorSpaceGetNumberOfComponents(sourceSpace);
|
||||
sourceFormat.hasAlpha = true;
|
||||
sourceFormat.isAlphaPremultiplied = false;
|
||||
sourceFormat.isAlphaLast = true;
|
||||
|
||||
OPImageFormat destFormat;
|
||||
destFormat.compFormat = kOPComponentFormatFloat32bpc;
|
||||
destFormat.colorComponents = CGColorSpaceGetNumberOfComponents(destSpace);
|
||||
destFormat.hasAlpha = true;
|
||||
destFormat.isAlphaPremultiplied = false;
|
||||
destFormat.isAlphaLast = true;
|
||||
|
||||
OPColorTransform *xform = [sourceSpace colorTransformTo: destSpace
|
||||
sourceFormat: sourceFormat
|
||||
destinationFormat: destFormat
|
||||
renderingIntent: intent
|
||||
pixelCount: 1];
|
||||
|
||||
[xform transformPixelData: originalComps
|
||||
output: tranformedComps];
|
||||
|
||||
// FIXME: hack, OPColorTransform doesn't yet copy the alpha
|
||||
tranformedComps[CGColorSpaceGetNumberOfComponents(destSpace)] = CGColorGetAlpha(self);
|
||||
|
||||
CGFloat cgfloatTransformedComps[CGColorSpaceGetNumberOfComponents(destSpace) + 1];
|
||||
for (size_t i=0; i < CGColorSpaceGetNumberOfComponents(destSpace) + 1; i++)
|
||||
{
|
||||
cgfloatTransformedComps[i] = tranformedComps[i];
|
||||
}
|
||||
// FIXME: release xform?
|
||||
|
||||
return [[[CGColor alloc] initWithColorSpace: destSpace components: cgfloatTransformedComps] autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -213,7 +260,7 @@ CGColorRef CGColorGetConstantColor(CFStringRef name)
|
||||
{
|
||||
_blackColor = CGColorCreateGenericGray(0, 1);
|
||||
}
|
||||
return _whiteColor;
|
||||
return _blackColor;
|
||||
}
|
||||
else if ([name isEqual: kCGColorClear])
|
||||
{
|
||||
@ -235,3 +282,8 @@ CGPatternRef CGColorGetPattern(CGColorRef clr)
|
||||
{
|
||||
return clr->pattern;
|
||||
}
|
||||
|
||||
CGColorRef OPColorGetTransformedToSpace(CGColorRef clr, CGColorSpaceRef space, CGColorRenderingIntent intent)
|
||||
{
|
||||
return [clr transformToColorSpace: space withRenderingIntent: intent];
|
||||
}
|
||||
|
95
Source/CGColorSpace-private.h
Normal file
95
Source/CGColorSpace-private.h
Normal file
@ -0,0 +1,95 @@
|
||||
/** <title>CGColorSpace</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
|
||||
#import "OPImageConversion.h"
|
||||
|
||||
@interface OPColorTransform : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
- (void) transformPixelData: (const unsigned char *)input
|
||||
output: (char *)output;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/**
|
||||
* Abstract superclass for color spaces.
|
||||
*/
|
||||
@interface CGColorSpace : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (CGColorSpace *)colorSpaceGenericGray;
|
||||
+ (CGColorSpace *)colorSpaceGenericRGB;
|
||||
+ (CGColorSpace *)colorSpaceGenericCMYK;
|
||||
+ (CGColorSpace *)colorSpaceGenericRGBLinear;
|
||||
+ (CGColorSpace *)colorSpaceAdobeRGB1998;
|
||||
+ (CGColorSpace *)colorSpaceSRGB;
|
||||
+ (CGColorSpace *)colorSpaceGenericGrayGamma2_2;
|
||||
|
||||
- (NSData*)ICCProfile;
|
||||
- (NSString*)name;
|
||||
- (id)initWithCalibratedGrayWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
gamma: (CGFloat)gamma;
|
||||
- (id)initWithCalibratedRGBWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
gamma: (const CGFloat *)gamma
|
||||
matrix: (const CGFloat *)matrix;
|
||||
- (id)initDeviceCMYK;
|
||||
- (id)initDeviceGray;
|
||||
- (id)initDeviceRGB;
|
||||
- (id)initICCBasedWithComponents: (size_t)nComponents
|
||||
range: (const CGFloat*)range
|
||||
profile: (CGDataProviderRef)profile
|
||||
alternateSpace: (CGColorSpaceRef)alternateSpace;
|
||||
- (CGColorSpaceRef) initIndexedWithBaseSpace: (CGColorSpaceRef)baseSpace
|
||||
lastIndex: (size_t)lastIndex
|
||||
colorTable: (const unsigned char *)colorTable;
|
||||
- (CGColorSpaceRef) initLabWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
range: (const CGFloat*)range;
|
||||
- (CGColorSpaceRef) initPatternWithBaseSpace: (CGColorSpaceRef)baseSpace;
|
||||
- (CGColorSpaceRef) initWithICCProfile: (CFDataRef)data;
|
||||
- (CGColorSpaceRef) initWithName: (NSString *)name;
|
||||
- (CGColorSpaceRef) initWithPlatformColorSpace: (void *)platformColorSpace;
|
||||
- (CGColorSpaceRef) baseColorSpace;
|
||||
- (void) getColorTable: (uint8_t*)table;
|
||||
- (size_t) colorTableCount;
|
||||
- (CGColorSpaceModel) model;
|
||||
- (size_t) numberOfComponents;
|
||||
|
||||
- (OPColorTransform*) colorTransformTo: (CGColorSpace *)aColorSpace
|
||||
sourceFormat: (OPImageFormat)aSourceFormat
|
||||
destinationFormat: (OPImageFormat)aDestFormat
|
||||
renderingIntent: (CGColorRenderingIntent)anIntent
|
||||
pixelCount: (size_t)aPixelCount;
|
||||
|
||||
@end
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2006 Free Software Foundation, Inc.</copy>
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
Author: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
Date: 2006
|
||||
|
||||
@ -22,17 +24,13 @@
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* FIXME: Color Management is not implemented yet. Consequently, color spaces
|
||||
* are usually ignored and assumed to be deviceRGB. With most current equipment
|
||||
* supporting the sRGB color space, this may be OK in most cases, though.
|
||||
*
|
||||
* We should properly implement this once Cairo supports color management.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
|
||||
#import "CGColorSpace-private.h"
|
||||
#import "OPColorSpaceIndexed.h"
|
||||
|
||||
const CFStringRef kCGColorSpaceGenericGray = @"kCGColorSpaceGenericGray";
|
||||
const CFStringRef kCGColorSpaceGenericRGB = @"kCGColorSpaceGenericRGB";
|
||||
const CFStringRef kCGColorSpaceGenericCMYK = @"kCGColorSpaceGenericCMYK";
|
||||
@ -41,53 +39,13 @@ const CFStringRef kCGColorSpaceAdobeRGB1998 = @"kCGColorSpaceAdobeRGB1998";
|
||||
const CFStringRef kCGColorSpaceSRGB = @"kCGColorSpaceSRGB";
|
||||
const CFStringRef kCGColorSpaceGenericGrayGamma2_2 = @"kCGColorSpaceGenericGrayGamma2_2";
|
||||
|
||||
static void opal_todev_rgb(CGFloat *dest, const CGFloat comps[]);
|
||||
static void opal_todev_gray(CGFloat *dest, const CGFloat comps[]);
|
||||
static void opal_todev_cmyk(CGFloat *dest, const CGFloat comps[]);
|
||||
|
||||
static CGColorSpaceRef _deviceRGB;
|
||||
static CGColorSpaceRef _deviceGray;
|
||||
static CGColorSpaceRef _deviceCMYK;
|
||||
|
||||
|
||||
|
||||
@interface CGColorSpace : NSObject
|
||||
{
|
||||
@public
|
||||
CGColorSpaceRef cspace;
|
||||
int numcomps;
|
||||
CGColorSpaceModel model;
|
||||
void (*todevice)(CGFloat *dest, const CGFloat comps[]);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CGColorSpace
|
||||
|
||||
+ (void) load
|
||||
{
|
||||
_deviceRGB = [[CGColorSpace alloc] init];
|
||||
_deviceRGB->numcomps = 3;
|
||||
_deviceRGB->model = kCGColorSpaceModelRGB;
|
||||
_deviceRGB->todevice = opal_todev_rgb;
|
||||
|
||||
_deviceGray = [[CGColorSpace alloc] init];
|
||||
_deviceGray->numcomps = 1;
|
||||
_deviceGray->model = kCGColorSpaceModelMonochrome;
|
||||
_deviceGray->todevice = opal_todev_gray;
|
||||
|
||||
_deviceCMYK = [[CGColorSpace alloc] init];
|
||||
_deviceCMYK->numcomps = 4;
|
||||
_deviceCMYK->model = kCGColorSpaceModelCMYK;
|
||||
_deviceCMYK->todevice = opal_todev_cmyk;
|
||||
}
|
||||
|
||||
- (id) retain
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) release
|
||||
+ (Class) colorSpaceClass
|
||||
{
|
||||
// FIXME:
|
||||
return NSClassFromString(@"OPColorSpaceLCMS");
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
@ -95,169 +53,61 @@ static CGColorSpaceRef _deviceCMYK;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) isEqual: (id)other
|
||||
{
|
||||
if (![other isKindOfClass: [CGColorSpace class]])
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
CGColorSpace *otherCS = (CGColorSpace *)other;
|
||||
|
||||
return (otherCS->numcomps == self->numcomps
|
||||
&& otherCS->model == self->model
|
||||
&& otherCS->cspace == self->cspace
|
||||
&& otherCS->todevice == self->todevice); // FIXME: will not accomodate all colorspace types
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
CFDataRef CGColorSpaceCopyICCProfile(CGColorSpaceRef cs)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
CFStringRef CGColorSpaceCopyName(CGColorSpaceRef cs)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateCalibratedGray(
|
||||
const CGFloat *whitePoint,
|
||||
const CGFloat *blackPoint,
|
||||
CGFloat gamma)
|
||||
{
|
||||
return _deviceGray;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateCalibratedRGB(
|
||||
const CGFloat *whitePoint,
|
||||
const CGFloat *blackPoint,
|
||||
const CGFloat *gamma,
|
||||
const CGFloat *matrix)
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateDeviceCMYK()
|
||||
{
|
||||
return _deviceCMYK;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateDeviceGray()
|
||||
{
|
||||
return _deviceGray;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateDeviceRGB()
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateICCBased(
|
||||
size_t nComponents,
|
||||
const CGFloat *range,
|
||||
CGDataProviderRef profile,
|
||||
CGColorSpaceRef alternateSpace)
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateIndexed(
|
||||
CGColorSpaceRef baseSpace,
|
||||
size_t lastIndex,
|
||||
const unsigned char *colorTable)
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateLab(
|
||||
const CGFloat *whitePoint,
|
||||
const CGFloat *blackPoint,
|
||||
const CGFloat *range)
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreatePattern(CGColorSpaceRef baseSpace)
|
||||
{
|
||||
return baseSpace;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateWithICCProfile(CFDataRef data)
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateWithName(CFStringRef name)
|
||||
{
|
||||
if ([name isEqualToString: kCGColorSpaceGenericGray])
|
||||
{
|
||||
return CGColorSpaceCreateDeviceGray();
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceGenericRGB])
|
||||
{
|
||||
return CGColorSpaceCreateDeviceRGB();
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceGenericCMYK])
|
||||
{
|
||||
return CGColorSpaceCreateDeviceCMYK();
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Unknown colorspace name");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateWithPlatformColorSpace(
|
||||
void *platformColorSpace)
|
||||
{
|
||||
return _deviceRGB;
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceGetBaseColorSpace(CGColorSpaceRef cs)
|
||||
{
|
||||
return cs;
|
||||
}
|
||||
|
||||
void CGColorSpaceGetColorTable(CGColorSpaceRef cs, unsigned char *table)
|
||||
- (void) getColorTable: (uint8_t*)table
|
||||
{
|
||||
}
|
||||
|
||||
size_t CGColorSpaceGetColorTableCount(CGColorSpaceRef cs)
|
||||
- (size_t) colorTableCount
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CGColorSpaceModel CGColorSpaceGetModel(CGColorSpaceRef cs)
|
||||
+ (CGColorSpaceRef) createWithName: (NSString *)name
|
||||
{
|
||||
return cs->model;
|
||||
if ([name isEqualToString: kCGColorSpaceGenericGray])
|
||||
{
|
||||
return [[[self class] colorSpaceGenericGray] retain];
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceGenericRGB])
|
||||
{
|
||||
return [[[self class] colorSpaceGenericRGB] retain];
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceGenericCMYK])
|
||||
{
|
||||
return [[[self class] colorSpaceGenericCMYK] retain];
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceGenericRGBLinear])
|
||||
{
|
||||
return [[[self class] colorSpaceGenericRGBLinear] retain];
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceAdobeRGB1998])
|
||||
{
|
||||
return [[[self class] colorSpaceAdobeRGB1998] retain];
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceSRGB])
|
||||
{
|
||||
return [[[self class] colorSpaceSRGB] retain];
|
||||
}
|
||||
else if ([name isEqualToString: kCGColorSpaceGenericGrayGamma2_2])
|
||||
{
|
||||
return [[[self class] colorSpaceGenericGrayGamma2_2] retain];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
size_t CGColorSpaceGetNumberOfComponents(CGColorSpaceRef cs)
|
||||
{
|
||||
return cs->numcomps;
|
||||
}
|
||||
@end
|
||||
|
||||
CFTypeID CGColorSpaceGetTypeID()
|
||||
{
|
||||
return (CFTypeID)[CGColorSpace class];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceRetain(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs retain];
|
||||
}
|
||||
|
||||
void CGColorSpaceRelease(CGColorSpaceRef cs)
|
||||
{
|
||||
[cs release];
|
||||
}
|
||||
@implementation OPColorTransform
|
||||
@end
|
||||
|
||||
/**
|
||||
* This is a fallback only used when building Opal without LittleCMS.
|
||||
* Note that it doesn't do any color management.
|
||||
*/
|
||||
#if 0
|
||||
static void opal_todev_rgb(CGFloat *dest, const CGFloat comps[])
|
||||
{
|
||||
dest[0] = comps[0];
|
||||
@ -284,9 +134,149 @@ static void opal_todev_cmyk(CGFloat *dest, const CGFloat comps[])
|
||||
dest[3] = comps[4];
|
||||
}
|
||||
|
||||
/* FIXME: This sould really convert to the color space of the device,
|
||||
* but Cairo only knows about RGBA, so we convert to that */
|
||||
void opal_cspace_todev(CGColorSpaceRef cs, CGFloat *dest, const CGFloat comps[])
|
||||
#endif
|
||||
|
||||
|
||||
CFDataRef CGColorSpaceCopyICCProfile(CGColorSpaceRef cs)
|
||||
{
|
||||
cs->todevice(dest, comps);
|
||||
return [cs IICProfile];
|
||||
}
|
||||
|
||||
CFStringRef CGColorSpaceCopyName(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs name];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateCalibratedGray(
|
||||
const CGFloat *whitePoint,
|
||||
const CGFloat *blackPoint,
|
||||
CGFloat gamma)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc]
|
||||
initWithCalibratedGrayWithWhitePoint: whitePoint
|
||||
blackPoint: blackPoint
|
||||
gamma: gamma];
|
||||
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateCalibratedRGB(
|
||||
const CGFloat *whitePoint,
|
||||
const CGFloat *blackPoint,
|
||||
const CGFloat *gamma,
|
||||
const CGFloat *matrix)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc]
|
||||
initWithCalibratedRGBWithWhitePoint: whitePoint
|
||||
blackPoint: blackPoint
|
||||
gamma: gamma
|
||||
matrix: matrix];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateDeviceCMYK()
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] colorSpaceGenericCMYK] retain];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateDeviceGray()
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] colorSpaceGenericGray] retain];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateDeviceRGB()
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] colorSpaceSRGB] retain];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateICCBased(
|
||||
size_t nComponents,
|
||||
const CGFloat *range,
|
||||
CGDataProviderRef profile,
|
||||
CGColorSpaceRef alternateSpace)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc] initICCBasedWithComponents: nComponents
|
||||
range: range
|
||||
profile: profile
|
||||
alternateSpace: alternateSpace];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateIndexed(
|
||||
CGColorSpaceRef baseSpace,
|
||||
size_t lastIndex,
|
||||
const unsigned char *colorTable)
|
||||
{
|
||||
return [[OPColorSpaceIndexed alloc] initWithBaseSpace: baseSpace
|
||||
lastIndex: lastIndex
|
||||
colorTable: colorTable];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateLab(
|
||||
const CGFloat *whitePoint,
|
||||
const CGFloat *blackPoint,
|
||||
const CGFloat *range)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc] initLabWithWhitePoint: whitePoint
|
||||
blackPoint: blackPoint
|
||||
range: range];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreatePattern(CGColorSpaceRef baseSpace)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc] initPatternWithBaseSpace: baseSpace];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateWithICCProfile(CFDataRef data)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc] initWithICCProfile: data];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateWithName(CFStringRef name)
|
||||
{
|
||||
return [[CGColorSpace colorSpaceClass] createWithName: name];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceCreateWithPlatformColorSpace(
|
||||
void *platformColorSpace)
|
||||
{
|
||||
return [[[CGColorSpace colorSpaceClass] alloc] initWithPlatformColorSpace: platformColorSpace];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceGetBaseColorSpace(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs baseColorSpace];
|
||||
}
|
||||
|
||||
void CGColorSpaceGetColorTable(CGColorSpaceRef cs, unsigned char *table)
|
||||
{
|
||||
[cs getColorTable: table];
|
||||
}
|
||||
|
||||
size_t CGColorSpaceGetColorTableCount(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs colorTableCount];
|
||||
}
|
||||
|
||||
CGColorSpaceModel CGColorSpaceGetModel(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs model];
|
||||
}
|
||||
|
||||
size_t CGColorSpaceGetNumberOfComponents(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs numberOfComponents];
|
||||
}
|
||||
|
||||
CFTypeID CGColorSpaceGetTypeID()
|
||||
{
|
||||
return (CFTypeID)[CGColorSpace class];
|
||||
}
|
||||
|
||||
CGColorSpaceRef CGColorSpaceRetain(CGColorSpaceRef cs)
|
||||
{
|
||||
return [cs retain];
|
||||
}
|
||||
|
||||
void CGColorSpaceRelease(CGColorSpaceRef cs)
|
||||
{
|
||||
[cs release];
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,13 @@
|
||||
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "CGContext-private.h"
|
||||
#include "CGGradient-private.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#import "CGContext-private.h"
|
||||
#import "CGGradient-private.h"
|
||||
#import "CGColor-private.h"
|
||||
#import "cairo/CairoFont.h"
|
||||
|
||||
/* The default (opaque black) color in a Cairo context,
|
||||
@ -37,7 +38,6 @@
|
||||
static cairo_pattern_t *default_cp;
|
||||
|
||||
extern void opal_surface_flush(cairo_surface_t *target);
|
||||
extern void opal_cspace_todev(CGColorSpaceRef cs, CGFloat *dest, const CGFloat comps[]);
|
||||
|
||||
extern cairo_surface_t *opal_CGImageGetSurfaceForImage(CGImageRef img);
|
||||
extern CGRect opal_CGImageGetSourceRect(CGImageRef image);
|
||||
@ -784,14 +784,17 @@ CGRect CGContextGetClipBoundingBox(CGContextRef ctx)
|
||||
|
||||
static inline void set_color(cairo_pattern_t **cp, CGColorRef clr, double alpha)
|
||||
{
|
||||
CGFloat cc[4];
|
||||
// FIXME: check why this might be called with a NULL clr
|
||||
if (!clr) return;
|
||||
cairo_pattern_t *newcp;
|
||||
cairo_status_t cret;
|
||||
|
||||
opal_cspace_todev(CGColorGetColorSpace(clr), cc, CGColorGetComponents(clr));
|
||||
|
||||
|
||||
CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
|
||||
CGColorRef srgbClr = OPColorGetTransformedToSpace(clr, srgb, kCGRenderingIntentRelativeColorimetric);
|
||||
CGColorSpaceRelease(srgb);
|
||||
|
||||
CGFloat *cc = CGColorGetComponents(srgbClr);
|
||||
NSLog(@"Set color with %f %f %f %f", (float)cc[0], (float)cc[1], (float)cc[2], (float)cc[3]*alpha);
|
||||
newcp = cairo_pattern_create_rgba(cc[0], cc[1], cc[2], cc[3]*alpha);
|
||||
cret = cairo_pattern_status(newcp);
|
||||
if (cret) {
|
||||
@ -799,7 +802,11 @@ static inline void set_color(cairo_pattern_t **cp, CGColorRef clr, double alpha)
|
||||
cairo_status_to_string(cret));
|
||||
return;
|
||||
}
|
||||
cairo_pattern_destroy(*cp);
|
||||
|
||||
if (*cp != NULL)
|
||||
{
|
||||
cairo_pattern_destroy(*cp);
|
||||
}
|
||||
*cp = newcp;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,8 @@
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#include <stdlib.h>
|
||||
#include <cairo.h>
|
||||
#include "image/OPImageConversion.h"
|
||||
|
||||
#import "OPImageConversion.h"
|
||||
|
||||
|
||||
@interface CGImage : NSObject
|
||||
@ -95,14 +96,22 @@
|
||||
|
||||
const size_t numComponentsIncludingAlpha = numComponents + (hasAlpha ? 1 : 0);
|
||||
|
||||
if (aBitsPerComponent < 1)
|
||||
if (aBitsPerComponent < 1 || aBitsPerComponent > 32)
|
||||
{
|
||||
NSLog(@"Unsupported bitsPerComponent: %d", aBitsPerComponent);
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
if ((aBitmapInfo & kCGBitmapFloatComponents) != 0 && aBitsPerComponent != 32)
|
||||
{
|
||||
NSLog(@"Only 32 bitsPerComponents supported for float components");
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
if (aBitsPerPixel < aBitsPerComponent * numComponentsIncludingAlpha)
|
||||
{
|
||||
// Note if an alpha channel is requrested, we require it to be the same size
|
||||
// as the other components
|
||||
NSLog(@"Too few bitsPerPixel for bitsPerComponent");
|
||||
[self release];
|
||||
return nil;
|
||||
@ -469,7 +478,7 @@ cairo_surface_t *opal_CGImageGetSurfaceForImage(CGImageRef img)
|
||||
const CGBitmapInfo dstBitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst;
|
||||
const CGColorSpaceRef dstColorSpace = srcColorSpace;
|
||||
|
||||
bool ok = OPImageConvert(
|
||||
OPImageConvert(
|
||||
dstData, srcData,
|
||||
srcWidth, srcHeight,
|
||||
dstBitsPerComponent, srcBitsPerComponent,
|
||||
@ -482,13 +491,6 @@ cairo_surface_t *opal_CGImageGetSurfaceForImage(CGImageRef img)
|
||||
OPDataProviderReleaseBytePointer(img->dp, srcData);
|
||||
|
||||
cairo_surface_mark_dirty(img->surf); // done modifying the surface outside of cairo
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
cairo_surface_destroy(img->surf);
|
||||
img->surf = NULL;
|
||||
NSLog(@"Image conversion to cairo surface failed.");
|
||||
}
|
||||
}
|
||||
|
||||
return img->surf;
|
||||
|
61
Source/OPColorSpaceIndexed.h
Normal file
61
Source/OPColorSpaceIndexed.h
Normal file
@ -0,0 +1,61 @@
|
||||
/** <title>OPColorSpaceIndexed</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
Author: BALATON Zoltan <balaton@eik.bme.hu>
|
||||
Date: 2006
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
#import "CGColorSpace-private.h"
|
||||
|
||||
@interface OPColorSpaceIndexed : CGColorSpace
|
||||
{
|
||||
@public
|
||||
CGColorSpaceRef base;
|
||||
size_t lastIndex;
|
||||
const unsigned char *table;
|
||||
}
|
||||
|
||||
- (id)initWithBaseSpace: (CGColorSpaceRef)aBaseSpace
|
||||
lastIndex: (size_t)aLastIndex
|
||||
colorTable: (const unsigned char *)aColorTable;
|
||||
- (size_t) tableSize;
|
||||
|
||||
- (void) getColorTable: (uint8_t*)table;
|
||||
- (size_t) colorTableCount;
|
||||
|
||||
- (OPColorTransform*) colorTransformTo: (CGColorSpace *)otherColor
|
||||
sourceFormat: (OPImageFormat)sourceFormat
|
||||
destinationFormat: (OPImageFormat)destFormat;
|
||||
|
||||
@end
|
||||
|
||||
@interface OPColorTransformIndexed : OPColorTransform
|
||||
{
|
||||
OPColorTransform *baseTransform;
|
||||
}
|
||||
|
||||
- (void) transformPixelData: (const unsigned char *)input
|
||||
output: (char *)output;
|
||||
|
||||
@end
|
||||
|
120
Source/OPColorSpaceIndexed.m
Normal file
120
Source/OPColorSpaceIndexed.m
Normal file
@ -0,0 +1,120 @@
|
||||
/** <title>OPColorSpaceIndexed</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "OPColorSpaceIndexed.h"
|
||||
|
||||
@implementation OPColorSpaceIndexed
|
||||
|
||||
- (id)initWithBaseSpace: (CGColorSpaceRef)aBaseSpace
|
||||
lastIndex: (size_t)aLastIndex
|
||||
colorTable: (const unsigned char *)aColorTable
|
||||
{
|
||||
self = [super init];
|
||||
ASSIGN(base, aBaseSpace);
|
||||
lastIndex = aLastIndex;
|
||||
|
||||
table = malloc([self tableSize]);
|
||||
if (NULL == table)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
memmove(table, aColorTable, [self tableSize]);
|
||||
|
||||
return self;
|
||||
}
|
||||
- (size_t) tableSize
|
||||
{
|
||||
return (lastIndex + 1) * CGColorSpaceGetNumberOfComponents(base);
|
||||
}
|
||||
- (void) dealloc
|
||||
{
|
||||
free(table);
|
||||
CGColorSpaceRelease(base);
|
||||
[super dealloc];
|
||||
}
|
||||
- (NSData*)ICCProfile
|
||||
{
|
||||
return [base IICProfile]; // FIXME: ???
|
||||
}
|
||||
- (NSString*)name
|
||||
{
|
||||
return [base name]; // FIXME: ???
|
||||
}
|
||||
- (CGColorSpaceRef) baseColorSpace
|
||||
{
|
||||
return base;
|
||||
}
|
||||
- (size_t) numberOfComponents
|
||||
{
|
||||
return [base numberOfComponents];
|
||||
}
|
||||
- (void) getColorTable: (uint8_t*)table
|
||||
{
|
||||
memmove(table, self->table, [self tableSize]);
|
||||
}
|
||||
- (size_t) colorTableCount
|
||||
{
|
||||
return self->lastIndex + 1;
|
||||
}
|
||||
- (CGColorSpaceModel) model
|
||||
{
|
||||
return [base model];
|
||||
}
|
||||
- (BOOL) isEqual: (id)other
|
||||
{
|
||||
if ([other isKindOfClass: [OPColorSpaceIndexed class]])
|
||||
{
|
||||
OPColorSpaceIndexed *otherIndexed = (OPColorSpaceIndexed*)other;
|
||||
return [self->base isEqual: otherIndexed->base]
|
||||
&& self->lastIndex == otherIndexed->lastIndex
|
||||
&& (0 == memcmp(otherIndexed->table,
|
||||
self->table,
|
||||
[self tableSize]));
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (OPColorTransform*) colorTransformTo: (CGColorSpace *)otherColor
|
||||
sourceFormat: (OPImageFormat)sourceFormat
|
||||
destinationFormat: (OPImageFormat)destFormat
|
||||
{
|
||||
return [[[OPColorTransformIndexed alloc] init] autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation OPColorTransformIndexed
|
||||
|
||||
- (void) transformPixelData: (const unsigned char *)input
|
||||
output: (char *)output
|
||||
pixelCount: (size_t)count
|
||||
{
|
||||
// FIXME:
|
||||
}
|
||||
|
||||
@end
|
||||
|
131
Source/OPColorSpaceLCMS.h
Normal file
131
Source/OPColorSpaceLCMS.h
Normal file
@ -0,0 +1,131 @@
|
||||
/** <title>OPColorSpaceLCMS</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <lcms.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
|
||||
#import "CGColorSpace-private.h"
|
||||
|
||||
@interface OPColorSpaceLCMS : CGColorSpace
|
||||
{
|
||||
@public
|
||||
cmsHPROFILE profile;
|
||||
NSData *data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a generic RGB color space
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericRGB;
|
||||
|
||||
/**
|
||||
* Returns a generic RGB color space with a gamma of 1.0
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericRGBLinear;
|
||||
|
||||
/**
|
||||
* Returns a CMYK colorspace following the FOGRA39L specification.
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericCMYK;
|
||||
|
||||
/**
|
||||
* Returns an Adobe RGB compatible color space
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceAdobeRGB1998;
|
||||
|
||||
/**
|
||||
* Returns an sRGB compatible color space
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceSRGB;
|
||||
|
||||
/**
|
||||
* Returns a grayscale color space with a D65 white point
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericGray;
|
||||
/**
|
||||
* Returns a grayscale color space with gamma 2.2 and a D65 white point
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericGrayGamma2_2;
|
||||
|
||||
// Initializers
|
||||
|
||||
/**
|
||||
* Creates a color space with the given LCMS profile. Takes ownership of the profile
|
||||
* (releases it when done.)
|
||||
*/
|
||||
- (id)initWithProfile: (cmsHPROFILE)profile;
|
||||
|
||||
/**
|
||||
* Returns ICC profile data for color spaces created from ICC profiles, otherwise nil
|
||||
*/
|
||||
- (NSData*)ICCProfile;
|
||||
|
||||
- (NSString*)name;
|
||||
|
||||
- (id)initWithCalibratedGrayWithWhitePoint: (const CGFloat*)whiteCIEXYZ
|
||||
blackPoint: (const CGFloat*)blackCIEXYZ
|
||||
gamma: (CGFloat)gamma;
|
||||
|
||||
- (id)initWithCalibratedRGBWithWhitePointCIExy: (const CGFloat*)white
|
||||
redCIExy: (const CGFloat*)red
|
||||
greenCIExy: (const CGFloat*)green
|
||||
blueCIExy: (const CGFloat*)blue
|
||||
gamma: (CGFloat)gamma;
|
||||
|
||||
- (id)initWithCalibratedRGBWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
gamma: (const CGFloat *)gamma
|
||||
matrix: (const CGFloat *)matrix;
|
||||
|
||||
- (id)initICCBasedWithComponents: (size_t)nComponents
|
||||
range: (const CGFloat*)range
|
||||
profile: (CGDataProviderRef)profile
|
||||
alternateSpace: (CGColorSpaceRef)alternateSpace;
|
||||
|
||||
- (CGColorSpaceRef) initIndexedWithBaseSpace: (CGColorSpaceRef)baseSpace
|
||||
lastIndex: (size_t)lastIndex
|
||||
colorTable: (const unsigned char *)colorTable;
|
||||
|
||||
- (CGColorSpaceRef) initLabWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
range: (const CGFloat*)range;
|
||||
|
||||
- (CGColorSpaceRef) initWithICCProfile: (CFDataRef)profileData;
|
||||
|
||||
- (CGColorSpaceRef) initWithPlatformColorSpace: (void *)platformColorSpace;
|
||||
|
||||
- (CGColorSpaceModel) model;
|
||||
|
||||
- (size_t) numberOfComponents;
|
||||
|
||||
- (OPColorTransform*) colorTransformTo: (CGColorSpace *)aColorSpace
|
||||
sourceFormat: (OPImageFormat)aSourceFormat
|
||||
destinationFormat: (OPImageFormat)aDestFormat
|
||||
renderingIntent: (CGColorRenderingIntent)anIntent
|
||||
pixelCount: (size_t)aPixelCount;
|
||||
|
||||
@end
|
||||
|
||||
|
326
Source/OPColorSpaceLCMS.m
Normal file
326
Source/OPColorSpaceLCMS.m
Normal file
@ -0,0 +1,326 @@
|
||||
/** <title>OPColorSpaceLCMS</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <lcms.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
|
||||
#import "OPColorSpaceLCMS.h"
|
||||
#import "CGColorSpace-private.h"
|
||||
#import "OPColorTransformLCMS.h"
|
||||
|
||||
|
||||
@implementation OPColorSpaceLCMS
|
||||
|
||||
static CGColorSpace *colorSpaceSRGB;
|
||||
static CGColorSpace *colorSpaceGenericRGBLinear;
|
||||
static CGColorSpace *colorSpaceGenericCMYK;
|
||||
static CGColorSpace *colorSpaceAdobeRGB1998;
|
||||
static CGColorSpace *colorSpaceGenericGrayGamma2_2;
|
||||
|
||||
/**
|
||||
* Returns a generic RGB color space
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericRGB
|
||||
{
|
||||
return [self colorSpaceSRGB];
|
||||
}
|
||||
/**
|
||||
* Returns a generic RGB color space with a gamma of 1.0
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericRGBLinear
|
||||
{
|
||||
if (nil == colorSpaceGenericRGBLinear)
|
||||
{
|
||||
// Use the sRGB white point and primaries with a gamma of 1.0
|
||||
CGFloat whiteCIExy[2] = {0.3127, 0.3290};
|
||||
CGFloat redCIExy[2] = {0.64, 0.33};
|
||||
CGFloat greenCIExy[2] = {0.30, 0.60};
|
||||
CGFloat blueCIExy[2] = {0.15, 0.06};
|
||||
colorSpaceGenericRGBLinear = [[OPColorSpaceLCMS alloc]
|
||||
initWithCalibratedRGBWithWhitePointCIExy: whiteCIExy
|
||||
redCIExy: redCIExy
|
||||
greenCIExy: greenCIExy
|
||||
blueCIExy: blueCIExy
|
||||
gamma: 1.0];
|
||||
}
|
||||
return colorSpaceGenericRGBLinear;
|
||||
}
|
||||
/**
|
||||
* Returns a CMYK colorspace following the FOGRA39L specification.
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericCMYK
|
||||
{
|
||||
if (nil == colorSpaceGenericCMYK)
|
||||
{
|
||||
NSString *path = [[NSBundle bundleForClass: [self class]]
|
||||
pathForResource: @"coated_FOGRA39L_argl"
|
||||
ofType: @"icc"];
|
||||
NSData *data = [NSData dataWithContentsOfFile: path];
|
||||
colorSpaceGenericCMYK = [[OPColorSpaceLCMS alloc] initWithICCProfile: data];
|
||||
}
|
||||
return colorSpaceGenericCMYK;
|
||||
}
|
||||
/**
|
||||
* Returns an Adobe RGB compatible color space
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceAdobeRGB1998
|
||||
{
|
||||
if (nil == colorSpaceAdobeRGB1998)
|
||||
{
|
||||
CGFloat whiteCIExy[2] = {0.3127, 0.3290};
|
||||
CGFloat redCIExy[2] = {0.6400, 0.3300};
|
||||
CGFloat greenCIExy[2] = {0.2100, 0.7100};
|
||||
CGFloat blueCIExy[2] = {0.1500, 0.0600};
|
||||
colorSpaceAdobeRGB1998 = [[OPColorSpaceLCMS alloc]
|
||||
initWithCalibratedRGBWithWhitePointCIExy: whiteCIExy
|
||||
redCIExy: redCIExy
|
||||
greenCIExy: greenCIExy
|
||||
blueCIExy: blueCIExy
|
||||
gamma: (563.0/256.0)];
|
||||
}
|
||||
return colorSpaceAdobeRGB1998;
|
||||
}
|
||||
/**
|
||||
* Returns an sRGB compatible color space
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceSRGB
|
||||
{
|
||||
if (nil == colorSpaceSRGB)
|
||||
{
|
||||
colorSpaceSRGB = [[OPColorSpaceLCMS alloc] initWithProfile: cmsCreate_sRGBProfile()];
|
||||
}
|
||||
return colorSpaceSRGB;
|
||||
}
|
||||
/**
|
||||
* Returns a grayscale color space with a D65 white point
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericGray
|
||||
{
|
||||
return [self colorSpaceGenericGrayGamma2_2];
|
||||
}
|
||||
/**
|
||||
* Returns a grayscale color space with gamma 2.2 and a D65 white point
|
||||
*/
|
||||
+ (CGColorSpace *)colorSpaceGenericGrayGamma2_2
|
||||
{
|
||||
if (nil == colorSpaceGenericGrayGamma2_2)
|
||||
{
|
||||
CGFloat whiteCIEXYZ[3] = {0.9504, 1.0000, 1.0888};
|
||||
CGFloat blackCIEXYZ[3] = {0, 0, 0};
|
||||
colorSpaceGenericGrayGamma2_2 = [[OPColorSpaceLCMS alloc] initWithCalibratedGrayWithWhitePoint: whiteCIEXYZ
|
||||
blackPoint: blackCIEXYZ
|
||||
gamma: 2.2];
|
||||
}
|
||||
return colorSpaceGenericGrayGamma2_2;
|
||||
}
|
||||
|
||||
// Initializers
|
||||
|
||||
/**
|
||||
* Creates a color space with the given LCMS profile. Takes ownership of the profile
|
||||
* (releases it when done.)
|
||||
*/
|
||||
- (id)initWithProfile: (cmsHPROFILE)aProfile
|
||||
{
|
||||
self = [super init];
|
||||
self->profile = aProfile;
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ICC profile data for color spaces created from ICC profiles, otherwise nil
|
||||
*/
|
||||
- (NSData*)ICCProfile
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSString*)name
|
||||
{
|
||||
return [NSString stringWithUTF8String: cmsTakeProductName(self->profile)];
|
||||
}
|
||||
|
||||
static inline cmsCIExyY CIExyzToCIExyY(const CGFloat point[3])
|
||||
{
|
||||
// LittleCMS docs say Y is always 1
|
||||
cmsCIExyY xyY = {point[0], point[1], 1.0};
|
||||
return xyY;
|
||||
}
|
||||
|
||||
static inline cmsCIExyY CIEXYZToCIExyY(const CGFloat point[3])
|
||||
{
|
||||
cmsCIEXYZ XYZ = {point[0], point[1], point[2]};
|
||||
cmsCIExyY xyY;
|
||||
cmsXYZ2xyY(&xyY, &XYZ);
|
||||
return xyY;
|
||||
}
|
||||
|
||||
- (id)initWithCalibratedGrayWithWhitePoint: (const CGFloat*)whiteCIEXYZ
|
||||
blackPoint: (const CGFloat*)blackCIEXYZ
|
||||
gamma: (CGFloat)gamma
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
// NOTE: we ignore the black point; LCMS computes it on its own
|
||||
|
||||
LPGAMMATABLE table = cmsBuildGamma(256, gamma);
|
||||
cmsCIExyY whiteCIExyY = CIEXYZToCIExyY(whiteCIEXYZ);
|
||||
self->profile = cmsCreateGrayProfile(&whiteCIExyY, table);
|
||||
cmsFreeGamma(table);
|
||||
|
||||
return self;
|
||||
}
|
||||
- (id)initWithCalibratedRGBWithWhitePointCIExy: (const CGFloat*)white
|
||||
redCIExy: (const CGFloat*)red
|
||||
greenCIExy: (const CGFloat*)green
|
||||
blueCIExy: (const CGFloat*)blue
|
||||
gamma: (CGFloat)gamma
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
LPGAMMATABLE tables[3] = {cmsBuildGamma(256, gamma),
|
||||
cmsBuildGamma(256, gamma),
|
||||
cmsBuildGamma(256, gamma)};
|
||||
cmsCIExyY whitePoint = {white[0], white[1], 1.0};
|
||||
cmsCIExyYTRIPLE primaries = {
|
||||
{red[0], red[1], 1.0},
|
||||
{green[0], green[1], 1.0},
|
||||
{blue[0], blue[1], 1.0}
|
||||
};
|
||||
|
||||
self->profile = cmsCreateRGBProfile(&whitePoint, &primaries, tables);
|
||||
|
||||
cmsFreeGamma(tables[0]);
|
||||
cmsFreeGamma(tables[1]);
|
||||
cmsFreeGamma(tables[2]);
|
||||
|
||||
return self;
|
||||
}
|
||||
- (id)initWithCalibratedRGBWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
gamma: (const CGFloat *)gamma
|
||||
matrix: (const CGFloat *)matrix
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
// NOTE: we ignore the black point; LCMS computes it on its own
|
||||
|
||||
LPGAMMATABLE tables[3] = {cmsBuildGamma(256, gamma[0]),
|
||||
cmsBuildGamma(256, gamma[1]),
|
||||
cmsBuildGamma(256, gamma[2])};
|
||||
|
||||
// FIXME: I'm not 100% sure this is the correct interpretation of matrix
|
||||
|
||||
// We can test it by checking the results in pdf manual vs doing a trasformation
|
||||
// with LCMS to XYZ.
|
||||
|
||||
cmsCIExyYTRIPLE primaries;
|
||||
primaries.Red = CIEXYZToCIExyY(matrix);
|
||||
primaries.Green = CIEXYZToCIExyY(matrix+3);
|
||||
primaries.Blue = CIEXYZToCIExyY(matrix+6);
|
||||
|
||||
cmsCIExyY whitePointCIExyY = CIEXYZToCIExyY(whitePoint);
|
||||
|
||||
self->profile = cmsCreateRGBProfile(&whitePointCIExyY, &primaries, tables);
|
||||
|
||||
cmsFreeGamma(tables[0]);
|
||||
cmsFreeGamma(tables[1]);
|
||||
cmsFreeGamma(tables[2]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initICCBasedWithComponents: (size_t)nComponents
|
||||
range: (const CGFloat*)range
|
||||
profile: (CGDataProviderRef)profile
|
||||
alternateSpace: (CGColorSpaceRef)alternateSpace
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
- (CGColorSpaceRef) initLabWithWhitePoint: (const CGFloat*)whitePoint
|
||||
blackPoint: (const CGFloat*)blackPoint
|
||||
range: (const CGFloat*)range
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
- (CGColorSpaceRef) initWithICCProfile: (CFDataRef)profileData
|
||||
{
|
||||
self = [super init];
|
||||
self->data = [profileData retain];
|
||||
self->profile = cmsOpenProfileFromMem([profileData bytes], [profileData length]);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGColorSpaceRef) initWithPlatformColorSpace: (void *)platformColorSpace
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
static CGColorSpaceModel CGColorSpaceModelForSignature(icColorSpaceSignature sig)
|
||||
{
|
||||
switch (sig)
|
||||
{
|
||||
case icSigGrayData:
|
||||
return kCGColorSpaceModelMonochrome;
|
||||
case icSigRgbData:
|
||||
return kCGColorSpaceModelRGB;
|
||||
case icSigCmykData:
|
||||
return kCGColorSpaceModelCMYK;
|
||||
case icSigLabData:
|
||||
return kCGColorSpaceModelLab;
|
||||
default:
|
||||
return kCGColorSpaceModelUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGColorSpaceModel) model
|
||||
{
|
||||
return CGColorSpaceModelForSignature(cmsGetColorSpace(profile));
|
||||
|
||||
}
|
||||
- (size_t) numberOfComponents
|
||||
{
|
||||
return _cmsChannelsOf(cmsGetColorSpace(profile));
|
||||
}
|
||||
|
||||
- (OPColorTransform*) colorTransformTo: (CGColorSpace *)aColorSpace
|
||||
sourceFormat: (OPImageFormat)aSourceFormat
|
||||
destinationFormat: (OPImageFormat)aDestFormat
|
||||
renderingIntent: (CGColorRenderingIntent)anIntent
|
||||
pixelCount: (size_t)aPixelCount
|
||||
{
|
||||
return [[OPColorTransformLCMS alloc]
|
||||
initWithSourceSpace: self
|
||||
destinationSpace: aColorSpace
|
||||
sourceFormat: aSourceFormat
|
||||
destinationFormat: aDestFormat
|
||||
renderingIntent: anIntent
|
||||
pixelCount: aPixelCount];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
52
Source/OPColorTransformLCMS.h
Normal file
52
Source/OPColorTransformLCMS.h
Normal file
@ -0,0 +1,52 @@
|
||||
/** <title>OPColorTransformLCMS</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <lcms.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
|
||||
#import "CGColorSpace-private.h"
|
||||
#import "OPColorSpaceLCMS.h"
|
||||
|
||||
@interface OPColorTransformLCMS : OPColorTransform
|
||||
{
|
||||
cmsHTRANSFORM xform;
|
||||
CGColorSpace *source, *dest;
|
||||
OPImageFormat sourceFormat, destFormat;
|
||||
CGColorRenderingIntent renderingIntent;
|
||||
size_t pixelCount;
|
||||
char *tempBuffer1, *tempBuffer2;
|
||||
}
|
||||
|
||||
- (id) initWithSourceSpace: (OPColorSpaceLCMS *)aSourceSpace
|
||||
destinationSpace: (OPColorSpaceLCMS *)aDestSpace
|
||||
sourceFormat: (OPImageFormat)aSourceFormat
|
||||
destinationFormat: (OPImageFormat)aDestFormat
|
||||
renderingIntent: (CGColorRenderingIntent)anIntent
|
||||
pixelCount: (size_t)aPixelCount;
|
||||
|
||||
- (void) transformPixelData: (const unsigned char *)input
|
||||
output: (char *)output;
|
||||
|
||||
@end
|
320
Source/OPColorTransformLCMS.m
Normal file
320
Source/OPColorTransformLCMS.m
Normal file
@ -0,0 +1,320 @@
|
||||
/** <title>OPColorTransformLCMS</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <lcms.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
|
||||
#import "CGColorSpace-private.h"
|
||||
#import "OPColorTransformLCMS.h"
|
||||
#import "OPPremultiplyAlpha.h"
|
||||
|
||||
@implementation OPColorTransformLCMS
|
||||
|
||||
|
||||
static int LcmsIntentForCGColorRenderingIntent(CGColorRenderingIntent intent)
|
||||
{
|
||||
switch (intent)
|
||||
{
|
||||
default:
|
||||
case kCGRenderingIntentDefault:
|
||||
return INTENT_RELATIVE_COLORIMETRIC; // FIXME: Check a user default
|
||||
case kCGRenderingIntentAbsoluteColorimetric:
|
||||
return INTENT_ABSOLUTE_COLORIMETRIC;
|
||||
case kCGRenderingIntentRelativeColorimetric:
|
||||
return INTENT_RELATIVE_COLORIMETRIC;
|
||||
case kCGRenderingIntentPerceptual:
|
||||
return INTENT_PERCEPTUAL;
|
||||
case kCGRenderingIntentSaturation:
|
||||
return INTENT_SATURATION;
|
||||
}
|
||||
}
|
||||
|
||||
static int LcmsPixelTypeForCGColorSpaceModel(CGColorSpaceModel model)
|
||||
{
|
||||
switch (model)
|
||||
{
|
||||
case kCGColorSpaceModelMonochrome:
|
||||
return PT_GRAY;
|
||||
case kCGColorSpaceModelRGB:
|
||||
return PT_RGB;
|
||||
case kCGColorSpaceModelCMYK:
|
||||
return PT_CMYK;
|
||||
case kCGColorSpaceModelLab:
|
||||
return PT_Lab;
|
||||
case kCGColorSpaceModelUnknown:
|
||||
case kCGColorSpaceModelDeviceN:
|
||||
case kCGColorSpaceModelIndexed:
|
||||
case kCGColorSpaceModelPattern:
|
||||
default:
|
||||
return PT_ANY;
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD LcmsFormatForOPImageFormat(OPImageFormat opalFormat, CGColorSpaceRef colorSpace)
|
||||
{
|
||||
DWORD cmsFormat = 0;
|
||||
|
||||
NSLog(@"LcmsFormatForOPImageFormat pixel comp format %d, channels %d, has alpha %d, is alpha last %d",
|
||||
opalFormat.compFormat, opalFormat.colorComponents, opalFormat.hasAlpha, opalFormat.isAlphaLast);
|
||||
|
||||
switch (opalFormat.compFormat)
|
||||
{
|
||||
case kOPComponentFormat8bpc:
|
||||
cmsFormat |= BYTES_SH(1);
|
||||
break;
|
||||
case kOPComponentFormat16bpc:
|
||||
cmsFormat |= BYTES_SH(2);
|
||||
break;
|
||||
case kOPComponentFormat32bpc:
|
||||
cmsFormat |= BYTES_SH(2); // Convert to 16-bit before passing to LCMS
|
||||
break;
|
||||
case kOPComponentFormatFloat32bpc:
|
||||
cmsFormat |= BYTES_SH(2); // Convert to 16-bit before passing to LCMS
|
||||
break;
|
||||
}
|
||||
|
||||
cmsFormat |= CHANNELS_SH((DWORD)opalFormat.colorComponents);
|
||||
|
||||
if (opalFormat.hasAlpha)
|
||||
{
|
||||
cmsFormat |= EXTRA_SH(1);
|
||||
}
|
||||
if (!opalFormat.isAlphaLast && opalFormat.hasAlpha)
|
||||
{
|
||||
cmsFormat |= SWAPFIRST_SH(1);
|
||||
}
|
||||
|
||||
cmsFormat |= COLORSPACE_SH(
|
||||
LcmsPixelTypeForCGColorSpaceModel(
|
||||
CGColorSpaceGetModel(colorSpace)
|
||||
)
|
||||
);
|
||||
|
||||
return cmsFormat;
|
||||
}
|
||||
|
||||
- (id) initWithSourceSpace: (OPColorSpaceLCMS *)aSourceSpace
|
||||
destinationSpace: (OPColorSpaceLCMS *)aDestSpace
|
||||
sourceFormat: (OPImageFormat)aSourceFormat
|
||||
destinationFormat: (OPImageFormat)aDestFormat
|
||||
renderingIntent: (CGColorRenderingIntent)anIntent
|
||||
pixelCount: (size_t)aPixelCount
|
||||
{
|
||||
self = [super init];
|
||||
ASSIGN(source, aSourceSpace);
|
||||
ASSIGN(dest, aDestSpace);
|
||||
|
||||
const int lcmsIntent = LcmsIntentForCGColorRenderingIntent(anIntent);
|
||||
int lcmsSrcFormat = LcmsFormatForOPImageFormat(aSourceFormat, aSourceSpace);
|
||||
int lcmsDstFormat = LcmsFormatForOPImageFormat(aDestFormat, aDestSpace);
|
||||
|
||||
self->xform = cmsCreateTransform(aSourceSpace->profile, lcmsSrcFormat,
|
||||
aDestSpace->profile, lcmsDstFormat,
|
||||
lcmsIntent, 0);
|
||||
// FIXME: check for success
|
||||
|
||||
self->renderingIntent = anIntent;
|
||||
self->sourceFormat = aSourceFormat;
|
||||
self->destFormat = aDestFormat;
|
||||
self->pixelCount = aPixelCount;
|
||||
|
||||
if (sourceFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| sourceFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
tempBuffer1 = malloc(2 * pixelCount); // Convert to 16-bit
|
||||
}
|
||||
else if (sourceFormat.isAlphaPremultiplied)
|
||||
{
|
||||
tempBuffer1 = malloc(OPComponentNumberOfBytes(sourceFormat.compFormat) * pixelCount);
|
||||
}
|
||||
|
||||
if (destFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| destFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
tempBuffer2 = malloc(OPComponentNumberOfBytes(destFormat.compFormat) * pixelCount);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
cmsDeleteTransform(self->xform);
|
||||
[source release];
|
||||
[dest release];
|
||||
if (tempBuffer1)
|
||||
{
|
||||
free(tempBuffer1);
|
||||
}
|
||||
if (tempBuffer2)
|
||||
{
|
||||
free(tempBuffer2);
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) transformPixelData: (const unsigned char *)input
|
||||
output: (char *)output
|
||||
{
|
||||
char *tempOutput = output;
|
||||
|
||||
const size_t totalComponentsIn = sourceFormat.colorComponents + (sourceFormat.hasAlpha ? 1 : 0);
|
||||
const size_t totalComponentsOut = destFormat.colorComponents + (destFormat.hasAlpha ? 1 : 0);
|
||||
|
||||
//NSLog(@"Transform %d pixels %d comps in %d out", pixelCount, totalComponentsIn, totalComponentsOut);
|
||||
|
||||
// Special case for kOPComponentFormatFloat32bpc, which LCMS 1 doesn't support directly
|
||||
if (sourceFormat.compFormat == kOPComponentFormatFloat32bpc)
|
||||
{
|
||||
for (size_t i=0; i<pixelCount; i++)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsIn; j++)
|
||||
{
|
||||
((uint16_t*)tempBuffer1)[i*totalComponentsIn + j] = UINT16_MAX * ((float*)input)[i*totalComponentsIn + j];
|
||||
//NSLog(@"Input comp: %f => %d", (float)((float*)input)[i*totalComponentsIn + j],(int)((uint16_t*)tempBuffer1)[i*totalComponentsIn + j]);
|
||||
if ( (float)((float*)input)[i*totalComponentsIn + j] > 1)
|
||||
{
|
||||
NSLog(@"oveflow");
|
||||
}
|
||||
}
|
||||
}
|
||||
input = tempBuffer1;
|
||||
}
|
||||
else if (sourceFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
for (size_t i=0; i<pixelCount; i++)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsIn; j++)
|
||||
{
|
||||
((uint16_t*)tempBuffer1)[i*totalComponentsIn + j] = ((uint32_t*)input)[i*totalComponentsIn + j] >> 16;
|
||||
}
|
||||
}
|
||||
input = tempBuffer1;
|
||||
}
|
||||
|
||||
// Special case: if outputting kOPComponentFormatFloat32bpc, we get LCMS
|
||||
// to convert to uint32, then manually convert that to float
|
||||
if (destFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| destFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
tempOutput = tempBuffer2;
|
||||
}
|
||||
|
||||
// Unpremultiply alpha in input
|
||||
if (sourceFormat.isAlphaPremultiplied)
|
||||
{
|
||||
if (sourceFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| sourceFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
OPImageFormat fake = sourceFormat;
|
||||
fake.compFormat = kOPComponentFormat16bpc;
|
||||
OPPremultiplyAlpha(tempBuffer1, pixelCount, fake, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t numBytes = OPComponentNumberOfBytes(sourceFormat.compFormat) * pixelCount;
|
||||
memmove(tempBuffer1, input, numBytes);
|
||||
OPPremultiplyAlpha(tempBuffer1, pixelCount, sourceFormat, true);
|
||||
input = tempBuffer1;
|
||||
}
|
||||
}
|
||||
|
||||
cmsDoTransform(xform, (void*)input, tempOutput, pixelCount);
|
||||
|
||||
if (destFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| destFormat.compFormat == kOPComponentFormat32bpc
|
||||
|| destFormat.compFormat == kOPComponentFormat16bpc)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsIn; j++)
|
||||
{
|
||||
//NSLog(@"Transformed comp: %d => %d", ((uint16_t*)input[j]), (uint16_t*)tempOutput[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now copy the alpha
|
||||
|
||||
#if 0
|
||||
if (destFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| destFormat.compFormat == kOPComponentFormat32bpc
|
||||
|| destFormat.compFormat == kOPComponentFormat16bpc)
|
||||
{
|
||||
for (size_t i=0; i<pixelCount; i++)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsOut; j++)
|
||||
{
|
||||
((uint16_t*)tempOutput)[i*totalComponentsOut + j] = ((uint16_t*)tempBuffer2)[i*totalComponentsOut + j] / ((float)UINT16_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i=0; i<pixelCount; i++)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsOut; j++)
|
||||
{
|
||||
((float*)output)[i*totalComponentsOut + j] = ((uint16_t*)tempBuffer2)[i*totalComponentsOut + j] / ((float)UINT16_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Premultiply alpha in output
|
||||
if (destFormat.isAlphaPremultiplied)
|
||||
{
|
||||
OPImageFormat fake = sourceFormat;
|
||||
if (sourceFormat.compFormat == kOPComponentFormatFloat32bpc
|
||||
|| sourceFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
fake.compFormat = kOPComponentFormat16bpc;
|
||||
}
|
||||
OPPremultiplyAlpha(tempOutput, pixelCount, fake, false);
|
||||
}
|
||||
|
||||
if (destFormat.compFormat == kOPComponentFormatFloat32bpc)
|
||||
{
|
||||
for (size_t i=0; i<pixelCount; i++)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsOut; j++)
|
||||
{
|
||||
((float*)output)[i*totalComponentsOut + j] = ((uint16_t*)tempBuffer2)[i*totalComponentsOut + j] / ((float)UINT16_MAX);
|
||||
//NSLog(@"Output comp: %d => %f", (int)((uint16_t*)tempBuffer2)[i*totalComponentsOut + j], (float)((float*)output)[i*totalComponentsOut + j]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (destFormat.compFormat == kOPComponentFormat32bpc)
|
||||
{
|
||||
for (size_t i=0; i<pixelCount; i++)
|
||||
{
|
||||
for (size_t j=0; j<totalComponentsOut; j++)
|
||||
{
|
||||
((uint32_t*)output)[i*totalComponentsOut + j] = ((uint16_t*)tempBuffer2)[i*totalComponentsOut + j] << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -22,7 +22,33 @@
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
bool OPImageConvert(
|
||||
#include <CoreGraphics/CGColorSpace.h>
|
||||
#include <CoreGraphics/CGImage.h>
|
||||
|
||||
/**
|
||||
* To make the internals sane and fast, we only work with these four pixel components
|
||||
* internally. They are all native-endian.
|
||||
*/
|
||||
typedef enum OPComponentFormat
|
||||
{
|
||||
kOPComponentFormat8bpc,
|
||||
kOPComponentFormat16bpc,
|
||||
kOPComponentFormat32bpc,
|
||||
kOPComponentFormatFloat32bpc
|
||||
} OPComponentFormat;
|
||||
|
||||
typedef struct OPImageFormat
|
||||
{
|
||||
OPComponentFormat compFormat;
|
||||
size_t colorComponents;
|
||||
bool hasAlpha;
|
||||
bool isAlphaPremultiplied;
|
||||
bool isAlphaLast;
|
||||
} OPImageFormat;
|
||||
|
||||
size_t OPComponentNumberOfBytes(OPComponentFormat fmt);
|
||||
|
||||
void OPImageConvert(
|
||||
unsigned char *dstData,
|
||||
const unsigned char *srcData,
|
||||
size_t width,
|
||||
@ -37,4 +63,4 @@ bool OPImageConvert(
|
||||
CGBitmapInfo srcBitmapInfo,
|
||||
CGColorSpaceRef dstColorSpace,
|
||||
CGColorSpaceRef srcColorSpace,
|
||||
CGColorRenderingIntent intent);
|
||||
CGColorRenderingIntent intent);
|
250
Source/OPImageConversion.m
Normal file
250
Source/OPImageConversion.m
Normal file
@ -0,0 +1,250 @@
|
||||
/** <title>CGImage-conversion.m</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <lcms.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
#include "CoreGraphics/CGImage.h"
|
||||
|
||||
#import "CGColorSpace-private.h"
|
||||
|
||||
size_t OPComponentNumberOfBytes(OPComponentFormat fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case kOPComponentFormat8bpc:
|
||||
return 1;
|
||||
case kOPComponentFormat16bpc:
|
||||
return 2;
|
||||
case kOPComponentFormat32bpc:
|
||||
return 4;
|
||||
case kOPComponentFormatFloat32bpc:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint64_t swap64(uint64_t val)
|
||||
{
|
||||
char out[8];
|
||||
char *in = (char *)(&val);
|
||||
for (unsigned int i = 0; i<8; i++)
|
||||
{
|
||||
out[i] = in[7-i];
|
||||
}
|
||||
return *((uint64_t*)&out);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_set_bit_value(unsigned char *base, size_t msb_off, size_t bit_width,
|
||||
uint32_t val)
|
||||
{
|
||||
if (msb_off % 32 == 0 && bit_width == 32)
|
||||
{
|
||||
((uint32_t*)base)[msb_off / 32] = val;
|
||||
}
|
||||
else if (msb_off % 16 == 0 && bit_width == 16)
|
||||
{
|
||||
((uint16_t*)base)[msb_off / 16] = val;
|
||||
}
|
||||
else if (msb_off % 8 == 0 && bit_width == 8)
|
||||
{
|
||||
((uint8_t*)base)[msb_off / 8] = val;
|
||||
}
|
||||
else if (bit_width <= 32)
|
||||
{
|
||||
int byte1 = msb_off / 8;
|
||||
int shift = 64 - bit_width - (msb_off % 8);
|
||||
|
||||
uint64_t value = val;
|
||||
value &= ((1 << bit_width) - 1);
|
||||
value <<= shift;
|
||||
value = swap64(value); // if little endian
|
||||
|
||||
uint64_t mask = ((1 << bit_width) - 1);
|
||||
mask <<= shift;
|
||||
mask = ~mask;
|
||||
mask = swap64(mask); // if little endian
|
||||
|
||||
*((uint64_t*)(base + byte1)) &= mask;
|
||||
*((uint64_t*)(base + byte1)) |= value;
|
||||
}
|
||||
else
|
||||
{
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
_get_bit_value(const unsigned char *base, size_t msb_off, size_t bit_width)
|
||||
{
|
||||
if (msb_off % 32 == 0 && bit_width == 32)
|
||||
{
|
||||
return ((uint32_t*)base)[msb_off / 32];
|
||||
}
|
||||
else if (msb_off % 16 == 0 && bit_width == 16)
|
||||
{
|
||||
return ((uint16_t*)base)[msb_off / 16];
|
||||
}
|
||||
else if (msb_off % 8 == 0 && bit_width == 8)
|
||||
{
|
||||
return ((uint8_t*)base)[msb_off / 8];
|
||||
}
|
||||
else
|
||||
{
|
||||
int byte1 = msb_off / 8;
|
||||
int byte2 = ((msb_off + bit_width - 1) / 8);
|
||||
int shift = 64 - bit_width - (msb_off % 8);
|
||||
|
||||
int bytes_needed = byte2 - byte1 + 1;
|
||||
char chars[8];
|
||||
|
||||
switch (bytes_needed)
|
||||
{
|
||||
case 5: chars[4] = base[byte1+4];
|
||||
case 4: chars[3] = base[byte1+3];
|
||||
case 3: chars[2] = base[byte1+2];
|
||||
case 2: chars[1] = base[byte1+1];
|
||||
case 1: chars[0] = base[byte1+0];
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
uint64_t value = *((uint64_t*)chars);
|
||||
value = swap64(value); // if little endian
|
||||
value >>= shift;
|
||||
value &= ((1<<bit_width)-1);
|
||||
|
||||
return (uint32_t)value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rounds up a format to a standard size.
|
||||
*/
|
||||
static void OPRoundUp(size_t bitsPerComponentIn, size_t bitsPerPixelIn, size_t *bitsPerComponentOut, size_t *bitsPerPixelOut)
|
||||
{
|
||||
if (bitsPerComponentIn < 8)
|
||||
{
|
||||
*bitsPerComponentOut = 8;
|
||||
}
|
||||
else if (bitsPerComponentIn < 16)
|
||||
{
|
||||
*bitsPerComponentOut = 16;
|
||||
}
|
||||
else if (bitsPerComponentIn < 32)
|
||||
{
|
||||
*bitsPerComponentOut = 32;
|
||||
}
|
||||
|
||||
*bitsPerPixelOut = (bitsPerPixelIn / bitsPerComponentIn) * (*bitsPerComponentOut);
|
||||
}
|
||||
|
||||
static bool OPImageFormatForCGFormat(
|
||||
size_t bitsPerComponent,
|
||||
size_t bitsPerPixel,
|
||||
CGBitmapInfo bitmapInfo,
|
||||
CGColorSpaceRef colorSpace,
|
||||
OPImageFormat *out)
|
||||
{
|
||||
switch (bitsPerComponent)
|
||||
{
|
||||
case 8:
|
||||
out->compFormat = kOPComponentFormat8bpc;
|
||||
break;
|
||||
case 16:
|
||||
out->compFormat = kOPComponentFormat16bpc;
|
||||
break;
|
||||
case 32:
|
||||
if (bitmapInfo & kCGBitmapFloatComponents)
|
||||
{
|
||||
out->compFormat = kOPComponentFormat32bpc;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->compFormat = kOPComponentFormatFloat32bpc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t colorComponents = CGColorSpaceGetNumberOfComponents(colorSpace);
|
||||
size_t actualComponents = bitsPerPixel / bitsPerComponent;
|
||||
CGImageAlphaInfo alpha = bitmapInfo & kCGBitmapAlphaInfoMask;
|
||||
|
||||
out->colorComponents = colorComponents;
|
||||
out->hasAlpha = (alpha != kCGImageAlphaNone && actualComponents > colorComponents);
|
||||
out->isAlphaPremultiplied = (alpha == kCGImageAlphaPremultipliedFirst ||
|
||||
alpha == kCGImageAlphaPremultipliedLast);
|
||||
out->isAlphaLast = (alpha == kCGImageAlphaPremultipliedLast ||
|
||||
alpha == kCGImageAlphaLast);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OPImageConvert(
|
||||
unsigned char *dstData,
|
||||
const unsigned char *srcData,
|
||||
size_t width,
|
||||
size_t height,
|
||||
size_t dstBitsPerComponent,
|
||||
size_t srcBitsPerComponent,
|
||||
size_t dstBitsPerPixel,
|
||||
size_t srcBitsPerPixel,
|
||||
size_t dstBytesPerRow,
|
||||
size_t srcBytesPerRow,
|
||||
CGBitmapInfo dstBitmapInfo,
|
||||
CGBitmapInfo srcBitmapInfo,
|
||||
CGColorSpaceRef dstColorSpace,
|
||||
CGColorSpaceRef srcColorSpace,
|
||||
CGColorRenderingIntent intent)
|
||||
{
|
||||
// For now, just support conversions that OPColorTransform can docs
|
||||
OPImageFormat srcFormat, dstFormat;
|
||||
|
||||
if (!OPImageFormatForCGFormat(srcBitsPerComponent, srcBitsPerPixel, srcBitmapInfo, srcColorSpace, &srcFormat))
|
||||
{
|
||||
NSLog(@"Input format not supported");
|
||||
}
|
||||
if (!OPImageFormatForCGFormat(srcBitsPerComponent, srcBitsPerPixel, srcBitmapInfo, srcColorSpace, &dstFormat))
|
||||
{
|
||||
NSLog(@"Output format not supported");
|
||||
}
|
||||
|
||||
OPColorTransform *xform = [srcColorSpace colorTransformTo: dstColorSpace
|
||||
sourceFormat: srcFormat
|
||||
destinationFormat: dstFormat
|
||||
renderingIntent: intent
|
||||
pixelCount: width];
|
||||
for (size_t row=0; row<height; row++)
|
||||
{
|
||||
// FIXME: alpha
|
||||
[xform transformPixelData: srcData + (row * srcBytesPerRow)
|
||||
output: dstData + (row * dstBytesPerRow)];
|
||||
}
|
||||
|
||||
}
|
33
Source/OPPremultiplyAlpha.h
Normal file
33
Source/OPPremultiplyAlpha.h
Normal file
@ -0,0 +1,33 @@
|
||||
/** <title>OPPremultiplyAlpha</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "OPImageConversion.h"
|
||||
#import "CGColorSpace-private.h"
|
||||
|
||||
void OPPremultiplyAlpha(
|
||||
unsigned char *row,
|
||||
size_t pixels,
|
||||
OPImageFormat format,
|
||||
bool unPremultiply
|
||||
);
|
67
Source/OPPremultiplyAlpha.m
Normal file
67
Source/OPPremultiplyAlpha.m
Normal file
@ -0,0 +1,67 @@
|
||||
/** <title>OPColorTransformLCMS</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "OPPremultiplyAlpha.h"
|
||||
|
||||
#define _OPPremultiplyAlpha(format, compType, compMax, rowStart, comps, pixels, unPremultiply) \
|
||||
for (compType *comp = (compType*)rowStart; comp < ((compType*)rowStart)+(pixels * comps); comp += comps) \
|
||||
{ \
|
||||
const size_t firstComp = (format.isAlphaLast ? 0 : 1); \
|
||||
const size_t lastComp = (format.isAlphaLast ? (comps - 2) : (comps - 1)); \
|
||||
const size_t alphaComp = (format.isAlphaLast ? (comps - 1) : 0); \
|
||||
const float alphaValue = comp[alphaComp] / (float)compMax; \
|
||||
for (size_t i = firstComp; i<=lastComp; i++) \
|
||||
{ \
|
||||
comp[i] *= (unPremultiply ? (1.0/alphaValue) : alphaValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
void OPPremultiplyAlpha(
|
||||
unsigned char *row,
|
||||
size_t pixels,
|
||||
OPImageFormat format,
|
||||
bool unPremultiply)
|
||||
{
|
||||
if (unPremultiply == !format.isAlphaPremultiplied || !format.hasAlpha)
|
||||
return;
|
||||
|
||||
const size_t comps = (format.colorComponents + 1);
|
||||
|
||||
switch (format.compFormat)
|
||||
{
|
||||
case kOPComponentFormat8bpc:
|
||||
_OPPremultiplyAlpha(format, uint8_t, UINT8_MAX, row, comps, pixels, unPremultiply);
|
||||
break;
|
||||
case kOPComponentFormat16bpc:
|
||||
_OPPremultiplyAlpha(format, uint16_t, UINT16_MAX, row, comps, pixels, unPremultiply);
|
||||
break;
|
||||
case kOPComponentFormat32bpc:
|
||||
_OPPremultiplyAlpha(format, uint32_t, UINT32_MAX, row, comps, pixels, unPremultiply);
|
||||
break;
|
||||
case kOPComponentFormatFloat32bpc:
|
||||
_OPPremultiplyAlpha(format, float, 1.0f, row, comps, pixels, unPremultiply);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,176 +0,0 @@
|
||||
/** <title>CGImage-conversion.m</title>
|
||||
|
||||
<abstract>C Interface to graphics drawing library</abstract>
|
||||
|
||||
Copyright <copy>(C) 2010 Free Software Foundation, Inc.</copy>
|
||||
|
||||
Author: Eric Wasylishen <ewasylishen@gmail.com>
|
||||
Date: July, 2010
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <lcms.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#include "CoreGraphics/CGColorSpace.h"
|
||||
#include "CoreGraphics/CGImage.h"
|
||||
|
||||
static int LcmsIntentForCGColorRenderingIntent(CGColorRenderingIntent intent)
|
||||
{
|
||||
switch (intent)
|
||||
{
|
||||
default:
|
||||
case kCGRenderingIntentDefault:
|
||||
return INTENT_RELATIVE_COLORIMETRIC; // FIXME: what should we do here?
|
||||
case kCGRenderingIntentAbsoluteColorimetric:
|
||||
return INTENT_ABSOLUTE_COLORIMETRIC;
|
||||
case kCGRenderingIntentRelativeColorimetric:
|
||||
return INTENT_RELATIVE_COLORIMETRIC;
|
||||
case kCGRenderingIntentPerceptual:
|
||||
return INTENT_PERCEPTUAL;
|
||||
case kCGRenderingIntentSaturation:
|
||||
return INTENT_SATURATION;
|
||||
}
|
||||
}
|
||||
|
||||
static int LcmsPixelTypeForCGColorSpaceModel(CGColorSpaceModel model)
|
||||
{
|
||||
switch (model)
|
||||
{
|
||||
case kCGColorSpaceModelMonochrome:
|
||||
return PT_GRAY;
|
||||
case kCGColorSpaceModelRGB:
|
||||
return PT_RGB;
|
||||
case kCGColorSpaceModelCMYK:
|
||||
return PT_CMYK;
|
||||
case kCGColorSpaceModelLab:
|
||||
return PT_Lab;
|
||||
case kCGColorSpaceModelUnknown:
|
||||
case kCGColorSpaceModelDeviceN:
|
||||
case kCGColorSpaceModelIndexed:
|
||||
case kCGColorSpaceModelPattern:
|
||||
default:
|
||||
return PT_ANY;
|
||||
}
|
||||
}
|
||||
|
||||
static bool LcmsFormatForCGFormat(
|
||||
size_t bitsPerComponent,
|
||||
size_t bitsPerPixel,
|
||||
CGBitmapInfo info,
|
||||
CGColorSpaceRef colorSpace,
|
||||
DWORD *outFormat)
|
||||
{
|
||||
DWORD format = 0;
|
||||
|
||||
if (info & kCGBitmapFloatComponents)
|
||||
{
|
||||
// LCMS 2 supports floats
|
||||
NSLog(@"Floats not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bitsPerComponent % 8 != 0)
|
||||
{
|
||||
NSLog(@"Only multiples of 8 BPC supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bitsPerPixel % bitsPerComponent != 0)
|
||||
{
|
||||
NSLog(@"bitsPerPixel not a multiple of bitsPerComponent");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t colorComponents = CGColorSpaceGetNumberOfComponents(colorSpace);
|
||||
size_t actualComponents = bitsPerPixel / bitsPerComponent;
|
||||
CGImageAlphaInfo alpha = info & kCGBitmapAlphaInfoMask;
|
||||
|
||||
format |= BYTES_SH(bitsPerComponent / 8);
|
||||
format |= CHANNELS_SH(colorComponents);
|
||||
|
||||
if (colorComponents == actualComponents - 1)
|
||||
{
|
||||
format |= EXTRA_SH(1);
|
||||
if (alpha == kCGImageAlphaFirst ||
|
||||
alpha == kCGImageAlphaNoneSkipFirst ||
|
||||
alpha == kCGImageAlphaPremultipliedFirst)
|
||||
{
|
||||
format |= SWAPFIRST_SH(1);
|
||||
}
|
||||
}
|
||||
else if (colorComponents != actualComponents)
|
||||
{
|
||||
NSLog(@"colorComponents don't make sense");
|
||||
return false;
|
||||
}
|
||||
|
||||
format |= COLORSPACE_SH(
|
||||
LcmsPixelTypeForCGColorSpaceModel(
|
||||
CGColorSpaceGetModel(colorSpace)
|
||||
)
|
||||
);
|
||||
|
||||
*outFormat = format;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OPImageConvert(
|
||||
unsigned char *dstData,
|
||||
const unsigned char *srcData,
|
||||
size_t width,
|
||||
size_t height,
|
||||
size_t dstBitsPerComponent,
|
||||
size_t srcBitsPerComponent,
|
||||
size_t dstBitsPerPixel,
|
||||
size_t srcBitsPerPixel,
|
||||
size_t dstBytesPerRow,
|
||||
size_t srcBytesPerRow,
|
||||
CGBitmapInfo dstBitmapInfo,
|
||||
CGBitmapInfo srcBitmapInfo,
|
||||
CGColorSpaceRef dstColorSpace,
|
||||
CGColorSpaceRef srcColorSpace,
|
||||
CGColorRenderingIntent intent)
|
||||
{
|
||||
DWORD lcmsSrcFormat, lcmsDstFormat;
|
||||
|
||||
if (!LcmsFormatForCGFormat(srcBitsPerComponent, srcBitsPerPixel, srcBitmapInfo, srcColorSpace, &lcmsSrcFormat))
|
||||
{
|
||||
NSLog(@"Couldn't find LCMS format for source format");
|
||||
return false;
|
||||
}
|
||||
if (!LcmsFormatForCGFormat(dstBitsPerComponent, dstBitsPerPixel, dstBitmapInfo, dstColorSpace, &lcmsDstFormat))
|
||||
{
|
||||
NSLog(@"Couldn't find LCMS format for dest format");
|
||||
return false;
|
||||
}
|
||||
|
||||
cmsHPROFILE srgb = cmsCreate_sRGBProfile();
|
||||
|
||||
cmsHTRANSFORM xform = cmsCreateTransform(srgb, lcmsSrcFormat, srgb, lcmsDstFormat,
|
||||
LcmsIntentForCGColorRenderingIntent(intent), 0);
|
||||
|
||||
for (size_t row = 0; row < height; row++)
|
||||
{
|
||||
unsigned char *dstRow = dstData + (dstBytesPerRow * row);
|
||||
const unsigned char *srcRow = srcData + (srcBytesPerRow * row);
|
||||
cmsDoTransform(xform, (void*)srcRow, dstRow, width);
|
||||
}
|
||||
|
||||
cmsDeleteTransform(xform);
|
||||
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue
Block a user