Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with loading CMYK jpeg as BufferedImage with CMYK color model #269

Closed
the21st opened this issue Jun 28, 2016 · 7 comments
Closed

Issue with loading CMYK jpeg as BufferedImage with CMYK color model #269

the21st opened this issue Jun 28, 2016 · 7 comments
Assignees
Milestone

Comments

@the21st
Copy link

the21st commented Jun 28, 2016

Hi!

First off, thanks so much for your work on this library and for your immense help on StackOverflow. It made my life a lot easier!

I am using your JPEGImageReader to load a CMYK JPEG image with an ICC profile. When I read it with the default setup, I get a BufferedImage with an sRGB color model, and its RGB values correspond to what I get in Photoshop. But my CMYK gamut is not a strict subset of sRGB, so I thought I wanted to keep the image in CMYK color space, so that no clipping to sRGB would occur.

In the tests, I found a method that does this: JPEGImageReaderTest.testReadCMYKAsCMYK. But the problem I encountered was that the CMYK BufferedImage generated this way returns different RGB values than the RGB image (using getRGB). If I'm understanding this correctly, it should return the same values – the only difference being whether the conversion ICC CMYK -> sRGB is done during loading or when calling getRGB.

I debugged the code to see what might be the issue, and it seems the problem is this line in JPEGImageReader:

convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);

the intended CS is the ICC CMYK that's loaded from the image, but the image's color space is different from that and as a result, the image is converted from one CMYK to another, but this conversion is redundant (and incorrect, in the end) if I understand it correctly.

Here's my Scala code that fails with the image I linked above, I can convert it to Java if that's an issue https://gist.github.com/the21st/7db788d0417dbff63d6c4ba6a80b5dc8

@haraldk haraldk self-assigned this Jun 28, 2016
@RolandColored
Copy link

I ran into the same problem with automatic conversion to RGB and solved it with this snippet: https://gist.github.com/RolandColored/1f98a7160b19f4fa5a13a91f8af21c31

Cause is that the reader has several destination types to choose from and it chooses the first one (which is RGB type) for the BufferedImage.

Unfortunately I don't use this ways anymore, because transforming images in CMYK via BufferedImages is incredible slow.

@haraldk
Copy link
Owner

haraldk commented Jun 28, 2016

Hi Simon,

Thanks for reporting!

After some debugging, I finally found out what is going on... There's a caching issue with the ColorSpaces (unfortunately, ColorSpace.equals() relies on object identity rather than content), causing the following test to convert, rather than pass through without conversion:

// NOTE: Avoid using CCOp if same color space, as it's more compatible that way
else if (intendedCS != image.getColorModel().getColorSpace()) {
    if (DEBUG) {
        System.err.println("Converting from " + intendedCS + " to " + (image.getColorModel().getColorSpace().isCS_sRGB() ? "sRGB" : image.getColorModel().getColorSpace()));
    }

    convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);
}
// Else, pass through with no conversion

I'll create a fix soon!

Harald K

@haraldk
Copy link
Owner

haraldk commented Jun 28, 2016

@RolandColored Thanks! Simon uses similar code in his Scala gist, to get the CMYK BufferedImage, however the colors are slightly off, because the CMYK is transformed from the original color space to another that is exactly the same, except the ICC profile has a different rendering intent. This is a bug.

PS: The reason I convert to RGB by default is exactly that, the performance of displaying CMYK images is terrible.

Harald K

@haraldk
Copy link
Owner

haraldk commented Jun 28, 2016

@the21st With your sample file, I get the exact same colors using getRGB after ColorConvertOp to sRGB and the original CMYK data. However, with my other sample files, I don't...

There are some minor differences in the color components, like: #ff1e769d vs #ff1d769d (the red component is 1 step off). I think these differences are caused by Java 2D using different code paths (and thus causing different rounding errors). I think you will have to live with that... :-)

Harald K

@haraldk haraldk added this to the 3.3 milestone Jun 28, 2016
@haraldk
Copy link
Owner

haraldk commented Jun 28, 2016

Fixed in b0eb668.

Will be released as 3.3 as soon as possible.

Harald K

@the21st
Copy link
Author

the21st commented Jun 29, 2016

Awesome, thank you for such a quick response! :)

@haraldk
Copy link
Owner

haraldk commented Nov 3, 2016

@the21st This bugfix is now included in the official 3.3 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants