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

При записи пикселей в контекст HTML-холста с использованием 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() в контексте (для этой маловероятной статьи ) не имеет значения.

Ответы [ 3 ]

15 голосов
/ 30 ноября 2010

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

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

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

5 голосов
/ 16 декабря 2010

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

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

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

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

4 голосов
/ 30 ноября 2010

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

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;)

РЕДАКТИРОВАТЬ: Конечно, это не объясняет, почему альфа-канал ведет себя ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...