2016-05-03 151 views
0

爲了將文件上傳大小減少到web服務,我們將圖像文件的高度/寬度限制爲最大值。
對於JPG文件,此工作正常:向下調整圖像尺寸會導致文件大小減小。減少PNG存儲大小

並非如此PNG文件,但:在大多數情況下,我們的代碼導致較大文件大小:

procedure TFrmImageCheckAndResize.ResizePNGImage; 
var 
    lSrcPNGImage, lTrgPNGImage: TdxPNGImage; 
    lSrcBitmap,lDestBitMap: TcxAlphaBitmap; 
    lNewWidth,lNewHeight: Integer; 
    lFactor: Real; 
begin 
    lSrcPNGImage := TdxPNGImage.Create; 
    lSrcPNGImage.LoadFromFile(FFileName); 
    lSrcBitmap := TcxAlphaBitmap.CreateSize(lSrcPNGImage.Width, lSrcPNGImage.Height, True); 
    lSrcBitmap.Canvas.Draw(0, 0, lSrcPNGImage); 
    if lSrcPNGImage.Width > lSrcPNGImage.Height then 
    if lSrcPNGImage.Width > FEditImageRes.Value then 
     lFactor := lSrcPNGImage.Width 
    else 
     lFactor := 0 
    else 
    if lSrcPNGImage.Height > FEditImageRes.Value then 
     lFactor := lSrcPNGImage.Height 
    else 
     lFactor := 0; 
    if lFactor <> 0 then 
    begin 
    lFactor := lFactor/FEditImageRes.Value; 
    lNewWidth := Trunc(lSrcPNGImage.Width/lFactor); 
    lNewHeight := Trunc(lSrcPNGImage.Height/lFactor); 
    lDestBitMap := TcxAlphaBitmap.CreateSize(lNewWidth,lNewHeight, True); 
    cxSmoothResizeBitmap(lSrcBitMap, lDestBitMap, true); 
    lTrgPNGImage := TdxPNGImage.CreateFromBitmap(lDestBitmap); 
    end 
    else 
    begin 
    lDestBitmap := nil; // Silence the compiler 
    lTrgPNGImage := TdxPNGImage.CreateFromBitmap(lSrcBitmap); 
    end; 
    lTrgPNGImage.SaveToFile(StringReplace(FFileName,'.','_' + IntToStr(FEditImageRes.Value) + '.',[])); 
    lSrcBitmap.Free; 
    lDestBitmap.Free; 
    lTrgPNGImage.Free; 
    lSrcPNGImage.Free; 
end; 

FFileName是從磁盤加載圖像,FEditImageRes.Value包含了我們降低到最大尺寸。

請注意,我們使用Developer Express組件,並且此代碼維護Alpha通道(透明度)。
我沒有依附任一。

我發佈了一個ticket with DevExpress,但這不是他們的代碼中的問題。

我看着其他什麼軟件做:

enter image description here

在Paint.Net,如果我減少以上890 * 161的屏幕截圖512 * 93我看到這取決於使用的算法混合的結果調整大小:

15.697 Original.png 
21.904 Resized_BiCubic.png 
19.995 Resized_Bilineair.png 
22.905 Resized_Fant.png 
6.729 Resized_NearestNeigbour.png 

enter image description here

對於本550x386照片減少到512 * 353 ,Paint.Net的結果是:

375.229 Photo.png 
419.122 Photo_Bicubic.png 
402.277 Photo_Bilineair.png 
407.959 Photo_Fant.png 
416.619 Photo_NearestNeighbor.png 

所以它看起來很不可預測結果會是什麼。

問題:
有什麼我可以做的(改變我的代碼),以確保(大多數)調整大小的PNG文件實際上會減少文件大小?

+2

PNG看起來像那個圖像的錯誤格式,應該是JPG –

+0

壓縮是無損的。當你縮小尺寸時,一個好的算法會保留更多的信息 - 具有更清晰圖像的大文件尺寸。粗略的算法保留較少的信息,較軟的模糊圖像和較小的文件大小。您需要解決一個算法,該算法在視覺上看起來與原始圖像具有相同的銳度,這應該會生成較小的文件大小而不會損壞圖像。如果圖像是混合類型(例如圖形與照片),那是不可能的。 –

+0

將photo.png保存在paint.net中?否則,該比較無效。 –

回答

3

有些規則如何從vcl.imaging.PngImage

首先得到最小的圖像尺寸可能與TPngImage,它已經CompressionLevel屬性,您可以設置整數值0..9,0是無壓縮AR所有,9是最好的壓縮(但最慢)。默認設置爲7。注意:PNG始終無損,此設置僅影響保存圖像所需的時間。

其次,Filters屬性的默認值爲[pfSub],但爲了達到最佳壓縮效果,應將其設置爲[pfNone, pfSub, pfUp, pfAverage, pfPaeth]。這些預測濾波器應用於每一行圖像,以便使用鄰居之間的相關性來獲得更好的壓縮效果。當所有的過濾器都被設置好後,每個過濾器都會被嘗試,最好的過濾器會被使用。

確保InterlaceMethod屬性設置爲imNone。也許你的原始圖像是交錯的,在這種情況下,與非交錯相比,文件大小增加了5..20%。

還有一種方法可以獲得較小尺寸的圖像,即增加MaxIDATSize屬性以比圖像尺寸多一點。要點是,PNG像素數據存儲在一個或多個IDAT塊中,每個塊有4個字節的大小,然後是其名稱的4個字節('IDAT'),然後是數據,然後是4個字節的CRC。默認情況下,每個塊的大小爲65535字節,因此在大圖中,您將擁有大量的塊,並且每個塊都有12個字節的浪費。但這裏增加的很小,只有0.2%,並不是很多。

事實上,通過這樣的設置,PNGImage製作了非常小的文件,通常比Paint.NET小10-20%,但專門的程序可以更好地壓縮PNG。

關於調整大小。嘗試調整屏幕截圖大小時,文件大小通常是這種情況。原始截圖有幾種顏色,在你的情況下它是431,很大程度上是因爲漸變。有相同顏色的大面積可以很好地保存。在調整大小之後,從一種顏色到另一種顏色的每個尖銳過渡變得模糊,因此創建更多的「混合」顏色,壓縮更加困難。正如你所看到的,最近鄰居的結果是最小的文件大小,因爲它不會創建原來不在原始圖像中的新顏色。

你的第二個例子,550x386照片在調整大小後必須具有較低的文件大小,事實上,我已經設法將調整大小的512x353照片壓縮到303 kB。 Paint.net根本不使用預測濾鏡,這就是爲什麼它會壓縮照片和其他真彩色圖像。