Неправильные цвета при рисовании в Graphics2D на глубине цвета 16 бит

1

Во время работы со старым ПК 1 я нашел то, что, по моему мнению, было странной ошибкой рендеринга.

Проблема возникает, когда глубина цвета установлена на 16 бит (32768 цветов).

Особенно это проявляется при окрашивании цветов с низким значением альфа с помощью Graphics2D. Следующее - это MVCE, чтобы воспроизвести проблему. Он просто рисует несколько наборов строк с белым цветом, значение альфа которого колеблется от 4 до 12. Результат запуска этой программы показан на следующем снимке экрана:

Изображение 174551

Можно видеть, что некоторые цвета на самом деле зеленые для некоторых альфа-значений, хотя, очевидно, должно быть 50 9 оттенков серого.

(Опять же, он появляется только тогда, когда глубина цвета установлена на 16 бит!)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class _WTFPaintTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        f.getContentPane().add(new JPanel()
        {
            @Override
            protected void paintComponent(Graphics gr)
            {
                super.paintComponent(gr);
                Graphics2D g = (Graphics2D)gr;
                g.setColor(Color.BLACK);
                g.fillRect(0,0,getWidth(),getHeight());

                for (int a=4; a<=12; a++)
                {
                    int x = (a-3) * 50;
                    g.setColor(Color.WHITE);
                    g.drawString(String.valueOf(a), x, 25);

                    g.setColor(new Color(255,255,255,a));
                    for (int j=0; j<3; j++)
                    {
                        for (int i=0; i<50; i++)
                        {
                            g.drawLine(x,50+i,x+25,75);
                        }
                    }
                }
            }
        });

        f.setSize(550,200);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

(Я размещаю его здесь с его первоначальным именем, чтобы подчеркнуть, насколько я раздражаю это...)

В чем причина нечетного цветопередачи в этом случае?


1: WinXP, 32 бит, графическая карта NVIDIA GeForce 2

Теги:
colors
alpha
graphics2d

1 ответ

3
Лучший ответ

Причина такого поведения заключается в том, что цветовые компоненты (красный, зеленый и синий) представлены с различным количеством бит в 16-битном цветовом режиме.

16 бит распределены между компонентами цвета следующим образом:

  • Красный представлен 5 битами
  • Зеленый представлен 6 битами
  • Синий представлен 5 битами

Это означает, что 16-битный цвет имеет 2 5= 32 разных оттенка красного и синего, но 2 6= 64 оттенка зеленого.

(Зеленый получает дополнительный бит, потому что чувствительность человеческого глаза больше для оттенков зеленого цвета, чем для оттенков красного или синего)

Теперь, когда стандартный 24-битный цвет RGB преобразуется в 16-битный цвет, будут возникать ошибки выборки. В 24-битном цвете каждый компонент цвета имеет 8 бит. Они преобразуются в соответствующий компонент для 16-битного цвета, беря биты наивысшего порядка цветового компонента.

В скриншоте примера можно увидеть линии, которые окрашены альфа-значением 7. Представление RGB этого цвета - (7,7,7). Бинарное представление этого цвета (00000111 b, 00000111 b, 00000111 b). При использовании битов наивысшего порядка для каждого компонента цвета результаты

  • 5 бит для красного: 00000 111 b → 00000 b
  • 6 бит для зеленого: 000001 11 b → 00000 1 b
  • 5 бит для синего: 00000 111 b → 00000 b

Таким образом, зеленый компонент является единственным компонентом с ненулевым значением. Зеленый компонент фактического цвета, который затем отображается на экране, можно представить как 6-битный зеленый компонент, сдвинутый слева на 2 бита:

  • 000001 b << 2 = 00000100 b

Это подтверждается рассмотрением соответствующих пикселей на 0x000C00 экрана, которые сохраняются как 0x000C00, или 24-битные значения RGB (0,12,0): темный оттенок зеленого.

  • 0
    это отличное объяснение! продолжай в том же духе! (Что касается меня, я знаю дело, но не могу написать такие хорошие ответы, действительно приятно!)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню