mandykoh / prism

Colour management for Go
MIT License
47 stars 7 forks source link

Converting arbitrary color profiles #9

Open kovidgoyal opened 1 year ago

kovidgoyal commented 1 year ago

It's not clear from the documentation how to linearise an image in an unknown color space. Given that I have gotten the ICCProfile struct from the metadata. How do I go from that to a linearisation? The equivalent code using lcms would be to use cmcCreateTransform with the input profile read from the image and whatever output profile you want.

Apologies if I am missing something obvious.

mandykoh commented 1 year ago

Hi @kovidgoyal, sorry, you haven't missed anything. As mentioned in the readme, there's currently no support for arbitrary profiles. Help would definitely be appreciated in this area.

kovidgoyal commented 1 year ago

Ah, sorry I missed that. I would actually be willing to help as I need this functionality in one of my own projects in pure Go, however I have no domain knowledge here. I guess the first step would be to read the color data from the profile? Which would mean adding support for that to the png/jpg/webp backends, or do those already extract complete profiles and we have to implement the actual reading/parsing/conversion?

mandykoh commented 1 year ago

Right now, meta/icc/profilereader.go can parse an ICC profile and extract the header and the tag table (into a icc.Profile struct). That's enough to get simple things like the name of the profile, which is sufficient to identify well-known profiles. But to work with arbitrary profiles we‘d need to extend this to also extract the actual bits pertaining to colour space conversion.

This is a fair bit of work (basically, it entails implementing most of the ICC profile format spec), but it's really the first necessary step. The main complexity comes from the many different ways profile information can be stored, but getting basic support for some commonly encountered profiles would be an enormous step forward.

Edit: The jpeg/png/webp loaders can already pull out the full ICC profile so those don't need to change.

kovidgoyal commented 1 year ago

OK I glanced through the spec writing a parser should be well within my abilities, if I commit to doing that, would you be willing to commit to implementing the actual color conversions, since acquiring the domain knowledge for that would take me a fair bit of time.

Also I notice prism is MIT licensed, is that a hard requirement for you? I personally prefer the GPL3.

Last question: Is there some pre-existing set of "representative" profiles I can use to test with as I work on the parser.

mandykoh commented 1 year ago

…would you be willing to commit to implementing the actual color conversions, since acquiring the domain knowledge for that would take me a fair bit of time.

I definitely want to have this in time, but can‘t commit to a deadline since I’m full time employed. Also I’d be learning some of the colour conversion math too, particularly anything to do with CMYK; the CMYK <-> RGB process is a bit involved and the math isn’t clear to me.

Are there specific kinds of profiles you’re trying to support?

Also I notice prism is MIT licensed, is that a hard requirement for you? I personally prefer the GPL3.

I’d like for this project to be legally unencumbered for anyone who wants to use it. I don’t particularly have a bugbear about closed source usage if someone so chooses. (And it may be worth noting that there are parts of the ICC spec which seem to be covered by their own patents already, that we may not be able to implement.)

Last question: Is there some pre-existing set of "representative" profiles I can use to test with as I work on the parser.

Yes! The images in test-images and the (single, currently) profile in test-profiles are a good start, and we can add more examples as we go.

kovidgoyal commented 1 year ago

On Sun, Jan 08, 2023 at 11:56:31PM -0800, Amanda Koh wrote:

…would you be willing to commit to implementing the actual color conversions, since acquiring the domain knowledge for that would take me a fair bit of time.

I definitely want to have this in time, but can‘t commit to a deadline since I’m full time employed. Also I’d be learning some of the colour conversion math too, particularly anything to do with CMYK; the CMYK <-> RGB process is a bit involved and the math isn’t clear to me.

Are there specific kinds of profiles you’re trying to support?

No, I just need to be able to read in images, resize them and display them to the user, keeping colors accurate. So I don't actually need color space conversion, just colorspace to linearised to sRGB.

(In case you care, this is for the icat kitten in the kitty terminal emulator, which I recently rewrote as a static binary in Go).

https://sw.kovidgoyal.net/kitty/kittens/icat/

Also I notice prism is MIT licensed, is that a hard requirement for you? I personally prefer the GPL3.

I’d like for this project to be legally unencumbered for anyone who wants to use it. I don’t particularly have a bugbear about closed source usage if someone so chooses. (And it may be worth noting that there are parts of the ICC spec which seem to be covered by their own patents already, that we may not be able to implement.)

OK, it's your project, your choice. Just thought I'd ask.

Last question: Is there some pre-existing set of "representative" profiles I can use to test with as I work on the parser.

Yes! The images in test-images and the (single, currently) profile in test-profiles are a good start, and we can add more examples as we go.

Cool, thanks.

mandykoh commented 1 year ago

No, I just need to be able to read in images, resize them and display them to the user, keeping colors accurate. So I don't actually need color space conversion, just colorspace to linearised to sRGB.

(In case you care, this is for the icat kitten in the kitty terminal emulator, which I recently rewrote as a static binary in Go).

Oh, that's pretty cool! Guessing it would still be useful even if we didn't have non-RGB support (ie we could look at just RGB colourspaces as a first step)?

kovidgoyal commented 1 year ago

On Mon, Jan 09, 2023 at 01:10:36PM -0800, Amanda Koh wrote:

No, I just need to be able to read in images, resize them and display them to the user, keeping colors accurate. So I don't actually need color space conversion, just colorspace to linearised to sRGB.

(In case you care, this is for the icat kitten in the kitty terminal emulator, which I recently rewrote as a static binary in Go).

Oh, that's pretty cool! Guessing it would still be useful even if we didn't have non-RGB support (ie we could look at just RGB colourspaces as a first step)?

Yes, increasing the fraction of images that are rendered accurately is always good and can be done incrementally. CMYK is not common anyway.

jsshapiro commented 1 year ago

Sorry to go off topic here, but I'm surprised that you say CMYK is not common. If you work on imaging for the web, I agree that CMYK is not common. If you target print, it's both universal and essential. If you aren't going to a monitor, the destination space will almost always be a CMYK space. Usually it will be a device specific space. More precisely, the destination space will tend to be a substrate+device space, because the reachable gamut when you are printing on (say) aluminum is very different from (say) polyester. And neither of those looks anything like what comes out of a toner-based digital press.

For input purposes, the only really widely used color space for CMYK is US Web Coated SWOP V2, which is mainly useful to help designers stay within the gamut that can be represented on specific types of widely used papers in digital presses. The problem being solved is that the RGB color spaces are too big. To see this, have a look at the gamuts. sRGB does not fully contain SWOP CMYK, and there are many colors in sRGB, Adobe RGB, and ProPhoto RGB that cannot be represented by the SWOP CMYK gamut. The end result is that the designer ends up selecting colors on their display that cannot be reproduced on the output substrate, and then they either have to fix the design or compress the color range in some way - that's what rendering intent is about.

Strangely, the most widely used commercial RIPs that drive digital presses, which print using CMYK toners, are not always able to handle input files that use a CMYK color space.

So it would be very helpful to be able to represent CMYK forms as destination color spaces, and the easiest way to do that is to be able to represent them generally.

And just for fun, more and more inkjet printers are implementing additional color channels. The HP Latex line and many UV printers (Mimaki, Canon Océ) to improve skin tones. The Xerox iGen presses can add orange, green, blue, and fluorescent yellow channels that allow it to print a much bigger part of the Pantone space than the others can do.

kovidgoyal commented 1 year ago

For my use case it isn't common.

jsshapiro commented 1 year ago

@kovidgoyal That seems fair!

I'm currently looking at RIP-related applications, so CMYK and channel extensions are kind of unavoidable.

mandykoh commented 1 year ago

@jsshapiro Thanks for the added colour (pun not intended)!

Some history: when Prism was initially conceived, it was targeting a proprietary application which regularly encountered CMYK (user generated content destined for print). Unfortunately, figuring out the maths and design blew up my personal time budget. Thankfully for us, there was a legacy component which already handled CMYK conversion so going RGB-only seemed like a good 80/20. So it was always in the vision that Prism would support CMYK (and eventually be able to replace that legacy component entirely); this is why we have a linear.RGB rather than a generic Color or such. And my thinking was that we would convert between the different colour models via the CIE spaces to get colour management.

Beyond CMYK, I also think there are worthwhile benefits to having a clear pathway to support multiple colour models, like monochrome and YCbCr.

(Aside: this is also why I like permissive licenses—because sometimes the OSS developer is also the proprietary software developer, and it's an easier sell to the company.)