GDI+ GetHBITMAP memory error? - c++

So I was trying to learn some GDI basics and my code breaks when I try to get the HBITMAP for a png image I want to display...
HBITMAP SplashScreen::LoadPng(WCHAR* path)
{
HBITMAP bmp;
fstream f;
f.open(path);
if(!f.good())
{
throw std::exception("Can't find/read file.");
}
f.close();
Gdiplus::Bitmap* img = Gdiplus::Bitmap::FromFile(path, FALSE);
Gdiplus::Color bg(0,0,0,0);
img->GetHBITMAP(bg, &bmp); // <--- Breaks here! Memory access exception!
return bmp;
}
The code is already so simple, I can't think of anything wrong with it, except maybe I just didn't set something up beforehand??
Thoughts?

Not sure what your problem is, though, I do note that you've got a memory leak.
img is never deleted - you should call delete img; after the call to GetHBITMAP
I use the following (less thorough code) in quick test projects.
// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
HBITMAP mLoadImg(WCHAR *szFilename)
{
HBITMAP result=NULL;
Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(szFilename,false);
bitmap->GetHBITMAP(0, &result);
delete bitmap;
return result;
}

I didn't initialize GDI correctly. After fixing my init code, it works fine. That was annoying. Now I know.

Related

PNG/JPG file to HBITMAP with GDI+

I need to load an image as a HBITMAP in C++ so I can send it to a printer.
I've tried using Gdiplus::Bitmap::FromFileand then Gdiplus::Bitmap->GetHBITMAP however the HBITMAP returned is still empty.
I can load .bmp files fine with LoadImage() but this doesn't work with PNG files.
Could anyone point me to the correct way of implementing this to work with .png (and more, if possible) file types?
EDIT: CODE
ZeroMemory(&hBitmap, sizeof(HBITMAP));
Gdiplus::Bitmap* gpBitmap = Gdiplus::Bitmap::FromFile(L"img.png");
gpBitmap->GetHBITMAP(0, &hBitmap);
EDIT 2: Solution found
HBITMAP GetHBITMAPFromImageFile(WCHAR* pFilePath)
{
GdiplusStartupInput gpStartupInput;
ULONG_PTR gpToken;
GdiplusStartup(&gpToken, &gpStartupInput, NULL);
HBITMAP result = NULL;
Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromFile(pFilePath, false);
if (bitmap)
{
bitmap->GetHBITMAP(Color(255, 255, 255), &result);
delete bitmap;
}
GdiplusShutdown(gpToken);
return result;
}

Can't bitblt CBitmap to dialog

Thanks for reading this.
I need to draw CBitmap instance which created by bitmap info header and byte array. Because I want them to be able to manipulate it real time in the future. Can't use LoadImage or such APIs that access my hard drive. Memory operations only.
Here's what I've tried.
void CBMPLoaderDlg::drawBitmapFromPath(CString path)
{
CFile file;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
BYTE* bits = NULL;
CBitmap bm;
CDC *clientDC;
CDC memDC;
try
{
if(! file.Open(path, CFile::modeRead))
throw "File not found";
if(file.Read(&bfh, sizeof(BITMAPFILEHEADER)) < sizeof(BITMAPFILEHEADER))
throw "Not bmp file";
if(file.Read(&bih, sizeof(BITMAPINFOHEADER)) < sizeof(BITMAPINFOHEADER))
throw "Not bmp file";
bits = new BYTE[bih.biSizeImage];
if(file.Read(bits, bih.biSizeImage) < bih.biSizeImage)
throw "Not bmp file";
if(! bm.CreateBitmap(bih.biWidth, bih.biHeight, bih.biPlanes, bih.biBitCount, bits))
throw "Could not create bitmap";
clientDC = this->GetDC();
memDC.CreateCompatibleDC(clientDC);
memDC.SelectObject(bm);
clientDC->BitBlt(0, 0, bih.biWidth, bih.biHeight, &memDC, 0, 0, SRCCOPY);
}
catch(char *e)
{
TRACE("%s\n", e);
}
}
The headers and byte array loads fine. And CBitmap creates fine too. Problem is, Bitblt returns TRUE but no changes on the dialog. Yes, Bitblt just be performed when OnPain() is called. I've tried that and result doesn't vary. I made this way to post this thread.
Am I getting it wrong? Please a little help would be great.

HBITMAP memory leak

No matter how hard I looked and whatever I tried, I couldn't find why this code is leaking. Actually, I'm not sure about the leak but the number of GDI objects increases everytime I use this piece of code.
HBITMAP hBmp;
hBmp = CreateDIBitmap(dc, &stBmpIH, CBM_INIT, m_pBitmapData, m_pBitmapInfo, DIB_RGB_COLORS) ;
Bitmap *pBMP = NULL;
HPALETTE hPal = NULL;
Color col = 0;
pBMP = Bitmap::FromHBITMAP(hBmp, hPal);
if (m_bFlip)
{
pBMP->RotateFlip( Rotate90FlipXY );
pBMP->GetHBITMAP(col,&hBmp);
m_bFlip = FALSE;
}
else
{
pBMP->RotateFlip( RotateNoneFlipX );
pBMP->GetHBITMAP(col,&hBmp);
}
delete pBMP;
I've checked the GDI objects with a tool, and what I found is the HBITMAP hBmp is the one that is leaking. How should I remove it?
DeleteObject is NOT working.
Thanks
From the FromHBITMAP documentation:
You are responsible for deleting the GDI bitmap and the GDI palette.
However, you should not delete the GDI bitmap or the GDI palette until
after the GDI+ Bitmap object is deleted or goes out of scope.
Deleting the Bitmap object is not enough, you need to call DeleteObject on hBmp afterwards.
DeleteObject is NOT working.
Let's assume that it is actually in your code even though the snippet doesn't show it. Then the next explanation is this statement:
pBMP->GetHBITMAP(col,&hBmp);
Which overwrites the value for hBmp, preventing you from releasing it properly. Fix:
HBITMAP prev = hBmp;
Status status = pBMP->GetHBITMAP(col,&hBmp);
if (status == Ok) DeleteObject(prev);
You'll probably need to do some more work on the error handling code.
You need a call to DeleteObjectto match the call to CreateDIBitmap. How exactly is it now working?

Load a CBitmap dynamically

I have a Bitmap image that i want to load dynamically. But I am unable to load it.
CBitmap bmp;
bmp.LoadBitmap("c:\\aeimg");
it does not seem to be working.
Can someone please help me.
Thanks.
You can also try something like this:
CImage image;
image.Load(_T("C:\\image.png"));
CBitmap bitmap;
bitmap.Attach(image.Detach());
According to CBitmap documentation: LoadBitmap() function takes resource identifier of the bitmap or resource id of the bitmap.
You can't specify the path of the bitmap file.
E.g.
MyProject.rc
------------
MYBMP BITMAP "res\myimage.bmp"
and make sure that resource.h does not have any entry of MYBMP otherwise during preprocessing its replaced by id and ultimately LoadBitmap() will fail since application can't locate the resource as FindResource() fails.
Now do this :
CBitmap bmp;
bmp.LoadBitmap(L"MYBMP");
It will definitely load the bitmap.
To load a bitmap from a file, you want to use LoadImage with the LR_LOADFROMFILE flag.
CBitmap doesn't support directly reading from a .bmp file. You can instead make use of CImage class as suggested in other answers. You'll need to include atlimage.h in your code to make CImage work:
#include <atlimage.h>
:
CImage img;
img.Load (_T("C:\\image.bmp"));
CBitmap bitmap;
bitmap.Attach(img.Detach());
Another way is to load the image using LoadImage Win32 API and then attaching CBitmap to that:
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,"c:\\image.bmp",
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (hBitmap != NULL)
bitmap.Attach(hBitmap);
CImage doesn't work with png last time I tried / checked. Have a look at CxImage - http://www.codeproject.com/KB/graphics/cximage.aspx .
It could be as simple as you forgetting to escape the backslash.
Instead of
bmp.LoadBitmap("c:\aeimg");
use
bmp.LoadBitmap("c:\\aeimg");
Otherwise you're passing an invalid path to the LoadBitmap method.
CString filename;
TCHAR szFilter[] = _T("Bitmap (*.bmp)|*.bmp|PNG (*.png)|*.png||");
CFileDialog selDlg(TRUE, NULL, NULL, OFN_OVERWRITEPROMPT | OFN_EXTENSIONDIFFERENT, szFilter, this);
if (selDlg.DoModal() == IDOK)
{
filename = selDlg.GetPathName();
CImage image;
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (hBitmap)
{
// Delete the current bitmap
if (m_bmpBitmap.DeleteObject())
m_bmpBitmap.Detach(); // If there was a bitmap, detach it
// Attach the currently loaded bitmap to the bitmap object
m_bmpBitmap.Attach(hBitmap);
Invalidate();
}
}
When using the solutions mentioned to date, with a member variable of CBitmap I kept getting memory leaking every time I loaded the CImage onto the CBitmap. I solved this with the following code:
CString _fileName(/*Path to image*/);
CImage _image;
HRESULT hr = _image.Load(_fileName);
if (SUCCEEDED(hr)) {
if (m_Display.m_bmpImage.DeleteObject())
m_Display.m_bmpImage.Detach();
m_bmpImage.Attach(_image->Detach());
}

Bitmap manipulation in C++ on Windows

I have myself a handle to a bitmap, in C++, on Windows:
HBITMAP hBitmap;
On this image I want to do some Image Recognition, pattern analysis, that sort of thing. In my studies at University, I have done this in Matlab, it is quite easy to get at the individual pixels based on their position, but I have no idea how to do this in C++ under Windows - I haven't really been able to understand what I have read so far. I have seen some references to a nice looking Bitmap class that lets you setPixel() and getPixel() and that sort of thing, but I think this is with .net .
How should I go about turning my HBITMAP into something I can play with easily? I need to be able to get at the RGBA information. Are there libraries that allow me to work with the data without having to learn about DCs and BitBlt and that sort of thing?
You can use OpenCV library as a full image processing tool.
You can also use MFC's CImage or VCL's TBitmap just to extract pixel values from HBITMAP.
Gdiplus::Bitmap* pBitmap = Gdiplus::Bitmap::FromHBITMAP( hBitmap, NULL );
Gdiplus::Color pixel_color;
pBitmap->GetPixel( x, y, &pixel_color ); // read pixel at x,y into pixel_color
// ...
delete pBitmap; // do not forget to delete
Try this using GetPixel from GDI:
COLORREF GetBitmapBixel(HBITMAP hBitmap, int xPos, int yPos)
{
HDC hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC);
COLORREF pixelColor;
HBITMAP hOld = (HBITMAP)SelectObject(hMemDC, hBitmap);
pixelColor = ::GetPixel(hMemDC, xPos, yPos);
SelectObject(hMemDC, hOld);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
return pixelColor;
}
With:
DIBSECTION ds;
::GetObject(hbmp/*your HBITMAP*/, sizeof DIBSECTION, &ds);
you will get all you need (including pixel format and pixel buffer adress) in ds.dsBm.
see the doc