palette icon indicating copy to clipboard operation
palette copied to clipboard

CMYK

Open flosse opened this issue 9 years ago • 7 comments

It would be cool to be able to convert to an from CMYK :)

flosse avatar Jan 12 '16 13:01 flosse

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. :)

Ogeon avatar Jan 12 '16 13:01 Ogeon

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.

Ogeon avatar Feb 03 '16 13:02 Ogeon

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?

flosse avatar Feb 03 '16 14:02 flosse

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...

Ogeon avatar Feb 03 '16 15:02 Ogeon