在Java中将图像从CMYK转换为RGB

时间:2013-10-23 11:10:29

标签: java image rgb cmyk

我已经尝试了两天来找到一种方法,可以在Java中将CMYK图像完美地转换为RGB图像。我经历了很多不同的方法,在Web上找到了所有这些,其中一些在Stackoverflow上,但我不能找到简单的方法,没有这种可怕的颜色褪色,这是这种转换的典型特征。我知道像Photoshop或Irfanview这样的工具可以通过两次点击完美地完成它,但我希望它是Java编码的。 好吧,长话短说,我找到了一种方法,就在这里。

2 个答案:

答案 0 :(得分:1)

感谢您的反馈。

是谁,我尝试过你的方式,但无论是使用ImageIO.write()还是使用JAI.create()保存图像,它都会给我反转或非常奇怪的颜色。

haraldk,我还没有尝试过你的代码。我看了一下它对我来说似乎并不简单。我稍后会试一试。

与此同时,请允许我以自己的方式发布,这实际上是由其他人组成的(这个人:https://stackoverflow.com/a/9470843/2435757和其他人:http://www.coderanch.com/t/485449/java/java/RGB-CMYK-Image等)。它可以工作,但是,当创建一个新的BufferedImage时,诸如分辨率或压缩方法(对于TIFF图像)等信息会丢失并且必须重置,这种方法不会(我认为只需要非JRE库)这里是Apache常见的xmlgraphics):

BufferedImage img = null;
try {
    img = ImageIO.read(new File("cmyk.jpg"));
} catch (IOException e) {}

ColorSpace cmyk = DeviceCMYKColorSpace.getInstance();
int w = img.getWidth(), h = img.getHeight();
BufferedImage image = null;
byte[] buffer = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
int pixelCount = buffer.length;
byte[] new_data = new byte[pixelCount / 4 * 3];
float lastC = -1, lastM = -1, lastY = -1, lastK = -1;
float C, M, Y, K;
float[] rgb = new float[3];
// loop through each pixel changing CMYK values to RGB
int pixelReached = 0;

for (int i = 0 ; i < pixelCount ; i += 4) {
    C = (buffer[i] & 0xff) / 255f;
    M = (buffer[i + 1] & 0xff) / 255f;
    Y = (buffer[i + 2] & 0xff) / 255f;
    K = (buffer[i + 3] & 0xff) / 255f;
    if (lastC == C && lastM == M && lastY == Y && lastK == K) {
        //use existing values if not changed
    } else { //work out new
        rgb = cmyk.toRGB(new float[] {C, M, Y, K});
        //cache values
        lastC = C;
        lastM = M;
        lastY = Y;
        lastK = K;
    }
    new_data[pixelReached++] = (byte) (rgb[0] * 255);
    new_data[pixelReached++] = (byte) (rgb[1] * 255);
    new_data[pixelReached++] = (byte) (rgb[2] * 255);
}

// turn data into RGB image
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
int[] l_bandoff = {0, 1, 2};
PixelInterleavedSampleModel l_sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_INT, w, h, 3, w * 3, l_bandoff);
image.setData(new ByteInterleavedRaster(l_sm, new DataBufferByte(new_data, new_data.length), new Point(0, 0)));

// write
ImageIO.write(image, "jpg", new File("rgb.jpg"));

上面的代码为JPEG和TIFF图像提供了出色的结果,虽然我的特定图像碰巧得到了一个非常奇怪的结果。

这是JMagick的另一种更为简单明了的方式:

ImageInfo info = new ImageInfo("cmyk.tif");
MagickImage image = new MagickImage(info);
image.transformRgbImage(ColorspaceType.CMYKColorspace);
image.setFileName("rgb.tif");
image.writeImage(info);

不能短,不是吗?也像JPEG和TIFF的魅力一样。

不,哈拉德克,我没有使用任何颜色配置文件的参考。这对我来说似乎很奇怪。我只能假设这两种方式都使用默认的颜色配置文件,而且我很幸运能够在所有情况下都能正常工作。

我正在等待您对此的反馈。

干杯。

PS:我很乐意给你链接到我使用的图像,但Stackoverflow说我不够可靠:-)在另一篇文章中,如果你需要它们。

答案 1 :(得分:0)

您尝试了哪些答案,发现无法正常工作?

他们中的任何人都提供了这个示例代码。它会产生褪色吗?请您分享一个创建问题的示例图片链接吗?

/**
 * ImageIO cannot read CMYK-jpegs, it throws IIOException(Unsupported Image Type).
 * This method tries to read cmyk image.
 * @param file
 * @return  image TYPE_4BYTE_ABGR
 * @throws Exception
 */
public static BufferedImage readCMYKImage(File file) throws Exception {
    Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
    ImageReader reader = null;
    while(readers.hasNext()) {
        reader = readers.next();
        if(reader.canReadRaster())
            break;
    }

    FileInputStream fis = new FileInputStream(file);
    try {
        ImageInputStream input = ImageIO.createImageInputStream(fis); 
        reader.setInput(input); // original CMYK-jpeg stream
        Raster raster = reader.readRaster(0, null); // read image raster 
        BufferedImage image = new BufferedImage(raster.getWidth(), raster.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
        image.getRaster().setRect(raster);
        return image;
    } finally {
        try { fis.close(); } catch(Exception ex) {}
    }
}