在做Web項目時,發現大量高品質圖檔加載嚴重影響性能。于是考慮進行圖檔壓縮預處理,也就是将高清圖檔等比壓縮成低品質圖檔,當使用者點選某張圖檔時再加載顯示該圖檔高清原圖。剛開始用C# Graphics DrawImage重繪方式批量進行圖檔壓縮。但是通過測試發現15M大小以上的圖檔進行重繪時就會出現記憶體不足異常(當然這個異常情況可能因不同電腦有所不同,也許有的電腦10M的圖檔進行Graphics重繪時就會出現異常)。通過Google、MSDN尋求各種方法,都無法解決Graphics對大圖檔重繪出現記憶體不足的異常。于是放棄治療,到Githup、CodePlex等等開源社群去找開源圖像操作庫,無意中發現開源庫Magick.NET。Magick.NET從名字上就能讓人隐約感覺到這個類庫并非使用.NET寫的。其實它是對ImageMagick的.NET封裝,而ImageMagick是一個很強大的圖像操作庫,支援超過 100 種的檔案格式。像圖檔壓縮這種操作,ImageMagick處理起來輕輕松松。使用ImageMagick庫.NET封裝的庫Magick.NET進行1GB的tif圖生成縮略圖操作(也就是圖檔壓縮),一點問題都沒有。當然1GB大小的tif圖處理起來肯定需要些時間,将1GB的tif圖按1%比例等比壓縮,生成一張新的圖檔大概需要2~3鐘(時間長短因電腦組態會有所不同)。
另外一點使用Magick.NET要注意,Magick.NET有64/32位之分,當然也有适應64/32位系統的庫。也就是說Magick.NET有三個版本,32位、64位以及AndyCPU版。使用時還需注意資源的釋放,.NET的程式員習慣把資源回收任務交給.NET垃圾回收機制進行處理。其實對于消耗資源的操作,必要時應該手動釋放資源,畢竟.NET垃圾回收不是萬能的,批量操作很有可能導緻資源無法及時釋放而出異常,嚴重點也許會爆記憶體。
- 方案一:使用Magick.NET壓縮圖檔(推薦)
/// <summary>
/// 生成縮略圖
/// </summary>
/// <param name="srcFileName">源圖像檔案</param>
/// <param name="destFileName">目标圖像檔案</param>
/// <param name="width">指定壓縮寬度</param>
/// <param name="height">指定壓縮高度</param>
private void MakeThumbnail(string srcFileName, string destFileName, int width, int height)
{
using (MagickImage image = new MagickImage(srcFileName))
{
if (width <= )
width = (int)Math.Ceiling(image.Width * GetScale(image.Height, height));
if (height <= )
height = (int)Math.Ceiling(image.Height * GetScale(image.Width, width));
image.Thumbnail(width, height);
image.Write(destFileName);
}
}
/// <summary>
/// 生成縮略圖
/// </summary>
/// <param name="srcFileName">源圖像檔案</param>
/// <param name="destFileName">目标圖像檔案</param>
/// <param name="percent">等比壓縮比例</param>
private void MakeThumbnail(string srcFileName, string destFileName, int percent)
{
using (MagickImage image = new MagickImage(srcFileName))
{
image.Thumbnail(new Percentage(percent));
image.Write(destFileName);
}
}
C# Magick.NET圖檔壓縮完整代碼
- 方案二:使用.NET Graphics重繪方式壓縮圖檔(壓縮大圖檔不建議使用)
#region 生成縮略圖
///<summary>
/// 生成縮略圖
/// </summary>
/// <param name="originalImagePath">源圖路徑(實體路徑)</param>
/// <param name="thumbnailPath">縮略圖路徑(實體路徑)</param>
/// <param name="width">縮略圖寬度</param>
/// <param name="height">縮略圖高度</param>
/// <param name="mode">生成縮略圖的方式</param>
public void MakeThumbnail(string originalImagePath, string thumbnailPath, int width, int height, ThumbnailMode mode, out string outthumbnailPath)
{
System.Drawing.Image originalImage = System.Drawing.Image.FromFile(originalImagePath);
int towidth = width;
int toheight = height;
int x = ;
int y = ;
int ow = originalImage.Width;
int oh = originalImage.Height;
switch (mode)
{
case ThumbnailMode.HeightAndWidth://指定高寬縮放(可能變形)
break;
case ThumbnailMode.Width://指定寬,高按比例
toheight = originalImage.Height * width / originalImage.Width;
break;
case ThumbnailMode.Height://指定高,寬按比例
towidth = originalImage.Width * height / originalImage.Height;
break;
case ThumbnailMode.Cut://指定高寬裁減(不變形)
if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
{
oh = originalImage.Height;
ow = originalImage.Height * towidth / toheight;
y = ;
x = (originalImage.Width - ow) / ;
}
else
{
ow = originalImage.Width;
oh = originalImage.Width * height / towidth;
x = ;
y = (originalImage.Height - oh) / ;
}
break;
default:
break;
}
//建立一個bmp圖檔
System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);
//建立一個畫闆
Graphics g = System.Drawing.Graphics.FromImage(bitmap);
//設定高品質插值法
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
//設定高品質,低速度呈現平滑程度
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//清空畫布并以透明背景色填充
g.Clear(Color.Transparent);
//在指定位置并且按指定大小繪制原圖檔的指定部分
g.DrawImage(originalImage, new Rectangle(, , towidth, toheight),
new Rectangle(x, y, ow, oh),
GraphicsUnit.Pixel);
try
{
//以jpg格式儲存縮略圖
bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg);
outthumbnailPath = thumbnailPath;
}
catch (System.Exception e)
{
throw e;
}
finally
{
originalImage.Dispose();
bitmap.Dispose();
g.Dispose();
}
}
public enum ThumbnailMode
{
/// <summary>
/// 指定高寬縮放(可能變形)
/// </summary>
HeightAndWidth = ,
/// <summary>
/// 指定寬,高按比例
/// </summary>
Height = ,
/// <summary>
/// 指定寬,高按比例
/// </summary>
Width = ,
/// <summary>
/// 指定高寬裁減(不變形)
/// </summary>
Cut =
}
#endregion