2011-02-01 42 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 2011-02-01 01:59:21

+0

這個解決方案是如何爲你工作的?我看到你試圖在沒有ICC_Colorspace的情況下繼續下去,你能保持它嗎? – TacB0sS 2014-05-30 20:39:46

回答

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 2011-11-15 20:28:23

4

要準確地從RGB轉換值CMYK,反之亦然,就像Photoshop一樣,您需要使用ICC顏色配置文件。所有在網頁中找到的簡單算法解決方案(如上面所發佈的解決方案)都是不準確的,並且會產生CMYK色域之外的顏色(例如,它們會將CMYK(100,0,0,0)轉換爲rgb(0 ,255,255),這顯然是錯誤的,因爲rgb(0,255,255)不能用CMYK再現)。 查看java.awt.color.ICC_ColorSpacejava.awt.color.ICC_Profile用於使用ICC顏色配置文件轉換顏色的類。 至於顏色配置文件本身,Adobe會免費發佈它們。

+0

這些來自JDK 7的ICC類是否?我在Java 6 doco中找不到它們。 – 2011-02-01 02:24:43

0

爲了正確顯示CMYK圖像應該包含color space information作爲ICC配置文件。所以,最好的辦法是使用ICC配置文件可以與Sanselan可以容易地提取:

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

但如果是附於圖像無ICC配置文件,我會用Adobe profiles爲默認值。

現在的問題是,你不能只加載使用ImageIO的自定義顏色空間的JPEG文件,因爲它會失敗拋出一個異常,抱怨它不支持一些色彩空間或sthing這樣。 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轉換算法,因爲您可以使用嵌入到圖像中或從Adobe免費獲得的ICC配置文件。如果不完美(使用嵌入式配置文件),所生成的圖像看起來會更好。

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

這裏是我的方式。請記住我reconverted原始顏色的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); 
}