現在的位置: 首頁 > 綜合 > 正文

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

2013年08月27日 ⁄ 綜合 ⁄ 共 3245字 ⁄ 字型大小 評論關閉

    由於CSDN博客和博客園的編輯方面有不一致的地方,導致文中部分圖片錯位,為不影響瀏覽效果,建議點擊打開鏈接 

    在很多圖像軟體中,打開一幅圖像的時候都會顯示其縮略圖,在看圖軟體中這樣的需求更為常見。如何快速的獲取縮略圖的信息並提供給用戶查看,是個值得研究的問題。在我所研究過的圖像格式中,只有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的源碼:

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,那縮略圖裡有要嵌入縮略圖....想想吧,會出現什麼。

   

    *****************************基本上我不提供源代碼,但是我會盡量用文字把對應的演算法描述清楚或提供參考文檔**************************

    *******************************因為靠自己的努力和實踐寫出來的效果才真正是自己的東西,人一定要靠自己******************************

    ********************************如果你真的要源代碼,那你得把你的腰包變得更瘦一點,這就是偷懶的懲罰*******************************

抱歉!評論已關閉.