一 引言
JPEG圖像壓縮標准隨然是一種有損圖像壓縮標准但由於人眼視覺的不敏感經壓縮後的畫質基本沒有發生變化很快便以較高的壓縮率得到了廣泛的認可GIF格式雖然僅支持色但它對於顏色較少的圖像有著很高的壓縮率甚至超過JPEG標准也得到了廣泛的認同但作為眾多程序員的一個重要的開發工具Microsoft Visual C++ 的MFC庫卻僅對沒有經過任何壓縮的BMP位圖文件有著良好的支持可以讀取顯示存儲甚至在內存中創建一塊內存位圖由於BMP格式的圖像沒有經過任何的壓縮不論是作為程序的外部文件還是作為程序的內部資源都要占據大量的空間尤其是後者會大大增加可執行文件的長度可以看出如果能用經過壓縮具有較好的壓縮率的JPEG或GIF格式的圖像來取代BMP文件在VC中的應用無疑還是很有吸引力的
二 設計思路
雖然有一些操作處理JPEGGIF等其他格式圖像的Active X控件但總的來說使用起來並不太方便筆者經過實驗摸索總結出了一種借助於COM接口的OLE方法來實現上述功能的一種簡便方法現介紹如下以飨廣大讀者
下面我們要使用IPicture 的COM接口有必要對該圖像接口做些了解該接口主要管理圖像對象及其屬性圖像對象為位圖圖標和圖元等提供一種與語言無關的抽象和標准的字體對象一樣系統也提供了對圖像對象的標准實現其主要的接口是IPicture和IPictureDisp後者是由IDispatch接口派生以便通過自動化對圖像的屬性進行訪問圖像對象也支持外部接口IPropertyNotifySink以便用戶能在圖像屬性發生改變時作出決定圖像對象也支持IPersistStream接口所以它能從一個IStream接口的實例對象保存裝載自己而IStream接口也支持對流對象的數據讀寫
我們可以用函數OleLoadPicture從包含有圖像數據的流中裝載圖像該函數簡化了基於流的圖像對象的創建過程可以創建一個新的圖像對象並且用流中的內容對它進行初始化其函數原型為
STDAPI OleLoadPicture( IStream * pStream //指向包含有圖像數據的流的指針LONG lSize //從流中讀取的字節數BOOL fRunmode //圖像屬性對應的初值REFIID riid //涉及到的接口標識描述要返回的接口指針的類型VOID ppvObj // 在rrid中用到的接口指針變量的地址);
三 具體的實現
在顯示圖像之前首先要獲取到圖像文件的存放路徑這裡采用標准的文件打開對話框來選取圖像文件文件名存放在CString型的變量m_sPath中
CFileDialog dlg(TRUEjpg*jpg
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT
JPEG文件(*jpg)|*jpg|GIF文件(*gif)|*gif||NULL);
if(dlgDoModal()==IDOK)
{
m_sPath=dlgGetPathName();
Invalidate();
}
為簡單計圖形顯示的代碼直接在視類中的OnDraw中編寫首先打開文件並判斷文件的可用性並把文件內容放到流接口IStream的對象pStm中
IStream *pStm;
CFileStatus fstatus;
CFile file;
LONG cb;
……
if (fileOpen(m_PathCFile::modeRead)&&fileGetStatus(m_Pathfstatus)&& ((cb = fstatusm_size) != ))
{
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE cb);
LPVOID pvData = NULL;
if (hGlobal != NULL)
{
if ((pvData = GlobalLock(hGlobal)) != NULL)
{
fileReadHuge(pvData cb);
GlobalUnlock(hGlobal);
CreateStreamOnHGlobal(hGlobal TRUE &pStm);
}
}
}
然後就直接調用OleLoadPicture函數從流中裝載圖像
IPicture *pPic;
……
OleLoadPicture(pStmfstatusm_sizeTRUEIID_IPicture(LPVOID*)&pPic));
由於該函數有時會導致失敗所以應當用SUCCEEDED宏來做一些適當的保護工作只有在數據裝載成功的前提下才能繼續下面的圖像顯示工作
if(SUCCEEDED(OleLoadPicture(pStmfstatusm_sizeTRUEIID_IPicture(LPVOID*)&pPic)))
{
OLE_XSIZE_HIMETRIC hmWidth;
OLE_YSIZE_HIMETRIC hmHeight;
pPic>get_Width(&hmWidth);
pPic>get_Height(&hmHeight);
double fXfY;
……
fX = (double)pDC>GetDeviceCaps(HORZRES)*(double)hmWidth/((double)pDC>GetDeviceCaps(HORZSIZE)*);
fY = (double)pDC>GetDeviceCaps(VERTRES)*(double)hmHeight/((double)pDC>GetDeviceCaps(VERTSIZE)*);
if(FAILED(pPic>Render(*pDC(DWORD)fX(DWORD)fYhmHeighthmWidthhmHeightNULL)))
AfxMessageBox(渲染圖像失敗!);
pPic>Release();
}
else
AfxMessageBox(從流中裝載圖像失敗!);
其中顯示工作主要是由IPicture接口對象的Render函數來完成的該函數主要用來將圖片的指定部分畫到指定的設備環境的指定位置原型如下
HRESULT Render( HDC hdc //渲染圖像用的設備環境句柄
long x //在hdc上的水平坐標
long y //在hdc上的垂直坐標
long cx //圖像寬度
long cy //圖像高度
OLE_XPOS_HIMETRIC xSrc //在源圖像上的水平偏移
OLE_YPOS_HIMETRIC ySrc //在源圖像上的垂直偏移
OLE_XSIZE_HIMETRIC cxSrc//在源圖像上水平拷貝的數量
OLE_YSIZE_HIMETRIC cySrc//在源圖像上垂直拷貝的數量
LPCRECT prcWBounds //指向目標圖元設備環境句柄的指針);
小結到此為止通過上述代碼已經能夠在程序的客戶區內顯示JPEGGIF等標准的圖像了但對於有多幀圖片(即有動畫)的GIF格式的圖像目前還只能顯示第一幀如要完整的顯示GIF 動畫的全過程還需要外部Active X控件的支持
From:http://tw.wingwit.com/Article/program/net/201311/13356.html