Смешивание двух изображений с помощью html5 canvas

Мне нужно нарисовать 2 варианта одного и того же изображения друг над другом, чьи альфа-значения составляют в целом 1.

Например:
- imageA имеет альфа 0.4, в то время как imageB имеет альфа 0.6,
- Желаемый результат - полностью непрозрачное изображение (альфа из 1.0 для каждого пикселя), который выглядит как смесь 60% imageBи 40% смесь imageA,

Однако я считаю, что холст html5 по умолчанию использует режим наложения, отличный от добавления альфа-смешанных изображений, поэтому две вещи, нарисованные с альфа-значениями ниже 1, не будут равны 1.
Я пробовал все разные режимы композитинга, а также режимы наложения Adobe, но ни один из них не дал желаемого результата.
Простой тестовый пример - нарисовать пурпурный прямоугольник дважды, оба с альфа 0.5, Мое желание, чтобы результирующие пиксели были rgb(255, 0, 255), Тем не менее, результат немного прозрачен.

Кто-нибудь знает какой-нибудь способ достижения этого результата?

1 ответ

Решение

• Если вы посмотрите на спецификацию canvas'context2D о режиме смешивания по умолчанию ('source-over'):

http://dev.w3.org/fxtf/compositing-1/

Вы увидите формулу (я переименовал переменные для ясности):

colorOut = prevColor x prevAlpha + newColor x newAlpha x (1 - prevAlpha)

И для получающейся альфы:

αlphaOut = prevAlpha + newAlpha x (1 - prevAlpha)

Заметить, что,
а) неожиданно формула не является линейной (из-за: новый альфа х (1 - пред альфа) фактор).
б) точка имеет как меньшие значения r,g,b, так и уменьшенную альфа. Таким образом, при повторном использовании он будет выделять квадрат (0,6)==0,36 до конечного изображения. (... совершенно нелогично...)

• Так что же происходит с вашими 60% / 40% дро?

1) изображение А нарисовано с альфа = 60%. Формула выше дает:

 colorOut = color_A * 0.6 ;
 alphaOut = 0.6 ;

2) изображение B нарисовано с альфа = 40%

 colorOut = color_A * 0.6 * 0.6 + color_B x 0.4 x (0.4);
 alphaOut = 0.6 + 0.4 * 0.4;

Итоговая формула ==>

 colorOut = 0.36 * color_A + 0.16 * color_B ;
 alphaOut = 0.76 ;

Вы видите, что это совсем не та смесь 60/40, которую вы ожидали.

• Как исправить?

1) Вы можете сделать это вручную, используя getImageData / putImageData. Помните о проблеме перекрестного происхождения: если ваши изображения не приходят с вашего домена, их imageData будет пустым. Для выступлений сделайте ставку на коэффициент замедления 50+ по сравнению с холстом (= GPU), выполняющим работу. "Реальное время" (=60 кадров в секунду) может быть невозможно в зависимости от размера изображения / вычислительной мощности / браузера. Но у вас есть полный контроль.

2) Но если вы сейчас посмотрите на комбинированный режим "светлее", кажется, у нас есть наш парень:

http://dev.w3.org/fxtf/compositing-1/

Формула сейчас:

colorOut = prevColor x prevAlpha + newColor x newAlpha 

И для получающейся альфы:

 αlphaOut = prevAlpha + newAlpha 

Вы видите, что это простой оператор "плюс", идеально подходящий для ваших требований.
Итак, решение:
сохранить ctx.
- установить более легкий композитный режим.
- нарисовать первое изображение на 60% альфа.
- нарисуйте второе изображение на 40% альфа.
восстановить ctx.

Последние слова: если вы хотите проверить правильность последней альфа (==255), используйте такую ​​функцию:

 function logAlpha(ctx,x,y) {
    var imDt = ctx.getImageData(x,y,1,1).data;
    if (!(imDt[0] || imDt[1] || imDt[2])) console.log('null point. CORS issue ?'); 
    console.log(' point at (' +x+ ',' +y+ ') has an alpha of ' + imDt[3] ) ;
 }
Другие вопросы по тегам