Load and draw a PNG picture using the MFC CImage class and GDI + image

Source: Internet
Author: User

First, use the MFC CImage class to load PNG images

To test the effect of CImage drawing a PNG image, we use the software to intercept a 360 interface, and then use tools such as Photoshop to add a transparent area around the image and then save it as a PNG image file. The CImage is first loaded from the file, i.e.

    cimage* M_PIMGBK;    ......        M_PIMGBK = new CImage;    M_pimgbk->load (_t ("res\\bk.png"));    if (M_pimgbk->isnull ())//Picture loading failed    {        delete m_pimgbk;        M_PIMGBK = NULL;    }

And then to the OnPaint in the Test dialog box,

void Ctestcimagedrawdlg::onpaint () {    cdialogex::onpaint ();    CWINDOWDC DC (this);    if (M_PIMGBK! = NULL)    {M_pimgbk->draw (DC). GETSAFEHDC (), (+), M_pimgbk->getwidth (), M_pimgbk->getheight ());}    

As a result, some of the following problems have been found.

1, directly using CImage to draw a PNG image with transparent parts, transparent area does not penetrate (non-scaling)

As the original size of the picture is drawn to the test dialog interface, the transparent area is not erased, as shown in the code below.

    CWINDOWDC DC (this);    if (M_PIMGBK! = NULL)    {M_pimgbk->draw (DC). GETSAFEHDC (), (+), M_pimgbk->getwidth (), M_pimgbk->getheight ());    }
The display is shown below.


The PNG images with transparent areas are checked for additional processing to determine if alpha transparent channels are enabled and, if enabled, to be processed as follows:

if (m_pimgbk->getbpp () = = +) {for (int i = 0; i < m_pimgbk->getwidth (); i++)   {for   (int j = 0; J < m_p Imgbk->getheight (); J + +)   {   unsigned char* puccolor = reinterpret_cast<unsigned char *> (m_pimgbk->getpixeladdress (i, j));   puccolor[0] = puccolor[0] * puccolor[3]/255;   PUCCOLOR[1] = puccolor[1] * puccolor[3]/255;   PUCCOLOR[2] = puccolor[2] * puccolor[3]/255;}}}   

The treated area is filtered out, as shown below.


2, using CImage::D raw directly draw scaled PNG picture, the display is not complete, distortion is serious

Considering that in some cases the PNG picture is scaled, the zoom drawing effect is tested. To zoom in and out of length and width, the relevant code is shown below.

CWINDOWDC DC (this), if (M_PIMGBK! = NULL) {int ndstwidth = 450;int ndstheight = (int) ((Ndstwidth*1.0/m_pimgbk->getwidt H ()) *m_pimgbk->getheight ()); Width and high scale M_pimgbk->draw (DC). GETSAFEHDC (), (), (Ndstwidth, ndstheight);}


Check out MSDN to see if there are interfaces or parameters that can handle this scaling problem better. found in CImage::D raw can add gdiplus::interpolationmode parameters, go used to look at a bit, you can choose gdiplus::interpolationmodehighquality high-quality type, It is found that the scaling distortion has improved a lot, but the transparent part that should have gone out is black, as shown below.

Therefore, the CImage handles PNG images with transparent portions, especially when zooming is defective. Later, instead of using the image class of GDI +, there is no similar problem . in fact, CImage internal is also using GDI + implementation, specifically why the above problems are not clear. PNG images can be processed directly using the image class of GDI +. Using the image class is drawn with Gdiplus::graphics, which uses image to load the picture, and Gdiplus::graphics to draw the picture in image to the interface DC.

Second, use the GDI + image class to load PNG pictures
1. Use the image class to encounter two problems

(1) Use image directly to define the object as follows:

Image img;
Tip: Error C2248: " gdiplus::image::image ": Unable to access protected member (declared in" Gdiplus::image "Class) C:\Program Files\Microsoft Sdks\windows\v7.0a\ Include\gdiplusheaders.h (471): See Declaration of "Gdiplus::image::image".

look at the declaration of the image, knowing that the constructor with the image without parameters is protected and cannot be accessed externally, so it does not, as follows:

Because there are also two of the following constructors:


So the following method of use is possible:

Image img (L "res\\bk.png");
This, of course, is only appropriate for local variables, not for defining member variables, and then loading the image for subsequent use at initialization time.

(2) In order to image* a member variable pointer, at initialization time new an image object, and load the picture, the code is as follows:

M_PIMGBK = new Image (L "res\\bk.png");
Result compilation problem: Error C2660: "Gdiplus::gdiplusbase::operator new": function does not accept 3 parameters
So to search the Internet, mainly is the Microsoft MFC Debug_new and GDI + mismatch caused by the following several methods:

Method 1:
Comment out the following code in the CPP this is good:

#ifdef _debug#define New Debug_new#endif

Method 2:
:: New Bitmap (CX,CY,PIXELFORMAT32BPPRGB); Plus global scope specifier

Method 3:
See MORE:
Microsoft Foundation Classes debug_new Does not work with GDI +

http://support.microsoft.com/kb/317799/

2. Use image static function to load PNG image

Use the following fromfile and FromStream functions to load and return the image pointer, which is stored exactly in the member variable image* M_PIMGBK. The functions are as follows:


Using the FromFile function is relatively simple, directly through the picture path to load, the code is as follows:

M_PIMGBK = Image::fromfile (L "res\\bk.png");
However, using FromFile, there is a problem, the picture file will be "locked", other objects will not load, so still use FromStream, butThe use of fromstream is more complex, the general idea is: to read the image file data into memory, and then use GlobalAlloc to allocate the same large memory hglobal, and then copy the picture data into the Hglobal, Then, using Hglobal call CreateStreamOnHGlobal to create the IStream, the group calls Image::fromstream eventually loads the picture into the image object.

There are two cases of using Image::fromstream, one is to load the picture file on the disk directly, and the other is to load the picture file data in the resource. When implemented, the image file data is first read into memory, as described in the above method. The code implements the interfaces that correspond to both cases.

(1) Loading the picture file on the disk

image* LoadFromFile (LPCTSTR lpszfile) {image* pimage = NULL; TCHAR acherrinfo[512] = {0}; HANDLE hfile =:: CreateFile (Lpszfile, generic_read, file_share_read, NULL, open_existing, file_attribute_normal, NULL); if (hfile = = Invalid_handle_value) {memset (acherrinfo, 0, sizeof (acherrinfo)); _stprintf (Acherrinfo, _t ("Load (file): Er Ror opening file%s\n "), Lpszfile);:: OutputDebugString (Acherrinfo); return NULL;} DWORD dwsize;dwsize =:: GetFileSize (hfile, NULL); Hglobal hglobal = GlobalAlloc (gmem_moveable | Gmem_nodiscard, dwsize); if (!hglobal) {:: OutputDebugString (_t ("Load (file): Error allocating memory\n"));:: Closehandl E (hfile); return NULL;}; Char *pdata = reinterpret_cast<char*> (GlobalLock (hglobal)), if (!pdata) {:: OutputDebugString (_T ("Load file"): Error locking memory\n ")); GlobalFree (HGLOBAL);:: CloseHandle (hfile); return NULL;}; Try{dword dwreadbytes = 0;::readfile (hfile, PData, dwsize, &dwreadbytes, NULL);}                                      catch (...)   {memset (acherrinfo, 0, sizeof (acherrinfo)) _stprintf (Acherrinfo, _t ("Load (file): An exception occured while reading The file%s\n "), Lpszfile);:: OutputDebugString (Acherrinfo); GlobalFree (HGLOBAL);:: CloseHandle (hfile); return NULL;} GlobalUnlock (HGLOBAL);:: CloseHandle (hfile); IStream *pstream = Null;if (CreateStreamOnHGlobal (Hglobal, TRUE, &pSt Ream)! = S_OK) {return NULL;} Pimage = Image::fromstream (PStream);//To add this sentence, otherwise hglobal memory obtained by GlobalAlloc is not released, resulting in memory leaks, due to// CreateStreamOnHGlobal The second parameter is set to True, so calling Pstream->release () will automatically// Hglobal memory (see MSDN for createstreamonhglobal Instructions) pstream->release (); return pimage;}

(2) Loading the picture file in the resource

image* loadfromres (UINT nresid, LPCTSTR lpszrestype, hinstance hinstance) {image* pimage = NULL; ASSERT (Lpszrestype); Hrsrc hPic = FindResource (hinstance, Makeintresource (NRESID), lpszrestype); HANDLE hresdata = null;if (!hpic | |! (hresdata = LoadResource (hinstance,hpic))) {:: OutputDebugString (_t ("Load (Reso Urce): Error Loading resource:%d\n ")); return NULL;} DWORD dwsize = Sizeofresource (hinstance, hPic);//Hresdata is not the real hglobal (we can ' t lock it)//Let's make it re Alhglobal hglobal = GlobalAlloc (gmem_moveable | Gmem_nodiscard, dwsize); if (!hglobal) {:: OutputDebugString (_t ("Load (Resource): Error allocating memory\n")); FreeResource (Hresdata); return NULL;} Char *pdest = Reinterpret_cast<char *> (GlobalLock (Hglobal)); char *psrc = Reinterpret_cast<char *> ( Lockresource (Hresdata)); if (!psrc | |!pdest) {:: OutputDebugString (_t ("Load (Resource): Error locking memory\n")); GlobalFree (HGLOBAL); FreeResource (Hresdata); return NULL;}; memcpy(PDest, PSRC, dwsize); FreeResource (Hresdata);  GlobalUnlock (hglobal); IStream *pstream = Null;if (CreateStreamOnHGlobal (Hglobal, TRUE, &pstream)! = S_OK) {return NULL;} Pimage = Image::fromstream (PStream);//To add this sentence, otherwise hglobal memory obtained by GlobalAlloc is not released, resulting in memory leaks, due to// CreateStreamOnHGlobal The second parameter is set to True, so calling Pstream->release () will automatically// Hglobal memory (see MSDN for createstreamonhglobal Instructions) pstream->release (); return pimage;}

Once the picture is loaded into the image object, it can be drawn using the Graphics object in GDI +, with the following code:

    Gdiplus::graphics Graphics (DC);      Graphics. DrawImage (M_PIMGBK, Ndstwidth, Ndstheight)  

Finally, it is necessary to note that thepointer returned by the Image::fromfile and Image::fromstream functions is a new image object that will delete the image object externally when it is finished. the instructions in MSDN are as follows:

The sample code given from MSDN can also be seen, and the returned image object is also to be delete, as follows:

VOID Example_fromstream (hdc hdc) {Graphics graphics (hdc);   image* pImage1 = NULL;   image* pImage2 = NULL;   istorage* pistorage = NULL;   istream* pIStream1 = NULL;   istream* pIStream2 = NULL;   HRESULT hr;   Status Stat;   Open an existing compound file, and get a pointer//to its IStorage interface. hr = StgOpenStorage (L "compoundfile.cmp", NULL, stgm_read|   Stgm_share_exclusive, NULL, 0, &pistorage);   if (FAILED (HR)) goto Exit;   Get a pointer to the stream StreamImage1 in the compound file. hr = Pistorage->openstream (L "StreamImage1", NULL, stgm_read|   Stgm_share_exclusive, 0, &pistream1);   if (FAILED (HR)) goto Exit;   Get a pointer to the stream StreamImage2 in the compound file. hr = Pistorage->openstream (L "StreamImage2", NULL, stgm_read|   Stgm_share_exclusive, 0, &pistream2);   if (FAILED (HR)) goto Exit; Create a new Image object based on StreamImage1.   PImage1 = Image::fromstream (pIStream1);     Stat = Pimage1->getlaststatus ();   if (stat! = Ok) goto Exit; Graphics.   DrawImage (PImage1, 10, 10);   Create a new Image object based on StreamImage2.   PImage2 = Image::fromstream (PISTREAM2);   Stat = Pimage2->getlaststatus ();   if (stat! = Ok) goto Exit; Graphics. DrawImage (PImage2, 200, 10);   Exit:if (pImage1) Delete pImage1;   if (pImage2) Delete pImage2;    if (pIStream1) pistream1->release ();   if (PISTREAM2) pistream2->release (); if (pistorage) pistorage->release ();}

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Load and draw a PNG picture using the MFC CImage class and GDI + image

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.