關於.net中獲取圖像縮略圖的函數GetThumbnailImage的一些認識。


  在很多圖像軟件中,打開一幅圖像的時候都會顯示其縮略圖,在看圖軟件中這樣的需求更為常見。如何快速的獲取縮略圖的信息並提供給用戶查看,是個值得研究的問題。在我所研究過的圖像格式中,只有JPG和PSD兩種格式可能內嵌了圖像自身的縮略圖信息。

  在.net中,圖像處理方面的內容主要是借助於GDI+的平板化API函數實現的。為了獲取GDI+能支持的那幾種格式的縮略圖,可以調用Bitmap或者Image類的GetThumbnailImage函數。用Reflecor反編譯后知道,這個函數的主要實現代碼如下所示:

public Image GetThumbnailImage(int thumbWidth, int thumbHeight, GetThumbnailImageAbort callback, IntPtr callbackData) { IntPtr zero = IntPtr.Zero; int status = SafeNativeMethods.Gdip.GdipGetImageThumbnail(new HandleRef(this, this.nativeImage), thumbWidth, thumbHeight, out zero, callback, callbackData); if (status != 0) { throw SafeNativeMethods.Gdip.StatusException(status); } return CreateImageObject(zero); }

  那么其實他也是直接調用GdipGetImageThumbnail函數。

    下面我們主要通過實驗說說這個函數的實質和其可應用的場合以及不應該應用的場合。

  為了測試公平,我們選用VB6作為測試語言,這有兩個原因:(1)因為VB6直接調用GDI+的API函數很方便,也可以降低.net中創建各種對象所用的時間。(2)我在C#中調用Bitmap.FromFile讀取文件的時間比VB6中使用同樣的API要慢很多,不知道為什么。

 

    結論1: 該函數首先判斷圖像是否內嵌了縮略圖,如果有,則直接讀取他,然后再將獲得的縮略圖縮放到用戶調用時指定的大小。如果沒有,則從圖像數據中抽樣填充到縮略圖數據中,至於抽樣算法,這個沒有研究,也許是線性插值吧。

       驗證前的准備工作: 

     (1)  一副4000*3000的數碼照片,JPG格式,內嵌了縮略圖信息(如何驗證:可以用很多查看EXIF信息的軟件查看),可在此處下載

       (2)  一副4000*3000的照片,JPG格式,沒有內嵌縮略圖信息(如何驗證:可以用很多查看EXIF信息的軟件查看),可在此處下載

       (3) 一副4000*3000的照片,Png格式,由於無法上傳大於5MB的文件,請朋友自行用工具轉換。

        對上述三幅圖像進行獲取縮略圖的操作,具體代碼如下:

 '第一步:加載圖像
    Elapse = GetTickCount GdipLoadImageFromFile StrPtr(FileName), Bitmap Result = Result + "加載圖像用時: " & GetTickCount - Elapse & " 毫秒。" + vbCrLf GdipGetImageWidth Bitmap, Width GdipGetImageHeight Bitmap, Height GetFitSize Width, Height, 600, 450, FitX, FitY, FitWidth, FitHeight '第二步:獲取縮略圖
    Elapse = GetTickCount GdipGetImageThumbnail Bitmap, FitWidth, FitHeight, Thumb Result = Result + "獲取縮略圖用時: " & GetTickCount - Elapse & " 毫秒。" + vbCrLf GdipCreateFromHDC Hdc, Graphics '第三步:繪制縮略圖
    Elapse = GetTickCount GdipDrawImageRect Graphics, Thumb, FitX, FitY, FitWidth, FitHeight Result = Result + "繪制縮略圖: " & GetTickCount - Elapse & " 毫秒。" + vbCrLf GdipDisposeImage Bitmap GdipDisposeImage Thumb GdipDeleteGraphics Graphics

     我們依次查看結果:

   

                                                            圖1 : 內嵌了縮略圖的JPG圖像

   

                                    圖2: 未內嵌縮略圖的JPG圖像

   

                                        圖3: PNG圖像

  上述縮略圖的大小設置為600*450。

   通過上面3個測試結果圖的比較,可以明顯看到:  內嵌了縮略圖的JPG圖像獲得最后的縮略圖很模糊,但是速度相當的塊,而未內嵌了縮略圖的JPG圖像以及PNG圖像獲得的縮略圖非常的清晰,但是耗時很多。因此我們可以初步的判斷如果內嵌了縮略圖,則GdipGetImageThumbnail會直接從內嵌的數據中進行縮放。為了進一步驗證這一點,我生成了一副縮略圖和原圖完全不配套的JPG圖像,來驗證這一點,可從此處下載:

     處理結果如下圖:

   

      可見,執行速度還是不錯的,縮略圖的結果卻是錯誤的,但是和我們嵌入的縮略圖卻是一致的。 

      附帶說一個問題:不知道大家注意到沒有,上述代碼中  GdipLoadImageFromFile 函數執行的時間都很短,而基本相同的函數在C#的Bitmap.FromFile函數中對於上述測試圖像都要200多ms,不知為什么,附上Bitmap.FromFile的源碼:

public static Image FromFile(string filename, bool useEmbeddedColorManagement) { int num; if (!File.Exists(filename)) { IntSecurity.DemandReadFileIO(filename); throw new FileNotFoundException(filename); } filename = Path.GetFullPath(filename); IntPtr zero = IntPtr.Zero; if (useEmbeddedColorManagement) { num = SafeNativeMethods.Gdip.GdipLoadImageFromFileICM(filename, out zero); } else { num = SafeNativeMethods.Gdip.GdipLoadImageFromFile(filename, out zero); } if (num != 0) { throw SafeNativeMethods.Gdip.StatusException(num); } num = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, zero)); if (num != 0) { SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, zero)); throw SafeNativeMethods.Gdip.StatusException(num); } Image image = CreateImageObject(zero); EnsureSave(image, filename, null); return image; } 
View Code

     上述源碼中多了一些錯誤處理的代碼,但那些代碼明顯不會太耗時間。這也是我這里用VB6做測試的原因。

     結論2:GetThumbnailImage不適合於做快速的圖像縮放預覽之類的工作,但是卻是選擇單開單個圖像預覽時的好選擇。

     由以上圖片測試結果可以看出,GetThumbnailImage是無法勝任任意大小預覽模式的,但是對於大哥圖像預覽時,大部分大小都只有160*120大小的預覽窗口的圖像,確實非常合適的。

    結論3:C#下的Bitmap或者Image類的GetThumbnailImage函數不適合於做預覽工作,原因就是他不如我在VB6下工作的快,特別是對於那些已經內嵌了縮略圖的圖像。如果是用C#做,我可能會像類似於VB中這樣,直接調用GDI+的API函數。 

  測試源碼下載: http://files.cnblogs.com/Imageshop/ThumbNail.rar

   附在的說一下: JPG的EXIF信息中的縮略圖格式其實也是JPG格式,這也可以看成為什么JPG內部不一定非要內嵌縮略圖的原因,不然縮略圖本身格式也是JPG,那縮略圖里有要嵌入縮略圖....想想吧,會出現什么。

    后記: 用了下美圖秀秀,在打開8000*6000這樣尺寸的JPG進行預覽時,初次打開的速度就很快,沒感覺到有延遲,並且圖像質量還可以,這個的算法過程期待有高人指點下。

   

 

 ***************************作者: laviewpbt   時間: 2013.6.16    聯系QQ:  33184777  轉載請保留本行信息*************************

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM