Для правильного отображения CMYK изображения должны содержать color space information как ICC Profile. Так что лучший способ использовать этот профиль ICC, который может быть легко извлечен с Sanselan:
ICC_Profile iccProfile = Sanselan.getICCProfile(new File("filename.jpg"));
ColorSpace cs = new ICC_ColorSpace(iccProfile);
В случае нет ICC-профиля крепится к изображению, я хотел бы использовать Adobe profiles по умолчанию.
Теперь проблема заключается в том, что вы не можете просто загружать JPEG-файл с помощью пользовательского цветового пространства с помощью ImageIO, поскольку он не сможет создать исключение, жалуясь на то, что оно не поддерживает какое-либо цветовое пространство или подобное звучание. Hense вам придется работать с растрами:
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new ByteArrayInputStream(data));
Raster srcRaster = decoder.decodeAsRaster();
BufferedImage result = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = result.getRaster();
ColorConvertOp cmykToRgb = new ColorConvertOp(cs, result.getColorModel().getColorSpace(), null);
cmykToRgb.filter(srcRaster, resultRaster);
Вы можете использовать result
везде, где вам нужно, и она будет иметь преобразованные цвета.
На практике, однако, я столкнулся с некоторыми изображениями (сделанными камерой и обработанными с помощью Photoshop), которые каким-то образом перевернули значения цвета, чтобы получившееся изображение всегда было инвертировано и даже после их инвертирования они были слишком яркими. Хотя я до сих пор не имею ни малейшего представления о том, как узнать, когда именно использовать его (когда мне нужно, чтобы инвертировать значение пикселей), у меня есть алгоритм, который корректирует эти значения и преобразование цвета попиксельны:
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new ByteArrayInputStream(data));
Raster srcRaster = decoder.decodeAsRaster();
BufferedImage ret = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = ret.getRaster();
for (int x = srcRaster.getMinX(); x < srcRaster.getWidth(); ++x)
for (int y = srcRaster.getMinY(); y < srcRaster.getHeight(); ++y) {
float[] p = srcRaster.getPixel(x, y, (float[])null);
for (int i = 0; i < p.length; ++i)
p[i] = 1 - p[i]/255f;
p = cs.toRGB(p);
for (int i = 0; i < p.length; ++i)
p[i] = p[i] * 255f;
resultRaster.setPixel(x, y, p);
}
Я довольно уверен, что RasterOp или ColorConvertOp могут использоваться, чтобы сделать разговор более эффективным, но этого было достаточно для меня.
Серьезно, нет необходимости использовать эти упрощенные алгоритмы преобразования CMYK в RGB, так как вы можете использовать профиль ICC, встроенный в изображение или доступный бесплатно от Adobe. Полученное изображение будет выглядеть лучше, если не идеально (со встроенным профилем).
Все всегда хотят быстрого ответа, его бесполезно указывать – Eric
Как это решение сработало для вас? Я вижу, что вы пытались обойти это без ICC_Colorspace, могли бы вы его поддерживать? – TacB0sS