Преобразование изображения из CMYK в RGB в Java

Я пытался в течение двух дней найти способ идеально преобразовать изображение CMYK в RGB на Java. Я перепробовал много разных способов сделать это, все нашел в Интернете, некоторые из них на Stackoverflow, но я не мог просто найти способ, который делал бы это просто и без этого ужасного выцветания цвета, типичного для таких преобразований. . Я знаю, что такие инструменты, как Photoshop или Irfanview, прекрасно справляются с этим в два клика, но я хотел, чтобы это было написано на языке Java. Короче говоря, я нашел способ, и вот он.


person Erwann    schedule 23.10.2013    source источник
comment
Для этого удалите ответ из своего вопроса и ответьте на свой вопрос сами. Вот как это должно быть, если вы хотите поделиться своими знаниями.   -  person Martijn Courteaux    schedule 23.10.2013
comment
Выполнено. ну ответь через 7 часов...   -  person Erwann    schedule 23.10.2013
comment
Почему в течение семи часов? О... Да, когда вы создаете вопрос, вы можете отметить его, если хотите немедленно ответить. Возможно, это действительно невозможно, если вы сначала разместили свой вопрос, а затем попытались добавить решение.   -  person Martijn Courteaux    schedule 23.10.2013


Ответы (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 говорит, что я недостаточно надежен :-) Возможно, в другом посте, если они вам потребуются.

person Erwann    schedule 24.10.2013

Какие ответы 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) {}
    }
}
person Whome    schedule 23.10.2013
comment
Вы не можете выполнить правильное преобразование без получения цветового профиля ICC, обычно встроенного в файл CMYK JPEG. Код, размещенный здесь, просто предполагает, что данные CMYK - это ABGR, что совсем не похоже на намерение... Я предлагаю вам взглянуть на stackoverflow.com/a/12132805/1428606 и stackoverflow.com/a/16149142/1428606 :-) - person Harald K; 23.10.2013