CxImage編譯

CxImage圖像庫

CxImage下載地址:http://www.codeproject.com/KB/graphics/cximage/cximage600_full.zip

作者:Davide Pizzolato

 

CxImage簡介

      CxImage是一個可以簡便而快速地打開、保存、顯示和轉換圖像文件的 C++類庫,它可以用於MFC,可以打開,保存,顯示,轉換各種常見格式的圖像文件,比如BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, J2K 等格式的文件。可以實現BMP<->JPG,PNG <->TIFF格式等等的互相轉換。CxImage不僅可以實現圖像文件的類型轉換,還可以實現在內存圖像數據的類型轉換,並且使用很方便。除了文件格式的相互轉換,它還提供了很多很多圖像後處理的功能,比如圖像模糊,銳化等等,功能非常強大和實用。另外,CxImage是開源的,並在zlib許可下發布,“如果你在你的產品中使用了這些源代碼,雖然致謝不是必須的,但是卻會得到衆人的欣賞。”簡單地說,你可以隨意地使用這些代碼,只要你不說它是你自己的就行了。

      CxImage中的x,大約代表了豐富的圖像格式支持和豐富的圖像處理功能,可以說CxImage是圖像處理的十全大補湯。

 


用CxImage實現的圖像處理程序

      開發環境:VC6, C++, Windows, MFC, Visual Studio, VS6, Dev

      文件格式和鏈接的庫:CxImage支持如下這些庫的最新版本:
   Zlib (1.2.3), Jasper ( 1.900.1), LibMNG (1.0.10), LibPNG (1.2.24). LibTIFF 3.8.2
j2k庫(現在被稱爲openjpeg)和相關的類CxImageJ2K已經從項目中刪除。JPEG2000格式的文件由Jasper和CximageJAS來支持。

 

      Cximage 6.00提供了一個新的類CximageRAW和新的庫LibDCR,用於讀取來自數碼相機的RAW圖像。常見的文件擴展名有:RAW, CRW, NEF, CR2, DNG, ORF, ARW, ERF, 3FR, DCR, X3F, MEF, RAF, MRW, PEF, SR2。

      CximageRAW提供了對圖像的基本解碼功能,它唯一的可選參數可以由SetCodecOption進行設置,以對插值質量進行可控制。可選的選項有(DECODE_QUALITY_LIN=0, DECODE_QUALITY_VNG=1, DECODE_QUALITY_PPG=2, DECODE_QUALITY_AHD=3).

      CximagePNG:現在可以讀取所有PNG_COLOR_TYPE_類型。但是,每個通道含有超過8位像素深度的PNG文件,會被轉換到8位,這是CxImage的一個主要限制。
      CxImageGIF:現在能夠更好地支持對動態GIF圖像的讀取,通過SetRetreiveAllFrames設置屬性,可以同時對圖像中的所有幀進行解碼。在CxImage的示例項目中,展示瞭如何實現這一選項,並展示瞭如何播放一副GIF動畫。

      CxImageBMP: 支持對32位圖像的讀寫(支持Alpha通道)

      CxImageICO: 支持對Vista PNG圖標的讀寫;添加對多頁圖標的支持。

      CxImageMNG: 支持對MNG Alpha圖層的讀取。
      CxImageSKA: 新的用於支持SKA圖像格式的類,這種圖像通常用在視頻租賃軟件中。

      CxImageJPG: 爲JPEG圖像格式的二次採樣提供了 新的選項。ENCODE_SUBSAMPLE_422,ENCODE_SUBSAMPLE_444),默認情況下是 高採樣率的4:1:1 。當然,也可以被設置成中等的4:2:2或者低等的4:4:4。

下圖展示了不同採樣率下,在壓縮圖像中所產生的不同數量的僞影。在壓縮有着明顯輪廓的圖像的時候,採用4:4:4的採樣率有助於減少輪廓的僞影。

 

可移植性

      所有的類和項目都通過了不同編譯器的測試,包括從VC++6 到VC++2008的微軟系列編譯器,Borland C++ Builder 3和6,同時部分地支持wxDev-C++和MinGW。

      所有的庫都支持UNICODE 和非UNICODE兩個版本。(感謝Eric Jesover)

      對於第一次使用的用戶,你可以使用一個輕量級的版本(cximage600_lite)。這個版本去除了C庫,但是添加了一個簡單的示例項目。
      所有控制檯示例(/demo2)和CxImageCrtDll項目可以在VC++Express2005和 Microsoft Platform SDK環境下編譯通過。如果你在編譯鏈接的時候,遇到像"unresolved external..."(無法找到外部符號…)這樣的錯誤,請檢查是否所有C庫都被編譯了。或者手動地添加gdi32.lib 和user32.lib爲項目的依賴庫。

      同時,CxImage也可以在Pocket PC 2003上工作。在CxImage中,爲VC++ 2005編譯器提供了一個可以工作的版本和相應的實例(cximage600_ce)。對於舊式的嵌入式VC編譯器,最主要的限制是無法支持對異常的處理。爲了解決這個問題,相應的異常處理語句try,throw和catch已經被定義在ximadef.h中的三個宏取代,同時還定義了CXIMAGE_SUPPORT_EXCEPTION_HANDLING。通過這樣的方法,取消對異常處理的支持,可以成功編譯鏈接整個庫。雖然這個解決辦法不是那麼優雅,但是當異常處理被取消的時候,對代碼的影響是最小的。同時,當異常處理被啓用的時候,同樣不會造成源代碼的修改與變動。

      對於平臺之間little-endian和big-endian的兼容性,對於內建支持的圖像文件格式(bmp, ico, tga, pcx, gif, ska),由ntohs和ntohl控制。

 

      示例 
      大多數新的特性可以在CxImage的主要示例程序中嘗試和體驗。這個示例程序只是一個測試平臺,雖然它提供很多有用的特性,但是它實在不是一個嚴謹的應用程序。

      ·CQuantizer : 這個類被DecreaseBpp菜單項所使用。在以前的版本中,這裏有一個取整的錯誤,在某些情況下,白色(255,255,255)會被轉換成(254,254,254)。在新的版本中,這個問題已經被修復了。
      ·Copy/Paste : 現在,新的粘貼功能支持元文件圖像(例如,從Office應用程序中複製而來的圖像)。這個示例內部使用了自定義的剪切板格式以測試Dump/Undump方法。Copy只工作在當前選區,但是你可以通過CxImage/Remove Selection 複製整幅圖像。
      ·FloodFill : (/View/Tools/Flood Fill) 通過一個浮動的對話框,你可以測試色彩填充的顏色,偏差,透明度和是否選擇。當透明度爲0並且選擇區域功能啓用的時候,這個功能就變現爲"魔法棒",用於根據顏色選區某個區域。
      ·Graph data extraction : (/Filters/graph data extraction) 這個示例演示瞭如何從圖像(從掃描儀獲取或者從互聯網下載所得)中提取數字信息。轉換後的數據被粘貼到剪切板,同時可以被保存成文本文件或者Excel表格文件。

數據提取對話框


數據提取結果


      ·RedEyeRemove : (/Filters/Non Linear/Remove Red Eye) 去除紅眼的功能在照片處理中經常用到。你 必須在紅眼周圍選擇一個區域,然後去除紅眼的功能就會對紅色通道進行過濾,從而去掉照片中的紅眼。紅眼的選區是一個矩形區域,同時可以包括部分的虹膜(眼黑),過濾器會在以選區中點爲中心的圓心區域工作,不會影響到選中的眼黑部分。

 

 

      ·SelectiveBlur / UnsharpMask : 這些非線性的濾鏡可以增加圖像的質量。SelectiveBlur可以去除二次噪聲(比如JPEG圖像中的僞影或者是數碼相機的噪聲),從而展示圖像中的更多細節。而UnsharpMask可以增強圖像的細節,但是卻不會添加噪聲。

      ·Custom linear filters : (/Filters/Linear/Custom) 一個用於測試新的濾鏡功能核心的圖像用戶界面。

      ·Histogram : (/Colors/Histogram/...) 爲了測試HistogramStretch(直方圖),這個示例中提供了很多菜單項,通過不同的方法(0 = luminance, 1 = linked channels , 2 = independent channels)來測試直方圖功能。對於有噪聲的圖像,閾值(threshold)這個參數增強了算法的健壯性。半飽和度(Half Saturation)和全飽和度(Full Saturation)可以測試轉換顏色空間(ConvertColorSpace),直方圖(Histogram)和飽和度(Saturate)在YUV顏色空間對直方圖的拉伸效果。

 


      ·Thresholding : ( /Colors/Threshold... and /Colors/Adaptive Threshold). 透明度閾值(OptimalThreshold)是一個新的用於查找二進制圖像透明度閾值的新方法。可選的算法有:

  1 = 最大類間方差 (Otsu);
  2 = 基特勒和伊爾林格沃斯(Kittler & Illingworth);
  3 = 最大熵(maximum entropy);
  4 = 位差(potential difference);
  0 = 平均所有方法 (默認情況下,這也是示例程序中所使用的方法);

      "保留低於閾值的顏色"(preserve colors less than the threshold)的選項,將測試Threshold2方法。這對於過濾帶有噪聲背景的彩色圖像很有用。經過處理,我們將得到一幅帶有一致背景的彩色圖像(噪聲被去除)。AdaptiveThreshold是對方法OptimalThreshold的一個應用,它將創建很多閾值模板。AdaptiveThreshold對於有着不一致的燈光照射效果的圖像,非常有用。對於這類圖像,我們不能簡單地在整幅圖像中使用某個單一的閾值。但是,如果我們的參數設置得不對,我們將得到一個非常差勁的處理結果。


      ·Add shadow : (/Filters/Add Shadow...) 這個菜單項的功能演示瞭如何將CxImage的多個小功能(選擇(selections),高斯模糊( GaussianBlur),混合( Mix))組合使用,以達到常見的圖像處理效果。

 


      ·Text smoothing : DrawStringEx 實現了一個新的選項CXTEXTINFO::smooth。我們可以通過文本工具(位於/View/Tools/Text),選中抗鋸齒("antialias")選項對這個功能進行測試。

      類似的效果也同樣可以利用TextBlur (/Filters/Non Linear/Text Blur)進行後處理獲得。這是一個非線性的過濾器,它只對角或圓形的邊緣起作用,從而不會影響到縱向或橫向的線。下圖展示了不同平滑方法的實際效果:

 

 

 

CxImage庫的結構

      在整個庫的繼承樹中,CxImage位於所有其他模塊的頂部。這不是一個完全的符合OOP的方式,但是至少從最初的版本一直到現在,它都工作得很好。現在想要改變整個結構,已經太晚了。但是,你總是可以使用這些繼承類來操作相應格式的圖像,例如你可以使用CxImageTIF來保存多頁的TIFF文件。這樣顯得非常直觀。

 

      連接所有模塊和C庫的是CxFile。這是一個虛類,它提供了標準的方法,用於訪問硬盤或者內存的文件數據。 


CxImage的繼承樹

      一個CxImage對象基本上對應於一幅位圖,同時添加了一些額外的成員變量用於存儲一些有用的信息。

  1. class CxImage  
  2.  {  
  3.  ...  
  4.  protected:  
  5.  void* pDib;            // 包含文件頭,調色板和像素數據  
  6.  BITMAPINFOHEADER head; // 標準文件頭   
  7.  CXIMAGEINFO info;      // 擴展信息  
  8.  BYTE* pSelection;      // 選區  
  9.  BYTE* pAlpha;          // alpha通道  
  10.  CxImage** ppLayers;    // 普通層   
  11.  CxImage** ppFrames;    // 動畫幀  
  12.  }  
  1. class CxImage  
  2.  {  
  3.  ...  
  4.  protected:  
  5.  void* pDib;            // 包含文件頭,調色板和像素數據  
  6.  BITMAPINFOHEADER head; // 標準文件頭  
  7.  CXIMAGEINFO info;      // 擴展信息  
  8.  BYTE* pSelection;      // 選區  
  9.  BYTE* pAlpha;          // alpha通道  
  10.  CxImage** ppLayers;    // 普通層  
  11.  CxImage** ppFrames;    // 動畫幀  
  12.  }  

      CxImage::head 是位圖文件的文件頭,而CxImage::pDib就是一個普通的位圖(就像你在CxImageBMP::Encode中看到的一樣)。  
      CxImage::info 是一個方便的信息容器。這些信息被不同的文件格式所共享,同時供所有成員函數訪問。

 

  1. typedef struct  tagCxImageInfo {  
  2.     DWORD   dwEffWidth;       //雙字節對齊寬度  
  3.     BYTE*   pImage;           //圖像數據  
  4.     void*   pGhost;           //如果這是一個備份(ghost),則pGhost指向它的原始對象   
  5.     DWORD   dwType;           //原始圖像格式  
  6.     char    szLastError[256]; //調試信息,最後的錯誤信息  
  7.     long    nProgress;        //進度  
  8.     long    nEscape;          //取消  
  9.     long    nBkgndIndex;      //GIF, PNG, MNG使用  
  10.     RGBQUAD nBkgndColor;      //RGB透明使用   
  11.     BYTE    nQuality;         //JPEG使用  
  12.     long    nFrame;           //TIF, GIF, MNG使用,表示當前活動幀  
  13.     long    nNumFrames;       //TIF, GIF, MNG使用,表示總幀數                          
  14.     DWORD   dwFrameDelay;     //GIF, MNG使用,表示幀的延遲  
  15.     long    xDPI;             //水平分辨率    
  16.     long    yDPI;             //垂直分辨率    
  17.     RECT    rSelectionBox;    //對象的外包圍框  
  18.     BYTE    nAlphaMax;        //最大透明度  
  19.     bool    bAlphaPaletteEnabled;  //如果調色板中的alpha值是啓用的,則這個變量爲true   
  20.     bool    bEnabled;         //啓用繪製函數  
  21.     long    xOffset;  
  22.     long    yOffset;  
  23.     DWORD   dwEncodeOption;   //GIF, TIF使用:0=def.1=unc,2=fax3,3=fax4, 4=pack,5=jpg  
  24.     RGBQUAD last_c;           //用於優化GetNearestIndex  
  25.     BYTE    last_c_index;  
  26.     bool    last_c_isvalid;  
  27.     long    nNumLayers;  
  28.     DWORD   dwFlags;  
  29. } CXIMAGEINFO;  
  1. typedef struct  tagCxImageInfo {  
  2.     DWORD   dwEffWidth;       //雙字節對齊寬度  
  3.     BYTE*   pImage;           //圖像數據  
  4.     void*   pGhost;           //如果這是一個備份(ghost),則pGhost指向它的原始對象   
  5.     DWORD   dwType;           //原始圖像格式  
  6.     char    szLastError[256]; //調試信息,最後的錯誤信息  
  7.     long    nProgress;        //進度  
  8.     long    nEscape;          //取消  
  9.     long    nBkgndIndex;      //GIF, PNG, MNG使用  
  10.     RGBQUAD nBkgndColor;      //RGB透明使用  
  11.     BYTE    nQuality;         //JPEG使用  
  12.     long    nFrame;           //TIF, GIF, MNG使用,表示當前活動幀  
  13.     long    nNumFrames;       //TIF, GIF, MNG使用,表示總幀數                          
  14.     DWORD   dwFrameDelay;     //GIF, MNG使用,表示幀的延遲  
  15.     long    xDPI;             //水平分辨率    
  16.     long    yDPI;             //垂直分辨率    
  17.     RECT    rSelectionBox;    //對象的外包圍框  
  18.     BYTE    nAlphaMax;        //最大透明度  
  19.     bool    bAlphaPaletteEnabled;  //如果調色板中的alpha值是啓用的,則這個變量爲true   
  20.     bool    bEnabled;         //啓用繪製函數  
  21.     long    xOffset;  
  22.     long    yOffset;  
  23.     DWORD   dwEncodeOption;   //GIF, TIF使用:0=def.1=unc,2=fax3,3=fax4, 4=pack,5=jpg  
  24.     RGBQUAD last_c;           //用於優化GetNearestIndex  
  25.     BYTE    last_c_index;  
  26.     bool    last_c_isvalid;  
  27.     long    nNumLayers;  
  28.     DWORD   dwFlags;  
  29. } CXIMAGEINFO;  

 
      CxImage對象同樣是圖層的集合,每個圖層的緩衝區只在需要的時候申請。
      CxImage::pDib是背景圖像。 CxImage::pAlpha是透明層。CxImage::pSelection是選區層,用於創建要對圖像的感興趣區域進行處理的選擇區域。在這三個特殊層之上,你可以添加通用的其他層,這些層都保存在CxImage::ppLayers中。通用層也是完整的CxImage對象,所以你可以創建複雜的嵌套層。CxImage::ppFrames 爲動態圖像(GIF)所預留。

      CxImage類成員和操作
      CxImage使用Doxygen 產生文檔,但是由於一些歷史的原因,很多不太通用的功能還沒有文檔。類成員的參考資料,發佈歷史以及許可信息都可以在這裏(here )找到。

 

      支持的格式和選項
      整個CxImage庫非常大,在主要的頭文件ximcfg.h中,你可以找到很多編譯選項開關,用於啓用或者禁用某些特定的圖像格式或者功能。每個JPG, PNG和 TIFF庫將使得應用程序增加大約100KB的大小,同時,CxImage將使得應用程序增加大約50KB的大小。所以,爲了減小你的應用程序的體積,你應該支持和鏈接你的應用程序確實需要的格式。

 

格式
定義#define
需要的庫
尺寸 [KB]
BMP
GIF
ICO
TGA
PCX
WBMP
WMF
SKA
CXIMAGE_SUPPORT_BMP
CXIMAGE_SUPPORT_GIF
CXIMAGE_SUPPORT_ICO
CXIMAGE_SUPPORT_TGA
CXIMAGE_SUPPORT_PCX
CXIMAGE_SUPPORT_WBMP
CXIMAGE_SUPPORT_WMF
CXIMAGE_SUPPORT_SKA

內建

24
JPEG
CXIMAGE_SUPPORT_JPG

jpeg

88
PNG
CXIMAGE_SUPPORT_PNG

png, zlib

104
MNG
CXIMAGE_SUPPORT_MNG

mng, zlib, jpeg

148
TIFF
CXIMAGE_SUPPORT_TIF

tiff, zlib, jpeg

124
JBIG
CXIMAGE_SUPPORT_JBG

jbig

28
PNM,PPM,PGM
RAS
CXIMAGE_SUPPORT_PNM
CXIMAGE_SUPPORT_RAS

jasper

176
JPEG-2000
CXIMAGE_SUPPORT_JP2
CXIMAGE_SUPPORT_JPC
CXIMAGE_SUPPORT_PGX

jasper

176
RAW
CXIMAGE_SUPPORT_RAW
libdcr
132

 

選項
定義#define
尺寸[KB]
CxImage核心
所有開關關閉
20
幾何變換
(geometric transformations)
CXIMAGE_SUPPORT_TRANSFORMATION
16
圖像處理
(image processing)
CXIMAGE_SUPPORT_DSP
24
繪製和特殊的窗口函數
(drawing and windows specific functions)
CXIMAGE_SUPPORT_WINDOWS
12
透明
(transparency)
CXIMAGE_SUPPORT_ALPHA
4
選擇
(selections)
CXIMAGE_SUPPORT_SELECTION
4
多層支持
(multiple layers)
CXIMAGE_SUPPORT_LAYERS
< 4
圖像格式轉換
(graphic formats conversion)
CXIMAGE_SUPPORT_DECODE
CXIMAGE_SUPPORT_ENCODE
< 4
插值函數
(interpolation functions)
CXIMAGE_SUPPORT_INTERPOLATION
< 4
異常處理
(exception handling)
CXIMAGE_SUPPORT_EXCEPTION_HANDLING
< 4

 

 

      在你的項目中使用CxImage
      如下圖所示,CxImgLib.dsw工作空間展示了構建一個包含絕大多數功能和支持大多數圖像格式的應用程序(demo.exe)所需要的所有庫。你必須先編譯所有的庫,然後纔可以鏈接你最終的應用程序。 

      CxImgLib.dsw工作空間
      在相同的工作空間中,你可以找到用於構建不同庫和應用程序的項目:

  ·CxImage : cximage.lib - 靜態庫 
  ·CxImageCrtDll : cximagecrt.dll - DLL,不使用MFC 
  ·CxImageMfcDll : cximage.dll - DLL,使用MFC
  ·Demo : 示例程序demo.exe,跟cximage.lib和C庫鏈接。 
  ·DemoDll : demodll.exe - 跟cximagecrt.dll鏈接 
  ·libdcr,jasper,jbig,jpeg,png,tiff,zlib : 靜態的C庫

      構建這些項目需要幾分鐘時間,當所有項目構建完成後,你可以選擇demo項目並執行應用程序。

      要想在你自己的項目中使用CxImage,你必須編輯下面這些項目設置設置(針對Visual C++ 6.0):
 
  Project Settings(項目設置)

  1. Project Settings  
  2.  |- C/C++  
  3.  |   |- Code Generation  
  4.  |   |   |- Use run-time library : Multithreaded DLL (must be the same for   
  5.  |   |   |  all the linked libraries)  
  6.  |   |   |- Struct member alignment : must be the same for all the linked   
  7.  |   |   |  libraries  
  8.  |   |- Precompiled headers : not using precompiled headers  
  9.  |   |- Preprocessor  
  10.  |       |- Additional Include Directories:  ../cximage  
  11.  |- Link  
  12.     |- General  
  13.         |- Object/library modules: ../png/Debug/png.lib    
  14.                                    ../raw/Debug/libdcr.lib  
  15.                                    ../jpeg/Debug/jpeg.lib   
  16.                                    ../zlib/Debug/zlib.lib   
  17.                                    ../tiff/Debug/tiff.lib  
  18.                                    ../jasper/Debug/jasper.lib  
  19.                                    ../cximage/Debug/cximage.lib  ...  
  1. Project Settings  
  2.  |- C/C++  
  3.  |   |- Code Generation  
  4.  |   |   |- Use run-time library : Multithreaded DLL (must be the same for   
  5.  |   |   |  all the linked libraries)  
  6.  |   |   |- Struct member alignment : must be the same for all the linked   
  7.  |   |   |  libraries  
  8.  |   |- Precompiled headers : not using precompiled headers  
  9.  |   |- Preprocessor  
  10.  |       |- Additional Include Directories:  ../cximage  
  11.  |- Link  
  12.     |- General  
  13.         |- Object/library modules: ../png/Debug/png.lib    
  14.                                    ../raw/Debug/libdcr.lib  
  15.                                    ../jpeg/Debug/jpeg.lib   
  16.                                    ../zlib/Debug/zlib.lib   
  17.                                    ../tiff/Debug/tiff.lib  
  18.                                    ../jasper/Debug/jasper.lib  
  19.                                    ../cximage/Debug/cximage.lib  ...  
 

      在你的源代碼中,你必須引入CxImage的頭文件ximage.h。在你的代碼中添加如下語句:#include "ximage.h"。
      注意,不要混合debug和release模塊,每個配置必須使用各自相應的庫文件。

 

      在CxImage中添加自定義的函數 
      爲CxImage添加一個新的圖像處理函數並不困難。在這裏,我將以CxImage::Jitter爲例子,描述如何爲CxImage添加自定義的函數。雖然這個函數很簡單, 但是它卻展示了使用CxImage時所需要注意的方方面面。

      首先,我們需要聲明這個函數:

  1. bool Jitter(long radius=2)  
  1. bool Jitter(long radius=2)  
 

      在ximage.h頭文件的CXIMAGE_SUPPORT_DSP部分,你可以在public區域的任何部分聲明這個函數。

      現在,我們開始定義這個函數:

[c-sharp] view plaincopy
  1. bool CxImage::Jitter(long radius)  
  2. {  
  3.     // 檢查圖像是否合法,這應當是這個函數的第一行   
  4.     if (!pDib) return false;  
  5.       
  6.     // 局部變量   
  7.     long nx,ny;  
  8.       
  9.     // 臨時圖像,用於存儲算法的部分結果   
  10.     CxImage tmp(*this,pSelection!=0,true,true);  
  11.       
  12.     // 限制函數僅僅作用在選區(通過Selection...()函數定義)的最小區域  
  13.     // 這將加快整個循環的速度,提高算法效率   
  14.     long xmin,xmax,ymin,ymax;  
  15.     if (pSelection){  
  16.         xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;  
  17.         ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;  
  18.     } else {  
  19.         xmin = ymin = 0;  
  20.         xmax = head.biWidth; ymax=head.biHeight;  
  21.     }  
  22.       
  23.     // 主循環 : 垂直方向掃描圖像   
  24.     for(long y=ymin; y <ymax; y++){  
  25.       
  26.         // 監視循環的進度   
  27.         info.nProgress = (long)(100*y/head.biHeight);  
  28.       
  29.         // 檢查應用程序是否已經退出   
  30.         if (info.nEscape) break;  
  31.       
  32.         // 主循環 : 水平方向掃描圖像   
  33.         for(long x=xmin; x<xmax; x++){  
  34.       
  35.         // 如果選區功能啓用了,則僅僅處理選區內部的像素 
  36. #if CXIMAGE_SUPPORT_SELECTION   
  37.             if (SelectionIsInside(x,y)) 
  38. #endif //CXIMAGE_SUPPORT_SELECTION   
  39.             {  
  40.                 // 主算法   
  41.                 nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));  
  42.                 ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));  
  43.                 if (!IsInside(nx,ny)) {  
  44.                     nx=x;  
  45.                     ny=y;  
  46.                 }  
  47.   
  48.                 // 保存結果到臨時圖像中.   
  49.                 // 如果可以,24位圖像請使用PixelColor,  
  50.                 // 而8,4和1位圖像請使用PixelIndex,這樣可以加快速度。  
  51.                 if (head.biClrUsed==0){  
  52.                     tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));  
  53.                 } else {  
  54.                     tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));  
  55.                 }  
  56.   
  57.                 // 如果啓用了透明度功能,則處理透明圖層中的像素  
  58. #if CXIMAGE_SUPPORT_ALPHA   
  59.                 tmp.AlphaSet(x,y,AlphaGet(nx,ny));  
  60. #endif //CXIMAGE_SUPPORT_ALPHA   
  61.   
  62.             }  
  63.         }  
  64.     }  
  65.   
  66.     // 保存結果並退出   
  67.     Transfer(tmp);  
  68.     return true;  
  69. }  
[c-sharp] view plaincopy
  1. bool CxImage::Jitter(long radius)  
  2. {  
  3.     // 檢查圖像是否合法,這應當是這個函數的第一行  
  4.     if (!pDib) return false;  
  5.       
  6.     // 局部變量  
  7.     long nx,ny;  
  8.       
  9.     // 臨時圖像,用於存儲算法的部分結果  
  10.     CxImage tmp(*this,pSelection!=0,true,true);  
  11.       
  12.     // 限制函數僅僅作用在選區(通過Selection...()函數定義)的最小區域  
  13.     // 這將加快整個循環的速度,提高算法效率  
  14.     long xmin,xmax,ymin,ymax;  
  15.     if (pSelection){  
  16.         xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;  
  17.         ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;  
  18.     } else {  
  19.         xmin = ymin = 0;  
  20.         xmax = head.biWidth; ymax=head.biHeight;  
  21.     }  
  22.       
  23.     // 主循環 : 垂直方向掃描圖像  
  24.     for(long y=ymin; y <ymax; y++){  
  25.       
  26.         // 監視循環的進度  
  27.         info.nProgress = (long)(100*y/head.biHeight);  
  28.       
  29.         // 檢查應用程序是否已經退出  
  30.         if (info.nEscape) break;  
  31.       
  32.         // 主循環 : 水平方向掃描圖像  
  33.         for(long x=xmin; x<xmax; x++){  
  34.       
  35.         // 如果選區功能啓用了,則僅僅處理選區內部的像素  
  36. #if CXIMAGE_SUPPORT_SELECTION  
  37.             if (SelectionIsInside(x,y))  
  38. #endif //CXIMAGE_SUPPORT_SELECTION  
  39.             {  
  40.                 // 主算法  
  41.                 nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));  
  42.                 ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));  
  43.                 if (!IsInside(nx,ny)) {  
  44.                     nx=x;  
  45.                     ny=y;  
  46.                 }  
  47.   
  48.                 // 保存結果到臨時圖像中.  
  49.                 // 如果可以,24位圖像請使用PixelColor,  
  50.                 // 而8,4和1位圖像請使用PixelIndex,這樣可以加快速度。  
  51.                 if (head.biClrUsed==0){  
  52.                     tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));  
  53.                 } else {  
  54.                     tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));  
  55.                 }  
  56.   
  57.                 // 如果啓用了透明度功能,則處理透明圖層中的像素   
  58. #if CXIMAGE_SUPPORT_ALPHA  
  59.                 tmp.AlphaSet(x,y,AlphaGet(nx,ny));  
  60. #endif //CXIMAGE_SUPPORT_ALPHA  
  61.   
  62.             }  
  63.         }  
  64.     }  
  65.   
  66.     // 保存結果並退出  
  67.     Transfer(tmp);  
  68.     return true;  
  69. }  

 

示例:

如何轉換一種格式到另外一種格式

  1. CxImage  image;  
  2. // bmp -> jpg   
  3. image.Load("image.bmp", CXIMAGE_FORMAT_BMP);  
  4. if (image.IsValid()){  
  5.     if(!image.IsGrayScale()) image.IncreaseBpp(24);  
  6.     image.SetJpegQuality(80);  
  7.     image.Save("image.jpg",CXIMAGE_FORMAT_JPG);  
  8. }  
  9. // png -> tif   
  10. image.Load("image.png", CXIMAGE_FORMAT_PNG);  
  11. if (image.IsValid()){  
  12.     image.Save("image.tif",CXIMAGE_FORMAT_TIF);  
  13. }  
  1. CxImage  image;  
  2. // bmp -> jpg  
  3. image.Load("image.bmp", CXIMAGE_FORMAT_BMP);  
  4. if (image.IsValid()){  
  5.     if(!image.IsGrayScale()) image.IncreaseBpp(24);  
  6.     image.SetJpegQuality(80);  
  7.     image.Save("image.jpg",CXIMAGE_FORMAT_JPG);  
  8. }  
  9. // png -> tif  
  10. image.Load("image.png", CXIMAGE_FORMAT_PNG);  
  11. if (image.IsValid()){  
  12.     image.Save("image.tif",CXIMAGE_FORMAT_TIF);  
  13. }  

 

如何從資源中加載圖像

  1. //Load the resource IDR_PNG1 from the PNG resource type  
  2. CxImage* newImage = new CxImage();  
  3. newImage->LoadResource(FindResource(NULL,MAKEINTRESOURCE(IDR_PNG1),  
  4.                        "PNG"),CXIMAGE_FORMAT_PNG);  
  5.   
  6. //Load the resource IDR_JPG1 from DLL   
  7. CxImage* newImage = new CxImage();  
  8. HINSTANCE hdll=LoadLibrary("imagelib.dll");  
  9. if (hdll){  
  10.     HRSRC hres=FindResource(hdll,MAKEINTRESOURCE(IDR_JPG1),"JPG");  
  11.     newImage->LoadResource(hres,CXIMAGE_FORMAT_JPG,hdll);  
  12.     FreeLibrary(hdll);  
  13. }  
  14.   
  15. //Load a bitmap resource;   
  16. HBITMAP bitmap = ::LoadBitmap(AfxGetInstanceHandle(),  
  17.                            MAKEINTRESOURCE(IDB_BITMAP1)));  
  18. CxImage *newImage = new CxImage();  
  19. newImage->CreateFromHBITMAP(bitmap);  
  1. //Load the resource IDR_PNG1 from the PNG resource type  
  2. CxImage* newImage = new CxImage();  
  3. newImage->LoadResource(FindResource(NULL,MAKEINTRESOURCE(IDR_PNG1),  
  4.                        "PNG"),CXIMAGE_FORMAT_PNG);  
  5.   
  6. //Load the resource IDR_JPG1 from DLL  
  7. CxImage* newImage = new CxImage();  
  8. HINSTANCE hdll=LoadLibrary("imagelib.dll");  
  9. if (hdll){  
  10.     HRSRC hres=FindResource(hdll,MAKEINTRESOURCE(IDR_JPG1),"JPG");  
  11.     newImage->LoadResource(hres,CXIMAGE_FORMAT_JPG,hdll);  
  12.     FreeLibrary(hdll);  
  13. }  
  14.   
  15. //Load a bitmap resource;  
  16. HBITMAP bitmap = ::LoadBitmap(AfxGetInstanceHandle(),  
  17.                            MAKEINTRESOURCE(IDB_BITMAP1)));  
  18. CxImage *newImage = new CxImage();  
  19. newImage->CreateFromHBITMAP(bitmap);  

 

      如何解碼內存中的圖像

[c-sharp] view plaincopy
  1. CxImage image((BYTE*)buffer,size,image_type);  
  2.   
  3. CxMemFile memfile((BYTE*)buffer,size);  
  4. CxImage image(&memfile,image_type);  
  5.   
  6. CxMemFile memfile((BYTE*)buffer,size);  
  7. CxImage* image = new CxImage();  
  8. image->Decode(&memfile,type);  
[c-sharp] view plaincopy
  1. CxImage image((BYTE*)buffer,size,image_type);  
  2.   
  3. CxMemFile memfile((BYTE*)buffer,size);  
  4. CxImage image(&memfile,image_type);  
  5.   
  6. CxMemFile memfile((BYTE*)buffer,size);  
  7. CxImage* image = new CxImage();  
  8. image->Decode(&memfile,type);  

 

如何對內存中的圖像編碼

  1. long size=0;  
  2. BYTE* buffer=0;  
  3. image.Encode(buffer,size,image_type);  
  4. ...  
  5. image.FreeMemory(buffer);  
  6.   
  7. CxMemFile memfile;  
  8. memfile.Open();  
  9. image.Encode(&memfile,image_type);  
  10. BYTE* buffer = memfile.GetBuffer();  
  11. long size = memfile.Size();  
  12. ...  
  13. image.FreeMemory(buffer);  
  1. long size=0;  
  2. BYTE* buffer=0;  
  3. image.Encode(buffer,size,image_type);  
  4. ...  
  5. image.FreeMemory(buffer);  
  6.   
  7. CxMemFile memfile;  
  8. memfile.Open();  
  9. image.Encode(&memfile,image_type);  
  10. BYTE* buffer = memfile.GetBuffer();  
  11. long size = memfile.Size();  
  12. ...  
  13. image.FreeMemory(buffer);  

 

如何創建一副多頁的TIFF

[c-sharp] view plaincopy
  1. CxImage *pimage[3];  
  2. pimage[0]=&image1;  
  3. pimage[1]=&image2;  
  4. pimage[2]=&image3;  
  5. FILE* hFile;  
  6. hFile = fopen("multipage.tif","w+b");  
  7. CxImageTIF multiimage;  
  8. multiimage.Encode(hFile,pimage,3);  
  9. fclose(hFile);  
  10.   
  11. FILE* hFile;  
  12. hFile = fopen("c://multi.tif","w+b");  
  13. CxImageTIF image;  
  14. image.Load("c://1.tif",CXIMAGE_FORMAT_TIF);  
  15. image.Encode(hFile,true);  
  16. image.Load("c://2.bmp",CXIMAGE_FORMAT_BMP);  
  17. image.Encode(hFile,true);  
  18. image.Load("c://3.png",CXIMAGE_FORMAT_PNG);  
  19. image.Encode(hFile);  
  20. fclose(hFile);  
[c-sharp] view plaincopy
  1. CxImage *pimage[3];  
  2. pimage[0]=&image1;  
  3. pimage[1]=&image2;  
  4. pimage[2]=&image3;  
  5. FILE* hFile;  
  6. hFile = fopen("multipage.tif","w+b");  
  7. CxImageTIF multiimage;  
  8. multiimage.Encode(hFile,pimage,3);  
  9. fclose(hFile);  
  10.   
  11. FILE* hFile;  
  12. hFile = fopen("c://multi.tif","w+b");  
  13. CxImageTIF image;  
  14. image.Load("c://1.tif",CXIMAGE_FORMAT_TIF);  
  15. image.Encode(hFile,true);  
  16. image.Load("c://2.bmp",CXIMAGE_FORMAT_BMP);  
  17. image.Encode(hFile,true);  
  18. image.Load("c://3.png",CXIMAGE_FORMAT_PNG);  
  19. image.Encode(hFile);  
  20. fclose(hFile);  

 

如何複製和粘貼圖像

[c-sharp] view plaincopy
  1. //複製(copy)   
  2. HANDLE hDIB = image->CopyToHandle();  
  3. if (::OpenClipboard(AfxGetApp()->m_pMainWnd->GetSafeHwnd())) {  
  4.     if(::EmptyClipboard()) {  
  5.         if (::SetClipboardData(CF_DIB,hDIB) == NULL ) {  
  6.             AfxMessageBox( "Unable to set Clipboard data" );  
  7. }    }    }  
  8. CloseClipboard();  
  9.   
  10. //粘貼(paste)   
  11. HANDLE hBitmap=NULL;  
  12. CxImage *newima = new CxImage();  
  13. if (OpenClipboard()) hBitmap=GetClipboardData(CF_DIB);  
  14. if (hBitmap) newima->CreateFromHANDLE(hBitmap);  
  15. CloseClipboard();  
[c-sharp] view plaincopy
  1. //複製(copy)  
  2. HANDLE hDIB = image->CopyToHandle();  
  3. if (::OpenClipboard(AfxGetApp()->m_pMainWnd->GetSafeHwnd())) {  
  4.     if(::EmptyClipboard()) {  
  5.         if (::SetClipboardData(CF_DIB,hDIB) == NULL ) {  
  6.             AfxMessageBox( "Unable to set Clipboard data" );  
  7. }    }    }  
  8. CloseClipboard();  
  9.   
  10. //粘貼(paste)  
  11. HANDLE hBitmap=NULL;  
  12. CxImage *newima = new CxImage();  
  13. if (OpenClipboard()) hBitmap=GetClipboardData(CF_DIB);  
  14. if (hBitmap) newima->CreateFromHANDLE(hBitmap);  
  15. CloseClipboard();  

 

如何在圖片框控件(Picture Box)中顯示圖像

  1. HBITMAP m_bitmap = NULL;  
  2. CxImage image("myfile.png", CXIMAGE_FORMAT_PNG);  
  3. ...  
  4. CDC* hdc = m_picture.GetDC();  
  5. HBITMAP m_bitmap = image.MakeBitmap(hdc->m_hDC);  
  6. HBITMAP hOldBmp = m_picture.SetBitmap(m_bitmap);  
  7. if (hOldBmp) DeleteObject(hOldBmp);  
  8. if (hdc->m_hDC) m_picture.ReleaseDC(hdc);  
  9. ...  
  10. if (m_bitmap) DeleteObject(m_bitmap);  
  1. HBITMAP m_bitmap = NULL;  
  2. CxImage image("myfile.png", CXIMAGE_FORMAT_PNG);  
  3. ...  
  4. CDC* hdc = m_picture.GetDC();  
  5. HBITMAP m_bitmap = image.MakeBitmap(hdc->m_hDC);  
  6. HBITMAP hOldBmp = m_picture.SetBitmap(m_bitmap);  
  7. if (hOldBmp) DeleteObject(hOldBmp);  
  8. if (hdc->m_hDC) m_picture.ReleaseDC(hdc);  
  9. ...  
  10. if (m_bitmap) DeleteObject(m_bitmap);  

 


      譯後序:

      關於圖像處理庫,我相信大家有一個共同的疑問:這麼多圖像處理庫,我該如何選擇?在CSDN的blog中有這樣一段文字,比較透徹地回答了這個問題,感謝作者的透徹解釋:

      "CxImage類庫是一 個優秀的圖像操作類庫。它可以快捷地存取、顯示、轉換各種圖像。有的讀者可能說,有那麼多優秀的圖形庫,如OpenIL,FreeImage, PaintLib等等,它們可謂是功能強大,齊全,沒必要用其它的類庫。但我要說,這些類庫基本上沒有免費的,使用這些類庫,你要被這樣那樣的許可協議所 束縛。

      在這點上,CxImage類庫是完全免費的。另外,在使用上述類庫時,你會遇到重重麻煩。因爲它們大部分是平臺無關的,且用C語言寫成,有的還夾雜 着基本的C++ wrapper和成堆德編譯選項的聲明需要你去處理。而CxImage類庫在這方面做得很好。還有讓我最看好的,就是作者完全公開了源代碼。相對於那些封 裝好的圖形庫和GDI+來說,這一點使我們可以進一步學習各種編解碼技術,而不再浮於各種技術的表面。"

發佈了21 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章