【轉載】 CImage類使用

原文: https://www.cnblogs.com/15157737693zsp/p/6015402.html

 

前言

         CImage類是基於GDI+的,但是這裏爲什麼要講歸於GDI?

         主要是基於這樣的考慮: 在GDI+環境中,我們可以直接使用GDI+ ,沒多少必要再使用CImage類

                                                       但是,如果再GDI環境中,我們要想使用GDI+,有點麻煩,還得加入頭文件,加入啓動GDI+的代碼和關閉GDI+的代碼,顯得太羅嗦了,GDI  的CBitmap 處理功能又有侷限,只能處理BMP格式的圖片。 怎麼辦?這時,我們便可使用CImage類,因爲這個類本身封裝了GDI+得使用環境,所以無需我們手動設置,簡化了我們的操作。  同時,又可以利用GDI+中強大的圖片處理功能,及可以簡便的與CBitmap對象進行轉換 ,大大方便了在GDI環境下,進行各種圖片處理工作 。

                                                        其實,將其稱作 GDI/ GDI+ 混合編程,這樣才更確切些。

        

    

 

爲什麼引入CImage類?

 

    CBitmap 類只能處理BMP格式的圖片,非常受限。

    而CImage可以處理JPGE GIF BMP PNG多種格式圖片,擴展了圖片處理功能 且能與CBitmap 進行轉換( 因爲所載入的位圖句柄都是HBITMAP,所以可相互轉換),因此引入CImage類進行圖像處理

     CImage provides enhanced bitmap support, including the ability to load and save images in JPEG, GIF, BMP, and Portable Network Graphics (PNG) formats

 

CImage類介紹

    

     CImage是MFC和ATL共享的新類,它能從外部磁盤中調入一個JPEG、GIF、BMP和PNG格式的圖像文件加以顯示,而且這些文件格式可以相互轉換。

     CImage是VC.NET中定義的一種MFC/ATL共享類,也是ATL的一種工具類,它提供增強型的(DDB和DIB)位圖支持,可以裝入、顯示、轉換和保存多種格式的圖像文件,包括BMP、GIF、JPG、PNG、TIF等。CImage是一個獨立的類,沒有基類。(CImage類是基於GDI+的,從VC.Net起引進,VC 6.0中沒有。)

    

      ATL(Active Template Library,活動模板庫)是一套基於模板的 C++ 類,用以簡化小而快的 COM 對象的編寫。

爲了在MFC程序中使用CImage類,必須包含ATL的圖像頭文件atlimage.h:(在VS08 SP1中不用包含)

     #include <atlimage.h>

 

 

1  加載位圖文件

 

  1.    // CImage可加載的圖片文件有JPG,BMP,TIF.PNG等格式  而CBitmap只能加載BMP圖片文件  
  2. if(!PathFileExists(imgFilePath))   
  3.     return NULL;  
  4.   
  5. CImage nImage;  
  6. nImage.Load(imgFilePath);  
  7. return nImage.Detach();  //返回HBITMAP    可用CBitmap 處理 也可用CImage處理   


2 與CBitmap轉換

 

  1. CImage nImage;  
  2. nImage.Load(imgFilePath);  
  3.   
  4. HBITMAP hBitmap=nImage.Detach(); // 獲得位圖句柄 用以轉換  
  5.   
  6.   
  7. // 轉換方式一:  
  8. CBitmap bmp;  
  9. bmp.DeleteObject();  
  10. bmp.Attach(hBitmap); //  轉換爲CBitmap對象  
  11.   
  12.   
  13. // 轉換方式二:  
  14.    
  15. CBitmap *pBitmap=CBitmap::FromHandle(nImage.m_hBitmap);  


3 獲得CImage對象的cdc

 

  1. CDC *pDC=CDC::FromHandle(nImage.GetDC());  
  2.   
  3. // Use pDC here  
  4.   
  5. nImage.ReleaseDC();  


 

4 顯示位圖

   思路: 將CImage對象 繪製在對應的DC中

   所使用的函數 BitBlt   StretchBlt  Draw等

   以Draw舉例:

  1. BOOL Draw(  
  2.    HDC hDestDC,  
  3.    int xDest,  
  4.    int yDest,  
  5.    int nDestWidth,  
  6.    int nDestHeight,  
  7.    int xSrc,  
  8.    int ySrc,  
  9.    int nSrcWidth,  
  10.    int nSrcHeight   
  11. const throw( );  
  12. BOOL Draw(  
  13.    HDC hDestDC,  
  14.    const RECT& rectDest,  
  15.    const RECT& rectSrc   
  16. const throw( );  
  17. BOOL Draw(  
  18.    HDC hDestDC,  
  19.    int xDest,  
  20.    int yDest   
  21. const throw( );  
  22. BOOL Draw(  
  23.    HDC hDestDC,  
  24.    const POINT& pointDest   
  25. const throw( );  
  26. BOOL Draw(  
  27.    HDC hDestDC,  
  28.    int xDest,  
  29.    int yDest,  
  30.    int nDestWidth,  
  31.    int nDestHeight   
  32. const throw( );  
  33. BOOL Draw(  
  34.    HDC hDestDC,  
  35.    const RECT& rectDest   
  36. const throw( );  


 

Draw performs the same operation as StretchBlt, unless the image contains a transparent color or alpha channel. In that case,Draw performs the same operation as eitherTransparentBlt orAlphaBlend as required.

For versions of Draw that do not specify a source rectangle, the entire source image is the default. For the version ofDraw that does not specify a size for the destination rectangle, the size of the source image is the default and no stretching or shrinking occurs.

 

 

EXAMPLE 1:

  1. CImage img;  
  2. img.Load("1.jpg");  
  3.   
  4. if (!img.IsNull())  
  5. {  
  6.     img.Draw(pDC->m_hDC,CRect(0,0,100,100));  
  7. }  


 

EXAMPLE 2: 畫在另一個位圖中

 

  1. CImage img;  
  2. img.Load(filePath);  
  3.   
  4. // 獲得CImage對象的 CDC  
  5. HDC hDC=img.GetDC();  
  6. CDC *pDC=CDC::FromHandle(hDC);  
  7.   
  8. CBitmap bmp;// 只是創建了位圖對象,但還沒有將位圖對象與位圖資源聯繫起來  
  9. bmp.CreateCompatibleBitmap(pDC,nWidth,nHeight); // 創建新的位圖資源  
  10.   
  11.   
  12. CDC memDC;  
  13. memDC.CreateCompatibleDC(pDC);  
  14. CBitmap *pOld=memDC.SelectObject(&bmp);  
  15.   
  16. // 將img圖像繪製到bmp中  
  17.   
  18. ::SetStretchBltMode(memDC.m_hDC,HALFTONE);  
  19. ::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);  
  20. img.StretchBlt(memDC.m_hDC,CRect(0,0,nWidth,nHeight)/*DestRect*/,CRect(0,0,nWidth,nHeight)/*SourceRect*/,SRCCOPY);  
  21.   
  22. HBITMAP hBitmap=(HBITMAP)memDC.SelectObject(pOld->m_hObject); // 獲得新創建的位圖資源句柄  
  23.   
  24. img.ReleaseDC();  


 

5 將位圖資源與對象進行分離

 

  1. inline HBITMAP CImage::Detach() throw()  
  2. {  
  3.     HBITMAP hBitmap;  
  4.   
  5.     ATLASSUME( m_hBitmap != NULL );  
  6.     ATLASSUME( m_hDC == NULL );  
  7.   
  8.     hBitmap = m_hBitmap;  
  9.     m_hBitmap = NULL;  
  10.     m_pBits = NULL;  
  11.     m_nWidth = 0;  
  12.     m_nHeight = 0;  
  13.     m_nBPP = 0;  
  14.     m_nPitch = 0;  
  15.     m_iTransparentColor = -1;  
  16.     m_bHasAlphaChannel = false;  
  17.     m_bIsDIBSection = false;  
  18.   
  19.     return( hBitmap );  
  20. }  


 

6 釋放資源

 

CBitmap 使用DeleteObject()來主動釋放掉位圖資源

CImage   沒有DeleteObject()函數 ,而是用Destroy()函數來主動釋放位圖資源

 

  1. inline void CImage::Destroy() throw()  
  2. {  
  3.     HBITMAP hBitmap;  
  4.   
  5.     if( m_hBitmap != NULL )  
  6.     {  
  7.         hBitmap = Detach();  
  8.         ::DeleteObject( hBitmap );  //釋放位圖資源  
  9.     }  
  10. }  

 

CBitmap 析構時,會自動釋放掉所佔用的位圖資源

CImage 析構時,也會自動釋放掉所佔用的位圖資源

  1. inline CImage::~CImage() throw()  
  2. {  
  3.     Destroy(); //釋放掉所佔用的位圖資源  
  4.     s_initGDIPlus.DecreaseCImageCount();  
  5. }  


 

7 讀寫圖像數據

 

主要用到3個函數 :

 

1 )GetBits() 獲得數據區的指針

Retrieves a pointer to the actual bit values of a given pixel in a bitmap.

 
void* GetBits( ) throw( );
 
  1. inline void* CImage::GetBits() throw()  
  2. {  
  3.     ATLASSUME( m_hBitmap != NULL );  
  4.     ATLASSERT( IsDIBSection() );  
  5.   
  6.     return( m_pBits );  
  7. }  

A pointer to the bitmap buffer. If the bitmap is a bottom-up DIB, the pointer points near the end of the buffer. If the bitmap is a top-down DIB, the pointer points to the first byte of the buffer.

Using this pointer, along with the value returned by GetPitch, you can locate and change individual pixels in an image.

 

 注意: 由GetBits()取得的指針不一定是圖片數據的起始行,必須結合GetPitch()的值來確定起始行位置

 

2)GetPitch()

  1. inline int CImage::GetPitch() const throw()  
  2. {  
  3.     ATLASSUME( m_hBitmap != NULL );  
  4.     ATLASSERT( IsDIBSection() );  
  5.   
  6.     return( m_nPitch );  
  7. }  


獲得圖像數據每一行的字節數

The pitch of the image. If the return value is negative, the bitmap is a bottom-up DIB and its origin is the lower left corner. If the return value is positive, the bitmap is a top-down DIB and its origin is the upper left corner.


GetBits 與 GetPitch 關係:

當GetPitch()<0時,GetBits()獲得的指針指向最後一行

當GetPitch()>0時,GetBits()獲得的指針指向第一行

 

圖像數據首行地址:

  1. BYTE *pData=NULL;  
  2.   
  3. if(img.GetPitch()<0)  
  4.   
  5.     pData=(BYTE*)img.GetBits()+(img.GetPitch()*(img.GetHeight()-1));  
  6.   
  7. else  
  8.     pData=(BYTE*)img.GetBits();  


  1. BYTE *pData=NULL;  
  2. if(img.GetPitch()<0)  
  3.   
  4.     pData=(BYTE *)img.GetPixelAddress(img.GetHeight()-1,0);  
  5.   
  6. else  
  7.   
  8.     pData=(BYTE *)img.GetPixelAddress(0,0);  


3)GetBPP() 返回每個像素所佔的bit數

  1. inline int CImage::GetBPP() const throw()  
  2. {  
  3.     ATLASSUME( m_hBitmap != NULL );  
  4.   
  5.     return( m_nBPP );  
  6. }  


 

The number of bits per pixel.

This value determines the number of bits that define each pixel and the maximum number of colors in the bitmap

 

一個綜合例子:

  1. void CMyImage::Negatives(void)  
  2. {  
  3.     int i, j;  
  4.   
  5.     //圖像每一行的字節數  
  6.     int nRowBytes = GetPitch();  
  7.     int nWidth = GetWidth();  
  8.     int nHeight = GetHeight();  
  9.   
  10.   
  11.     //每個像素所佔的字節數  
  12.     int nClrCount = GetBPP() / 8;  
  13.     LPBYTE p;  
  14.     for(int index = 0; index < nClrCount; index++)  
  15.     {  
  16.         p = (LPBYTE)GetBits();  
  17.         for(i = 0; i < nHeight; i++)  
  18.         {  
  19.             for(j = 0; j < nWidth; j++)  
  20.             {  
  21.                 p[j*nClrCount + index] = 255 - p[j*nClrCount + index];  
  22.             }  
  23.               
  24.             //如果nRowBytes>0  則從開始到結尾  
  25.             //如果nRowBytes<0, 則從結尾到開始  
  26.             p += nRowBytes;   
  27.         }  
  28.     }  
  29. }  


 

8 保存到圖像文件中

Saves an image as the specified file name and type.

 

 
HRESULT Save(
   IStream* pStream,
   REFGUID guidFileType
) const throw();
HRESULT Save(
   LPCTSTR pszFileName,
   REFGUID guidFileType= GUID_NULL
)

 

  1. inline HRESULT CImage::Save( LPCTSTR pszFileName, REFGUID guidFileType ) const throw()  
  2. {  
  3.     if( !InitGDIPlus() )  
  4.     {  
  5.         return( E_FAIL );  
  6.     }  
  7.   
  8.     UINT nEncoders;  
  9.     UINT nBytes;  
  10.     Gdiplus::Status status;  
  11.   
  12.     status = Gdiplus::GetImageEncodersSize( &nEncoders, &nBytes );  
  13.     if( status != Gdiplus::Ok )  
  14.     {  
  15.         return( E_FAIL );  
  16.     }  
  17.   
  18.     USES_CONVERSION_EX;  
  19.     Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );  
  20.   
  21.     if( pEncoders == NULL )  
  22.         return E_OUTOFMEMORY;  
  23.   
  24.     status = Gdiplus::GetImageEncoders( nEncoders, nBytes, pEncoders );  
  25.     if( status != Gdiplus::Ok )  
  26.     {  
  27.         return( E_FAIL );  
  28.     }  
  29.   
  30.     CLSID clsidEncoder = CLSID_NULL;  
  31.     if( guidFileType == GUID_NULL )  
  32.     {  
  33.         // Determine clsid from extension  
  34.         clsidEncoder = FindCodecForExtension( ::PathFindExtension( pszFileName ), pEncoders, nEncoders );  
  35.     }  
  36.     else  
  37.     {  
  38.         // Determine clsid from file type  
  39.         clsidEncoder = FindCodecForFileType( guidFileType, pEncoders, nEncoders );  
  40.     }  
  41.     if( clsidEncoder == CLSID_NULL )  
  42.     {  
  43.         return( E_FAIL );  
  44.     }  
  45.   
  46.     LPCWSTR pwszFileName = T2CW_EX( pszFileName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD );  
  47. #ifndef _UNICODE  
  48.     if( pwszFileName == NULL )  
  49.         return E_OUTOFMEMORY;  
  50. #endif // _UNICODE  
  51.     if( m_bHasAlphaChannel )  
  52.     {  
  53.         ATLASSUME( m_nBPP == 32 );  
  54.         Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast< BYTE* >( m_pBits ) );  
  55.         status = bm.Save( pwszFileName, &clsidEncoder, NULL );  
  56.         if( status != Gdiplus::Ok )  
  57.         {  
  58.             return( E_FAIL );  
  59.         }  
  60.     }  
  61.     else  
  62.     {  
  63.         Gdiplus::Bitmap bm( m_hBitmap, NULL );  
  64.         status = bm.Save( pwszFileName, &clsidEncoder, NULL );  
  65.         if( status != Gdiplus::Ok )  
  66.         {  
  67.             return( E_FAIL );  
  68.         }  
  69.     }  
  70.   
  71.     return( S_OK );  
  72. }  


 

pStream

A pointer to a stream containing the file name for the image.

pszFileName

A pointer to the file name for the image.

guidFileType

The file type to save the image as. Can be one of the following:

  • ImageFormatBMP   An uncompressed bitmap image.

  • ImageFormatPNG   A Portable Network Graphic (PNG) compressed image.

  • ImageFormatJPEG   A JPEG compressed image.

  • ImageFormatGIF   A GIF compressed image.

Call this function to save the image using a specified name and type. If the guidFileType parameter is not included, the file name's file extension will be used to determine the image format. If no extension is provided, the image will be saved in BMP format.

 

MSDN例子:

  1.   Copy Code   
  2. // Demonstrating saving various file formats  
  3. int _tmain(int argc, _TCHAR* argv[])  
  4. {  
  5.    CImage myimage;  
  6.    // load existing image  
  7.    myimage.Load("image.bmp");   
  8.       // save an image in BMP format  
  9.    myimage.Save("c:\image1.bmp");  
  10.    // save an image in BMP format  
  11.    myimage.Save("c:\image2",ImageFormatBMP);  
  12.    // save an image in JPEG format  
  13.    myimage.Save("c:\image3.jpg");  
  14.    // save an image in BMP format, even though jpg file extension is used  
  15.    myimage.Save("c:\image4.jpg",ImageFormatBMP);  
  16.    return 0;  
  17. }  
  18.    


 

 

 9 應用實例: 將兩個圖像合併爲一個新的圖像

 

    1. //圖像路徑  
    2. CString img1Path;  
    3. CString img2Path;  
    4. CString img3Path;  
    5.   
    6. img1Path=_T("1.bmp");  
    7. img2Path=_T("2.bmp");  
    8. img3Path=_T("3.bmp");  // 將 圖片1、2 合併成圖片3  
    9.   
    10.   
    11. CImage img1,img2,img3;  
    12.   
    13. img1.Load(img1Path);  
    14. img2.Load(img2Path);  
    15.   
    16.   
    17. CBitmap bmp;  
    18. CDC memDC;  
    19. HDC hDC=NULL;  
    20. CDC *pDC=NULL;  
    21. CBitmap *pOld=NULL;  
    22. HBITMAP hBitmap=NULL;  
    23.   
    24.   
    25. //創建位圖  
    26. hDC=img1.GetDC();  
    27. pDC=CDC::FromHandle(hDC);  
    28. bmp.DeleteObject();  
    29. bmp.CreateCompatibleBitmap(pDC,img1.GetWidth()/2,img1.GetHeight());  
    30. memDC.DeleteDC();  
    31. memDC.CreateCompatibleDC(pDC);  
    32. pOld=memDC.SelectObject(&bmp);  
    33.   
    34.   
    35. ::SetStretchBltMode(memDC.m_hDC,HALFTONE);  
    36. ::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);  
    37.   
    38. // 背景置白色  
    39. CRgn rectRgn;  
    40. rectRgn.CreateRectRgn(0,0,img1.GetWidth()/2,img1.GetHeight());  
    41. CBrush brush;  
    42. brush.CreateSolidBrush(RGB(255,255,255));  
    43. memDC.FillRgn(&rectRgn,&brush);  
    44.   
    45.   
    46. //畫圖  
    47. img1.StretchBlt(memDC.m_hDC,CRect(0,0,img1.GetWidth()/2,img1.GetHeight()/2),CRect(0,0,img1.GetWidth(),img1.GetHeight()),SRCCOPY);  
    48. img2.StretchBlt(memDC.m_hDC,CRect(0,img1.GetHeight()/2,img1.GetWidth()/2,img1.GetHeight()),CRect(0,0,img2.GetWidth(),img2.GetHeight()),SRCCOPY);  
    49.   
    50. hBitmap=(HBITMAP)memDC.SelectObject(pOld->m_hObject);  
    51. img3.Attach(hBitmap);// 載入位圖資源  
    52. img3.Save(img3Path); // 保存新的位圖  
    53.   
    54. img1.ReleaseDC();  
    55. img1.Destroy();  
    56. img2.Destroy();  
    57. img3.Destroy();  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章