使用来自其他 32 位位图的 Alpha 通道组成新的 32 位位图

Posted

技术标签:

【中文标题】使用来自其他 32 位位图的 Alpha 通道组成新的 32 位位图【英文标题】:Compose new 32bit bitmap with alpha channel from other 32bit bitmaps 【发布时间】:2014-03-12 05:15:42 【问题描述】:

我有几个带有 Alpha 通道的 32 位位图。

我需要编写一个新的位图,该位图又有一个 Alpha 通道。所以最终的位图稍后与 AlphaBlend 一起使用。

不需要拉伸。如果没有 alpha 通道,我会使用 BitBlt 创建新的位图。

我没有使用托管代码,我只想使用标准的 GDI / WinAPI 函数来执行此操作。我也对不需要一些特殊库的解决方案感兴趣。

TIA

注意:我知道我可以使用多个 AphaBlend 函数在最终输出中进行相同的合成。但是为了在我的程序中易于使用,我更愿意编写一次这样的位图。

【问题讨论】:

this SO answer 有帮助吗?或this? 这是GDI+,一定有办法,只用GDI。 或this answer? 它链接的文章非常详细地解释了 alpha 混合 GDI,包括将许多位图相互组合成最终位图,然后您可以混合一次。它有一个你也可以使用的 Delphi 类(你没有提到你正在使用什么语言。) 具体来说,您在处理过程的哪个部分有困难:从文件加载位图、合成、使用结果、将结果保存到文件中,还是其他? 【参考方案1】:

您可以遍历每个像素并手动组合它们:

void ComposeBitmaps(BITMAP* bitmaps, int bitmapCount, BITMAP& outputBitmap)

    for(int y=0; y<outputBitmap.bmHeight; ++y)
    
        for(int x=0; x<outputBitmap.bmWidth; ++x)
        
            int b = 0;
            int g = 0;
            int r = 0;
            int a = 0;
            for(int i=0; i<bitmapCount; ++i)
            
                unsigned char* samplePtr = (unsigned char*)bitmaps[i].bmBits+(y*outputBitmap.bmWidth+x)*4;
                b += samplePtr[0]*samplePtr[3];
                g += samplePtr[1]*samplePtr[3];
                r += samplePtr[2]*samplePtr[3];
                a += samplePtr[3];
            
            unsigned char* outputSamplePtr = (unsigned char*)outputBitmap.bmBits+(y*outputBitmap.bmWidth+x)*4;
            if(a>0)
            
                outputSamplePtr[0] = b/a;
                outputSamplePtr[1] = g/a;
                outputSamplePtr[2] = r/a;
                outputSamplePtr[3] = a/bitmapCount;
            
            else
                outputSamplePtr[3] = 0;
        
    

(假设所有位图都是 32 位且具有相同的宽度和高度)

或者,如果您想在另一个之上绘制位图,而不是按相等的比例混合它们:

    unsigned char* outputSamplePtr = (unsigned char*)outputBitmap.bmBits+(y*outputBitmap.bmWidth+x)*4;
    outputSamplePtr[3] = 0;
    for(int i=0; i<bitmapCount; ++i)
    
        unsigned char* samplePtr = (unsigned char*)bitmaps[i].bmBits+(y*outputBitmap.bmWidth+x)*4;
        outputSamplePtr[0] = (outputSamplePtr[0]*outputSamplePtr[3]*(255-samplePtr[3])+samplePtr[0]*samplePtr[3]*255)/(255*255);
        outputSamplePtr[1] = (outputSamplePtr[1]*outputSamplePtr[3]*(255-samplePtr[3])+samplePtr[1]*samplePtr[3]*255)/(255*255);
        outputSamplePtr[2] = (outputSamplePtr[2]*outputSamplePtr[3]*(255-samplePtr[3])+samplePtr[2]*samplePtr[3]*255)/(255*255);
        outputSamplePtr[3] = samplePtr[3]+outputSamplePtr[3]*(255-samplePtr[3])/255;
    

【讨论】:

当然最好使用 AlphaBlend 将所有位图组合在一起,然后在需要时绘制一个组合图像? AlphaBlend 将比大多数手动代码更快。 @David M:AlphaBlend 是否保留 Alpha 通道?怎么样? @David M:AlphaBlend 可能更快,但是:1) 如果位图尚未进行 alpha 预乘,您仍然需要在调用 AlphaBlend 之前手动进行预乘。 2)只有一种混合方法;例如,它不能独立于顺序混合位图。 3)最重要的是,它有兼容性问题。见:AlphaBlend on 64bit Windows 7 Not Working【参考方案2】:

我找到了以下最适合我的解决方案。

    我用 CreateDIBSection 创建一个新的目标位图 我用完全透明的像素预填充新位图。 (FillMemory/ZeroMemory) 我收到需要使用 GetDIBits 复制的像素。如果可能的话,我直接将行复制到我之前创建的缓冲区中。否则,我将数据逐行复制到步骤中创建的缓冲区中。 生成的位图可以与 AlphaBlend 和 CImageList 对象一起使用。

因为位图不重叠,所以我不需要关心目标数据。

【讨论】:

以上是关于使用来自其他 32 位位图的 Alpha 通道组成新的 32 位位图的主要内容,如果未能解决你的问题,请参考以下文章

在 Win32 中显示带 alpha 通道的 32 位图像

ARGB与RGBRGBA的区别

请使用CGBitmapContext和16位图像帮助

加载和使用 Alpha 通道位图

photoshop中说选用的颜色模式中8位,16位,24位,32位色彩是啥意思?会有啥区别?哪位知道的讲解下,谢谢!

调配 32 位 alpha 通道所需的 Intel 内在函数