本站首页    管理页面    写新日志    退出

The Neurotic Fishbowl

[C/C++]Loading JPEG and GIF pictures
silenceZRY 发表于 2006-4-5 20:49:48

转载自: http://www.arstdesign.com/articles/picloader.html Loading JPEG and GIF pictures  Download demo source code - 95 Kb Download C++ source code - 3 Kb   This article provides source code in order to read and display JPEG and GIF pictures using no third-party library at all. Both MFC and non-MFC source code is provided as to fit the largest requirements. Why such a thing in first place? Simple, I am used to have a dependency on a GIF read/write third-party library and a JPEG read/write third-party library whenever I have to use non-flat *.BMP files. Regardless the GIF licensing issues, which have ended up in the united states since june 2003, I have always relied on third-parties because of the lack of such thing along with the WIN32 API. Wrong was I. OLE/COM provides an interface I have even played with last year, and the MSDN documentation is kept so out-of-sync that it doesn't even mention what the IPicture interface really supports. So, while MSDN limits the capabilities of the IPicture interface to BMP, ICO, CUR and WMF pics, actually this interface supports non-animated GIF as well as JPEG pics. In addition, the interface manages the rendering by passing it a device context. Igor, someone I have met in codeproject forums, was kind enough to show me a link[^] to an existing MFC sample implementation for it, basically a single class called CPicture. So I decided that, because my needs are such that I don't want any MFC in my code, I have rewritten the CPicture class with raw WIN32/GDI calls. And that's what I am showing here. In the remainder of this article, I provide the code for the WIN32/GDI implementation, then a sample code to use it. This is followed by the reproduced MFC implementation from PaulDiLascia, and then again a sample showing how to use it. A pic needs to be inserted in the .rc file. How it works is as follows : open the .rc editor, righ-click on Resources, and choose Import. In the open dialog, select the *.* file types in order to show .gif and .jpeg files, then choose one. At insertion time, VisualStudio prompts for a category name since obviously those file extensions are unsupportedi in version 6.0. Enter IMAGE, and then enter a unique id to reference the pic. Please note that the source code explicitely references the IMAGE category. Make sure to get the code sync with it.     Implementing it with WIN32/GDI WIN32/GDI declaration and implementation Picture.h -------------------CUT HERE---------------------- #pragma once ////////////////// // Picture object--encapsulates IPicture // class CPicture { public: CPicture(); ~CPicture(); // Load frm various sosurces BOOL Load(HINSTANCE hInst, UINT nIDRes); BOOL Load(LPCTSTR pszPathName); BOOL Load(IStream* pstm); // render to device context BOOL Render(HDC dc, RECT* rc, LPCRECT prcMFBounds=NULL) const; SIZE GetImageSize(HDC dc=NULL) const; operator IPicture*() { return m_spIPicture; } void GetHIMETRICSize(OLE_XSIZE_HIMETRIC& cx, OLE_YSIZE_HIMETRIC& cy) const { cx = cy = 0; const_cast(this)->m_hr = m_spIPicture->get_Width(&cx); const_cast(this)->m_hr = m_spIPicture->get_Height(&cy); } void Free() { if (m_spIPicture) { m_spIPicture.Release(); } } protected: void SetHIMETRICtoDP(HDC hdc, SIZE* sz) const; CComQIPtrm_spIPicture; // ATL smart pointer to IPicture HRESULT m_hr; // last error code }; Picture.cpp -------------------CUT HERE---------------------- #include "stdafx.h" #include #include "Picture.h" #define HIMETRIC_INCH 2540 // HIMETRIC units per inch //////////////////////////////////////////////////////////////// // CPicture implementation // CPicture::CPicture() { } CPicture::~CPicture() { } ////////////////// // Load from resource. Looks for "IMAGE" type. // BOOL CPicture::Load(HINSTANCE hInst, UINT nIDRes) { // find resource in resource file HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nIDRes), "IMAGE"); // type if ( !hRsrc ) return FALSE; // load resource into memory DWORD len = ::SizeofResource(hInst, hRsrc); HGLOBAL hResData = ::LoadResource(hInst, hRsrc); if ( !hResData ) return FALSE; HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, len); if ( !hGlobal ) { ::FreeResource(hResData); return FALSE; } char* pDest = reinterpret_cast ( ::GlobalLock(hGlobal) ); char* pSrc = reinterpret_cast ( ::LockResource(hResData) ); if (!pSrc || !pDest) { ::GlobalFree(hGlobal); ::FreeResource(hResData); return FALSE; } ::CopyMemory(pDest,pSrc,len); ::FreeResource(hResData); ::GlobalUnlock(hGlobal); // don't delete memory on object's release IStream* pStream = NULL; if ( ::CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK ) { ::GlobalFree(hGlobal); return FALSE; } // create memory file and load it BOOL bRet = Load(pStream); ::GlobalFree(hGlobal); return bRet; } ////////////////// // Load from path name. // BOOL CPicture::Load(LPCTSTR pszPathName) { HANDLE hFile = ::CreateFile(pszPathName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( !hFile ) return FALSE; DWORD len = ::GetFileSize( hFile, NULL); // only 32-bit of the actual file size is retained if (len == 0) return FALSE; HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, len); if ( !hGlobal ) { ::CloseHandle(hFile); return FALSE; } char* lpBuffer = reinterpret_cast ( ::GlobalLock(hGlobal) ); DWORD dwBytesRead = 0; while ( ::ReadFile(hFile, lpBuffer, 4096, &dwBytesRead, NULL) ) { lpBuffer += dwBytesRead; if (dwBytesRead == 0) break; dwBytesRead = 0; } ::CloseHandle(hFile); ::GlobalUnlock(hGlobal); // don't delete memory on object's release IStream* pStream = NULL; if ( ::CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK ) { ::GlobalFree(hGlobal); return FALSE; } // create memory file and load it BOOL bRet = Load(pStream); ::GlobalFree(hGlobal); return bRet; } ////////////////// // Load from stream (IStream). This is the one that really does it: call // OleLoadPicture to do the work. // BOOL CPicture::Load(IStream* pstm) { Free(); HRESULT hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&m_spIPicture); return hr == S_OK; } ////////////////// // Render to device context. Covert to HIMETRIC for IPicture. // // prcMFBounds : NULL if dc is not a metafile dc // BOOL CPicture::Render(HDC dc, RECT* rc, LPCRECT prcMFBounds) const { if ( !rc || (rc->right == rc->left && rc->bottom == rc->top) ) { SIZE sz = GetImageSize(dc); rc->right = sz.cx; rc->bottom = sz.cy; } long hmWidth,hmHeight; // HIMETRIC units GetHIMETRICSize(hmWidth, hmHeight); m_spIPicture->Render(dc, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, 0, hmHeight, hmWidth, -hmHeight, prcMFBounds); return TRUE; } ////////////////// // Get image size in pixels. Converts from HIMETRIC to device coords. // SIZE CPicture::GetImageSize(HDC dc) const { SIZE sz = {0,0}; if (!m_spIPicture) return sz; LONG hmWidth, hmHeight; // HIMETRIC units m_spIPicture->get_Width(&hmWidth); m_spIPicture->get_Height(&hmHeight); sz.cx = hmWidth; sz.cy = hmHeight; if ( dc == NULL ) { HDC dcscreen = ::GetWindowDC(NULL); SetHIMETRICtoDP(dcscreen,&sz); // convert to pixels } else { SetHIMETRICtoDP(dc,&sz); } return sz; } void CPicture::SetHIMETRICtoDP(HDC hdc, SIZE* sz) const { int nMapMode; if ( (nMapMode = ::GetMapMode(hdc)) < MM_ISOTROPIC && nMapMode != MM_TEXT) { // when using a constrained map mode, map against physical inch ::SetMapMode(hdc,MM_HIMETRIC); POINT pt; pt.x = sz->cx; pt.y = sz->cy; ::LPtoDP(hdc,&pt,1); sz->cx = pt.x; sz->cy = pt.y; ::SetMapMode(hdc, nMapMode); } else { // map against logical inch for non-constrained mapping modes int cxPerInch, cyPerInch; cxPerInch = ::GetDeviceCaps(hdc,LOGPIXELSX); cyPerInch = ::GetDeviceCaps(hdc,LOGPIXELSY); sz->cx = MulDiv(sz->cx, cxPerInch, HIMETRIC_INCH); sz->cy = MulDiv(sz->cy, cyPerInch, HIMETRIC_INCH); } POINT pt; pt.x = sz->cx; pt.y = sz->cy; ::DPtoLP(hdc,&pt,1); sz->cx = pt.x; sz->cy = pt.y; } Using the WIN32/GDI codePictureActiveX.h -------------------CUT HERE---------------------- class CPictureActiveX { ... CPicture picture; // read the picture void Read(UINT nResID); // that's where CPictureActiveX draws the picture HRESULT OnDraw(ATL_DRAWINFO& di); }; PictureActiveX.cpp -------------------CUT HERE---------------------- #include //You may derive a class from CComModule and use it if you want to override //something, but do not change the name of _Module extern CComModule _Module; #include #include // the two following lines of code may be pasted and used somewhere else instead CComModule _Module; _Module.Init(ObjectMap, hInstance, &LIBID_VUMETERLib); // read the picture void CPictureActiveX::Read(UINT nResID) { picture.Load(_Module.GetResourceInstance(),nResID); } // that's where CPictureActiveX draws the picture HRESULT CPictureActiveX::OnDraw(ATL_DRAWINFO& di) { HDC hdc = di.hdcDraw; RECT& rc = *(RECT*)di.prcBounds; picture.Render(hdc, &rc); ... return S_OK; }     Implementing it with MFC MFC implementationPicture.h -------------------CUT HERE---------------------- //////////////////////////////////////////////////////////////// // MSDN Magazine -- October 2001 // If this code works, it was written by Paul DiLascia. // If not, I don't know who wrote it. // Compiles with Visual C++ 6.0 for Windows 98 and probably Windows 2000 too. // Set tabsize = 3 in your editor. // #pragma once #include ////////////////// // Picture object--encapsulates IPicture // class CPicture { public: CPicture(); ~CPicture(); // Load frm various sosurces BOOL Load(UINT nIDRes); BOOL Load(LPCTSTR pszPathName); BOOL Load(CFile& file); BOOL Load(CArchive& ar); BOOL Load(IStream* pstm); // render to device context BOOL Render(CDC* pDC, CRect rc=CRect(0,0,0,0), LPCRECT prcMFBounds=NULL) const; CSize GetImageSize(CDC* pDC=NULL) const; operator IPicture*() { return m_spIPicture; } void GetHIMETRICSize(OLE_XSIZE_HIMETRIC& cx, OLE_YSIZE_HIMETRIC& cy) const { cx = cy = 0; const_cast(this)->m_hr = m_spIPicture->get_Width(&cx); ASSERT(SUCCEEDED(m_hr)); const_cast(this)->m_hr = m_spIPicture->get_Height(&cy); ASSERT(SUCCEEDED(m_hr)); } void Free() { if (m_spIPicture) { m_spIPicture.Release(); } } protected: CComQIPtrm_spIPicture; // ATL smart pointer to IPicture HRESULT m_hr; // last error code }; Picture.cpp -------------------CUT HERE---------------------- #include "stdafx.h" #include "Picture.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////// // CPicture implementation // CPicture::CPicture() { } CPicture::~CPicture() { } ////////////////// // Load from resource. Looks for "IMAGE" type. // BOOL CPicture::Load(UINT nIDRes) { // find resource in resource file HINSTANCE hInst = AfxGetResourceHandle(); HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nIDRes), "IMAGE"); // type if (!hRsrc) return FALSE; // load resource into memory DWORD len = SizeofResource(hInst, hRsrc); BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc); if (!lpRsrc) return FALSE; // create memory file and load it CMemFile file(lpRsrc, len); BOOL bRet = Load(file); FreeResource(hRsrc); return bRet; } ////////////////// // Load from path name. // BOOL CPicture::Load(LPCTSTR pszPathName) { CFile file; if (!file.Open(pszPathName, CFile::modeRead|CFile::shareDenyWrite)) return FALSE; BOOL bRet = Load(file); file.Close(); return bRet; } ////////////////// // Load from CFile // BOOL CPicture::Load(CFile& file) { CArchive ar(&file, CArchive::load | CArchive::bNoFlushOnDelete); return Load(ar); } ////////////////// // Load from archive--create stream and load from stream. // BOOL CPicture::Load(CArchive& ar) { CArchiveStream arcstream(&ar); return Load((IStream*)&arcstream); } ////////////////// // Load from stream (IStream). This is the one that really does it: call // OleLoadPicture to do the work. // BOOL CPicture::Load(IStream* pstm) { Free(); HRESULT hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&m_spIPicture); ASSERT(SUCCEEDED(hr) && m_spIPicture); return TRUE; } ////////////////// // Render to device context. Covert to HIMETRIC for IPicture. // BOOL CPicture::Render(CDC* pDC, CRect rc, LPCRECT prcMFBounds) const { ASSERT(pDC); if (rc.IsRectNull()) { CSize sz = GetImageSize(pDC); rc.right = sz.cx; rc.bottom = sz.cy; } long hmWidth,hmHeight; // HIMETRIC units GetHIMETRICSize(hmWidth, hmHeight); m_spIPicture->Render(*pDC, rc.left, rc.top, rc.Width(), rc.Height(), 0, hmHeight, hmWidth, -hmHeight, prcMFBounds); return TRUE; } ////////////////// // Get image size in pixels. Converts from HIMETRIC to device coords. // CSize CPicture::GetImageSize(CDC* pDC) const { if (!m_spIPicture) return CSize(0,0); LONG hmWidth, hmHeight; // HIMETRIC units m_spIPicture->get_Width(&hmWidth); m_spIPicture->get_Height(&hmHeight); CSize sz(hmWidth,hmHeight); if (pDC==NULL) { CWindowDC dc(NULL); dc.HIMETRICtoDP(&sz); // convert to pixels } else { pDC->HIMETRICtoDP(&sz); } return sz; } Using the MFC code Once the source code is inserted, it's possible to use the code in a typical doc/view model with this code :class CDocument { ... CPicture m_pict; // picture loader instance in some class void Load(UINT nResId) { m_pict.Load(nResId); } CPicture* GetPicture() { return &m_pict; } ... }; class CView { ... void OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); ASSERT_VALID(pDoc); CPicture* ppic = pDoc->GetPicture(); ASSERT(ppic); if (*ppic) { CRect rc; GetImageRect(rc); ppic->Render(pDC,rc); } } ... };   For those interested in supporting animated GIF sequences as well, there is an outstanding article[^] on codeproject to do just this.    Enjoy!Stephane Rodriguez- September 26, 2003.  

阅读全文(4998) | 回复(0) | 编辑 | 精华

 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)

 
 



The Neurotic Fishbowl

.: 公告

暂无公告...


Bloginess

«November 2019»
12
3456789
10111213141516
17181920212223
24252627282930

.: 我的分类(专题)

首页(18)
数据结构/算法(0)
web design(0)
J2SDK(3)
C/C++(5)
设计模式(1)
基础知识(8)


In the Bowl

.: 最新日志

设计模式-各类模式简介
药品批号及条形码知识
ape cue 刻录
英文书信书写[转载]
Matlab
Using the LockBits m
Working with 8bit im
Using the LockBits m
VC6中如何使用GDI+ 最近的工作,需
Loading JPEG and GIF


.: 最新回复

回复:ASCII 编码表
回复:ASCII 编码表
回复:ASCII 编码表
回复:ASCII 编码表
回复:ASCII 编码表
回复:ASCII 编码表
回复:ASCII 编码表
回复:ape cue 刻录
回复:ASCII 编码表
回复:颜色空间FAQ


The Fishkeeper
blog名称:
日志总数:18
评论数量:86
留言数量:-1
访问次数:193081
建立时间:2005年7月17日



Text Me

.: 留言板

签写新留言

请大师帮忙


Other Fish in the Sea

.: 链接





站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.031 second(s), page refreshed 144327294 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号