2010-10-18 33 views
32

當我加載一個jpg文件並轉身並將其保存爲100的質量並且尺寸幾乎是原來的4倍時,我剛剛獲得了真正的驚喜。爲了進一步調查,我打開並保存,沒有明確設置質量和文件大小是完全一樣的。我想這是因爲沒有改變,所以它只是寫完全相同的位回到一個文件。爲了測試這個假設,我在對角線上繪製了一條大胖線,並且沒有設置質量再次保存(這次我預計文件會跳起來,因爲它會變髒),但是它減少了〜10Kb!Image.Save()用於jpeg文件的質量等級是什麼?

在這一點上我真的不明白當我簡單地調用Image.Save()w/out指定壓縮質量時發生了什麼。當質量設置爲100(基本上不壓縮)時,文件大小如何接近(在圖像修改後)原始大小,如果沒有設置質量,文件大小比原始大幾倍?

我已經閱讀了關於Image.Save()的文檔,並且缺少關於幕後發生的事情的任何細節。我已經搜索了每種我能想到的方式,但我找不到任何可以解釋我所看到的信息。我已經連續工作了31個小時,所以也許我錯過了一些明顯的東西; 0)

所有這些都是因爲我實現了一些庫方法來保存圖像到數據庫。我已經重載了我們的「SaveImage」方法來允許明確地設置一個質量,在我的測試過程中,我遇到了上面解釋的奇怪(對我)結果。任何你可以擺脫的燈將不勝感激。

下面是一些代碼,將說明什麼我遇到:

string filename = @"C:\temp\image testing\hh.jpg"; 
string destPath = @"C:\temp\image testing\"; 

using(Image image = Image.FromFile(filename)) 
{ 
    ImageCodecInfo codecInfo = ImageUtils.GetEncoderInfo(ImageFormat.Jpeg); 

    // Set the quality 
    EncoderParameters parameters = new EncoderParameters(1); 

    // Quality: 10 
    parameters.Param[0] = new EncoderParameter(
     System.Drawing.Imaging.Encoder.Quality, 10L); 
    image.Save(destPath + "10.jpg", codecInfo, parameters); 

    // Quality: 75 
    parameters.Param[0] = new EncoderParameter(
     System.Drawing.Imaging.Encoder.Quality, 75L); 
    image.Save(destPath + "75.jpg", codecInfo, parameters); 

    // Quality: 100 
    parameters.Param[0] = new EncoderParameter(
     System.Drawing.Imaging.Encoder.Quality, 100L); 
    image.Save(destPath + "100.jpg", codecInfo, parameters); 

    // default 
    image.Save(destPath + "default.jpg", ImageFormat.Jpeg); 

    // Big line across image 
    using (Graphics g = Graphics.FromImage(image)) 
    { 
     using(Pen pen = new Pen(Color.Red, 50F)) 
     { 
      g.DrawLine(pen, 0, 0, image.Width, image.Height); 
     } 
    } 

    image.Save(destPath + "big red line.jpg", ImageFormat.Jpeg); 
} 

public static ImageCodecInfo GetEncoderInfo(ImageFormat format) 
{ 
    return ImageCodecInfo.GetImageEncoders().ToList().Find(delegate(ImageCodecInfo codec) 
    { 
     return codec.FormatID == format.Guid; 
    }); 
} 
+2

我做了一些關於.NET中的JPG壓縮和相應錯誤的實驗,請參閱http://www.c4real.biz/jpgCompression.aspx。 – 2012-02-27 18:38:25

+0

基於一些快速測試,看起來你的原始直覺是正確的:如果你有一個原本是jpg的圖像,並且在沒有指定質量的情況下調用Save,它只會將原始位轉儲到文件中。如果您修改了內存中的圖像,或者您請求了特定的壓縮級別,則會重新對圖像進行編碼。如果您對來自低質量源的圖像請求高質量級別,則會浪費大量空間,試圖非常準確地描述原始壓縮引入的所有工件。 – sethobrien 2012-11-12 17:18:28

回答

19

使用反射器,事實證明Image.Save()歸結爲GDI +函​​數GdipSaveImageToFile,其中encoderParams NULL。所以我認爲這個問題是JPEG編碼器在得到空值encoderParams時所做的。這裏已經提出了75%,但是我找不到任何可靠的參考。

編輯你也許可以運行你的程序上面的1..100質量值,並將它們與保存在默認畫質的JPG比較找出自己(使用,比如說,FC.EXE/B)

+0

啊,我忘了反射器! ; 0)很高興知道這種方法沒有神祕的魔法發生。我想我會按照你的建議來做一個測試,以便讓我放心。我將在此線程上報告結果。 – 2010-10-18 17:13:18

+7

我做了一個快速測試並打開了一個* .bmp文件,然後用默認設置保存爲jpg,並且質量明確設置爲75.這些文件的尺寸完全相同。所以一定是編碼器內部默認爲75.我認爲這應該在文檔的某個地方,不是嗎? – 2010-10-18 17:19:57

+0

當然,但我不確定*哪些*文檔。據我瞭解,這是默認的Windows JPEG編碼器的功能,其文檔駐留在我不知道的地方... – 2010-10-18 17:31:39

5

IIRC,它是75%,但我不記得在那裏我閱讀。

+0

75%是用於在屏幕上顯示的可接受壓縮率。 – Stefanvds 2010-10-18 08:23:37

+3

我用他的方法保存爲75L,並保存了另一個默認值。結果:'75L = 36.7 KB'和'默認= 36.8 KB'。如果它不是75%,那麼它就是75.1%...... – BrunoLM 2011-04-19 13:25:55

0

我對Image.Save方法不太瞭解,但我可以告訴你,添加fat line會邏輯地減小jpg圖像的大小。這是由於jpg保存(和編碼)的方式。

粗黑線代表一個非常簡單和較小的編碼(如果我沒有記錯,這主要是在離散餘弦變換之後),所以修改後的圖像可以使用較少的數據(字節)進行存儲。

jpg encoding steps

關於在尺寸上的變化(不加行),我不知道你重新打開這些圖像和重新保存

爲了進一步研究我打開並保存沒有明確設置質量並且文件大小是一模一樣的

如果你打開了舊的(原來的正常大小)的圖像,並重新保存它,那麼也許默認的壓縮和原始圖像壓縮是一樣。 如果您打開新的(4倍大)圖像並對其進行了重新保存,則可能默認的保存壓縮方法是從圖像中導出的(與加載時相同)。

再一次,我不知道保存方法,所以我只是拋出想法(也許他們會給你帶頭)。

+0

你說得對,一個大的,堅實的地區將會有效地壓縮是非常合理的。我試圖完成並應該更好地解釋的是強制對數據進行重新編碼。我試圖確定我是否看到相同的文件大小,因爲Save()正在對磁盤進行直接轉儲。我想如果我跺腳了整個圖像,然後保存它會觸發文件重新編碼。感謝您的鏈接和其他信息。 – 2010-10-18 17:11:07

0

當您將圖像保存爲質量級別爲<的JPEG文件時,會將文物引入保存的圖像中,這是壓縮過程的副作用。這就是爲什麼將圖像重新保存爲100%的原因實際上是將文件的大小增加到原始大小之外 - 具有諷刺意味的是,位圖中存在更多信息。

這也是爲什麼你應該總是試圖保存在非損失的格式(如PNG),如果你打算之後對你的文件進行任何編輯,否則你會通過多重影響輸出的質量有損變革。

+0

作爲切線,在高色深下保存也很重要。在對圖像進行某些操作時,特別是對具有梯度的圖像進行操作時,可能會導致分層。使用高色彩深度的源圖像有助於平滑色彩漸變以保持平滑。 – 2010-10-18 13:40:15

+0

感謝您的信息。我在photoshop上做了一個快速測試,看看這個圖像以100的質量保存時會做什麼,實際上它增加了大約與我在100測試時的大小相同。 – 2010-10-18 17:07:30