1

I several a 32bit bitmap with Alpha channel.

I need to compose a new Bitmap that has again an alpha channel. So the final bitmap is later used with AlphaBlend.

There is no need for stretching. If there would be no alpha channel, I would just use BitBlt to create the new bitmap.

I am not using managed code, I just want to do this with standard GDI / WinAPI functions. Also I am interested in a solution that there is no need for some special libraries.

TIA

Note: I know that I can use several AphaBlend functions to do the same composition in the final output. But for the ease of use in my program I would prefer to compose such a bitmap once.

xMRi
  • 14,982
  • 3
  • 26
  • 59
  • does [this SO answer](http://stackoverflow.com/a/342212/1850797) help? or [this](http://stackoverflow.com/a/183512/1850797)? – Edward Clements Feb 13 '14 at 13:13
  • This is GDI+, there must be a way, using only the GDI. – xMRi Feb 13 '14 at 13:37
  • 1
    Or [this answer?](http://stackoverflow.com/questions/10118935/alpha-channel-in-devicecontext-hdc/10120657#10120657) The articles it links to explain alpha-blended GDI in extreme detail, including composing many bitmaps over each other into a final bitmap you can then blend once. It has a Delphi class you can use too (you don't mention what language you're using.) – David Feb 15 '14 at 01:28
  • Specifically which part of the process are you having difficulty with: loading the bitmaps from a file, compositing, using the result, saving the result to a file, something else? – Adrian McCarthy Mar 20 '14 at 16:15

2 Answers2

0

You can go through every pixel and compose them manually:

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;
        }
    }

(Assuming all bitmaps are 32-bit and have the same width and height)

Or, if you want to draw bitmaps one on top of another, rather than mix them in equal proportions:

    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;
    }
Anton
  • 3,113
  • 14
  • 12
  • Surely it's better to compose all bitmaps together using AlphaBlend, and then draw that one composed image whenever required? AlphaBlend will be faster than most manual code. – David Feb 15 '14 at 13:07
  • @David M: Does AlphaBlend keeps the Alpha channel? How? – xMRi Feb 15 '14 at 14:18
  • @David M: AlphaBlend probably is faster, but: 1) If the bitmaps are not already alpha-premultiplied, you still have to do the premultiplication manually before calling AlphaBlend. 2) There is only one blending method; it can't blend bitmaps order-independently, for example. 3) And most important, it has compatibility issues. See: [AlphaBlend on 64bit Windows 7 Not Working](http://social.msdn.microsoft.com/Forums/en-US/34f16345-8b61-4427-b72a-64a42261fa1c/alphablend-on-64bit-windows-7-not-working) – Anton Feb 15 '14 at 14:51
0

I found the following solution that fits best for me.

  1. I Create a new target bitmap with CreateDIBSection
  2. I prefill the new bitmap with fully transparent pixels. (FillMemory/ZeroMemory)
  3. I Receive the Pixel that needs to be copied with GetDIBits. If possible form the width I directly copy the rows into the buffer I previously created. Otherwise I copy the data row by row into the buffer created in step.
  4. The resulting bitmap can be used with AlphaBlend and in CImageList objects.

Because the bitmaps don't overlap I don't need take care about the target data.

xMRi
  • 14,982
  • 3
  • 26
  • 59