Почему цвет после Image.Clear(x) не совсем совпадает с цветом x?
Пример кода для этой проблемы не требует пояснений, поэтому:
[Fact]
private void Color_in_should_equal_color_out()
{
var bitmap = new Bitmap(128,128,PixelFormat.Format32bppArgb);
var color = Color.FromArgb(30,60,90,120);
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(color);
}
var result = bitmap.GetPixel(0,0);
Assert.Equal(color, result);
}
В этом случае я ожидаю, что цвет фона будет идентичен цвету, который я очистил. Вместо этого я получаю это:
Assert.Equal() Failure
Expected: Color [A=30, R=60, G=90, B=120]
Actual: Color [A=30, R=59, G=93, B=119]
Как это вообще возможно?
Некоторые проходят:
Color.FromArgb(0, 0, 0, 0);
Color.FromArgb(255, 255, 255, 255);
Еще несколько примеров, которые терпят неудачу:
Expected: Color [A=32, R=64, G=96, B=128]
Actual: Color [A=32, R=63, G=95, B=127]
Expected: Color [A=128, R=192, G=32, B=16]
Actual: Color [A=128, R=191, G=31, B=15]
Expected: Color [A=32, R=192, G=127, B=90]
Actual: Color [A=32, R=191, G=127, B=87]
1 ответ
Комментарий @redwyre правильный (но у меня недостаточно репутации, чтобы комментировать). Поэтому я отсылаю вас к комментарию Винсента Повирка на Рисование изображений PixelFormat32bppPARGB с GDI+ использует обычную формулу вместо предварительно умноженной:
Формат изображения переднего плана не имеет значения (учитывая, что оно имеет альфа-канал), потому что вы устанавливаете его в Gdiplus::Color. Цветовые значения определены как неумноженные, поэтому gdiplus умножает компоненты на альфа-значение, когда очищает изображение переднего плана. Альтернативой было бы, чтобы значения Color имели различное значение в зависимости от формата цели рендеринга, и в этом заключается безумие.
Пример в этом посте использует Gdiplus напрямую, но также и System.Drawing.Graphics, как вы можете видеть здесь в источниках.NET.
Различные значения, которые вы видите, напрямую связаны с циклическим переключением от значения цветового канала к предварительно умноженному значению и обратно с использованием 8-битной арифметики. (Например, из вашего последнего примера альфа =32 и B=90: 90*32/255 = 11,2+ усекает до 11, затем обратно 11*255/32 = 87,6+ усекает до 87).