【问题标题】:RGB to CMYK and back algorithmRGB 到 CMYK 和反向算法
【发布时间】:2011-02-01 01:56:02
【问题描述】:

我正在尝试实施一种解决方案来计算 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};
        }
    }

【问题讨论】:

  • 每个人都希望快速得到答案,指定也没有用
  • 此解决方案对您有何帮助?我看到你试图在没有 ICC_Colorspace 的情况下继续它,你能坚持下去吗?

标签: java rgb cmyk


【解决方案1】:

要像 Photoshop 那样准确地将值从 RGB 转换为 CMYK,反之亦然,您需要使用 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 免费分发。

【讨论】:

  • 这些 ICC 类是否来自 JDK 7?我在 Java 6 文档中找不到对它们的引用。
  • 已使用链接编辑答案。据我所知,它们既不是新的(我在 2 年前使用过),也不是在某些外部库中,它们是内置的。
【解决方案2】:

正如 Lea Verou 所说,您应该利用色彩空间信息,因为没有将 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 转换为色彩空间调整的 RGB 吗?当我使用BogusColorSpace 运行此示例时,我只返回相同的 R、G、B 值,而不是正确的 C、M、Y、K 数组。
  • 请注意,我还针对驱动程序提供的.icc 配置文件运行了此示例,并产生了看起来是 R、G、B 的内容。如果我们真的想直接与 C、M、Y、K 墨盒/色带/碳粉对话怎么办?如何获取这 4 个值?
  • 回答我自己的问题...显然并非所有.icc 配置文件都是平等创建的。我刚刚在C:\Windows\system32\spool\drivers\color 中使用供应商提供的.icc 配置文件进行了测试,它没有返回CMYK - 而是RGB 值......但是此评论中提到的Adobe 驱动程序确实返回CMYK。 :)
【解决方案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(); }

【讨论】:

    【解决方案4】:

    为了正确显示 CMYK 图像应包含 color space information 作为 ICC 配置文件。所以最好的方法是使用可以通过Sanselan轻松提取的ICC配置文件:

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

    如果图像没有附加 ICC 配置文件,我会使用 Adobe profiles 作为默认值。

    现在的问题是,您不能只使用 ImageIO 加载具有自定义颜色空间的 JPEG 文件,因为它会抛出异常,抱怨它不支持某些颜色空间或类似的东西。因此,您将不得不使用栅格:

    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 转换算法,因为您可以使用嵌入到图像中或 Adob​​e 免费提供的 ICC 配置文件。如果不完美(嵌入配置文件),生成的图像会更好看。

    【讨论】:

      【解决方案5】:
      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;
      }
      

      【讨论】:

        【解决方案6】:

        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;
        

        【讨论】:

        • -1:这些转换公式的结果太差了,结果几乎没用。他们被张贴在整个网络上的事实并没有使它变得更好。请停止进一步传播它们。
        猜你喜欢
        • 2018-07-04
        • 2011-06-17
        • 1970-01-01
        • 2012-01-30
        • 1970-01-01
        • 1970-01-01
        • 2014-07-22
        • 1970-01-01
        • 2012-11-29
        相关资源
        最近更新 更多