开罗中的alpha透明度

6
我在使用GTK和Cairo显示alpha透明度时遇到了问题。我试图显示这张图片:1 如果我自己进行alpha混合,则一切正常。 Manual alpha blending 如果我直接将alpha值传递给Cairo,则阴影似乎渲染良好,但发光效果会损坏。 Cairo alpha rendering 这是Cairo 1.14.2的错误,还是我漏掉了什么?
//Need deprecated API to get background color
GdkColor color = gtk_widget_get_style(widget)->bg[GTK_STATE_NORMAL];
Pixel color_blend
    {
     uint8_t(255*color.red/65535.0f)
    ,uint8_t(255*color.green/65535.0f)
    ,uint8_t(255*color.blue/65535.0f)
    ,255
    };
while(ptr!=ptr_end)
    {
//  TODO: Interpolate
    auto row_src=size_t(row*factor);
    auto col_src=size_t(col*factor);

    auto alpha=ptr_src[row_src*width_in + col_src].v3/255.0f;
    *ptr=
        {
    //  Using manual alpha blend works  
        uint8_t(alpha*ptr_src[row_src*width_in + col_src].v2 + (1-alpha)*color_blend.v2)
        ,uint8_t(alpha*ptr_src[row_src*width_in + col_src].v1 + (1-alpha)*color_blend.v1)
        ,uint8_t(alpha*ptr_src[row_src*width_in + col_src].v0 + (1-alpha)*color_blend.v0)
        ,255
    /*  This appears to be broken 
        ptr_src[row_src*width_in + col_src].v2
        ,ptr_src[row_src*width_in + col_src].v1
        ,ptr_src[row_src*width_in + col_src].v0
        ,ptr_src[row_src*width_in + col_src].v3*/
        };

    ++col;
    if(col==width_out)
        {
        col=0;
        ++row;
        }
    ++ptr;
    }

我使用像素点来进行推动。
auto surface=cairo_image_surface_create_for_data((uint8_t*)pixels.begin(),CAIRO_FORMAT_ARGB32,width_out,height_out,width_out*sizeof(Pixel));

cairo_set_source_surface(cr, surface, 0.5*(width-width_out), 0.0);
cairo_paint(cr);

cairo_surface_destroy(surface);

明确将操作符设置为CAIRO_OPERATOR_OVER并没有帮助,结果仍然相同。


你是否使用了正确的运算符,即 CAIRO_OPERATOR_OVER 而不是 CAIRO_OPERATOR_SOURCE? - H. Guijt
@H. Guijt CAIRO_OPERATOR_OVER 是默认的,显式指定它会产生相同的结果。然而,改变为 CAIRO_OPERATOR_SOURCE 会有正确的行为,也就是我得到了一个半透明的窗口。 - user877329
@H.Guijt,您是指我创建的表面,还是GTK提供的cairo上下文支持格式? - user877329
你正在绘制的对象,即你示例中的“cr”。 - H. Guijt
你的像素格式是什么?变量类型有哪些?所有这些“auto”都没有说太多。你是怎么想出混合公式的(http://www.cairographics.org/operators/使用另一种公式进行OVER)?你知道什么是预乘alpha吗?以下哪个值描述了“完全透明度为50%的红色”?(1)(0.5,0,0,0.5)还是(2)(1,0,0,0.5)(提示:(1)是正确的) - Uli Schlachter
显示剩余3条评论
1个回答

5
正如您在上面的评论中提到的,您的像素值是错误的。您需要使用预乘alpha。回到我在问题中的示例(忽略字节序),50%透明度的全红在Cairo中为0x7f << 24 | 0x7f。具有无效值的像素(某些颜色分量大于alpha值)会产生未定义的结果,而您的0xff << 24 | 0x7f属于此类别。
请参见http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t:

使用了预乘alpha。(即50%透明的红色为0x80800000,而不是0x80ff0000。)

附注:我认为访问像素数据的正确方式是通过uint32_t和移位,例如uint32_t pixel = (r << 24) | (g << 16) | (b << 8) | a;。这样,您就不必担心字节序问题。
另外,对于OVER和完全不透明的目标,Cairo使用的公式简化为source_color + target_color *(1-source_alpha),而您的代码使用source_color * source_alpha + target_color *(1-source_alpha)。请参见http://www.cairographics.org/operators/。这两个公式显然不等价。
编辑:好吧,也许在使用预乘alpha时它们是等价的。对于造成的困惑,我很抱歉。

当使用预乘alpha时,它们是等效的。而且Cairo使用的公式只在这种情况下才正确。因此,您可以删除“也许”。 - user877329

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接