2011-02-01 2 views
10

Я пытаюсь реализовать решение для вычисления преобразования между RGB и CMYK и наоборот. Вот то, что я до сих пор:RGB для CMYK и алгоритм обратной связи

public static int[] rgbToCmyk(int red, int green, int blue) 
    { 
     int black = Math.min(Math.min(255 - red, 255 - green), 255 - blue); 

     if (black!=255) { 
      int cyan = (255-red-black)/(255-black); 
      int magenta = (255-green-black)/(255-black); 
      int yellow = (255-blue-black)/(255-black); 
      return new int[] {cyan,magenta,yellow,black}; 
     } else { 
      int cyan = 255 - red; 
      int magenta = 255 - green; 
      int yellow = 255 - blue; 
      return new int[] {cyan,magenta,yellow,black}; 
     } 
    } 

    public static int[] cmykToRgb(int cyan, int magenta, int yellow, int black) 
    { 
     if (black!=255) { 
      int R = ((255-cyan) * (255-black))/255; 
      int G = ((255-magenta) * (255-black))/255; 
      int B = ((255-yellow) * (255-black))/255; 
      return new int[] {R,G,B}; 
     } else { 
      int R = 255 - cyan; 
      int G = 255 - magenta; 
      int B = 255 - yellow; 
      return new int[] {R,G,B}; 
     } 
    } 
+0

Все всегда хотят быстрого ответа, его бесполезно указывать – Eric

+0

Как это решение сработало для вас? Я вижу, что вы пытались обойти это без ICC_Colorspace, могли бы вы его поддерживать? – TacB0sS

ответ

6

Как сказал Леа Вероу, вы должны использовать информацию о цветовом пространстве, потому что нет алгоритма для отображения из RGB в CMYK. Adobe имеет некоторые цветовые профили ICC, доступные для скачивания 1, но я не уверен, как они лицензированы.

После того, как у вас есть цветовые профили что-то вроде следующего будет делать работу:

import java.awt.color.ColorSpace; 
import java.awt.color.ICC_ColorSpace; 
import java.awt.color.ICC_Profile; 
import java.io.IOException; 
import java.util.Arrays; 


public class ColorConv { 
    final static String pathToCMYKProfile = "C:\\UncoatedFOGRA29.icc"; 

    public static float[] rgbToCmyk(float... rgb) throws IOException { 
     if (rgb.length != 3) { 
      throw new IllegalArgumentException(); 
     } 
     ColorSpace instance = new ICC_ColorSpace(ICC_Profile.getInstance(pathToCMYKProfile)); 
     float[] fromRGB = instance.fromRGB(rgb); 
     return fromRGB; 
    } 
    public static float[] cmykToRgb(float... cmyk) throws IOException { 
     if (cmyk.length != 4) { 
      throw new IllegalArgumentException(); 
     } 
     ColorSpace instance = new ICC_ColorSpace(ICC_Profile.getInstance(pathToCMYKProfile)); 
     float[] fromRGB = instance.toRGB(cmyk); 
     return fromRGB; 
    } 

    public static void main(String... args) { 
     try { 
      float[] rgbToCmyk = rgbToCmyk(1.0f, 1.0f, 1.0f); 
      System.out.println(Arrays.toString(rgbToCmyk)); 
      System.out.println(Arrays.toString(cmykToRgb(rgbToCmyk[0], rgbToCmyk[1], rgbToCmyk[2], rgbToCmyk[3]))); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
-1

Here идентичная вопрос к вашему

Вот копия/паста этой страницы:

/** CMYK to RGB conversion */ 
/* Adobe PhotoShop algorithm */ 
cyan = Math.min(255, cyan + black); //black is from K 
magenta = Math.min(255, magenta + black); 
yellow = Math.min(255, yellow + black); 
rgb[0] = 255 - cyan; 
rgb[1] = 255 - magenta; 
rgb[2] = 255 - yellow; 


/* GNU Ghostscript algorithm -- this is better*/ 
int colors = 255 - black; 
rgb[0] = colors * (255 - cyan)/255; 
rgb[1] = colors * (255 - magenta)/255; 
rgb[2] = colors * (255 - yellow)/255; 
+8

-1: Результат этих формул преобразования настолько низок, результат почти бесполезен. Тот факт, что они размещены по всей сети, не делает его лучше. Пожалуйста, прекратите распространять их еще больше. – Codo

4

Для точного преобразования значений из RGB в CMYK и наоборот, как это делает Photoshop, вам нужно использовать цветовой профиль ICC. Все простые алгоритмические решения, которые вы найдете в interwebs (например, выше, выше), являются непостоянными и создают цвета, которые находятся за пределами цветовой гаммы CMYK (например, они преобразуют CMYK (100, 0, 0, 0) в rgb (0 , 255, 255), что, очевидно, неверно, так как rgb (0, 255, 255) не может быть воспроизведено с помощью CMYK). Изучите классы java.awt.color.ICC_ColorSpace и java.awt.color.ICC_Profile для преобразования цветов с использованием цветовых профилей ICC. Что касается самих файлов профиля цвета, Adobe распространяет их бесплатно.

+0

Являются ли эти классы ICC для JDK 7? Я не нахожу ссылки на них в Java 6 doco. –

+0

Ответ отредактирован со ссылками. Насколько я знаю, они не новы (я использовал их 2 года назад), ни в какой-то внешней библиотеке, они встроены. –

0

Для правильного отображения 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. Полученное изображение будет выглядеть лучше, если не идеально (со встроенным профилем).

3

Лучший способ сделать это:

try { 
     // The "from" CMYK colorspace 
     ColorSpace cmykColorspace = new ICC_ColorSpace(ICC_Profile.getInstance("icc/CoatedFOGRA27.icc")); 
     // The "to" RGB colorspace 
     ColorSpace rgbColorspace = new ICC_ColorSpace(ICC_Profile.getInstance("icc/AdobeRGB1998.icc")); 

     // Bring in to CIEXYZ colorspace (refer to Java documentation: http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/color/ColorSpace.html) 
     float[] ciexyz = cmykColorspace.toCIEXYZ(cmyk); 
     float[] thisColorspace = rgbColorspace.fromCIEXYZ(ciexyz); 
     float[] rgb = thisColorspace; 
     Color c = new Color(rgb[0], rgb[1], rgb[2]); 

     // Format RGB as Hex and return 
     return String.format("#%06x", c.getRGB() & 0xFFFFFF); 
    } catch (IOException e) { e.printStackTrace(); } 
-1

Вот мой путь. Имейте в виду, что я переконвертировал цвета RGB из исходного цвета.

public static String getCMYK(int c){ 
    float computedC = 0; 
    float computedM = 0; 
    float computedY = 0; 
    float computedK = 0; 

    int r = (c >> 16) & 0xFF; 
    int g = (c >> 8) & 0xFF; 
    int b = (c >> 0) & 0xFF; 

    // BLACK 
    if (r==0 && g==0 && b==0) { 
     computedK = 1; 
     return "0 0 0 100"; 
    } 

    computedC = 1 - (r/255f); 
    computedM = 1 - (g/255f); 
    computedY = 1 - (b/255f); 

    float minCMY = Math.min(computedC,Math.min(computedM,computedY)); 

    if (1 - minCMY != 0){ 
     computedC = (computedC - minCMY)/(1 - minCMY) ; 
     computedM = (computedM - minCMY)/(1 - minCMY) ; 
     computedY = (computedY - minCMY)/(1 - minCMY) ; 
    } 
    computedK = minCMY; 

    return (int)(computedC*100f) + " " + (int)(computedM*100f) + " " + (int)(computedY*100f) + " " + (int)(computedK*100f); 
} 
+0

Это все равно такое же «неправильное» преобразование цвета. Не зная, какой цвет имеют значения RGB и CMYK, вы не можете конвертировать. Вам необходимо работать с профилями ICC, как описано в принятом ответе за 4 года до вашего поста. –