混合2位图

时间:2016-01-01 21:08:51

标签: winapi gdi+

我有2个缓冲区指向不同大小的RGB32图像,所以我的想法是缩放一个缓冲区以匹配另一个缓冲区并对这些图像进行alphablend。

目前,我能够将StretchBlt(用于缩放性能)和GDI + drawimage函数与用于alphablending的colormatrix混合。这似乎有点慢,并且它也存在使用DirectX的不同组件使用缓冲区的问题。对于缓冲区问题,我尝试以相反的顺序复制行,除了DirectX相关组件外,它的工作原理。

Bitmap bmp1(width, height, 4bytesperpixel, RGB32, bufferpointer1);
Bitmap blend(width, height, 4bytesperpixel);
Graphics g(&newbmp)

using GDI function
Bitmap bmp2(scaleWidth, scaleHeight, 4bytesperpixel, RGB32, bufferpointer2)
HDC memdc = g.GetHDC();

////  scaling the bufferpointer2 to actual width & height
StretchDIBits(memdc, x,y, width, height, 0, 0,scaleWidth, scaleHeight, bufferpointer2,..)
g.ReleaseDC(memdc); // so that content is copied to the bitmap

//// Then alphablending bmp1 on top of the scaled imaged bmp2
//// Using lockbits to copy the bitmap bytes and unlocking it.

所以我需要替换GDI +函​​数并使用像AlphaBlend这样的Win32函数。我试过这样的东西,它显示黑屏

    BITMAPINFO bminfo1 = {};
    bminfo1.bmiHeader.biSize = sizeof( BITMAPINFO );
    bminfo1.bmiHeader.biWidth = w;
    bminfo1.bmiHeader.biHeight = h;
    bminfo1.bmiHeader.biBitCount = m_nBytesPerPixel * 8;
    bminfo1.bmiHeader.biCompression = BI_RGB;
    bminfo1.bmiHeader.biPlanes = 1;

    BITMAPINFO bminfo2 = {};
    bminfo2.bmiHeader.biSize = sizeof( BITMAPINFO );
    bminfo2.bmiHeader.biWidth = sW;
    bminfo2.bmiHeader.biHeight = sH;
    bminfo2.bmiHeader.biBitCount = m_nBytesPerPixel * 8;
    bminfo2.bmiHeader.biCompression = BI_RGB;
    bminfo2.bmiHeader.biPlanes = 1;

    char* pBytes1, *pBytes2;

    HDC hmemdc1 = CreateCompatibleDC(GetDC(0));
    HDC hmemdc2 = CreateCompatibleDC(GetDC(0));

    HBITMAP hBitmap1 = CreateDIBSection(hmemdc1, &bminfo1, DIB_RGB_COLORS, (void**) &pBytes1, NULL, 0);
    SetDIBits(hmemdc1, hBitmap1, 0, bminfo1.bmiHeader.bih, pBuffer[0], &bminfo1, DIB_RGB_COLORS);

    HBITMAP hBitmap2 = CreateDIBSection(hmemdc2, &bminfo2, DIB_RGB_COLORS, (void**) &pBytes2, NULL, 0);
    SelectObject(hmemdc2,hBitmap2);
    StretchDIBits(hmemdc2, 0, 0, w, h, 0, 0,
        sW, sH, pBuffer[1], &bminfo2, DIB_RGB_COLORS, SRCCOPY );

    BLENDFUNCTION bStruct; 
    bStruct.BlendOp = AC_SRC_OVER;
    bStruct.BlendFlags = 0;
    bStruct.SourceConstantAlpha = 255;
    bStruct.AlphaFormat = AC_SRC_ALPHA;

    SelectObject(hmemdc1,hBitmap1);
    SelectObject(hmemdc2,hBitmap2);

    //blend bmp2 on bmp1
    BOOL res = AlphaBlend(hmemdc1, 0, 0, w, h, hmemdc2, 0, 0, w, h, bStruct);

    //for testing output
    SelectObject(hmemdc1,hBitmap1);
    BitBlt(GetDC(0),0,0,width,height,hmemdc1,100,100,SRCCOPY);


    //copy the bitmap buffer
    memcpy(out, pBytes1, (w * m_nBytesPerPixel) * h);

我不确定是否可以使用AlphaBlend函数根据2个内存DC混合每像素位图。任何帮助都将受到高度赞赏。

1 个答案:

答案 0 :(得分:2)

这部分错了:

bminfo1.bmiHeader.biSize = sizeof( BITMAPINFO );

它应该是 sizeof(BITMAPINFOHEADER) ,否则会破坏一切。此外,您无法使用GetDC(0)进行任何正确的绘画。改为使用:

HDC hdc = GetDC(hwnd);
...
ReleaseDC(hwnd, hdc);

或使用HDC中的BeginPaint。由于您使用的是GDI +,因此您必须拥有HBITMAP的{​​{1}}个句柄,没有理由转换为内存并返回bmp->GetHBITMAP()

对于HBITMAP设置AlphaBlend,如果未设置Alpha通道。

SourceConstantAlpha = 128;

如果您想获取dib,请不要在void blend(HDC hdc, RECT rc, HBITMAP hbitmap1, HBITMAP hbitmap2) { HDC memdc1 = CreateCompatibleDC(hdc); HDC memdc2 = CreateCompatibleDC(hdc); BITMAP bmp1, bmp2; GetObject(hbitmap1, sizeof(BITMAP), &bmp1); GetObject(hbitmap2, sizeof(BITMAP), &bmp2); SelectObject(memdc1, hbitmap1); SelectObject(memdc2, hbitmap2); BLENDFUNCTION blend = { 0 }; blend.SourceConstantAlpha = 128; SetStretchBltMode(hdc, COLORONCOLOR); AlphaBlend(memdc2, 0, 0, bmp2.bmWidth, bmp2.bmHeight, memdc1, 0, 0, bmp1.bmWidth, bmp1.bmHeight, blend); StretchBlt(hdc, 0, 0, rc.right, rc.bottom, memdc2, 0, 0, bmp2.bmWidth, bmp2.bmHeight, SRCCOPY); //or create another memdc to get dibs DeleteDC(memdc1); DeleteDC(memdc2); } 上绘图,而是创建第三个hdc和另一个memdc,然后使用HBITMAP

GetDIBits

修改

方法2:此方法应该更快,因为它使用一个HDC memdc = CreateCompatibleDC(hdc); HBITMAP hbmp = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); SelectObject(memdc, hbmp); SetStretchBltMode(memdc, COLORONCOLOR); StretchBlt(memdc, 0, 0, rc.right, rc.bottom, memdc2, 0, 0, bmp2.bmWidth, bmp2.bmHeight, SRCCOPY); int w = rc.right; int h = rc.bottom; BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) }; bmpInfoHeader.biWidth = w; bmpInfoHeader.biHeight = h; bmpInfoHeader.biBitCount = 32; bmpInfoHeader.biCompression = BI_RGB; bmpInfoHeader.biPlanes = 1; DWORD size = w * 4 * h; char *dib = new char[size]; GetDIBits(hdc, hbmp, 0, h, dib, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS); ... DeleteDC(memdc); DeleteObject(hbitmap); delete[]dib; 和一个StretchBlt。这样你就可以使用预先计算出的alphas,尽管没有必要。

仅当您要将两个图像与背景混合时,才使用另一个方法2 AlphaBlend

AlphaBlend