Skip to content

Instantly share code, notes, and snippets.

@Tricertops
Last active August 27, 2015 12:35
Show Gist options
  • Save Tricertops/9f145fb3e92920211d8a to your computer and use it in GitHub Desktop.
Save Tricertops/9f145fb3e92920211d8a to your computer and use it in GitHub Desktop.
Converting colors on OS X between RGB color spaces without clamping their values. Will not work on iOS, because kCGBitmapFloatComponents is not supported.
// © 2015 PixelCut, provided under MIT license.
//! Inputs
CGColorSpace sourceSpace; // Display RGB, Generic RGB, sRGB, any RGB
CGFloat sourceRed; // Can be out of 0..1 range.
CGFloat sourceGreen; // Can be out of 0..1 range.
CGFloat sourceBlue; // Can be out of 0..1 range.
CGColorSpaceRef targetSpace; // Display RGB, Generic RGB, sRGB, any RGB
//! Setup all required values
NSUInteger const componentsPerPixel = CGColorSpaceGetNumberOfComponents(targetSpace) + 1; // alpha
NSUInteger const bytesPerComponent = sizeof(float);
NSUInteger const bitsPerComponent = bytesPerComponent * CHAR_BIT;
NSUInteger const bitsPerPixel = bitsPerComponent * componentsPerPixel;
NSUInteger const dimension = 1;
NSUInteger const bytesPerRow = bytesPerComponent * componentsPerPixel * dimension;
CGFloat const* decode = nil;
BOOL const shouldInterpolate = NO;
CGBitmapInfo const options = (kCGBitmapFloatComponents | kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast);
//! Populate source bitmap.
NSMutableData* sourceBitmap = [NSMutableData dataWithLength: bytesPerRow];
float* sourceComponents = sourceBitmap.mutableBytes;
sourceComponents[0] = sourceRed;
sourceComponents[1] = sourceGreen;
sourceComponents[2] = sourceBlue;
sourceComponents[3] = 1;
//! Create source image.
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)sourceBitmap);
CGImageRef sourceImage = CGImageCreate(dimension, dimension,
bitsPerComponent, bitsPerPixel, bytesPerRow,
sourceSpace, options,
provider,
decode, shouldInterpolate, kCGRenderingIntentDefault);
CFRelease(sourceSpace);
CFRelease(provider);
//! Create target context.
NSMutableData* bitmap = [NSMutableData dataWithLength: bytesPerRow];
CGContextRef context = CGBitmapContextCreate(bitmap.mutableBytes,
dimension, dimension,
bitsPerComponent, bytesPerRow,
targetSpace,
options);
//! Convert the single sample
CGContextDrawImage(context, CGRectMake(0, 0, dimension, dimension), sourceImage);
CFRelease(sourceImage);
CFRelease(context);
CFRelease(targetSpace);
//! Grab the converted components.
const float* targetComponents = bitmap.bytes;
CGFloat targetRed = targetComponents[0]; // Can be out of 0..1 range.
CGFloat targetGreen = targetComponents[1]; // Can be out of 0..1 range.
CGFloat targetBlue = targetComponents[2]; // Can be out of 0..1 range.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment