2

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

4

2 回答 2

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 lib这是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。

不,haraldk,我没有使用任何对颜色配置文件的引用。这对我来说也很奇怪。我只能假设两种方式都使用默认颜色配置文件,并且到目前为止我很幸运能够在所有情况下正常工作。

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

干杯。

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

于 2013-10-24T09:28:07.273 回答
0

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

他们中的任何一个都给出了这个示例代码。它会造成褪色吗?您能否分享一个创建问题的示例图片链接?

/**
 * 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) {}
    }
}
于 2013-10-23T11:36:16.000 回答