bennyguitar / Colours

A beautiful set of predefined colors and a set of color methods to make your iOS/OSX development life easier.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

New method to get colour given distance and variable parameter

danhalliday opened this issue · comments

I'm working on a project that needs a fair bit of colour work, and thought I'd take a stab at contributing here as your project already has some of what I'll need (LAB support).

I'm looking to add some methods which produce a derivative colour with a set perceptual distance, based on altering some parameter of the original colour. For example, say you want a highlight colour that's just noticeable on top of a given background colour, regardless what the background is. Maybe it'd look something like this:

let highlight = base.colourWithDistance(5, variable: .CIE_L, direction: .Up, type: .CIE76)

I thought I knew how to do it (rearrange the various formulas in the distanceFromColor:colortype:distanceType methods and solve for variable), but I'm stuck on the basic LAB manipulation. Does anyone have an idea why in the following code, when I change L, A and B also change? Am I misunderstanding how the LAB model works? Are L, A and B not independent?

let firstColour = ...

let dictionary1 = firstColour.CIE_LabDictionary() as [NSString:NSNumber]
println(dictionary1)

dictionary1[kColoursCIE_L] = 60

let secondColour = UIColor(fromCIE_LabDictionary: dictionary1)
dictionary2 = secondColour.CIE_LabDictionary() as [NSString:NSNumber]
println(dictionary2)


// Gives:
// [LABa-A: -57.8215, LABa-L: 91.2403, LABa-B: 87.4349, LABa-a: 1]
// [LABa-A: -54.8815, LABa-L: 60.2418, LABa-B: 61.5021, LABa-a: 1]

Thanks for any input!

My initial mathematical inclination is that _a and b should be unaffected as L changes, but I'm not extremely familiar with how it all works. I basically just transcribed the formulas from Wikipedia (going from RGB to L_a_b, and then the distances between L_ab values).

My guess is that there is some loss of precision with the RGB -> L_a_b and vice versa calculations that make it inexact. I'll explore this in depth when I get some free time.

Just tried this with an Objective-C only app and seems to confirm it's a precision thing, as the following works fine (to several decimal places):

NSColor *first = [NSColor seafoamColor];
NSArray *firstLab = [first CIE_LabArray];

float l = [[firstLab objectAtIndex:0] floatValue];
float a = [[firstLab objectAtIndex:1] floatValue];
float b = [[firstLab objectAtIndex:2] floatValue];

NSLog(@"%@", firstLab);

NSColor *second = [NSColor colorFromCIE_LabArray:@[@(l-50), @(a), @(b), @1]];
NSArray *secondLab = [second CIE_LabArray];

NSLog(@"%@", secondLab);

// Gives:
// ("80.66308836072838", "-58.30120582025216", "30.79395128553721", 1)
// ("30.66368317685438", "-58.30043357569728", "30.79344302647758", 1)

I'm going to close this for now, as it seems to be a bug with Swift's precision and not necessarily my library.