Using PNGs with Button Controls - c++

I am trying to render a PNG on a button control for my dialog box (Visual Studio 2010 Professional). After doing some research, I found the following method which works for BMP files:
HBITMAP hBitmap = (HBITMAP) LoadImage(NULL, L"test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
SendMessage(GetDlgItem(hDlg, IDC_BUTTON1), BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
This does not work with PNG files, though. After some more research, I found that there is a simple way to do this using GDI+:
HBITMAP hBitmap;
Gdiplus::Bitmap b(L"a.png");
b.GetHBITMAP(NULL, &hBitmap);
SendMessage(GetDlgItem(hDlg, IDC_BUTTON1), BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
I am not using GDI+ anywhere else in my program but I still need to include the headers, link to the library and initialize it just to accomplish this simple task. Is it worth all of this trouble? Is there a more standard way to do this?
I plan to render multiple PNGs (some transparent) on a single button.
EDIT: The (slightly modified) CreateDIBSectionFromBitmapSource() function that I am using to create the HBITMAP can be found here:
http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=win7wicsamples&DownloadId=7549

Can you be a bit more specific about you mean by "Rendering" a PNG on a button control...
If you mean that you are trying to stick a .PNG image on a button, then yes there is an easier way. Just click on the button and go to 'Appearance in the properties menu. Click on 'BackgroundImage', select local resource, then browse to the image and load it. Done.
If this isn't what you mean to do, then I might suggest researching
System.Drawing.Image and using the GDI+
I am actually sitting here learning GDI+ as we speak. Be forewarned, it's a time and a half to learn.

GDI+ is a standard way for reading and rendering images in different format. Other way of doing this would be to create the PNG decoder component and acquiring the stream from it and pass it to LoadImage function, which is exactly what GDI+ does for you in the back ground. The image format encoders and decoders are part of window imaging component.
In terms of how decoding and rendering is going to perform for multiple images depends on what you are looking for and I am not sure about it. Let me just leave a few comments. What you may do and are doing now (through button's back-ground image option) is to decode the images once and keep them as bit map so when painting has to be done the bitmap is ready and no decoding needs to be done. This is what button's back-ground image painting does too, the button component keeps the bitmap handle you pass it and would just paint the same every it has to repaint. I don't think you need to worry about performance of painting a bitmap because it is done using Bitblt to the display device directly.

Related

How to save image which is specific area that I clicked of picture Control?

Hello I'm studying MFC and I wanna know how to save a specific part of image which is in Picture Control when I click.
Here is the sequence what I want to do
I already make a function that when I click grab button, it shows the image in picture control.
After that, I want to save image when I click specific area.
I attach the image to help understand.
"I want to know how to save the surrounding area as an image when I click a specific part of the picture control as shown above."
It would be easy problem, but I'd appreciate it if you understand because it's my first time doing this.
I tryed to use ScreenToClient function, but I failed.
There are quite a few ways to do this, but the general idea is usually pretty much the same:
Get a DC to the screen or the window's client area (aka DC1).
Create a DC compatible with DC1 (aka DC2).
create a CBitmap compatible with DC1, of the size you want to copy/save.
select the bitmap into DC2.
bitblt the area you care about from DC1 to DC2.
Create a CImage object.
Detach the bitmap from the CBitmap, and attach it to the CImage.
Use CImage::Save to save the bitmap to a file.
There are variations (e.g., writing the data to a file without using a CImage), but they tend to be tedious, and unless you're willing to put quite a bit of effort into things, fairly limited as well. e.g., writing a .BMP file on your own isn't terribly difficult, but is a bit tedious.If you want to support writing JPEG, TIFF, PNG, etc., you either need to integrate a number of libraries, or else write quite a bit of code for the file formats. CImage is somewhat limited as well, but at least supports a half dozen or so of the most common formats (and most people find just JPEG, PNG and possibly GIF sufficient).
Here's a bit of tested sample code for saving a 200x200 chunk of whatever's displayed in the current view window into a file named capture.jpg:
void CPicCapView::OnLButtonDown(UINT nFlags, CPoint point) {
// width and height of area to capture
static const uint32_t width = 200;
static const uint32_t height = 200;
CClientDC dc(this);
CDC temp;
temp.CreateCompatibleDC(&dc);
CBitmap bmp;
bmp.CreateCompatibleBitmap(&dc, width, height);
temp.SelectObject(&bmp);
// x-width/2, y-width/2 to get area centered at click point
temp.BitBlt(0, 0, width, height, &dc, point.x- width/2, point.y-height/2, SRCCOPY);
CImage dest;
dest.Attach((HBITMAP)bmp.Detach());
// for the moment, just saving to a fixed file name
dest.Save(L".\\capture.jpg");
CView::OnLButtonDown(nFlags, point);
}
It might initially seem like you should be able to create the CImage object, use its Create to create a bitmap, and then blit directly from the screen bitmap to the CImage bitmap. Unfortunately, CImage's BitBlt uses the CImage as a source, not a destination, so although there may be some way to get this to work, the obvious method doesn't.

Drawing an image on a window using GFL SDK in MFC

I want to load an image and want to draw it on a window in OnPaint of CMainFrame. Can any body tell me how can we achieve this using XnView's gfl library.
Thank You
I don't know anything about this library, but 20 seconds of Google shows that you should use one of http://www.xnview.com/wiki/index.php/GFL_Windows_specific to convert your image data to an HBITMAP, then use BitBlt() to copy that onto your window (you can find a lot of examples on how to do that everywhere, but in short you do CDC dc; dc.CreateCompatibleDC(); dc.SelectObject(your_bitmap); paintdc.BitBlt(dc, etc); )

Loading PNG file. Need to get RGBA HBITMAP

I'm trying to create a splash screen that will show transparent png background. So at first I need to load png file into format that is acceptable for the UpdateLayeredWindow calls (basically HBITMAP with RGBA format).
At the moment, I've found Windows Imaging Component, but that does not work for VS2005 (which is mandatory requirement). Using some additional libraries is also a problem.
I've heard that GDI+ can do the trick, but I can't find a proper example unfortunately :( Can anyone help?

Show Win32 popup menu with PNG icons from resources

It's been a long time since I've had to deal with Win32 menus. I need to add some PNG icons to a Win32 context popup menu. Naturally, I want to preserve PNG transparency and all the per-pixel-alpha in the process. Is this possible?
I was thinking on using SetMenuItemBitmaps. Is that the way to go?
I imported my PNGs as "PNG" resources but I can't seem to load them neither with LoadBitmap nor with LoadImage. I found some suggestions about using Gdi+ but obviously I won't be drawing the menu - the system will.
There seems to be a way to get a HBITMAP from a Gdi+ Bitmap but it looks as if all the alpha is getting lost in the process. AFAIK, a HBITMAP can happily host alpha information.
You need GDI+ to load a PNG. Then you need to create a 32-bit alpha bitmap of the correct size, create a Graphics on the bitmap, and use DrawImage to copy the PNG to the bitmap. That gives you a bitmap with an alpha channel.
Something like this:
Image* pimgSrc = Image::FromFile("MyIcon.png"L, FALSE);
Bitmap* pbmpImage = new Bitmap(
iWidth, iHeight,
PixelFormat32bppARGB
);
Graphics* pgraphics = Graphics::FromImage(bmpImage))
{
// This draws the PNG onto the bitmap, scaling it if necessary.
// You may want to set the scaling quality
graphics->DrawImage(
imageSrc,
Rectangle(0,0, bmpImage.Width, bmpImage.Height),
Rectangle(0,0, imgSrc.Width, imgSrc.Height),
GraphicsUnitPixel
);
}
// You can now get the HBITMAP from the Bitmap object and use it.
// Don't forget to delete the graphics, image and bitmap when done.
Perhaps you could use icon instead?
Here are my reasons for using icons instead of PNGs:
The Win32 API has good support icons, and it relatively much easier to draw icons, since GDI+ is not required.
Icons also support 8-bit transparency (just like PNGs).
Icons can be any size in pixels (just like PNGs).
Icons can easily be embedded in the executable as a resource.
Icons can be edited via Visual Studio.
To load an icon from a resource or a file use:
LoadImage()
To draw the icon, use:
DrawIcon() or DrawIconEx()

C++ Win32, easiest way to show a window with a bitmap

It's only for 'debugging' purposes, so I don't want to spend a lot of time with this, nor it is very important. The program exports the data as a png, jpg, svg, etc... -so it's not a big deal, though it could be good to see the image while it is being generated. Also, the program is going to be used in a Linux server; but I'll limit this 'feature' to the Win version.
I also don't want to use a library, except if it is very, very lightweight (I used CImg for a while, but I wasn't very happy with its speed, so I ended up writing the important functions myself and just using libjpeg and libpng directly).
I have the image in an ARGB format (32bpp), though converting the format won't be a problem at all. I would like to use Win32, creating a window from a function deep inside the code (no known hInstance, etc), and writing the bitmap. Fast and easy, hopefully.
But I don't know the win32api enough. I've seen that the only option to draw (GDI) is trough a HBITMAP object... Any code snippet or example I can rely on? Any consideration I might not overlook? Or maybe -considering my time constrains- should I just forget it?
Thanks!
The biggest piece of work here is actually registering the window class and writing a minimal window procedure. But if this is debug only code, you can actually skip that part. (I'll come back to that later).
If you have an HBITMAP, then you would use BitBlt or StretchBlt to draw it, but if you don't already have the image as an HBITMAP, then StretchDIBits is probably a better choice since you can use it if you only have a pointer to the bitmap data. You have to pass it a source and destination rectangle, a BITMAPINFOHEADER and a pointer to the raw bitmap data. Something like this
SIZE sBmp = { 100, 200 };
LPBITMAPINFOHEADER pbi; // the bitmap header from the file, etc.
LPVOID pvBits; // the raw bitmap bits
StretchDIBits (hdc, 0, 0, sBmp.cx, sBmp.cy,
0, 0, sBmp.cx, sBmp.cy,
pvBits, pbi,
DIB_RGB_COLORS,
SRCCOPY);
So the next part is how do I get a HDC to draw in? Well for Debug code, I often draw directly to the screen. HDC hdc = GetDC(NULL) will get a DC that can draw to the screen, but there are security issues and it doesnt' work the same with Aero in Windows Vista, so the other way is to draw onto a window. If you have a window that you can just draw over, then HDC hdc = GetDC(hwnd) will work.
The advantage of doing it this way is that you don't have to create and show a window, so it's less disruptive of code flow, It's helpful for debugging a specific problem, but not the sort of thing you can leave turned on all of the time.
For a longer term solution, You could create a dialog box and put your bitmap drawing call in the WM_PAINT or WM_ERASEBKGND message handler for the dialog box. But I don't recommend that you show a dialog box from deep inside code that isn't supposed to be doing UI. Showing a window, especially a dialog window will interfere with normal message flow in your application. If you want to use a dialog box for this bitmap viewer, then you want that dialog window to be something that the User shows, and that you just draw onto if it's there.
If you don't have access to an HINSTANCE, it's still possible to show a dialog box, it's just more work. That's sort of a different question.
About all you need is a handle to a device context (HDC). To display your data on it:
CreateDibSection to create a DIBSection.
Copy your data to the memory block returned by CreateDibSection.
create a DC compatible with the target DC.
Select the DIBSection into your newly created DC.
BitBlt (or StretchBlt) from your DC to the target DC.