JColorChooser 中的异常行为(或可能的错误)

Posted

技术标签:

【中文标题】JColorChooser 中的异常行为(或可能的错误)【英文标题】:Anomalous behavior (or possible bug) in JColorChooser 【发布时间】:2019-08-31 05:45:09 【问题描述】:

使用 JColorChooser 时,输入的 CMYK 值会转换为特定的 RGB 颜色。当在 RGB 端手动输入该颜色时,CMYK 值 和以前不一样了。

以下程序可用于演示我遇到的行为。

import java.awt.*;
import javax.swing.*;

public class ColorChooserProblem 
    JFrame f = new JFrame("Testing Color Chooser");

    public static void main(String[] args) 
        new ColorChooserProblem().start();
    

    public void start() 
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JColorChooser jc1 = new JColorChooser();
        JColorChooser jc2 = new JColorChooser();
        f.add(jc1, BorderLayout.NORTH);
        f.add(jc2, BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    

    在两个面板中,选择 CMYK 并输入 CMYK 的任何有效数字。两个面板必须具有相同的值。 现在比较每个面板的 RGB 值。它们应该是相同的。 选择单个面板并将滑块重置为 0。 现在在同一面板中重新输入 RGB 值。 为两个面板切换到 CMYK。我看到的面板中的值是不同的。

请注意,当采用另一种方式时(即先选择 RGB 并重新输入 CMYK 值),一切都会按预期进行。我错过了什么吗 转换过程的预期是什么,或者这是一个错误?

我在 Windows 10 上运行 Java 10,我的 IDE 是 Eclipse。

也发布在http://www.javaprogrammingforums.com/java-theory-questions/41836-possible-bug-jcolorchooser.html

【问题讨论】:

【参考方案1】:

我在JColorChooser 使用的颜色模型中做了一些调试,特别是ColorModelCMYK(包私有类)。

计算非常简单,除了所有值 0..255 通过缩放 255.0f 转换为浮点 0.0..1.0。这会在最低有效位(IEEE754 浮点表示)中引入舍入误差。

这里 C=254 被转换为 ~R=1 (请注意,两个数组都是同一个对象,并且会就地更新,因此 CMYK 值会在转换中丢失。

在转换回整数值进行显示时进行适当的半舍入,这应该不是问题。然而,深入ColorModel 本身,我发现这个函数被用于将浮点数组转换为压缩的 32 位 RGB 值的例程:

private static int to8bit(float value) 
    return (int) (255.0f * value);

它被截断了!我不知道这是否是一个错误,但这肯定是一个可用性问题。

【讨论】:

【参考方案2】:

从一种(离散)颜色模型到另一种(离散)颜色模型的转换永远不会完美。

CMYK 到 RGB 到 CMYK 无法在 JColorChooser 中完美运行的原因仅仅是因为 JColorChooser 显示 整数 而不是浮点数。例如在 CMYK 模型中选择黄色=255 并返回到 RGB。你会看到这个黄色是由 red=255 和 green=255 混合而成的。现在回到 CMYK,将黄色降低到 254 并检查 RGB 值 - 它仍然是 red=255 和 green=255 !

现在将 CMYK 中的黄色更改为 253,然后返回 RGB。红色和绿色仍然是 255,蓝色加上值 1。CMYK 黄色=254(前一种情况)的正确值可能是蓝色=0.4,但为了使使用更简单,只有整数显示在 JColorChooser 中,所以蓝色显示为0.

由于这些整数颜色模型的“颜色敏感度”不同,这个数字问题变得更加严重。而 CMYK 有 4 个维度(青色、品红色、黄色、键),因此可以表示 256^4 = 4294967296 种不同的颜色 RGB 有 3 个维度,只能表示 256^3 = 16777216 种颜色。因此,在将 CMYK 转换为这种类型的 RGB 时,您总是会丢失相当多的信息。

换句话说,平均而言,CMYK 颜色空间中的 256 个点仅由 RGB 颜色空间中的 1 个点表示。当您将一种颜色从 RGB 转换回 CMYK 时,平均而言,CMYK 空间中的 255 种颜色永远无法“达到”。

【讨论】:

您的回答启发了我使用 255..254..253 步骤作为指导来编写自己的答案。但是,我不同意您对“更大”色彩空间的解释。在 Java 的(过于简化的)CMYK 中,添加 K 只是意味着减去等量的 C、M、Y。这只是意味着有很多不明确的色点,唯一色点的数量仍然等于2^24。 嗨,马克,恭喜您在源代码中找到,但我并不完全同意您的评论。使用 CMYK 可能会有许多多余的颜色组合,但 CMYK 肯定有超过 256^3 的颜色组合。例如考虑深黄色的情况:r=1,g=1,b=0 这应该映射到 y=1 和 k=0 的 CMYK。但是我们有 y=1 和 k=1,2,3,..,255,它们甚至比 r=1,g=1,b=0 更暗。因此,离散 CMYK 可以表示 r=0.5,g=0.5,y=1 和 k=128。 仅供参考,另一个有趣的注意事项是,理论上,RGB 和 CMYK 实际上是不同的,而不是完全重叠的颜色空间。查看***上 Gamut 条目中的这句话:en.wikipedia.org/wiki/Gamut" .... "例如,虽然纯红色可以在 RGB 颜色空间中表示,但不能在 CMYK 颜色空间中表示;纯红色在 CMYK 颜色空间中超出了色域。” - 因此,当您查看此颜色空间时,事情会很快变得复杂且非线性。 您对非模棱两可的分数颜色是正确的。我知道非重叠性。这就是为什么我在括号中称其为“过度简化”。最简单的线索是油漆青色更像是深天蓝色而不是加色青色。 “真正的”转换(打印机应该使用)也是非线性的,因为 RGB 在 sRGB 中,而 CMYK 显然不是。【参考方案3】:

我也在 E​​clipse 上将 Java 8 与 Windows 一起使用,它给了我相同的结果,但这不是问题。它对您来说很好,但是将 RGB 转换为 CMYK 与 CMYK 转换为 RGB 的工作方式不同。 您可以在此转换器中在线查看:

https://www.rapidtables.com/convert/color/rgb-to-cmyk.html

CMYK 适用于青色、品红色和黄色百分比。另一方面 RGB 值从 0 到 255 的红色、绿色和蓝色。 在我传递给您的网络中,您放置了该转换的公式,并且不能以相同的双向方式工作。

【讨论】:

以上是关于JColorChooser 中的异常行为(或可能的错误)的主要内容,如果未能解决你的问题,请参考以下文章

仅 RGB 的 JColorChooser (Java 7)

使用 JColorChooser 绘图

Java Swing JColorChooser 颜色 RGB 到 sRGB

使用 JColorChooser 获取 Html 颜色代码

java JColorChooser的

如何覆盖 JColorChooser 重置按钮?