Композиция Pixman против альфа-смешивания

Ниже приведена небольшая тестовая программа (работает на машинах с прямым порядком байтов).

Как есть, результат мне уже странен:

 in: r=20 g=20 b=80 a=FF (#202080FF, ok!)
 out: r=90 g=90 b=C0 a=FF (#9090C0FF, strange...)

Где, как я и ожидал, цвет заливки #FFFFFFFF x маска 0x80 = #FFFFFF80 и, таким образом, вывод #9090FFFF...

Теперь, если я установлю цвет заливки на #FFFFFF80, изменив "cfill.alpha = uint16_t(0x80) ‹‹ 8;" , результат кажется действительно неправильным:

in: r=20 g=20 b=80 a=FF
out: r=98 g=98 b=E0 a=FF

Я бы ожидал, что fill x mask => #FFFFFF40 и, следовательно, вывод: #606060C0FF.

Я особенно не понимаю, как входной цвет с более низким альфа-каналом может оказаться более светлым на выходе целевого изображения.

Что я здесь делаю неправильно? Есть ли другой PIXMAP_OP_xxx, который будет работать так, как я ожидаю?

Спасибо.

#include <stdlib.h>
#include <stdio.h>
#include "pixman.h"

union C {
    uint32_t value;
    struct RGBA8888 {
        uint8_t a;
        uint8_t b;
        uint8_t g;
        uint8_t r;
    } rgba;
};

int main()
{
    // create target image full with r=0x20 g=0x20 b=0x80 a=0xFF
    size_t w = 100; // multiple of 4 for alignment
    size_t h = 100;
    C *target = (C*)malloc(w * h * sizeof(C));
    for(size_t i = 0; i < w * h; ++i)
        target[i].value = 0x202080FF;
    printf("in: r=%02X g=%02X b=%02X a=%02X\n", 
        target[0].rgba.r, target[0].rgba.g, target[0].rgba.b, target[0].rgba.a);

    // connect target to pixman image
    pixman_image_t *ptarget = pixman_image_create_bits(PIXMAN_r8g8b8a8, w, h, (uint32_t*)target, w * sizeof(uint32_t));

    // create fill
    pixman_color_t cfill;
    cfill.red   = uint16_t(0xFF) << 8;
    cfill.green = uint16_t(0xFF) << 8;
    cfill.blue  = uint16_t(0xFF) << 8;
    cfill.alpha = uint16_t(0xFF) << 8;
    pixman_image_t *pfill = pixman_image_create_solid_fill(&cfill);

    // create mask with a=0x80
    uint8_t *mask = (uint8_t*)malloc(w * h);
    for(size_t i = 0; i < w * h; ++i)
        mask[i] = 0x80;
    pixman_image_t *pmask = pixman_image_create_bits(PIXMAN_a8, w, h, (uint32_t*)mask, w);

    // do compositing
    pixman_image_composite(
                           PIXMAN_OP_OVER,
                           pfill, pmask, ptarget,
                           // src_x, src_y
                           0, 0,
                           // mask_x, mask_y
                           0, 0,
                           // dest_x, dest_y, width, height
                           0, 0, w, h);

    // display one pixel of target
    printf("out: r=%02X g=%02X b=%02X a=%02X\n", 
        target[0].rgba.r, target[0].rgba.g, target[0].rgba.b, target[0].rgba.a);
}

person Eric Nicolas    schedule 11.06.2014    source источник


Ответы (1)


Оказывается, Pixman работает с предварительно умноженной альфой! Таким образом, белый цвет с альфой должен быть #80808080, а затем #40404040, а не #FFFFFF80 и #FFFFFF40.

Надеюсь, это поможет кому-то еще ;)

person Eric Nicolas    schedule 12.06.2014