在VC下顯示JPEG、GIF格式圖像的一種簡便方法

 

在VC下顯示JPEG、GIF格式圖像的一種簡便方法  
    
  -------------------------------------------------------------------------------  
    一、   引言    
  JPEG圖像壓縮標準隨然是一種有損圖像壓縮標準,但由於人眼視覺的不敏感,經壓縮後的畫質基本沒有發生變化,很快便以較高的壓縮率得到了廣泛的認可。GIF格式雖然僅支持256色但它對於顏色較少的圖像有着很高的壓縮率,甚至超過JPEG標準,也得到了廣泛的認同。但作爲衆多程序員的一個重要的開發工具--Microsoft   Visual   C++   6.0的MFC庫卻僅對沒有經過任何壓縮的BMP位圖文件有着良好的支持,可以讀取、顯示、存儲甚至在內存中創建一塊內存位圖。由於BMP格式的圖像沒有經過任何的壓縮,不論是作爲程序的外部文件,還是作爲程序的內部資源都要佔據大量的空間,尤其是後者會大大增加可執行文件的長度。可以看出,如果能用經過壓縮、具有較好的壓縮率的JPEG或GIF格式的圖像來取代BMP文件在VC中的應用,無疑還是很有吸引力的。    
  二、   設計思路    
  雖然有一些操作、處理JPEG、GIF等其他格式圖像的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(TRUE,"jpg","*.jpg",    
  OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,    
  "JPEG文件(*.jpg)|*.jpg|GIF文件(*.gif)|*.gif||",NULL);    
  if(dlg.DoModal()==IDOK)    
  {    
  m_sPath=dlg.GetPathName();    
  Invalidate();    
  }    
      
  爲簡單計,圖形顯示的代碼直接在視類中的OnDraw中編寫,首先打開文件並判斷文件的可用性,並把文件內容放到流接口IStream的對象pStm中:    
  IStream   *pStm;      
  CFileStatus   fstatus;      
  CFile   file;      
  LONG   cb;      
  ……    
  if   (file.Open(m_Path,CFile::modeRead)&&file.GetStatus(m_Path,fstatus)&&   ((cb   =   fstatus.m_size)   !=   -1))      
  {      
  HGLOBAL   hGlobal   =   GlobalAlloc(GMEM_MOVEABLE,   cb);      
  LPVOID   pvData   =   NULL;      
  if   (hGlobal   !=   NULL)      
  {      
  if   ((pvData   =   GlobalLock(hGlobal))   !=   NULL)      
  {      
  file.ReadHuge(pvData,   cb);      
  GlobalUnlock(hGlobal);      
  CreateStreamOnHGlobal(hGlobal,   TRUE,   &pStm);      
  }    
  }    
  }    
  然後,就直接調用OleLoadPicture函數從流中裝載圖像:      
  IPicture   *pPic;      
  ……    
  OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic));    
  由於該函數有時會導致失敗,所以應當用SUCCEEDED宏來做一些適當的保護工作,只有在數據裝載成功的前提下才能繼續下面的圖像顯示工作:    
  if(SUCCEEDED(OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic)))    
  {    
  OLE_XSIZE_HIMETRIC   hmWidth;      
  OLE_YSIZE_HIMETRIC   hmHeight;      
  pPic->get_Width(&hmWidth);      
  pPic->get_Height(&hmHeight);      
  double   fX,fY;      
  ……    
  fX   =   (double)pDC->GetDeviceCaps(HORZRES)*(double)hmWidth/((double)pDC->GetDeviceCaps(HORZSIZE)*100.0);      
  fY   =   (double)pDC->GetDeviceCaps(VERTRES)*(double)hmHeight/((double)pDC->GetDeviceCaps(VERTSIZE)*100.0);      
  if(FAILED(pPic->Render(*pDC,0,0,(DWORD)fX,(DWORD)fY,0,hmHeight,hmWidth,-hmHeight,NULL)))      
  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   //指向目標圖元設備環境句柄的指針);    
  小結:到此爲止,通過上述代碼已經能夠在程序的客戶區內顯示JPEG、GIF等標準的圖像了,但對於有多幀圖片(即有動畫)的GIF格式的圖像,目前還只能顯示第一幀,如要完整的顯示GIF   動畫的全過程,還需要外部Active   X控件的支持。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章