Skip to content

Instantly share code, notes, and snippets.

@sandymc
Last active September 3, 2020 23:25
Show Gist options
  • Save sandymc/7382989 to your computer and use it in GitHub Desktop.
Save sandymc/7382989 to your computer and use it in GitHub Desktop.
This code snippet shows how to convert an image buffer between color spaces (e.g., transform from ProPhoto to sRGB or whatever) using Apple's new (and entirely undocumented) ColorSyncTransformConvert function. Firstly, a transform is created, then that transform is used to convert an image buffer.
const void *keys[] = {kColorSyncProfile, kColorSyncRenderingIntent, kColorSyncTransformTag};
const void *srcVals[] = {[srcProfile ref], kColorSyncRenderingIntentUseProfileHeader, kColorSyncTransformDeviceToPCS};
const void *dstVals[] = {[destProfile ref], kColorSyncRenderingIntentUseProfileHeader, kColorSyncTransformPCSToDevice};
CFDictionaryRef srcDict = CFDictionaryCreate (
NULL,
(const void **)keys,
(const void **)srcVals,
3,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryRef dstDict = CFDictionaryCreate (
NULL,
(const void **)keys,
(const void **)dstVals,
3,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
const void* arrayVals[] = {srcDict, dstDict, NULL};
CFArrayRef profileSequence = CFArrayCreate(NULL, (const void **)arrayVals, 2, &kCFTypeArrayCallBacks);
transform = ColorSyncTransformCreate (profileSequence, NULL);
if (srcDict) CFRelease (srcDict);
if (dstDict) CFRelease (dstDict);
if (profileSequence) CFRelease (profileSequence);
Notes to the code:
1. This is designed to work on buffers that are either 32 bit float or 16 bit uint; RGBA packed
2. [srcProfile ref] and [destProfile ref] return ColorSyncProfileRefs
3. srcProfile is the existing color profile; destProfile is what you want
3. transform is a ColorSyncTransformRef, and must be released when done
5. This example operates in place; there's no documentation to suggest whether in-place operation is actually supported. But then, there's no documentation at all.
void* dst;
void* scr;
ColorSyncDataDepth depth;
ColorSyncDataLayout layout;
size_t bytesPerRow;
if (_imageBuf.isFloat) {
scr = [_imageBuf bufferFloatForRow:0 col:0];
dst = scr;
depth = kColorSync32BitFloat;
layout = kColorSyncAlphaLast;
bytesPerRow = _imageBuf.imageWidth*4*sizeof(float);
}
else {
scr = [_imageBuf bufferU16ForRow:0 col:0];
dst = scr;
depth = kColorSync16BitInteger;
layout = kColorSyncAlphaLast;
bytesPerRow = _imageBuf.imageWidth*4*sizeof(uint16);
}
bool result = ColorSyncTransformConvert (
transform, // transform - transform to be used for converting color
_imageBuf.imageWidth, // width - width of the image in pixels
_imageBuf.imageHeight, // height - height of the image in pixels
dst, // dst - a pointer to the destination where the results will be written.
depth, // dstDepth - describes the bit depth and type of the destination color components
layout, // dstFormat - describes the format and byte packing of the destination pixels
bytesPerRow, // dstBytesPerRow - number of bytes in the row of data
scr, // src - a pointer to the data to be converted.
depth, // srcDepth - describes the bit depth and type of the source color components
layout, // srcFormat - describes the format and byte packing of the source pixels
bytesPerRow, // srcBytesPerRow - number of bytes in the row of data
nil); // CFDictionaryRef options
if (!result) {
NSLog(@"%s error in ColorSyncTransformConvert", __PRETTY_FUNCTION__);
}
@iollmann
Copy link

iollmann commented Sep 3, 2020

I think you are almost always better off using vImageConvert_AnyToAny with a CGColorConversionInfoRef these days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment