Click to See Complete Forum and Search --> : Help copying HBITMAP from file to new HBITMAP


jreck2112
February 20th, 2008, 06:41 AM
I am trying to load a .bmp into an HBITMAP and then copy a portion of it into a new memory HBITMAP. I am pretty familiar with device contexts, memory bitmaps, and GDI - but I think I am missing something about HBITMAP creation. I've read and reread everything on the net but nothing has a complete code sample for this simple task so my efforts have been futile.

The following code (simplified) produces black squares on the screen - what am I missing?

//first load the source bitmap from a file - this works fine and will print to
// the screen with no problem
HBITMAP hbmsource = (HBITMAP)LoadImage(NULL,filepath,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

//get the screen device context
CDC* pDC = GetDC();

//create two memory dcs compatible with the screen
HDC memDCsource = CreateCompatibleDC(pDC->m_hDC);
HDC memDCtarget= CreateCompatibleDC(pDC->m_hDC);

//select the source bitmap into the source DC
HBITMAP pOldBitmap1 = (HBITMAP)SelectObject(memDCsource,hbmsource);

//create a new bitmap compatible with the screen dc
HBITMAP hbmtarget = CreateCompatibleBitmap(pDC->m_hDC,w,h);

//.....I suspect that I am missing something here required to create the new
// bitmap... ie bitmap header, CreateDIB, etc. - I thought that CreateCompatibleBitmap
//covered all that.....

//select the new bitmap into the target dc
HBITMAP pOldBitmap2 = (HBITMAP)SelectObject(memDCtarget,hbmtarget);

//bitblt the source to the target
BitBlt(memDCtarget,0,0,w,h,memDCsource,0,0,SRCCOPY);

//cleanup
SelectObject(memDCsource,pOldBitmap1);
SelectObject(memDCtarget,pOldBitmap2);
DeleteDC(memDCsource);
DeleteDC(memDCtarget);

ReleaseDC(pDC);

.......Now when I try and display the new HBITMAP on the screen it is all black.

thanks for any help

VladimirF
February 20th, 2008, 11:09 AM
//create a new bitmap compatible with the screen dc
HBITMAP hbmtarget = CreateCompatibleBitmap(pDC->m_hDC,w,h);

.......Now when I try and display the new HBITMAP on the screen it is all black.Try to create your hbmtarget compatible to memDCsource (after you have selected source bitmap into it).

ramin.zaghi
February 20th, 2008, 12:01 PM
or try to make the loaded bitmap compatible.
MSDN states that LoadImage makes it compatible but
you should see what works in action.

to test/debug try to BitBlt onto the screen ( a display DC ) to
see if the loaded image does appear correctly ( i.e. it is
loaded and compatible ).

CBasicNet
February 21st, 2008, 02:15 AM
Use GDI+. It is much simpler to use than GDI. Below is the code for cropping the image and saving them. If you do not want to save, just commented the Save function in CropImage().


using namespace Gdiplus;
void Test()
{

Bitmap SrcBmp(L"E:\\Hello.jpg", TRUE);

bool bRet = CropImage(
SrcBmp,
160,
35,
510,
490,
L"E:\\Hello2.jpg",
L"image/jpeg" );

if( bRet )
MessageBox(L"Successful");
else
MessageBox(L"Failed");
}

bool CropImage(
Bitmap &SrcBmp,
int x,
int y,
int nWidth,
int nHeight,
const std::wstring& szDestFile,
const std::wstring& szEncoderString )
{
Rect rect(x, y, nWidth, nHeight);
Bitmap* pDestBmp = SrcBmp.Clone(rect, PixelFormatDontCare);

if( !pDestBmp )
return false;

CLSID Clsid;
int result = GetEncoderClsid(szEncoderString.c_str(), &Clsid);

if( result < 0 )
return false;

Status status = pDestBmp->Save( szDestFile.c_str(), &Clsid );

delete pDestBmp;
pDestBmp = NULL;

return status == Ok;
}

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure

GetImageEncoders(num, size, pImageCodecInfo);

for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}

free(pImageCodecInfo);
return -1; // Failure
}



If you want to display the cropped image, just use the code below,


Graphics graphics(hDC);
graphics.DrawImage(pDestBmp,0,0,nWidth,nHeight);

CBasicNet
February 21st, 2008, 02:20 AM
If the OP only wants to display the cropped image, here is the edited code.


bool CropImage(
Bitmap &SrcBmp,
int x,
int y,
int nWidth,
int nHeight,
const std::wstring& szDestFile,
const std::wstring& szEncoderString )
{
Rect rect(x, y, nWidth, nHeight);
Bitmap* pDestBmp = SrcBmp.Clone(rect, PixelFormatDontCare);

if( !pDestBmp )
return false;

Graphics graphics(hDC);
graphics.DrawImage(pDestBmp,0,0,nWidth,nHeight);

delete pDestBmp;
pDestBmp = NULL;

return status == Ok;
}



Remember to include the Gdiplus.h and link to Gdiplus.lib

jreck2112
February 26th, 2008, 08:28 AM
Thanks for the suggestions....

- I had tried making the CDC compatible with the source DC but that did not make a difference (and in past experiences, had made things worse).

- The loaded images were working fine standalone (and could be succesfully displayed on the screen).

- I'd love to switch to GDI+ but haven't explored yet the easiest way to use with C++ (i.e. VC6) - can't bring myself to jump into C# yet.

BOTTOM LINE - the problem turned out to be quite fundamental... I wasn't allocating any memory for the new target bitmap. It was properly compatible and coded correctly, but without the Alloc - nowhere to put all the pretty pixels.

Thanks for the help.