How would I load a PNG image using Win32/GDI (no GDI+ if possible)?
You can use the Windows Imaging Component to load PNG files (on Windows XP SP2 and later). See MSDN Magazine for an introduction on how to use the API and my blog post for a code sample that loads a PNG from an IStream and converts it to an HBITMAP.
How would I draw a PNG image using LoadImage and StretchDIBits?
I think the PNG support inside bitmaps is only really for use by printer drivers. For screen display, you will probably have to decompress the PNG data yourself using some code such as libpng.
Is there any way to load a .png from my resources without using GDI+?
The "new" way to do it would be Direct2D and WIC, which is demonstrated in the Windows Imaging Component and Direct2D Image Viewer Win32 Sample.
But if the rest of your application is basic controls, Direct2D is overkill. The image has to be converted to a bitmap at some point to be displayed – whether in your GPU or in memory – and GDI+ fits this use case.
If these resources are icons or some other small-ish file (<2mp), I would reccomend embedding the resource as a bitmap. You can keep your asset pipeline as PNG, just add a pre-build step to convert your PNGs to pre-multiplied BGRA bitmaps and use LoadResource
. There are pre-built tools to meet this need.
C++ GDI+ how to get and load image from resource?
TLDR: FindResource, LoadResource, and LockResource to get a pointer to the image bytes. Then make an IStream from it. The IStream can be used to initialize a Gdi+ Image or Bitmap object. (Gdiplus::Bitmap derives from Gdiplus::Image)
Stick a new line into your .rc file:
IDI_MY_IMAGE_FILE PNG "foo.png"
And make sure IDI_MY_IMAGE_FILE is defined as an integer in your resource.h header file.
#define IDI_MY_IMAGE_FILE 131
Then to load the image at runtime:
Gdiplus::Bitmap* pBmp = LoadImageFromResource(hInstance, MAKEINTRESOURCE(IDI_MY_IMAGE_FILE), L"PNG");
Where LoadImageFromResource
is a helper function that does all the heavy work of loading a PNG from your application resources.
Gdiplus::Bitmap* LoadImageFromResource(HMODULE hMod, const wchar_t* resid, const wchar_t* restype)
{
IStream* pStream = nullptr;
Gdiplus::Bitmap* pBmp = nullptr;
HGLOBAL hGlobal = nullptr;
HRSRC hrsrc = FindResourceW(hInst, resid, restype); // get the handle to the resource
if (hrsrc)
{
DWORD dwResourceSize = SizeofResource(hMod, hrsrc);
if (dwResourceSize > 0)
{
HGLOBAL hGlobalResource = LoadResource(hMod, hrsrc); // load it
if (hGlobalResource)
{
void* imagebytes = LockResource(hGlobalResource); // get a pointer to the file bytes
// copy image bytes into a real hglobal memory handle
hGlobal = ::GlobalAlloc(GHND, dwResourceSize);
if (hGlobal)
{
void* pBuffer = ::GlobalLock(hGlobal);
if (pBuffer)
{
memcpy(pBuffer, imagebytes, dwResourceSize);
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pStream);
if (SUCCEEDED(hr))
{
// pStream now owns the global handle and will invoke GlobalFree on release
hGlobal = nullptr;
pBmp = new Gdiplus::Bitmap(pStream);
}
}
}
}
}
}
if (pStream)
{
pStream->Release();
pStream = nullptr;
}
if (hGlobal)
{
GlobalFree(hGlobal);
hGlobal = nullptr;
}
return pBmp;
}
Save HBITMAP as PNG image using GDI?
Unfortunately, GDI does not support PNGs.
Button with PNG using GDI+
As Jonathan Potter pointed out in the comments, STM_SETIMAGE
needs the HBITMAP
to stick around. The clean-up semantics are somewhat convoluted, but you cannot generally call DeleteObject
before WM_DESTROY
.
Loading png-file from resources (without MFC, ATL)
Well, GDI+ can easily create an HBITMAP from PNG data in an IStream or file, but going from a resource to an IStream takes some work.
If you call CreateStreamOnHGlobal(NULL, TRUE, &stm), where stm is an IStream* variable, it will basically give you a temporary in-memory stream. You can use FindResource, LoadResource, LockResource, and SizeofResource to get a pointer to your resource data and its size. Once you have both of those things, you can use IStream::Write to copy the data from your resource into the IStream.
Once you have an IStream with your PNG data, pass the IStream to the GDI+ Bitmap constructor, and use the GetHBITMAP method to get an HBITMAP.
Save HBITMAP as PNG image using GDI?
Unfortunately, GDI does not support PNGs.
Related Topics
How to Use String.Substr() Function
Reading and Writing to the Same File Using the Same Fstream
Is It Legal to Compare Dangling Pointers
Function Overloading Based on Value VS. Const Reference
C++ Uninitialized Local Variable
Which Boost Features Overlap with C++11
Difference Between a Virtual Function and a Pure Virtual Function
Spirit Qi Attribute Propagation Issue with Single-Member Struct
Using Struct Keyword in Variable Declaration in C++
Access Array Beyond the Limit in C and C++
Issue When Scheduling Tasks Using Clock() Function
How to Add 2 Arbitrarily Sized Integers in C++
What Is the C++ Compiler Required to Do with Ill-Formed Programs According to the Standard
Uses of a C++ Arithmetic Promotion Header
Forward Declaration with Unique_Ptr
Why Is Std::Unordered_Map Slow, and How to Use It More Effectively to Alleviate That