AlphaBlend генерира неправилни цветове

Успях да избегна Windows GDI в продължение на десетилетия и сега плащам цената. Следният C++ код не води до правилните цветове. Просто трябва да запълни с бяло прозорец и след това да смеси алфа единично растерно изображение. Цялата алфа е алфа на пиксел в растерното изображение.

// Create a memory DC
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hbmMem = CreateCompatibleBitmap(hdc, cxWnd, cyWnd);
SelectObject(hdcMem, hbmMem);

// White-fill the BG
FillRect(hdcMem, &rectWnd, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));

// Alpha blend the bitmap into the memory DC
HDC hdcSrc = CreateCompatibleDC(hdcMem);
HBITMAP hbmOld = static_cast<HBITMAP>(SelectObject(hdcSrc, hbm));
BLENDFUNCTION bfn = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(hdcMem, x, y, cxBmp, cyBmp, hdcSrc, 0, 0, cxBmp, cyBmp, bfn);
SelectObject(hdcSrc, hbmOld);
DeleteDC(hdcSrc);

// Blit the memory DC to the screen
BitBlt(hdc, 0, 0, cxWnd, cyWnd, hdcMem, 0, 0, SRCCOPY);

Проверих, че всички стойности на променливите са правилни и че растерното изображение в hbm има правилните цветове и алфа пиксели.

Резултатът показва много грешни цветове, например син пиксел с ниска алфа трябва да е бледосин, но вместо това е тъмночервен. Пикселите с висока алфа са много по-близо до това, което трябва да бъдат.

Всяка помощ се оценява. TIA.


person chrisd    schedule 06.07.2014    source източник
comment
Един проблем с AlphaBlend е, че работи най-правилно, когато RGB е предварително умножен със стойността A. т.е. растерната карта никога не трябва да има R › A или G › A или B › A. В резултат на тази конвенция напълно прозрачни за RGBA са всички нули, което е черно за RGBx, така че напр. поставянето на прозрачно растерно изображение в Word и експортирането на документа на Word като PDF води до черни области, където растерното изображение трябва да е напълно прозрачно.   -  person Cheers and hth. - Alf    schedule 06.07.2014
comment
Освен предварителното умножаване на вашето растерно изображение, което трябва да направите, изглежда, че вашият източник е в ABGR ред, докато GDI се нуждае от пикселните данни в ARGB ред. Опитайте да размените червените и сините стойности на всеки пиксел.   -  person Jonathan Potter    schedule 06.07.2014
comment
@JonathanPotter: хм, доколкото си спомням, това не е правилно. може и да греша. но доколкото си спомням, форматът COLORREF е изложен за лесно четене като RGB... в дъмп на паметта с малък ред.   -  person Cheers and hth. - Alf    schedule 06.07.2014
comment
@Jonathan Potter: Стойностите на пикселите бяха ОК. Това беше предварителното умножение, което ми липсваше. Виж отдолу. Благодаря на всички.   -  person chrisd    schedule 06.07.2014


Отговори (1)


Отговорът от съветите в коментарите: Всеки цветен канал във всеки пиксел трябва да бъде предварително умножен по алфата преди смесване.

get DIB bits
for each pixel
  r = r * alpha / 255
  g = g * alpha / 255
  b = b * alpha / 255
set DIB bits

MS не прави тези неща лесни за намиране. Няма и намек за това в единствената проба за алфа смесване, която успях да намеря:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd183353%28v=vs.85%29.aspx

person chrisd    schedule 06.07.2014