3

Simple question, more than likely complex answer:

How can I get CMYK and Lab values from a UIColor object (of which I know the RGB values if it helps)?

I have found this regarding getting CMYK values but I can't get any accurate values out of it, despite it being everywhere, I've heard it's not a great snippet.

CGFloat rgbComponents[4];
    [color getRed:&rgbComponents[0] green:&rgbComponents[1] blue:&rgbComponents[2] alpha:&rgbComponents[3]];

    CGFloat k = MIN(1-rgbComponents[0], MIN(1-rgbComponents[1], 1-rgbComponents[2]));
    CGFloat c = (1-rgbComponents[0]-k)/(1-k);
    CGFloat m = (1-rgbComponents[1]-k)/(1-k);
    CGFloat y = (1-rgbComponents[2]-k)/(1-k);
halfer
  • 19,824
  • 17
  • 99
  • 186
Josh Kahane
  • 16,765
  • 45
  • 140
  • 253
  • See http://stackoverflow.com/questions/4858131/rgb-to-cmyk-and-back-algorithm?rq=1 It's for Java but the basics apply. – rmaddy Feb 16 '13 at 18:37
  • I also thought that ICC based color conversion is the right thing to do. But the ColorSync API is not available on iOS (and deprecated as of OS X 10.6). – Martin R Feb 16 '13 at 20:22
  • @Josh Kahane: The color conversion formula you have pasted can be found all over the web. Yet since color conversion is far from a simple system that can be captured in a single formula, the result of a formula will be poor and useless. There's no way around using color profiles. – Codo Feb 17 '13 at 08:51

2 Answers2

5

For ICC-based color conversion, you can use the Little Color Management System. (I have just added all .c and .h files from the download archive to an iOS Xcode project. It compiled and ran the following code without problems.)

Remark: RGB and CMYK are a device dependent color spaces, Lab is a device independent color space. Therefore, to convert from RGB to Lab, you have to choose a device independent (or "calibrated") RGB color space for the conversion, for example sRGB.

Little CMS comes with built-in profiles for sRGB and Lab color spaces. A conversion from sRGB to Lab looks like this:

Create a color transformation:

cmsHPROFILE rgbProfile = cmsCreate_sRGBProfile();
cmsHPROFILE labProfile = cmsCreateLab4Profile(NULL);
cmsHTRANSFORM xform = cmsCreateTransform(rgbProfile, TYPE_RGB_FLT, labProfile,
                                         TYPE_Lab_FLT,
                                         INTENT_PERCEPTUAL, 0);
cmsCloseProfile(labProfile);
cmsCloseProfile(rgbProfile);

Convert colors:

float rgbValues[3];
// fill rgbValues array with input values ...
float labValues[3];
cmsDoTransform(xform, rgbValues, labValues, 1);
// labValues array contains output values.

Dispose of color transformation:

cmsDeleteTransform(xform);

Of course, the transformation would be created only once and used for all color conversions.

For RGB to CMYK conversion you can also use Little CMS, but you have to provide an ICC-Profile, e.g. one from the free Adobe download page ICC profile downloads for Mac OS.

Code example for RGB to CMYK conversion:

float rgb[3]; // fill with input values (range 0.0 .. 1.0)
float cmyk[4]; // output values (range 0.0 .. 100.0)

cmsHPROFILE rgbProfile = cmsCreate_sRGBProfile();

// The CMYK profile is a resource in the application bundle:
NSString *cmykProfilePath = [[NSBundle mainBundle] pathForResource:@"YourCMYKProfile.icc" ofType:nil];
cmsHPROFILE cmykProfile = cmsOpenProfileFromFile([cmykProfilePath fileSystemRepresentation], "r");

cmsHTRANSFORM xform = cmsCreateTransform(rgbProfile, TYPE_RGB_FLT, cmykProfile,
                                         TYPE_CMYK_FLT,
                                         INTENT_PERCEPTUAL, 0);

cmsCloseProfile(cmykProfile);
cmsCloseProfile(rgbProfile);

cmsDoTransform(xform, rgb, cmyk, 1);

cmsDeleteTransform(xform);
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Just curious, is iOS using sRGB as display color space? – guitarflow Feb 16 '13 at 23:47
  • @guitarflow: I don't know (and I don't even know if it is documented). I took sRGB as an example in the code because it widely used. But I will edit my answer to make that more clear. – Martin R Feb 16 '13 at 23:59
  • Ah ok. Thanks. I assumed that UIScreen also has a color space attached one can query for. It seems like it isn't. So you have to assume a color space. I guess sRGB would be a good assumption. – guitarflow Feb 17 '13 at 00:07
  • I still think that writing a category for UIColor would be the easiest way to do this. Just use littleCMS there and you're good. – guitarflow Feb 17 '13 at 10:53
  • @guitarflow: Of course you can do the color conversion in a UIColor category method. But for efficiency the creation of the color transform should be done only once. – Martin R Feb 17 '13 at 13:56
  • First obstacle. I have added all the Little CMS source .c and .h files and failed to compile as jpeglib.h is not found. Its not included int he download, any ideas why you had success compiling? Nor mex.h or lcmd.h – Josh Kahane Feb 24 '13 at 19:33
  • @Josh I will reproduce my steps later when I am at my computer again. – Martin R Feb 24 '13 at 20:25
  • Ok, no worries and thanks. They seem to be mystery files, nowhere to be seen, yet included in the files. – Josh Kahane Feb 24 '13 at 20:26
  • 1
    @JoshKahane: I added the following files from lcms to the Xcode project: lcms2.h and lcms2_plugin.h from the include directory, all .c and .h files from the src directory. That's all you need for the library. In your code you only have to `#include "lcms2.h"`. - I hope that helps, otherwise let me know. – Martin R Feb 24 '13 at 21:55
  • Huh, that will teach me to be a bit more thorough, I had added exactly those, deleted them and re-added and I had success this time. Well the conversion to Lab works wonderfully which is brilliant, but I'm struggling to see how to achieve a CMYK conversion, sorry, but thanks for getting me this far! – Josh Kahane Feb 25 '13 at 00:57
  • A note to others who may see this. From testing the Lab conversion is slightly strange, not entirely accurate. One or two of the values are always out by 1-3 ish. For example, convert black RGB, 0, 0, 0 and I get this in Lab: 3, 0, 0. Its should be 0, 0, 0. – Josh Kahane Feb 25 '13 at 13:49
  • Turns out this is because (as in the sample code above) `cmsCreateLab4Profile` is used, for Photoshop Lab color replication you want `cmsCreateLab2Profile` instead. – Josh Kahane Feb 25 '13 at 14:03
  • @JoshKahane: Thank you for the information! Did you have success with the conversion to CMYK? – Martin R Feb 25 '13 at 18:06
  • Sadly not! I have tried using `cmsOpenProfileFromFile("USWebCoatedSWOP.icc", "r");` for the custom profile but it crashes during the transform. Had no luck finding a solution. – Josh Kahane Feb 25 '13 at 18:25
  • @JoshKahane: I have added a code example, perhaps it helps. Note that (for whatever reason) CMYK values are scaled to 0..100, not 0..1 as the RGB input values. – Martin R Feb 25 '13 at 18:46
  • Bugger me, that worked a charm. The single thing I wasn't doing was pointing to the file location of the profile and doing so made everything work. Thanks a lot, you've been ever such a lot of help! Hopefully will be to others too, I've seen this question pop up an awful lot unanswered! Thanks again. (P.S CMYK is scaled from 0..100 because its a percentage of color, cyan, magenta, yellow, key/black). – Josh Kahane Feb 25 '13 at 19:19
  • 1
    @guitarflow and Martin, it seems that starting with the iPhone 5 Apple claimed the screen had a full sRGB gamut (It comes very close: [AnandTech](http://www.anandtech.com/show/6334/iphone-5-screen-performance), [Mark Meyer](http://www.photo-mark.com/notes/2012/sep/25/iphone-5-color/)). I am still curious however, if we can get the device color profile! converting from RGB -> Lab with some other profile seems problematic to me. – Warpling May 28 '14 at 17:32
2

To get the LAB values you need to convert the RGB values into XYZ values which you can then convert into RGB values.

- (NSMutableArray *) convertRGBtoLABwithColor: (UIColor *)color



////make variables to get rgb values
CGFloat red3;
CGFloat green3;
CGFloat blue3;
//get rgb of color
[color getRed:&red3 green:&green3 blue:&blue3 alpha:nil];

float red2 = (float)red3*255;
float blue2 = (float)blue3*255;
float green2 = (float)green3*255;

//first convert RGB to XYZ

// same values, from 0 to 1
red2 = red2/255;
green2 = green2/255;
blue2 = blue2/255;

// adjusting values
if(red2 > 0.04045)
{
    red2 = (red2 + 0.055)/1.055;
    red2 = pow(red2,2.4);
} else {
    red2 = red2/12.92;
}

if(green2 > 0.04045)
{
    green2 = (green2 + 0.055)/1.055;
    green2 = pow(green2,2.4);
} else {
    green2 = green2/12.92;
}

if(blue2 > 0.04045)
{
    blue2 = (blue2 + 0.055)/1.055;
    blue2 = pow(blue2,2.4);
} else {
    blue2 = blue2/12.92;
}

red2 *= 100;
green2 *= 100;
blue2 *= 100;

//make x, y and z variables
float x;
float y;
float z;

// applying the matrix to finally have XYZ
x = (red2 * 0.4124) + (green2 * 0.3576) + (blue2 * 0.1805);
y = (red2 * 0.2126) + (green2 * 0.7152) + (blue2 * 0.0722);
z = (red2 * 0.0193) + (green2 * 0.1192) + (blue2 * 0.9505);

//then convert XYZ to LAB

x = x/95.047;
y = y/100;
z = z/108.883;

// adjusting the values
if(x > 0.008856)
{
    x = powf(x,(1.0/3.0));
} else {
    x = ((7.787 * x) + (16/116));
}

if(y > 0.008856)
{
    y = pow(y,(1.0/3.0));
} else {
    y = ((7.787 * y) + (16/116));
}

if(z > 0.008856)
{
    z = pow(z,(1.0/3.0));
} else {
    z = ((7.787 * z) + (16/116));
}

//make L, A and B variables
float l;
float a;
float b;

//finally have your l, a, b variables!!!!
l = ((116 * y) - 16);
a = 500 * (x - y);
b = 200 * (y - z);

NSNumber *lNumber = [NSNumber numberWithFloat:l];
NSNumber *aNumber = [NSNumber numberWithFloat:a];
NSNumber *bNumber = [NSNumber numberWithFloat:b];

//add them to an array to return.
NSMutableArray *labArray = [[NSMutableArray alloc] init];
[labArray addObject:lNumber];
[labArray addObject:aNumber];
[labArray addObject:bNumber];

return labArray;
}
creeperspeak
  • 5,403
  • 1
  • 17
  • 38
Nathan L
  • 21
  • 1
  • 1