我已经尝试了两天来找到一种在 Java 中将 CMYK 图像完美转换为 RGB 图像的方法。我经历了很多不同的方法来做到这一点,所有这些都在网上找到,其中一些在 Stackoverflow 上,但我不能只是找到一种简单的方法,而且没有这种转换所特有的可怕的褪色. 我知道像 Photoshop 或 Irfanview 这样的工具只需单击两次即可完美完成,但我希望它是 Java 编码的。好吧,长话短说,我找到了一种方法,就在这里。
2 回答
感谢您的反馈。
谁,我尝试了你的方式,但无论我使用 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 说我不够可靠 :-) 如果您需要它们,可能在另一篇文章中。
您尝试了哪些 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) {}
}
}