2014-02-06 26 views
0

我有然而這需要作物的圖像的部位上的操作,將得到的,裁剪圖像出來在文件大小方面顯著較大(原來是24K和裁剪後的圖像是像650K)。所以我發現我需要在保存之前對圖像應用一些壓縮。我想出了以下幾點:圖像壓縮是不工作

public static System.Drawing.Image CropImage(System.Drawing.Image image, Rectangle cropRectangle, ImageFormat format) 
{ 
    var croppedImage = new Bitmap(cropRectangle.Width, cropRectangle.Height); 
    using (var g = Graphics.FromImage(croppedImage)) 
    { 
     g.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     g.DrawImage(
      image, 
      new Rectangle(new Point(0,0), new Size(cropRectangle.Width, cropRectangle.Height)), 
      cropRectangle, 
      GraphicsUnit.Pixel); 
     return CompressImage(croppedImage, format); 
    } 
} 

public static System.Drawing.Image CompressImage(System.Drawing.Image image, ImageFormat imageFormat) 
{ 
    var bmp = new Bitmap(image); 
    var codecInfo = EncoderFactory.GetEncoderInfo(imageFormat); 
    var encoder = System.Drawing.Imaging.Encoder.Quality; 
    var parameters = new EncoderParameters(1); 
    var parameter = new EncoderParameter(encoder, 10L); 
    parameters.Param[0] = parameter; 

    using (var ms = new MemoryStream()) 
    { 
     bmp.Save(ms, codecInfo, parameters); 
     var resultImage = System.Drawing.Image.FromStream(ms); 
     return resultImage; 
    } 
} 

我設置質量低,看看是否有任何改變。沒有。作物被正確地保存在外觀上,但壓縮並不是一種快樂。如果我完全繞過CompressImage(),則文件大小和圖像質量都不會有任何不同。

所以,2個問題。爲什麼沒有發生?有沒有一種更簡單的方法來壓縮生成的圖像以進行「網頁優化」,類似於photoshop保存網頁圖像的方式(我認爲它只是從中減少了大量信息以減小尺寸)。

+1

什麼圖像格式你在讀取和保存? BMP幾乎不壓縮。 PNG或JPG壓縮好得多。我可以很容易地從一個24k的PNG想象成一個650k的BMP。 –

+0

我正在用png/jpg閱讀。位圖只是一箇中間對象 – Sinaesthetic

+0

問題不在於你正在閱讀什麼......你在保存什麼。 Plaese檢查condecInfo和參數對象的正確設置...也許你保存圖像的質量比原來的更高... – HiperiX

回答

2

你的問題是你必須「壓縮」(真編碼),你保存它,你保存它沒有之前的圖像。程序中的Image對象始終未壓縮。

通過保存到的MemoryStream並從流中讀取背出將編碼的圖像,然後再次(有一些質量損失的過程中,如果你使用的是JPEG)解碼回到同一尺寸。但是,如果使用壓縮參數將其保存到文件中,則會得到壓縮的圖像文件。

使用這種常規帶153 KB源圖像上的JPEG質量級別90給出了102 KB的輸出圖像。如果你想有一個更小的文件(有更多的編碼假象),編碼器參數更改爲小於90

public static void SaveJpegImage(System.Drawing.Image image, string fileName) 
{ 
    ImageCodecInfo codecInfo = ImageCodecInfo.GetImageEncoders() 
     .Where(r => r.CodecName.ToUpperInvariant().Contains("JPEG")) 
     .Select(r => r).FirstOrDefault(); 

    var encoder = System.Drawing.Imaging.Encoder.Quality; 
    var parameters = new EncoderParameters(1); 
    var parameter = new EncoderParameter(encoder, 90L); 
    parameters.Param[0] = parameter; 

    using (FileStream fs = new FileStream(fileName, FileMode.Create)) 
    { 
     image.Save(fs, codecInfo, parameters); 
    } 
} 
+0

因此,在我的特定實現中,圖像永遠不會保存到磁盤。該圖像作爲二進制信息保存在數據庫中,然後直接讀回網頁(MVC FileResult)。我如何壓縮圖像並保存字節?如果我從數據庫中讀取壓縮字節到一個圖像(中間),根據您的說法,它會重新膨脹大小。 – Sinaesthetic

+0

這與我目前所使用的幾乎完全相同,唯一的區別是我在返回之前將它讀回「Image」。我嘗試省略該部分並將字節數組從MemoryStream中退出,但結果相同 - 原始文件爲24k時文件爲600k。 – Sinaesthetic

+0

不知道這是多麼優化,但我有一個生產中的應用程序將圖像保存到Oracle Blob。在您的示例中,在將位圖保存到內存流之後,從流中獲取原始的btyes:'byte [] imageBytes = ms.ToArray();'並將字節數組存儲在數據庫中。你可以使用不同的編碼 - 當你從數據庫中讀回數據時,它就像你做了File.Read到一個字節數組一樣 - 注意它是一個jpg或png,而不是一個Image對象。你需要從byte []創建一個流,並加載它得到一個Image。 – Doug

-1

我相信,當您使用使用圖像的圖像創建你不應該處置的MemoryStream的。 FromStream引用流。直接從流中創建位圖也不起作用。

試試這個:

private static Image CropAndCompressImage(Image image, Rectangle rectangle, ImageFormat imageFormat) 
{ 
    using(Bitmap bitmap = new Bitmap(image)) 
    { 
     using(Bitmap cropped = bitmap.Clone(rectangle, bitmap.PixelFormat)) 
     { 
      using (MemoryStream memoryStream = new MemoryStream()) 
      { 
       cropped.Save(memoryStream, imageFormat); 
       return new Bitmap(Image.FromStream(memoryStream)); 
      } 
     } 
    } 
}