When using JColorChooser, entered CMYK values translate to a specific RGB color. When that color is entered manually on the RGB side, the CMYK values are not the same as before.
The following program can be used to demonstrate the behavior I am encountering.
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);
}
}
Note that when going the other way (i.e. selecting RGB first and re-entering the CMYK values), all works as one might expect. Am I missing something in what's expected of the conversion process, or is this a bug?
I am running Java 10 on Windows 10 and my IDE is Eclipse.
Also posted at http://www.javaprogrammingforums.com/java-theory-questions/41836-possible-bug-jcolorchooser.html
I did some debugging inside the color models used by JColorChooser
, in particular ColorModelCMYK
(package-private class).
The calculation is mostly straightforward, except that all values 0..255 are converted to float 0.0..1.0 by scaling by 255.0f. This introduces roundoff errors in the least significant bit (of the IEEE754 float representation).
Here C=254 is converted to ~R=1 (note that both arrays are the same object and it's updated in-place, so the CMYK values are lost in the conversion.
With proper half-up rounding while converting back to integer values for displaying, this shouldn't be any issue. However, digging onto ColorModel
itself, I found this function is used by the routine that converts the float array to a packed 32-bit RGB value:
private static int to8bit(float value) {
return (int) (255.0f * value);
}
It's truncated! I don't know if this is a bug, but it certainly is a usability issue.