SetBitmapBits not Working as Expected
-
Hi there, i have written this function to draw a image held in raw pixel data in my own class to a window. It is not working as expected, say it doesn't draw a single pixel. Where is the fault? I am trying to solve this for days now and can't see where i made the mistake. Here comes the code.
void CImageViewerView::drawImage(CDC* pDC, CpilImage* pImage) {
// create compatible memory dc
CDC memDC;
memDC.CreateCompatibleDC(pDC);// draw image into the bitmap CBitmap imageBitmap; BITMAP bmp; BYTE\* imageBits; BYTE\* pImageBits; imageBitmap.CreateBitmap(pImage->getWidth(), pImage->getHeight(), 1, 24, NULL); imageBitmap.GetBitmap(&bmp); imageBits = (BYTE\*) GlobalAlloc(GPTR, bmp.bmHeight \* bmp.bmWidthBytes); for (unsigned int y = 0; y < pImage->getHeight(); y++) { unsigned int\* line = pImage->getPixelRegion(0, y, pImage->getWidth(), 1); unsigned int\* pLine = line; pImageBits = imageBits + (bmp.bmWidthBytes \* y); for (unsigned int x = 0; x < pImage->getWidth(); x++) { pImageBits\[0\] = getRedValue(pLine); pImageBits\[1\] = getGreenValue(pLine); pImageBits\[2\] = getBlueValue(pLine); pImageBits += 3; pLine++; } } if (imageBitmap.SetBitmapBits(bmp.bmHeight \* bmp.bmWidthBytes, imageBits) == 0) { AfxMessageBox("Could not set bitmap bits."); } GlobalFree((HGLOBAL) imageBits); // draw bitmap CBitmap\* pOldBitmap = memDC.SelectObject(&imageBitmap); if (pDC->BitBlt(0, 0, pImage->getWidth(), pImage->getHeight(), &memDC, 0, 0, SRCCOPY) ==0) { AfxMessageBox("BitBlt failed."); } memDC.SelectObject(pOldBitmap);
}
CpilImage
is a class which stores a image plus the pixel data in rgb-quads. ThegetXXXValue()
-functions are utility functions which extract the red, green and blue values from the quads. The class and functions are working, cause if i alter the function to work withCDC::SetPixelV()
the image is drawn. But as this is very slow i tryed to speed it up withSetBitmapBits()
andBitBlt()
which seems to not work. Walter -
Hi there, i have written this function to draw a image held in raw pixel data in my own class to a window. It is not working as expected, say it doesn't draw a single pixel. Where is the fault? I am trying to solve this for days now and can't see where i made the mistake. Here comes the code.
void CImageViewerView::drawImage(CDC* pDC, CpilImage* pImage) {
// create compatible memory dc
CDC memDC;
memDC.CreateCompatibleDC(pDC);// draw image into the bitmap CBitmap imageBitmap; BITMAP bmp; BYTE\* imageBits; BYTE\* pImageBits; imageBitmap.CreateBitmap(pImage->getWidth(), pImage->getHeight(), 1, 24, NULL); imageBitmap.GetBitmap(&bmp); imageBits = (BYTE\*) GlobalAlloc(GPTR, bmp.bmHeight \* bmp.bmWidthBytes); for (unsigned int y = 0; y < pImage->getHeight(); y++) { unsigned int\* line = pImage->getPixelRegion(0, y, pImage->getWidth(), 1); unsigned int\* pLine = line; pImageBits = imageBits + (bmp.bmWidthBytes \* y); for (unsigned int x = 0; x < pImage->getWidth(); x++) { pImageBits\[0\] = getRedValue(pLine); pImageBits\[1\] = getGreenValue(pLine); pImageBits\[2\] = getBlueValue(pLine); pImageBits += 3; pLine++; } } if (imageBitmap.SetBitmapBits(bmp.bmHeight \* bmp.bmWidthBytes, imageBits) == 0) { AfxMessageBox("Could not set bitmap bits."); } GlobalFree((HGLOBAL) imageBits); // draw bitmap CBitmap\* pOldBitmap = memDC.SelectObject(&imageBitmap); if (pDC->BitBlt(0, 0, pImage->getWidth(), pImage->getHeight(), &memDC, 0, 0, SRCCOPY) ==0) { AfxMessageBox("BitBlt failed."); } memDC.SelectObject(pOldBitmap);
}
CpilImage
is a class which stores a image plus the pixel data in rgb-quads. ThegetXXXValue()
-functions are utility functions which extract the red, green and blue values from the quads. The class and functions are working, cause if i alter the function to work withCDC::SetPixelV()
the image is drawn. But as this is very slow i tryed to speed it up withSetBitmapBits()
andBitBlt()
which seems to not work. Walteri am prety sure no one wants to read long code as in ur post. 1. bitmap width must be aligned with 2 or 4 bytes. 2. bottom-up or top-down bitmap is determined by BITMAPINFIHEADER.dbHeight.
A nice tool for optimizing your Microsoft html-help contents. Includeh10 -- modified at 8:12 Wednesday 1st March, 2006
-
i am prety sure no one wants to read long code as in ur post. 1. bitmap width must be aligned with 2 or 4 bytes. 2. bottom-up or top-down bitmap is determined by BITMAPINFIHEADER.dbHeight.
A nice tool for optimizing your Microsoft html-help contents. Includeh10 -- modified at 8:12 Wednesday 1st March, 2006
I tryed to cut it down, but i thought everything could be important. But your post shows that you haven't read the code, either. I use the calculated width from the bitmap info header bmWidthBytes. This is calculated by windows and 4 bytes aligned. I put traces in there and the height is calculated correct. If any of this values would be false there should be something on the screen at last and if it is only crap. But there is nothing, not a single pixel. I try to break the code down a bit:
// create compatible memory dc CDC memDC; memDC.CreateCompatibleDC(pDC); // draw image into the bitmap CBitmap imageBitmap; BITMAP bmp; BYTE\* imageBits; BYTE\* pImageBits; imageBitmap.CreateBitmap(pImage->getWidth(), pImage->getHeight(), 1, 24, NULL); imageBitmap.GetBitmap(&bmp); imageBits = (BYTE\*) GlobalAlloc(GPTR, bmp.bmHeight \* bmp.bmWidthBytes); //... doing some pixel transform stuff if (imageBitmap.SetBitmapBits(bmp.bmHeight \* bmp.bmWidthBytes, imageBits) == 0) { AfxMessageBox("Could not set bitmap bits."); } GlobalFree((HGLOBAL) imageBits); // draw bitmap CBitmap\* pOldBitmap = memDC.SelectObject(&imageBitmap); if (pDC->BitBlt(0, 0, pImage->getWidth(), pImage->getHeight(), &memDC, 0, 0, SRCCOPY) ==0) { AfxMessageBox("BitBlt failed."); } memDC.SelectObject(pOldBitmap);
-
Hi there, i have written this function to draw a image held in raw pixel data in my own class to a window. It is not working as expected, say it doesn't draw a single pixel. Where is the fault? I am trying to solve this for days now and can't see where i made the mistake. Here comes the code.
void CImageViewerView::drawImage(CDC* pDC, CpilImage* pImage) {
// create compatible memory dc
CDC memDC;
memDC.CreateCompatibleDC(pDC);// draw image into the bitmap CBitmap imageBitmap; BITMAP bmp; BYTE\* imageBits; BYTE\* pImageBits; imageBitmap.CreateBitmap(pImage->getWidth(), pImage->getHeight(), 1, 24, NULL); imageBitmap.GetBitmap(&bmp); imageBits = (BYTE\*) GlobalAlloc(GPTR, bmp.bmHeight \* bmp.bmWidthBytes); for (unsigned int y = 0; y < pImage->getHeight(); y++) { unsigned int\* line = pImage->getPixelRegion(0, y, pImage->getWidth(), 1); unsigned int\* pLine = line; pImageBits = imageBits + (bmp.bmWidthBytes \* y); for (unsigned int x = 0; x < pImage->getWidth(); x++) { pImageBits\[0\] = getRedValue(pLine); pImageBits\[1\] = getGreenValue(pLine); pImageBits\[2\] = getBlueValue(pLine); pImageBits += 3; pLine++; } } if (imageBitmap.SetBitmapBits(bmp.bmHeight \* bmp.bmWidthBytes, imageBits) == 0) { AfxMessageBox("Could not set bitmap bits."); } GlobalFree((HGLOBAL) imageBits); // draw bitmap CBitmap\* pOldBitmap = memDC.SelectObject(&imageBitmap); if (pDC->BitBlt(0, 0, pImage->getWidth(), pImage->getHeight(), &memDC, 0, 0, SRCCOPY) ==0) { AfxMessageBox("BitBlt failed."); } memDC.SelectObject(pOldBitmap);
}
CpilImage
is a class which stores a image plus the pixel data in rgb-quads. ThegetXXXValue()
-functions are utility functions which extract the red, green and blue values from the quads. The class and functions are working, cause if i alter the function to work withCDC::SetPixelV()
the image is drawn. But as this is very slow i tryed to speed it up withSetBitmapBits()
andBitBlt()
which seems to not work. WalterInstead of using
CreateBitmap()
, useCreateCompatibleBitmap()
passingpDC
as the DC parameter, and then use the contents of theBITMAP
structure to determine what format the bitmap is in. You may very well find that it's a 32-bpp bitmap, not a 24-bpp bitmap. RememberBitBlt()
only works if the source bitmap is monochrome or in the same format as the device context - hence theCreateCompatibleBitmap()
function.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
-
Hi there, i have written this function to draw a image held in raw pixel data in my own class to a window. It is not working as expected, say it doesn't draw a single pixel. Where is the fault? I am trying to solve this for days now and can't see where i made the mistake. Here comes the code.
void CImageViewerView::drawImage(CDC* pDC, CpilImage* pImage) {
// create compatible memory dc
CDC memDC;
memDC.CreateCompatibleDC(pDC);// draw image into the bitmap CBitmap imageBitmap; BITMAP bmp; BYTE\* imageBits; BYTE\* pImageBits; imageBitmap.CreateBitmap(pImage->getWidth(), pImage->getHeight(), 1, 24, NULL); imageBitmap.GetBitmap(&bmp); imageBits = (BYTE\*) GlobalAlloc(GPTR, bmp.bmHeight \* bmp.bmWidthBytes); for (unsigned int y = 0; y < pImage->getHeight(); y++) { unsigned int\* line = pImage->getPixelRegion(0, y, pImage->getWidth(), 1); unsigned int\* pLine = line; pImageBits = imageBits + (bmp.bmWidthBytes \* y); for (unsigned int x = 0; x < pImage->getWidth(); x++) { pImageBits\[0\] = getRedValue(pLine); pImageBits\[1\] = getGreenValue(pLine); pImageBits\[2\] = getBlueValue(pLine); pImageBits += 3; pLine++; } } if (imageBitmap.SetBitmapBits(bmp.bmHeight \* bmp.bmWidthBytes, imageBits) == 0) { AfxMessageBox("Could not set bitmap bits."); } GlobalFree((HGLOBAL) imageBits); // draw bitmap CBitmap\* pOldBitmap = memDC.SelectObject(&imageBitmap); if (pDC->BitBlt(0, 0, pImage->getWidth(), pImage->getHeight(), &memDC, 0, 0, SRCCOPY) ==0) { AfxMessageBox("BitBlt failed."); } memDC.SelectObject(pOldBitmap);
}
CpilImage
is a class which stores a image plus the pixel data in rgb-quads. ThegetXXXValue()
-functions are utility functions which extract the red, green and blue values from the quads. The class and functions are working, cause if i alter the function to work withCDC::SetPixelV()
the image is drawn. But as this is very slow i tryed to speed it up withSetBitmapBits()
andBitBlt()
which seems to not work. WalterI just noticed what you're trying to do :-O Have a look at
CreateDIBitmap()
andSetDIBitsToDevice()
. They will work with any bitmap format and will convert between them when displaying the bitmap. Slower thanBitBlt()
, but the performance will be substantially quicker than what you are doing here.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
-
Instead of using
CreateBitmap()
, useCreateCompatibleBitmap()
passingpDC
as the DC parameter, and then use the contents of theBITMAP
structure to determine what format the bitmap is in. You may very well find that it's a 32-bpp bitmap, not a 24-bpp bitmap. RememberBitBlt()
only works if the source bitmap is monochrome or in the same format as the device context - hence theCreateCompatibleBitmap()
function.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
Yeah! Just found out that this is the problem. It seems SelectObject() for the bitmap is returning an error, because of the bitmap is not compatible with the device context. I think i change my strategy and have a look into device independent bitmaps (DIB). Maybe this solves my problem. Programming Windows API can be frustrating sometimes. The only thing i want to do is to put some raw 24bit RGB pixel data fast on to the screen. This can't be that difficult. Thanks for your help!
-
I just noticed what you're trying to do :-O Have a look at
CreateDIBitmap()
andSetDIBitsToDevice()
. They will work with any bitmap format and will convert between them when displaying the bitmap. Slower thanBitBlt()
, but the performance will be substantially quicker than what you are doing here.Ryan
"Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"