Entretoize
Entretoize

Reputation: 2251

stack error while trying to modify hbitmap data

I'm trying to modify a hbitmap to add transparent pixels before rendering it (but that's not the question) and after some googling I can't mak my code to work. This is what I'm trying:

HBITMAP hBitmap = NULL, hBitmapOld = NULL;
HDC hMemDC = NULL;
BLENDFUNCTION bf;


hMemDC = CreateCompatibleDC(hdc);

hBitmapOld = (HBITMAP)SelectObject(hMemDC, bitmap);

BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

if (0 == GetDIBits(hMemDC, bitmap, 0, height, NULL, &MyBMInfo, DIB_RGB_COLORS))
    return;

// create the pixel buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];

if (0 == GetDIBits(hMemDC, bitmap, 0, height, lpPixels, &MyBMInfo, DIB_RGB_COLORS))
    return;

for (int i = 0; i < width*height; i++)//i know there's 4 bytes per pixel, it's just to try
    lpPixels[i] = 0;

if (0 == SetDIBits(hMemDC, bitmap, 0, height, lpPixels, &MyBMInfo, DIB_RGB_COLORS))
    return;

delete[] lpPixels;

bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255; //transparency value between 0-255
bf.AlphaFormat = 0;

AlphaBlend(hdc, xabs, yabs, width, height, hMemDC, 0, 0, width, height, bf);

SelectObject(hMemDC, hBitmapOld);

DeleteDC(hMemDC);
DeleteObject(hBitmap);

Actualy I'm just trying to set the pixel to 0 which should set black (eventualy transparent) pixels for a quarter of the image (as I'm just going from 0 to w*x and pixels are 4 bytes long).

But there's some data corruption so that when that function exits I get a exception. Then my code is not correct.

I can say the bitmap is well loaded, and I get the good bitmap info from GetDIBits.

Thanks

Upvotes: 0

Views: 215

Answers (2)

Entretoize
Entretoize

Reputation: 2251

I folowwed the advice of VTT but it still didn't work, it seems that the problem came from the BITMAPINFO which was not used properly, so I followed the way microsoft does here and it works:

BITMAPINFOHEADER   bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
if (0 == GetDIBits(hMemDC, bitmap, 0, height, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS))
    return;

// create the pixel buffer
BYTE* lpPixels = new BYTE[bi.biWidth * bi.biHeight * bi.biBitCount / 8];

if (0 == GetDIBits(hMemDC, bitmap, 0, height, lpPixels, (BITMAPINFO*)&bi, DIB_RGB_COLORS))
    return;

for (int i = 0; i < width*height; i++)//i know there's 4 bytes per pixel, it's just to try
    lpPixels[i] = 0;

if (0 == SetDIBits(hMemDC, bitmap, 0, height, lpPixels, (BITMAPINFO*)&bi, DIB_RGB_COLORS))
    return;

Upvotes: 1

user7860670
user7860670

Reputation: 37523

From MSDN:

biSizeImage

The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps. If biCompression is BI_JPEG or BI_PNG, biSizeImage indicates the size of the JPEG or PNG image buffer, respectively.

So I suspect that you create effectively empty array since bitmaps are typically not compressed and suffer from buffer overrun later.

To obtain require buffer size you should check biCompression and then (assuming that it is uncompressed BI_RGB) multiply biWidth * biHeight * biBitCount / 8

Upvotes: 1

Related Questions