agg_pixfmt_rgba32.h blending formula

针对讨论:

I have played with the blending functions found in agg_pixfmt_rgba32.h
and have come to the conclusion that the formulae used to compute the
output alpha in all blend_... functions is wrong.

Here is a snippet of what blend_solid_hspan does:

    int alpha = (*covers++) * c.a;
    ...
    int r = p[Order::R];
    ...
    int a = p[Order::A];
    p[Order::R] = (((c.r - r) * alpha) + (r << 16)) >> 16;
    ...
    p[Order::A] = (((c.a - a) * alpha) + (a << 16)) >> 16;

The computation for R, G and B is OK: the destination color is the
result of destination color added to the difference multiplied by
alpha.

However, for alpha, this is wrong. You don‘t want to compute the
destination alpha based on (c.a - a) * (c.a * coverage), but
instead, I would write :

    p[Order::A] = ((alpha + (a << 8)) - ((alpha * a) >> 8)) >> 8;

实际问题说明:

I was experimenting with RGBA images long ago and used WinAPI function
AlphaBlend(). I‘m not sure if I used exactly yours formulae for the
Alpha-channel, but something like that. The result of alpha-blending was
strange. Honestly, it‘s a bit confusing to me, because I tried to use regular
and premultiplied color spaces, but end up with complete mess. Then I tried to
use use the same formula for the alpha-channel and got some appropriate result:http://www.antigrain.com/agg_alpha_blend.gif (I reproduced it a couple of
minutes ago). Here I clear the frame buffer with rgba8(0,0,0,0) and use the
following code to display:

         // Alpha-blending the buffer
         BLENDFUNCTION blend;
         blend.BlendOp = AC_SRC_OVER;
         blend.BlendFlags = 0;

#if defined(AC_SRC_ALPHA)
         blend.AlphaFormat = AC_SRC_ALPHA;
#elif defined(AC_SRC_NO_PREMULT_ALPHA)
         // this is only for old version of wingdi.h that exists in Visual-C
6.x
         blend.AlphaFormat = AC_SRC_NO_PREMULT_ALPHA;
#else 
#error "No appropriate constant for alpha format. Check version of wingdi.h,
There must be AC_SRC_ALPHA or AC_SRC_NO_PREMULT_ALPHA"
         blend.AlphaFormat = 1; // just in case if the compiler treats "#error"
as a warning
#endif

邮件回复:

        blend.SourceConstantAlpha = 255;
         ::AlphaBlend(
            m_dc,      
            m_devRect.x1,
            m_devRect.y1,
            m_rbuf.width(),
            m_rbuf.height(),
            m_memDC,
            0,
            0,     
            m_rbuf.width(), 
            m_rbuf.height(),
            blend
         );

Although, if you clear the buffer with rgba8(255,255,255,0) the result will be
wrong. I‘ll try to experiment with your formula later and see what will happen.
Maybe I do something wrong when calling AlphaBlend too?

But in general, there‘re many ways to blend pixels in RGBA, you always can
write your own :-)
> I was experimenting with RGBA images long ago and used WinAPI function
> AlphaBlend(). I‘m not sure if I used exactly yours formulae for the
> Alpha-channel, but something like that. The result of alpha-blending was
> strange. Honestly, it‘s a bit confusing to me, because I tried to use
> regular and premultiplied color spaces, but end up with complete mess.

Same for me. I finally stopped messing with AlphaBlend since it did not
do what I expected. What I did was to paint using AGG into an RGBA buffer
initialised to rgba8(0,0,0,0) and that was OK. The differences between
your original blending code and my modified version usually only apply
to the areas where anti-aliasing is used, and thus don‘t show significant
differences, unless you paint surfaces with a given alpha value.

With your code, setting alpha to 50% and painting a pure red color over
a transparent (0,0,0,0) background results in the premultiplied red and
somehow-premultiplied alpha :

  r = 50%
  g = 0%
  b = 0%
  alpha = 25%
My code produces alpha = 50% in this case, which makes more sense. I
checked with the formulae used in Intel IPPI imaging library, and their
definition of premultiplied RGBA produces indeed 50%,0%,0%,50%.

> [...]
> Although, if you clear the buffer with rgba8(255,255,255,0) the result
> will be wrong. I‘ll try to experiment with your formula later and see
> what will happen. Maybe I do something wrong when calling AlphaBlend too?

I tried using AlphaBlend too. Here was my scenario:

- Paint into a transparent RGBA buffer (0,0,0,0) with AGG
- Set up an empty pixmap in .NET (premultiplied RGBA or plain RGBA, it
  does not seem to matter) and use AlphaBlend to copy the buffer into it.
  Somehow, .NET allows me to create an HDC from a Bitmap object, and that
  is what I needed to set up layered windows.
- Use that pixmap as the layered window background.

As soon as I paint with alpha!=0, AlphaBlend sets the alpha value of the
pixmap to 1.0, which is nonsense. Compositing a buffer onto another with
AlphaBlend does not preserve transparency, from what I have experimented.

> But in general, there‘re many ways to blend pixels in RGBA, you always can
> write your own :-)
I finally replaced the call of AlphaBlend with a simple byte-by-byte
buffer manipulation and now I get semi-transparency working quite well
in .NET windows. But I hate to have to give up because of lack of
understanding/documentation related to AlphaBlend.
时间: 2024-10-27 04:43:40

agg_pixfmt_rgba32.h blending formula的相关文章

整型和浮点坐标渲染线宽问题

代码如下:        agg::path_storage path;        for (int i = 100; i < 500; i=i+100)        {            path.move_to(i, 100);            path.line_to(i, 400);        } for (int ii = 120; ii < 550; ii=ii+100)        {            path.move_to(ii+0.5, 100)

Problem with blending edges of connected shapes

提供展示代码: agg::rendering_buffer &rbuf = rbuf_window();      agg::pixfmt_bgr24 pixf(rbuf); typedef agg::renderer_base<agg::pixfmt_bgr24> renderer_base_type;      renderer_base_type renb(pixf); typedef agg::renderer_scanline_aa_solid<renderer_bas

Calculate the formula

Problem Description You just need to calculate the sum of the formula: 1^2+3^2+5^2+……+ n ^2. Input In each case, there is an odd positive integer n. Output Print the sum. Make sure the sum will not exceed 2^31-1 Sample Input 3 Sample Output 10 用普通的做法

hdu 5139 Formula (找规律+离线处理)

Formula Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 206    Accepted Submission(s): 83 Problem Description f(n)=(∏i=1nin−i+1)%1000000007You are expected to write a program to calculate f(n) w

h?i?b?e?r?n?a?t?e?.?h?b?m?.?x?m?l?配?置?详?解

在Hibernate中,各表的映射文件….hbm.xml可以通过工具生成.配置文件的基本结构如下: Xml代码 1 <?xml version="1.0" encoding='UTF-8'?> 2 3 <!DOCTYPE hibernate-mapping PUBLIC 4 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 5 "http://hibernate.sourceforge.net/hi

outdated: 32.Picking, Alpha Blending, Alpha Testing, Sorting

一个射击类的小demo.分为三个文件,Previous.h.Previous.cpp和Main.cpp. 在Previous.cpp的CreateWindowGL中新增了AdjustWindowRectEx()函数,可以根据客户端的期望大小计算窗口大小,矩形通过函数创建一个理想大小的窗口. ChoosePixelFormat()函数试图匹配一个最接近的像素格式通过上下文给的像素格式规格. 在Mian.cpp文件的Selection()函数中,glGetIntegerv()函数返回一个选定后的参数

H.264视频的RTP荷载格式

Status of This Memo This document specifies an Internet standards track protocol for the   Internet community, and requests discussion and suggestions for   improvements.  Please refer to the current edition of the "Internet   Official Protocol Stand

CUDA编程(十)使用Kahan&amp;#39;s Summation Formula提高精度

CUDA编程(十) 使用Kahan's Summation Formula提高精度 上一次我们准备去并行一个矩阵乘法.然后我们在GPU上完毕了这个程序,当然是非常单纯的把任务分配给各个线程.也没有经过优化.终于我们看到,执行效率相当的低下,可是更重要的是出现了一个我们之前做整数立方和没遇到的问题,那就是浮点数精度损失的问题. 关注GPU运算的精度问题: 在程序的最后.我们计算了精度误差,发现最大相对误差偏高,而一般理想上应该要低于 1e-6. 我们之前将评估CUDA程序的时候也提过了.精度是CU

【URAL 1519】【插头dp模板】Formula 1

1519. Formula 1 Time limit: 1.0 second Memory limit: 64 MB Background Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely