Я пытался в течение двух дней найти способ идеально преобразовать изображение CMYK в RGB на Java. Я перепробовал много разных способов сделать это, все нашел в Интернете, некоторые из них на Stackoverflow, но я не мог просто найти способ, который делал бы это просто и без этого ужасного выцветания цвета, типичного для таких преобразований. . Я знаю, что такие инструменты, как Photoshop или Irfanview, прекрасно справляются с этим в два клика, но я хотел, чтобы это было написано на языке Java. Короче говоря, я нашел способ, и вот он.
Преобразование изображения из CMYK в RGB в Java
Ответы (2)
Спасибо за ваши отзывы.
Whome, я попробовал ваш способ, но он дал мне либо инвертированные, либо очень странные цвета, независимо от того, сохранил ли я изображение с помощью 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 библиотека вот общая xmlgraphics Apache):
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) {}
}
}