Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > chingachgoog

Оценить эту запись

Определение цвета в прозрачной BitmapData

Запись от chingachgoog размещена 02.02.2009 в 14:39

Хотя тут некоторые продолжают утверждать, что флешеру не надо знать внутреннию реализацию механизмов флеш плеера (знай мол себе AS и не думай ни о чем, за тебя уже подумали дяди из адоба), жизнь и практика показывают обратное.

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

С выходом очередной нетленки Мука ситуация прояснилась.
(Анализ растрового изображения. Влияние прозрачности на получение значения цвета. с. 729)

Цитата:
Из-за особенностей внутренней архитектуры механизма визуализации ... Для повышения производительности процесса визуализации, ... среда Flash преобразует это значение [значение цвета] во внутренний формат, называемым предумноженным значением цвета. Оно объединяет значения канала Alpha и каналов Red, Green и Blue этого цвета... В результате исходные значения, присвоенные каналам Red, Green и Blue, будут потеряны.
При получение значений цвета ... Flash осуществляет их автоматическое преобразование из предумноженного в стандартный (неумноженный) формат ARGB, ... приводя к потери точности.
Далее все это Мук иллюстрирует гениальным кодом с цветом 0x00FFFFFF, т.е. белым полностью прозрачным, что при getPixel32 выдает 0.

Ну да - перемножив на ноль - ноль и получим.
Но не все так просто.
Вот мой пример:
Код:
import flash.display.BitmapData;

bmd=new BitmapData(100, 100, true, 0x90CCCCCC)
trace("getPixel32>> = 0x"+(bmd.getPixel32(10,10)>>>24).toString(16)+(bmd.getPixel32(10,10) & 0xFFFFFF).toString(16))
Цвет 0x90CCCCCC заменился на 0x90CBCBCB
(всего-то вместо 204 показывает 203 для канала)

Непонятно как так "предумножился" каждый цвет 0xCC на альфу 0x90, что при обратном преобразовании вышло 0xCB.

Ведь альфа-то как раз показывается при getPixel32 верно! Т.е. множитель 0x90 не изменился. Для обычных чисел флеш тут не глючит:

Код:
zz=0x90CCCCCC
del=(zz>>>24)/0xFF
zz*=del
zz/=del
trace("0xZZ=0x"+(zz>>>24).toString(16)+(zz & 0xFFFFFF).toString(16))
Результат соответствует исходному!

Значит механизм "предумножения" работает еще хитрее и в чем прав Мук, так в том, что на getPixel32 в точке с прозрачностью не равной 0xFF нельзя положиться.
Всего комментариев 19

Комментарии

Старый 27.09.2009 18:43 flash33 вне форума
flash33
 
Аватар для flash33
Прав мук, ты что то неверно подсчитываешь. При операциях setPixel32, copyPixels и draw это бесспорно, а с 0xCCCCCC - это монохромный цвет, поэтому искажения на высоких альфа не такие высокие (но все же есть)
Старый 28.09.2009 01:44 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
flash33, почему бы перед ответом не прочитать то, на что отвечаешь более внимательно? )))
В чем прав Мук? Что я неверно считаю?
Может вам известна формула по которой подсчитывается предумноженный цвет и обратное преобразование из него? Вот это было бы очень круто, но очень сомневаюсь, что это вообще где-либо есть. Тот же Мук ничего толком не написал - одни намеки.
Старый 28.09.2009 12:57 Котяра вне форума
Котяра
 
Аватар для Котяра
Цитата:
0xCCCCCC - это монохромный цвет
2 flash33 - что есть , по Вашему, монохромный цвет?
И почему он должен лучше кодироваться/декодироваться?
Обновил(-а) Котяра 28.09.2009 в 15:42
Старый 28.09.2009 18:47 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Это у вас соответствует, потому что вы используете 64-бит число с плавающей запятой. Но это было бы не умно использовать такие числа для операций с картинками... потому что будет очень долго считать.
Код AS3:
var zz:uint = 0x90CCCCCC;
var del:Number = (zz >>> 24) / 0xFF;
zz *= del;
zz /= del;
trace("0xZZ=0x" + (zz >>> 24).toString(16) + (zz & 0xFFFFFF).toString(16));
//0xZZ=0x90ccccca
Старый 28.09.2009 20:57 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Ну, да, AVM2 при типизации uint дало сбой при подсчете... (при умножении, видимо, разрядов не хватило)
Но сбой совсем другой, чем в реальности. И в реальности этот сбой наблюдается и на AVM1. Возможно что в самом флеш-плеере, даже в AVM1 тип uint (или как там по-настоящему считают и хранят предумноженный цвет) существует (во внутренней реализации) - привет тем кто говорил, что в AVM1 нельзя добавить новые типы - это бы объяснило механизм причины. Но все равно сама формула подсчета пока загадочна (((
Старый 28.09.2009 23:01 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Ну да естественно в реальности перемножаются компоненты цвета каждый в отдельности при этом на каждый компонент отводится по одному октету... и это... с чего вы взяли, что операции, которые плеер делает на нативном уровне используют те же типы данных, что и AS? Плеер же не на AS написан... т.е. грубо говоря, что, как мне кажется происходит:

Код:
R = 0xFF & (k * R);
G = 0xFF & (k * G);
B = 0xFF & (k * B);
color = (R << 16) | (G << 8) | B;
где k - коефициент прозрачности.
так вы сможете бесконечно накладывать цвета один на другой (что собственно и требуется для отображения).
Т.е. предположим, что пиксел, который был под уже рассчитаным пикселом имел так же посчитаные значения, тогда, чтобы узнать результирующий цвет мы просто сделаем:
Код:
resultColor = color | backgroundColor;
И как бы это совсем не сбой Это ожидаемое поведение... если у вас есть всего 4 октета, куда вы будете писать биты, которые в эти 4 октета не влезли?

EDIT: А, и ну, естесственно, когда мы рассчитываем "процент" цветовой компоненты, то из-за того, что для подсчета мы используем число с восмю октетами, совсем не следует, что плеер использует тот же самый численный тип для подсчетов, так, например, если бы он использовал SF32 (signed 32-bit float), то подсчеты бы выглядели примерно так:
Код:
trace((0x90 / 0xFF).toFixed(8)); //0.56470588 
trace((0.56470588 * 0xFF).toString(16)); //8f
Обновил(-а) wvxvw 28.09.2009 в 23:23
Старый 29.09.2009 14:38 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Цитата:
с чего вы взяли, что операции, которые плеер делает на нативном уровне используют те же типы данных, что и AS? Плеер же не на AS написан...
Никто и не говорит, что на нативном уровне используются ТЕ ЖЕ САМЫЕ типы данных (я писал "или как там по-настоящему считают и хранят предумноженный цвет"). Мой привет (сами знаете кому) в том, что во внутренней реализации могут быть свои типы и нет никаких проблем добавить новый тэг в swf для нового типа.

Цитата:
И как бы это совсем не сбой Это ожидаемое поведение...
Ожидаемое поведение - это когда ты знаешь механизм работы, а он вообще нигде не описан и не упомянут. Поэтому ожидаемое поведение - это чтение РОВНО ТОГО цвета, которые и записал. А выходит ДРУГОЙ цвет, что ожидаемым поведением назвать никак нельзя.
Оттого данное поведение - либо сбой, либо утаивание важной информации. Почему я должен о чем-то догадываться и что-то предполагать? Это, конечно, увлекательно, может, лично для меня, но вовсе не для всех.
Старый 29.09.2009 22:07 Яски вне форума
Яски
Абсолютно согласен с chingachgoog, я проработал с плеером ровно 7 месяцев когда узнал о этом поведении из этого поста. Раньше были мысли использовать битмапдату для хранения данных. Не представляю как бы попался я, если бы попытался это сделать. А реализация такая в плеере наверное потому, что так быстрее сделать смешивание прозрачной картинки с тем что уже нарисовано — одно сложение и одно умножение вместо двух. Судя потому, что мало недовольных это был правильный шаг.
Старый 01.10.2009 10:19 Котяра вне форума
Котяра
 
Аватар для Котяра
Я тоже хотел делать кроп png с прозрачностями и хранить данные об обрезке в первом пиксле, но в ходе тестов получал неправильные значения) грешил на свой алгоритм и забил на это дело (сделал генерацию xml)
Старый 02.10.2009 18:30 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Цитата:
getPixel32 () method
public function getPixel32(x:int, y:int):uint

Language Version : ActionScript 3.0
Runtime Versions : AIR 1.0, Flash Player 9

Returns an ARGB color value that contains alpha channel data and RGB data. This method is similar to the getPixel() method, which returns an RGB color without alpha channel data.

All pixels in a BitmapData object are stored as premultiplied color values. A premultiplied image pixel has the red, green, and blue color channel values already multiplied by the alpha data. For example, if the alpha value is 0, the values for the RGB channels are also 0, independent of their unmultiplied values. This loss of data can cause some problems when you perform operations. All BitmapData methods take and return unmultiplied values. The internal pixel representation is converted from premultiplied to unmultiplied before it is returned as a value. During a set operation, the pixel value is premultiplied before the raw image pixel is set.
Я не согласен, возможно это неудачная формулировка, или использован не самый удачный пример для иллюстрации, но уж точно не "утаивание" информации...
Старый 03.10.2009 03:16 Яски вне форума
Яски
wvxvw, Вы теперь за этих .
Старый 03.10.2009 03:56 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Не, я "между" и давайте не флудить.
Я согласен, что "прозрачнее" было бы наверное назвать getPixel32Premultyplied() вместо getPixel32(). Но с другой стороны формат записи битмапдаты описан и в доках по языку и в доках по SWF формату... Но, опять же, это то, что есть... не знаю, может SL сделают лучше, а может кто-то другой сделает лучше. Или может Адоби добавят какой-нибудь класс типа BitmapData32 Или напишите в Алхимии класс, который будет хранить пикселы как 32 бита... было бы желание
Старый 03.10.2009 23:44 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Это хорошо, что ТЕПЕРЬ в описании хотя бы по AS3 есть намек на проблему. Но это не значит, что утаивания информации не было. Т.к. данная проблема не только в AVM2, но и в AVM1. Хотя я, быть может, забыл? Может там было что-то про предумножение цвета?

Ну да это на совести адоба и макромедии. Мне интересно в данной теме лишь описание предумножения, формула так сказать.
Старый 04.10.2009 03:25 Яски вне форума
Яски
Код:
function setPixel32(color) {
  A = (color >>> 24);
  R = (color >>> 16) & 0xFF;
  G = (color >>> 8) & 0xFF;
  B = color & 0xFF;
  newA = A;
  newR = Math.round(A*R/255);
  newG = Math.round(A*G/255);
  newB = Math.round(A*B/255);
  color = (newA << 24) | (newR << 16) | (newG << 8) | newB;
}

function getPixel32() {
  A = (color >>> 24);
  R = (color >>> 16) & 0xFF;
  G = (color >>> 8) & 0xFF;
  B = color & 0xFF;
  oldA = A;
  oldR = R*255/A;
  oldG = G*255/A;
  oldB = B*255/A;
  color = (oldA << 24) | (oldR << 16) | (oldG << 8) | oldB;
  return color;
}
Обновил(-а) Яски 05.10.2009 в 15:26
Старый 05.10.2009 14:40 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Яски, что-то не смог добиться вашей формулой результата
0x90CCCCCC -> 0x90CBCBCB

Код:
focus=0x90CCCCCC
toHex(focus) // 0x90cccccc

focus=setPixel32(focus)
toHex(focus) // 0xd6666666

focus=getPixel32(focus)
toHex(focus) // 0x00



function setPixel32(color) {
  A = (color << 24);
  R = (color << 16) & 0xFF;
  G = (color << 8) & 0xFF;
  B = color & 0xFF;
  newA = A;
  newR = Math.round(A*R/255);
  newG = Math.round(A*G/255);
  newB = Math.round(A*B/255);
  color = (newA << 24) | (newR << 16) | (newG << 8) | newB;
  return color
}

function getPixel32(color) {
  A = (color << 24);
  R = (color << 16) & 0xFF;
  G = (color << 8) & 0xFF;
  B = color & 0xFF;
  oldA = A;
  oldR = R*255/A;
  oldG = G*255/A;
  oldB = B*255/A;
  color = (oldA << 24) | (oldR << 16) | (oldG << 8) | oldB;
  return color;
}

function toHex(num){
	trace("0x"+(num>>>24).toString(16)+(num & 0xFFFFFF).toString(16))
}
Старый 05.10.2009 15:27 Яски вне форума
Яски
Так странно, в посте почему то указал left shift, вместо right shift. Исправил старый пост.
Старый 06.10.2009 11:15 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Ну все!
Тайна формулы предумножения раскрыта Яски! Респект!
Старый 09.10.2009 22:07 iNils вне форума
iNils
 
Аватар для iNils
Яски, а откуда формулу взял? Или силой мысли?
Старый 11.10.2009 01:49 Яски вне форума
Яски
Это просто получение компонентов цвета, умножение и немного грубой силы
 

 


Часовой пояс GMT +4, время: 19:36.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.