palette
palette copied to clipboard
CMYK
It would be cool to be able to convert to an from CMYK :)
I have been holding off on device specific color spaces because of the hairy business around different devices. The values of CMYK depends on printers and the colors of their ink, which makes it particularly tricky, but I think I saw some "standard" formula somewhere that may be "good enough". Same for CMY. It's definitely worth investigating, since they are both very common. :)
Looks like there's no way to implement accurate CMYK without a color profile, since it depends on paper color, ink, etc. The only possibility without implementing color profile support is the naive implementation, where
black = 1 - max(red, green, blue)
cyan = (1 - red - black) / (1 - black), or 0 if black is 1
magenta = (1 - green - black) / (1 - black), or 0 if black is 1
yellow = (1 - blue - black) / (1 - black), or 0 if black is 1
red = 1 - min(1, cyan * (1 - black) + black)
green = 1 - min(1, magenta * (1 - black) + black)
blue = 1 - min(1, yellow * (1 - black) + black)
Some people may prefer to define their colors this way, so it may still be useful as an input interface, but the colors won't be accurate.
hm... I think something like black = 1 - max(red, green, blue)
is not the solution we want.
But having a stuct that can hold CMYK values is useful. More general, a generic type that can hold n
different channels could allow to define custom spaces. Let's say you want to print something special, then you'd define the colors c
, m
, y
, k
but also e.g. two spot colors custom0
and custom1
.
And transforming from color space A
to color space B
should only be implemented if it is definite. In all other cases I'd offer a convert
function where you can pass in your custom function.
That would look like this (pseudocode):
let my_rgb = Rgb::new(0.5, 0.3, 0.7);
let my_foo: FooColor = my_rgb.convert::<FooColor>(|channels|{
let a = some_calc(channels[0], channels[2]);
let b = some_cals(channels[1], channels[2]);
FooColor::new(a,b)
});
Then you can also offer official standard profiles and just do s.th. like
let my_cmyk = my_rgb.convert::<Cmyk>(Cmyk::Profiles::ISOUncoded_v2);
What do you think?
Yea, something like that is probably the way to go. The main problem with implementing the naive variant is that it can be mistaken for the accurate variant, so I feel like it should be avoided. I'll postpone this for the time being, until a concrete solution comes up, but it looks like some form of color profile support is desirable. A more generic conversion interface can still be independently added. I'll open a couple of issues...