Подтвердить что ты не робот

Почему HTML Canvas getImageData() не возвращает те же самые значения, которые были только что установлены?

При записи пикселей в контекст HTML Canvas с помощью putImageData я обнаруживаю, что значения пикселей не совсем совпадают, когда я их снова извлекаю. Я поставил тестовую страницу , показывая эту проблему. Свернувшись, проблема в том, что:

var id = someContext.getImageData(0,0,1,1);
id.data[0]=id.data[3]=64; // 25% red, 25% alpha
id.data[1]=id.data[2]=0;  // No blue or green
someContext.putImageData(id,0,0);
var newData = someContext.getImageData(0,0,1,1);
console.log( newData.data[0] );

В Chrome v8 красное значение возвращается как 63; на Firefox v3.6, Safari v5 и IE9 красное значение возвращается как 67 (все в Windows). В OS X Chrome v7, Safari v5 и Firefox v3.6 также возвращаются как 67. Ни один из них не возвращается в качестве значения 64, изначально заданного!

Использование setTimeout для задержки между настройкой и повторной выборкой не имеет значения. Изменение фона страницы не имеет значения. Использование save() и restore() в контексте (за эта маловероятная статья) не имеет значения.

4b9b3361

Ответ 1

ImageData определяется как HTML5 как неускоренный, но в большинстве реализаций canvas используется предварительно умноженный буфер поддержки для ускорения компоновки и т.д. Это означает, что когда данные записываются, а затем считываются из резервного буфера, он может меняться.

Я бы предположил, что Chrome v8 поднял ошибку на предыдущем выпуске [un] премьютипирующего кода с webkit.org(он был сломан раньше, хотя я не помню никаких недавних событий, и это не объясняет окна только дисперсия)

[править]. Возможно, стоит проверить webkit в ночное время на окнах? поскольку реализация imagedata не имеет какой-либо конкретной платформы, которую она разделяла между всеми браузерами webkit и могла просто быть разбита на сборках на основе MSVC]

Ответ 2

Похож на вопрос округления для меня...

64/255 = 0.2509... (rounded down to give 0.25)
0.25 * 255 = 63.75 (rounded down to give 63)
== OR ==
64/255 = 0.2509... (rounded up to give 0.26)
0.26 * 255 = 66.3  (rounded up to give 67)

Помните, что 255 - максимальное значение, а не 256;)

EDIT: Конечно, это не объяснит, почему ведет себя альфа-канал...

Ответ 3

Спецификация HTML5 поощряет поставщиков браузеров к использованию того, что называется Premultiplied Alpha. По существу это означает, что пиксели хранятся в 32-битных целых числах, где каждый канал содержит 8-битное значение цвета. По соображениям производительности премультиплексированная альфа-версия используется браузерами. Это означает, что он предварительно умножает значения цвета на основе альфа-значения.

Вот пример. У вас есть такой цвет, чтобы значения для RGB были 128, 64, 67. Теперь, ради большей производительности, значения цвета будут предварительно умножены на значение альфа. Итак, если значение альфа 16, все значения цвета будут умножаться на 16/256 (= 0.0625). В этом случае результирующие значения для RGB становятся 8, 4, 4.1875 (округлены до 4, потому что значения цвета пикселя не являются плавающими). ​​

Проблема возникает, когда вы делаете именно то, что вы здесь делаете; задавая цветовые данные с определенным альфа-значением, а затем отбрасывая фактические значения цвета. Предыдущий синий цвет 4.1875, который был округлен до 4, станет 64 вместо 67, когда вы вызываете getImageData().

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