Аномальное поведение (или возможная ошибка) в JColorChooser

#java #swing #undefined-behavior #cmyk #jcolorchooser

#java #swing #неопределенное поведение #cmyk #jcolorchooser

Вопрос:

При использовании 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);
    }
}
  
  1. На обеих панелях выберите CMYK и введите любые допустимые числа для CMYK. Обе панели должны иметь одинаковые значения.
  2. Теперь сравните значения RGB для каждой панели. Они должны быть одинаковыми.
  3. Выберите отдельную панель и сбросьте значения ползунков на 0.
  4. Теперь повторно введите значения RGB в ту же панель.
  5. Переключитесь на CMYK для обеих панелей. Значения в панелях, которые я вижу, отличаются.

Обратите внимание, что при переходе другим путем (т. Е. при первом выборе RGB и повторном вводе значений CMYK) все работает так, как можно было бы ожидать. Я что-то упускаю в том, что ожидается от процесса преобразования, или это ошибка?

Я использую Java 10 в Windows 10, и моей IDE является Eclipse.

Также опубликовано на http://www.javaprogrammingforums.com/java-theory-questions/41836-possible-bug-jcolorchooser.html

Ответ №1:

Я провел некоторую отладку внутри цветовых моделей, используемых JColorChooser , в частности ColorModelCMYK (package-private class).

Вычисление в основном простое, за исключением того, что все значения 0 ..255 преобразуются в float 0.0..1.0 путем масштабирования на 255.0f. Это приводит к ошибкам округления в младшем значащем бите (представления IEEE754 с плавающей точкой).

Здесь C = 254 преобразуется в ~ R = 1 (обратите внимание, что оба массива являются одним и тем же объектом и обновляются на месте, поэтому значения CMYK теряются при преобразовании. rgb [0]*255f = 0.99999994

При правильном округлении вдвое при преобразовании обратно в целочисленные значения для отображения это не должно быть проблемой. Однако, покопавшись в ColorModel себе, я обнаружил, что эта функция используется подпрограммой, которая преобразует массив с плавающей точкой в упакованное 32-разрядное значение RGB:

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

Оно усечено! Я не знаю, ошибка ли это, но это, безусловно, проблема удобства использования.

Ответ №2:

Преобразование из одной (дискретной) цветовой модели в другую (дискретную) цветовую модель никогда не может быть идеальным.

Причина, по которой преобразование CMYK из RGB в CMYK никогда не будет работать идеально в JColorChooser, заключается просто в том, что JColorChooser отображает целые числа вместо чисел с плавающей запятой. Например, выберите yellow=255 в модели CMYK и вернитесь к RGB. Вы увидите, что этот желтый цвет смешан с красным = 255 и зеленым = 255. Теперь вернитесь к CMYK, уменьшите желтый цвет до 254 и проверьте значения RGB — он по-прежнему красный = 255 и зеленый = 255 !

Теперь измените желтый цвет на 253 в CMYK и вернитесь к RGB. Красный и зеленый по-прежнему равны 255, а синий добавляется со значением 1. Правильное значение для CMYK yellow = 254 (предыдущий случай) может быть blue = 0.4, но для упрощения использования в JColorChooser отображаются только целые числа, поэтому синий отображается как 0.

Эта числовая проблема усугубляется тем фактом, что «чувствительность к цвету» этих целочисленных цветовых моделей различна. В то время как CMYK имеет 4 измерения (голубой, пурпурный, желтый, ключевой) и, следовательно, может представлять 256 ^ 4 = 4294967296 различных цветов, RGB имеет 3 измерения и может представлять только 256 ^ 3 = 16777216 цветов. Таким образом, вы всегда будете терять значительную информацию при преобразовании CMYK в этот тип RGB.

Другими словами, в среднем 256 точек в цветовом пространстве CMYK представлены только 1 точкой в цветовом пространстве RGB. При обратном преобразовании одного цвета из RGB в CMYK в среднем 255 цветов в пространстве CMYK никогда не могут быть «достигнуты».

Комментарии:

1. Ваш ответ вдохновил меня написать свой собственный ответ, используя 255 .. 254 .. 253 шага в качестве ориентира. Однако я не согласен с вашим объяснением «большего» цветового пространства. В Java (упрощенном) CMYK добавление K просто означает вычитание эквивалентных количеств C, M, Y. Это просто означает, что существует множество неоднозначных цветовых точек, а количество уникальных цветовых точек по-прежнему равно 2 ^ 24.

2. Привет, Марк, поздравляю с твоей находкой в исходном коде, но я не полностью согласен с твоим комментарием здесь. В CMYK может быть много избыточных цветовых комбинаций, но для CMYK их определенно больше, чем 256 ^ 3. Подумайте, например, о случае темно-желтого цвета: r = 1, g = 1, b = 0 это должно быть отображено в CMYK с y = 1 и k = 0. Но тогда мы имеем y = 1 и k = 1,2,3, .., 255, которые еще темнее, чем r = 1, g = 1, b = 0. Таким образом, дискретный CMYK может выражать r = 0,5, g = 0,5 при y = 1 и k = 128.

3. К вашему сведению, еще одно интересное замечание заключается в том, что теоретически RGB и CMYK на самом деле разные, не полностью перекрывающиеся цветовые пространства. Ознакомьтесь с этой цитатой из записи Gamut в википедии: en.wikipedia.org/wiki/Gamut » …. «Например, хотя чистый красный цвет может быть выражен в цветовом пространстве RGB, он не может быть выражен в цветовом пространстве CMYK; чистый красный находится вне гаммы в цветовом пространстве CMYK». — таким образом, материал быстро усложняется, а также нелинейен, когда вы смотрите на эти цветовые пространства.

4. Вы правы насчет неоднозначных фракционных цветов. Я знаю о неперекрываемости. Вот почему в я назвал это «упрощенным» в скобках. Самый простой ключ к разгадке заключается в том, что paint-cyan больше похож на глубокий небесно-голубой, чем addtive-cyan. «Истинное» преобразование (которое должны использовать принтеры) также нелинейно, поскольку RGB используется в sRGB, а CMYK, очевидно, нет.

Ответ №3:

Я также использую Java 8 с Windows в Eclipse, и это дает мне тот же результат, но проблема не в этом. У вас все работает нормально, но преобразование RGB в CMYK работает не так, как CMYK в RGB. Вы можете увидеть это в этом онлайн-конвертере:

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

CMYK работает с процентами голубого, пурпурного и желтого цветов. С другой стороны, RGB со значениями красного, зеленого и синего цветов от 0 до 255. В Сети, которую я вам передал, помещаются формулы этого преобразования и не работает таким же двунаправленным образом.