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}; } } 

Как сказала Леа Вероу, вы должны использовать информацию о цветовом пространстве, потому что нет алгоритма для отображения из 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(); } } } 

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

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

  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(); } 

Чтобы правильно отображаться, изображения CMYK должны содержать информацию о цветовом пространстве как профиль ICC. Таким образом, лучший способ – использовать этот профиль ICC, который можно легко извлечь с помощью Sanselan :

 ICC_Profile iccProfile = Sanselan.getICCProfile(new File("filename.jpg")); ColorSpace cs = new ICC_ColorSpace(iccProfile); 

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

Теперь проблема заключается в том, что вы не можете просто загружать JPEG-файл в пользовательское цветовое пространство с помощью ImageIO, так как оно не будет выдавать исключение, жалуясь на то, что оно не поддерживает какое-то цветовое пространство или подобное звучание. Хенс вам придется работать с растрами:

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

 public static String makeCMYKString(int color) { double red = Color.red(color); double green = Color.green(color); double blue = Color.blue(color); double red1 = red / 255; double green1 = green / 255; double blue1 = blue / 255; double max = (Math.max(Math.max(red1, green1), blue1)); double K = 1 - max; double C = (1 - red1 - K) / (1 - K); double M = (1 - green1 - K) / (1 - K); double Y = (1 - blue1 - K) / (1 - K); double CMYK[] = {C, M, Y, K}; String cmyk = "CMYK = (" + Math.round(C * 100) + " , " + Math.round(M * 100) + " , " + Math.round(Y * 100) + " , " + Math.round(K * 100) + ")"; return cmyk; } 

Вот такой же вопрос для вас

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

 /** 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; 

Вот мой путь. Имейте в виду, что я переконвертировал цвета 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); } 
  • Преобразование шестнадцатеричного цвета в RGB и наоборот
  • Преобразование цвета HSL в RGB
  • Алгоритм проверки подобия цветов
  • Название цвета базы данных RGB
  • Цветовой индекс Star BV до уровня RGB
  • Преобразование значения цвета RGB в шестнадцатеричное
  • Как я могу считывать значения пикселей изображения как RGB в 2d-массив?
  • Изменение оттенка цвета RGB
  • Как конвертировать 16-битный RGB565 в 24-разрядный RGB888?
  • Значения RGB видимого спектра
  • C # преобразовать значение RGB в CMYK с помощью профиля ICC?
  • Давайте будем гением компьютера.