This discussion is archived
3 Replies Latest reply: Nov 24, 2011 4:25 PM by Maxideon RSS

CMYK to RGB conversion with icc profile. Output is too dark

893663 Newbie
Currently Being Moderated
Similar question has been asked many times. But I didn't found the answer.
It looks like this code
cmykToRgb.filter(r, resultRaster)
doesn't convert anything.
But I presume each pixel from the raster "r" should be converted to RGB colorSpace and put into the resultRaster. Am I right?
Any help appreciated.

That profile file got from adobe site.

see
[before image|http://i.stack.imgur.com/HHGes.png]
[after image|http://i.stack.imgur.com/4erZj.png]
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpeg");
ImageReader reader = null;
while (readers.hasNext()){
      reader = readers.next();
      if (reader.canReadRaster()){
          break;
      }
}
// read
ImageInputStream ios = ImageIO.createImageInputStream(new FileInputStream(new File(myPic.jpg)));
reader.setInput(ios);
Raster r = reader.readRaster(0, null);

BufferedImage result = new BufferedImage(r.getWidth(), r.getHeight(), bufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = result.getRaster();
ICC_Profile iccProfile = ICC_Profile.getInstance(new File("profile_name.icc");
ColorSpace cs = new ICC_ColorSpace(iccProfile);
ColorConvertOp cmykToRgb = new ColorConvertOp(cs, result.getColorModel().getColorSpace(), null);
cmykToRgb.filter(r, resultRaster);

// write
ImageIo.write(resul, "jpg", new File("myPic.jpg"));
Thanks

Edited by: n0d on Nov 15, 2011 4:59 AM
  • 1. Re: CMYK to RGB conversion with icc profile. Output is too dark
    Maxideon Explorer
    Currently Being Moderated
    I don't think there's any CMYK jpeg standard, so applications kind of do their own thing when saving. In the case of adobe it includes the CMYK profile in the metadata, but then saves the raw image data as inverted YCbCrK colors. So my guess is you have to do YCCK --> CMYK --> sRGB.

    Try passing the source raster through the following method before filtering it. See what happens.
    public static void YCCKtoCMYK(WritableRaster rast, boolean invertedColors){
        int w = rast.getWidth(), h = rast.getHeight();
        double c,m,y,k;
        double Y,Cb,Cr,K;
    
        //turn YCCK in Raster to CYMK using formula
        int[] pixels = null;
        for(int row = 0; row < h; row++) {
            pixels = rast.getPixels(0,row,w,1,pixels);
    
            for(int i = 0; i < pixels.length; i+=4) {
                Y  = pixels;
    Cb = pixels[i+1];
    Cr = pixels[i+2];
    K = pixels[i+3];

    c =255 - (Y + 1.402*Cr - 179.456);
    m =255 - (Y - 0.34414*Cb - 0.71414*Cr + 135.45984);
    y =255 - (Y + 1.7718d*Cb - 226.816);
    k = K;

    //clamp
    c = Math.min(255,Math.max(0,c));
    m = Math.min(255,Math.max(0,m));
    y = Math.min(255,Math.max(0,y));

    if(invertedColors) {
    pixels[i] = (byte) (255-c);
    pixels[i+1] = (byte) (255-m);
    pixels[i+2] = (byte) (255-y);
    pixels[i+3] = (byte) (255-k);
    }else {
    pixels[i] = (byte) c;
    pixels[i+1] = (byte) m;
    pixels[i+2] = (byte) y;
    pixels[i+3] = (byte) k;
    }
    }
    rast.setPixels(0,row,w,1,pixels);
    }
    }
  • 2. Re: CMYK to RGB conversion with icc profile. Output is too dark
    893663 Newbie
    Currently Being Moderated
    Thanks a lot your code was helpful.

    If I do YCCK -> CMYK -> RGB It looks almost the same, just a little bit darker.

    You said:
    In the case of adobe it includes the CMYK profile in the metadata, but then saves the raw image data as inverted YCbCrK colors
    Some of my images should be processed with CMYK -> RGB algorithm,
    and after your tip I realized that for others I should apply YCCK -> CMYK -> RGB algorithm.

    But how to know when exactly should I use CMYK -> RGB and when YCCK -> CMYK -> RGB?
  • 3. Re: CMYK to RGB conversion with icc profile. Output is too dark
    Maxideon Explorer
    Currently Being Moderated
    From the javax_imageio_jpeg_image_1.0 specification:
    If an Adobe APP14 marker segment is present, the colorspace is determined by consulting the transform flag. The transform flag takes one of three values:
    2 - The image is encoded as YCCK (implicitly converted from CMYK on encoding).
    1 - The image is encoded as YCbCr (implicitly converted from RGB on encoding).
    0 - Unknown. 3-channel images are assumed to be RGB, 4-channel images are assumed to be CMYK.
    What it's talking about is the metadata returned from ImageReader#getImageMetadata. For jpeg's, it has the following structure.
    javax_imageio_jpeg_imageio_1.0
         JPEGVariety
              app0JFIF
                   app2ICC (if present, user object is ICC_Profile)
                   ...
         markerSequence
              app14Adobe
                   ...
                   transform Value (0, 1, or 2)
    Basically if the transform value is 2 then it's YCCK->CMYK->RGB. If the transform value is 1, then it's YCC->RGB. If the transform value is 0, then it's CMYK->RGB if the raster has 4 bands, otherwise it's already in RGB if it has 3 bands.

    The problem is that the default JPEGImageReader that comes with installing java is buggy. It usually throws an exception if you try to read the metadata of a cmyk jpeg. So the bad news is that you're sort of out of luck on that front.

    The good news is that Sun did create a jpeg reader that can read any jpeg, including a cmyk one. It's called the CLibJPEGImageReader and you get it with installing JAI-ImageIO - http://download.java.net/media/jai-imageio/builds/release/1.1/ . It's a 'natively' accelerated ImageReader that doesn't have all the bells and whisles of your standard ImageReader. It can't read rasters, the writer can't write custom metadata, but it's fast and can read essentially all jpegs.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points