The author's words: GDI looks a better solution, but iPicture's OLE implementation is simpler.
Origin
I have been troubled by a problem for a long time. Regarding the problem of displaying images in the program, I searched for a long time, I found countless solutions, such as analyzing file format, reading files directly; use controls (Koda's IMGEDIT control); and I don't know internal Imaging (ImageLoad). And what I found is mostly not easy, especially those who are directly brought directly. Many times I have to write a code for each file format.
Currently my solution
After using a variety of graphic display schemes, I decided to use Microsoft's iPicture OLE implementations to display images. Since the MFC's CPICTureHolder class is a package that is implemented, and it comes with the function of reading the graphic from the image handle, my work is based on the CPICTureHolder class. If you don't like MFC, you can separate the code of the CPICTureHolder class from the source code of the MFC.
The design purpose of the CPICTureHolder class is to implement the Picture property of the ActiveX control, allowing users to display images in the control. As a default Picture property, developers can specify a bitmap, icon (icon), or Metafile to display. Although Microsoft's documentation does not illustrate an image that supports JPEG format, after my test, in Windows98 or more, and Windows2000, it is actually supported by Microsoft's documentation, supported image format has BMP, DIB , WMF, ICO. The author did not test whether other image formats were supported, such as PNG, GIF, PCX, etc., interested readers can test themselves. (According to the 111222 document http://www.9cbs.net/develop/read_article.asp?id=10632, also support GIF format)
Since the CPICTureHolder class does not implement the image from file / resource / memory, it is very inconvenient, so I extend this class to support the above functions. Part is based on Dr. YovAv gad, (Sources@supermain.com, www.supermain.com) and http://www.thecodeProject.com/bitmap/cpicture.asp code.
To use the CPICTUREHOLDER class, you must first contain AFXCTL.H.
Source code
#include
PSRCRECT = NULL / * Source rectangle, unit is 0.01 mm, if it is empty, pull the entire image to the target rectangle * /, lpcRect prcwbounds = null / * primitive file dedicated, binding rectangle * /); // Decided DC drawing, cpicture (); virtual ~ cpicture (); void unloadPicture (); // Release image, effect as cpictureholder :: ~ cmitureHolder () public: long get_height (); // in 0.01 mm in units of 0.01 mm Image height long get_width (); // in an image width} in 0.01 mm;
/ / -------------------------------------------------------------------------------------------- ----------------------------- // DOES: Free the allocated memory That Holdes the ipicture interface data / / ~~~~ and Clear Picture Information //// NOTE: THIS Might Also Be Useful if uLY Need To Show The Picture Once // ~~~~~ or if u Copy The Picture to The Device Context, So It Can Still // Remain On Screen - But ipicture data is not needed no more /// ------------------------------------- ---------------------------------------- Void cpicture :: unloadPicture () // = ============================================================================================================================================================================================================= ========================== {if (m_ppict! = Null) {m_ppict-> release (); m_ppict = null;}} // -------------------------------------------------- --------------------------- // DOES: Open a resource and load it ipicture (interface) / / ~~~~ (. Bmp.dib .emf .gif .ico .jpg .wmf) //// Note: when adding a bitmap resource it Would Automatically show on "Bitmap" // ~~~~ this Not Good Coz We need to load it from A CUST Om Resource "BMP" // to Add a Custom Rresource: Import Resource -> Open as -> Custom // (Both .Bmp and .dib Should Be Found Under "BMP") //// INPUT: Resourceename - As a uint Defined (Example: idR_Picture_Resource) // ~~~~~ Resourcetype - Type Name (Example: "JPG"
) //// Output: True if succeeded ... // ~~~~~~ / / --------------------------- -------------------------------------------------- Bool CPICTURE :: Load (Hinstance Hinstance, LPCTSTSTR LPSZRESOURCENAME, LPCSTR ResourceType) / / ================================= ===================================================== {hglobal hglobal = NULL; HRSRC hSource = NULL; LPVOID lpVoid = NULL; int nSize = 0; BOOL bResult = FALSE; if (m_pPict = NULL!) UnloadPicture (); // Important - Avoid Leaks ... hSource = FindResource (hInstance, lpszResourceName, ResourceType) ;
IF (hSource == null) {hWnd hWnd = AFXGetApp () -> getMainWnd () -> m_hwnd; messageboxex (hwnd, "findresource () failed / t", error_title, mb_ok | mb_iconstop, lang_english; return (false); }
hGlobal = LoadResource (hInstance, hSource); if (hGlobal == NULL) {HWND hWnd = AfxGetApp () -> GetMainWnd () -> m_hWnd; MessageBoxEx (hWnd, "LoadResource () Failed / t", ERROR_TITLE, MB_OK | MB_ICONSTOP , LANG_ENGLISH; Return (false);}
lpVoid = LockResource (hGlobal); if (lpVoid == NULL) {HWND hWnd = AfxGetApp () -> GetMainWnd () -> m_hWnd; MessageBoxEx (hWnd, "LockResource () Failed / t", ERROR_TITLE, MB_OK | MB_ICONSTOP, LANG_ENGLISH Return (false);
nsize = (uint) SizeOfResource (Hinstance, HSource); if (LoadPictureData ((byte *) hglobal, nsize) BRESULT = TRUE;
UnlockResource (Hglobal); // 16bit Windows Needs this freeeresource (hglobal); // 16bit Windows Needs this (32bit - Automatic Release) Return (BRESULT);} // -------------- -------------------------------------------------- ------------- // DOES: Open a file and load it ipicture (interface) // ~~~~ (.bmp .dib .emf .gif .ico .jpg .wmf) //// INPUT: SFILEPATHNAME - Path and filename target to save // ~~~~~ //// output: true if succeeded ... // ~~~~~~ / / ------- -------------------------------------------------- ------------------- Bool cpicture :: load (cstring sfilepathname) / / =================== ============================================================================================================================================================================================================= ======== {if (! Pathfileexists (sfilepathname)) Return False; Bool Bresult = false; cfile picturefile; cfileException E; int nsize = 0;
IF (m_ppict! = null) unloadPicture (); // important - Avoid Leaks ...
if (PictureFile.Open (sFilePathName, CFile :: modeRead | CFile :: typeBinary, & e)) {nSize = PictureFile.GetLength (); BYTE * pBuffer = new BYTE [nSize]; if (PictureFile.Read (pBuffer, nSize) > 0) {IF (LoadPictureData (PBuffer, nsize) BRESULT = true;
Picturefile.close (); delete [] pbuffer;} else // open failed ... {tchar szcause [255]; E.GETERRORMESSAGE (SZCAUSE, 255, NULL); HWND HWND = AFXGetApp () -> getMainWnd () - > m_hwnd; messageboxex (hwnd, szcause, error_title, mb_ok | mb_iconstop, lang_english; bresult = false;} return (BRESULT);}
/ / -------------------------------------------------------------------------------------------- ----------------------------- // Does: Read the Picture Data from a Source (File / Resource) / / ~~~ ~ And load it 通 的 u //// INPUT: BUFFER OF TATA SOURCE (File / Resource) And ITS size // ~~~~~ //// Output: Feed The iPicture Object with the Picture Data // ~~~~~~ (Use Draw functions to show it on a device context) // true if succeeded ... // -------------------- -------------------------------------------------- ------- Bool CPICTURE :: LoadPictureData (Byte * Pbuffer, int nsize) / / ============================ ========================================================= { BOOL bResult = FALSE; hGLOBAL hGlobal = GlobalAlloc (GMEM_MOVEABLE, nSize); if (hGlobal == NULL) {HWND hWnd = AfxGetApp () -> GetMainWnd () -> m_hWnd; MessageBoxEx (hWnd, "Can not allocate enough memory / t ", Error_title, mb_ok | MB_ICONSTOP, LANG_ENGLISH); Return (false);}
Void * pdata = Globalock (Hglobal); Memcpy (PDATA, PBUFFER, NSIZE); GlobalUnlock (Hglobal);
IStream * pstream = NULL;
if (CreateStreamOnHGlobal (hGlobal, TRUE, & pStream) == S_OK) {HRESULT hr; if ((hr = OleLoadPicture (pStream, nSize, FALSE, IID_IPicture, (LPVOID *) & m_pPict)) == E_NOINTERFACE) {HWND hWnd = AfxGetApp ( ) -> getMainwnd () -> m_hwnd; messageboxex (hwnd, "iPicture Interface is not supported / t", error_title, mb_ok | MB_ICONSTOP, LANG_ENGLISH; Return (false);} else // s_ok {pstream-> release () PStream = null; BRESULT = true;}} freeeresource (hglobal); // 16bit Windows Needs this (32bit - Automatic Release)
Return (BRESULT);
/ / -------------------------------------------------------------------------------------------- ----------------------------- // DOES: DRAW The loaded Picture Direct to The Client DC / / ~~~~ // // NOTE: BIGGER OR SMALLER DIMENTIONS THAN THE ORIGINAL PICTURE Size // ~~~~ Will Draw The Picture Streat: PDC - Given DC To Draw ON / / ~~ ~~~ psrcrect- Diments of the Picture to Draw from (As a Rectangle) // DrawRect - DiMentions of The Picture to Draw to Draw to Draw to Draw to (As a Rectangle) // Output: True If succeeded ... // ~~~~~ ~ // ----------------------------------------------- ------------------------------ / / =================== ============================================================================================================================================================================================================= =========
Void CPICTURE :: Render (CDC * PDC, LPRECT PDRAWRECT, LPRECT PSRCRECT / * = NULL * /, LPCRECT PrcwBounds / * = NULL * /) {IF (PDC == NULL || m_ppict == null) Return; CRECT RECRDEST PDRAWRECT); long width = 0; long heiGHT = 0; m_ppict-> get_width (& width); m_ppict-> get_height (& height);
CRECT SRCRECT (0, 0, Width, Height);
IF (psrcrect) {srcRect = * psrcRect;} CRECT DRAWRECT; HRESULT HRP = NULL;
HRP = m_ppict-> render (PDC-> M_HDC, DrawRect.Left, // LEFT DRAWRECT.TOP, // Top DrawRect.Width (), // Right DrawRect.Height (), // Bottom srcRect.Left, SrcRect. Top, srcRect.Width (), SrcRect.Height (), prcwbounds;
IF (succeeded (hrp)) Return; AfXTHROWMEMORYEXCEPTION (); return;} // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------- // Does: Saves The Picture That Is Stored in The iPicture Object As a Bitmap // ~~~~ (Converts from any Known Picture Type to a bitmap / icon file) //// INPUT: SFILEPATHNAME - PATH AND FileName Target to save // ~~ ~~~ //// Output: True if succeeded ... // ~~~~~~ / / ------------------------- -------------------------------------------------- --Bool CPICTURE :: SaveASbitmap (CString sfilepathname) / / ====================================== ================================================= {bool BRESULT = false; ilockbytes * buffer = 0; IStorage * pStorage = 0; IStream * FileStream = 0; BYTE * BufferBytes; STATSTG BytesStatistics; DWORD OutData; long OutStream; CFile bitmapFile; CFileException e; double SkipFloat = 0; DWORD ByteSkip = 0; _ULARGE_INTEGER realData; CreateILockBytesOnHGlobal (NULL, True, & buffer; // Create iLockBytes Buffer
HRESULT HR = :: StegcreatedocfileonIlockBytes (buffer, str_share_exclusive | str_create | strg_readwrite, 0, & pstorage);
HR = PStorage-> CreateStream (l "picture", strg_share_exclusive | str_create | STGM_Readwrite, 0, 0, & FileStream);
M_ppict-> saveasfile (filestream, true, & outstream); // Copy Data Stream filestream-> Release (); pstorage-> release (); buffer-> flush ();
// Get Statistics For Final Size Of Byte Array Buffer-> Stat (& BytesStatistics, STATFLAG_NONAME); // Cut UnNeeded Data Coming From SaveAsFile () (Leave Only "Pure" Picture Data) SkipFloat = (double (OutStream) / 512); // Must Be in A 512 Blocks ... if (Skipfloat> DWORD (Skipfloat)) BYTESKIP = (DWORD) Skipfloat 1; Else Byteskip = (DWORD) Skipfloat; Byteskip = BYTESKIP * 512; // Must Be in A 512 Blocks ... // Find Difference Between The Two Values BYTESKIP = (DWORD) (Bytesstatistics.cbsize.quadpart - byteskip);
// Allocate Only The "Pure" Picture Data RealData.LowPart = 0; RealData.HighPart = 0; RealData.QuadPart = ByteSkip; BufferBytes = (BYTE *) malloc (OutStream); if (BufferBytes == NULL) {Buffer-> Release (); hwnd hwnd = afxgetApp () -> getMainWnd () -> m_hwnd; messageboxex (hwnd, "can not allocate enough memory / t", error_title, mb_ok | mb_iconstop, lang_english;}
Buffer-> Readat (RealData, Bufferbytes, Outstream, & Outdata);
if (BitmapFile.Open (sFilePathName, CFile :: typeBinary | CFile :: modeCreate | CFile :: modeWrite, & e)) {BitmapFile.Write (BufferBytes, OutData); BitmapFile.Close (); bResult = TRUE;} else // Write File Failed ... {TCHAR szCause [255]; e.GetErrorMessage (szCause, 255, NULL); HWND hWnd = AfxGetApp () -> GetMainWnd () -> m_hWnd; MessageBoxEx (hWnd, szCause, ERROR_TITLE, MB_OK | MB_ICONSTOP , LANG_ENGLISH; BRESULT = false;} buffer-> Release (); free (bufferbytes);
Return (BRESULT);
Long cpicture :: get_height () {long nHEight = 0;
IF (m_ppict! = null) {m_ppict-> get_height (& nHeiGHT);
Return nheight;} long cpicture :: get_width () {long nwidth = 0;
IF (m_ppict! = null) {m_ppict-> get_width (& nwidth);} return nwidth;
}