Bitmap.GetThumbnailImage 產生的縮圖品質較差(預設低品質雙線性插值)。若直接用 Graphics.DrawImage 配合 HighQualityBicubic 雖畫質佳,但輸出未壓縮的 JPEG 體積過大。解決方案:**高品質繪製 + Encoder 參數指定 JPEG 品質**。
| 方法 | API | 畫質 | 檔案大小 | 適用場景 |
|---|---|---|---|---|
| 1. 內建縮圖 | GetThumbnailImage | 低 | 小 | 快速預覽、不在意畫質 |
| 2. 高品質繪製 | Graphics.InterpolationMode = HighQualityBicubic | 高 | 大 (無壓縮) | 列印、後續再處理 |
| 3. 高品質 + 壓縮 | 方法 2 + Encoder.Quality | 高 | 小 (約原圖 1/10) | Web 縮圖、儲存空間敏感 |
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
class Program
{
const int TargetW = 190, TargetH = 190;
static void Main()
{
string src = @"G:\photoes\20060725\Picture 057.jpg";
string dir = @"E:\Diary\Test\thumbnail";
Directory.CreateDirectory(dir);
// 方法 1:內建
MakeThumb1(src, Path.Combine(dir, "th_1.jpg"));
// 方法 2:高品質繪製
MakeThumb2(src, Path.Combine(dir, "th_2.jpg"));
// 方法 3:高品質 + JPEG 壓縮 (品質 75)
MakeThumb3(src, Path.Combine(dir, "th_3.jpg"), 75L);
Console.WriteLine("完成,請比較三個檔案大小與畫質。");
Console.ReadKey();
}
// 共用:計算保持長寬比的目標尺寸
static Size CalcSize(Image src)
{
if (src.Width > src.Height)
return new Size(TargetW, (int)(src.Height * (double)TargetW / src.Width));
else
return new Size((int)(src.Width * (double)TargetH / src.Height), TargetH);
}
// 方法 1
static void MakeThumb1(string srcPath, string destPath)
{
using (var src = new Bitmap(srcPath))
using (var thumb = src.GetThumbnailImage(CalcSize(src).Width, CalcSize(src).Height, null, IntPtr.Zero))
thumb.Save(destPath);
}
// 方法 2
static void MakeThumb2(string srcPath, string destPath)
{
using (var src = new Bitmap(srcPath))
{
var sz = CalcSize(src);
using (var bmp = new Bitmap(sz.Width, sz.Height))
using (var g = Graphics.FromImage(bmp))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.Clear(Color.White);
g.DrawImage(src, 0, 0, sz.Width, sz.Height);
}
bmp.Save(destPath); // 預設無壓縮
}
}
// 方法 3:核心差異在 EncoderParameters
static void MakeThumb3(string srcPath, string destPath, long quality)
{
// 1. 取得 JPEG Encoder
var jpegCodec = ImageCodecInfo.GetImageEncoders()
.FirstOrDefault(c => c.FormatDescription == "JPEG");
if (jpegCodec == null) throw new InvalidOperationException("系統未安裝 JPEG 編碼器");
// 2. 設定品質參數 (0~100)
var ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(Encoder.Quality, quality);
using (var src = new Bitmap(srcPath))
{
var sz = CalcSize(src);
using (var bmp = new Bitmap(sz.Width, sz.Height))
using (var g = Graphics.FromImage(bmp))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.Clear(Color.White);
g.DrawImage(src, 0, 0, sz.Width, sz.Height);
}
bmp.Save(destPath, jpegCodec, ep); // 關鍵:指定編碼器與參數
}
}
}
g.Clear(Color.White) 避免透明背景存成 JPEG 變黑。Encoder.Compression + Png codec。Parallel.ForEach 多核心加速。Image.GetThumbnailImageAbort 回調取消。