Bitmap.GetThumbnailImage 生成的縮略圖品質較差。本文展示三種方案遞進:內建方法、Graphics 高質量雙三次插值、加入 JPEG 編碼器參數壓縮,兼顧清晰度與檔案大小。
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace ThumbnailDemo
{
class Program
{
const int TARGET_W = 190, TARGET_H = 190;
static void Main()
{
string src = @"G:\photos\source.jpg";
string destDir = @"E:\Thumbnails";
Method1_GetThumbnailImage(src, destDir);
Method2_GraphicsHighQuality(src, destDir);
Method3_GraphicsPlusJpegCompression(src, destDir);
Console.ReadKey();
}
// 方案 1:內建 GetThumbnailImage(品質最低)
static void Method1_GetThumbnailImage(string src, string destDir)
{
using (var source = new Bitmap(src))
{
CalcSize(source, out int w, out int h);
using (var thumb = source.GetThumbnailImage(w, h, null, IntPtr.Zero))
thumb.Save(Path.Combine(destDir, "th_1.jpg"));
}
}
// 方案 2:Graphics 高質量雙三次插值
static void Method2_GraphicsHighQuality(string src, string destDir)
{
using (var source = new Bitmap(src))
{
CalcSize(source, out int w, out int h);
using (var thumb = new Bitmap(w, h))
using (var g = Graphics.FromImage(thumb))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.FillRectangle(Brushes.White, 0, 0, w, h);
g.DrawImage(source, 0, 0, w, h);
thumb.Save(Path.Combine(destDir, "th_2.jpg"));
}
}
}
// 方案 3:方案 2 + JPEG 壓縮品質 75%
static void Method3_GraphicsPlusJpegCompression(string src, string destDir)
{
// 設定 JPEG 編碼器參數
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 75L);
var jpegCodec = ImageCodecInfo.GetImageEncoders()
.FirstOrDefault(c => c.FormatDescription == "JPEG");
using (var source = new Bitmap(src))
{
CalcSize(source, out int w, out int h);
using (var thumb = new Bitmap(w, h))
using (var g = Graphics.FromImage(thumb))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.FillRectangle(Brushes.White, 0, 0, w, h);
g.DrawImage(source, 0, 0, w, h);
thumb.Save(Path.Combine(destDir, "th_3.jpg"), jpegCodec, encoderParams);
}
}
}
static void CalcSize(Bitmap source, out int w, out int h)
{
w = TARGET_W; h = TARGET_H;
if (source.Width > source.Height)
h = (int)(source.Height * ((decimal)TARGET_W / source.Width));
else
w = (int)(source.Width * ((decimal)TARGET_H / source.Height));
}
}
}
| 方案 | 清晰度 | 檔案大小 | 速度 |
|---|---|---|---|
| 1. GetThumbnailImage | 低(預設雙線性) | 中 | 最快 |
| 2. Graphics HighQualityBicubic | 高(銳利、無鋸齒) | 大(無壓縮或預設壓縮) | 中 |
| 3. + JPEG Quality 75% | 高 | **小(約方案 2 的 1/10)** | 中 |
GetImageEncoders() 尋找 JPEG 編碼器。CalcSize 依長邊縮放,短邊等比例計算。Parallel.ForEach 並行化。Image.FromStream 避免檔案鎖定。結合 Graphics 高質量插值與 JPEG 編碼器參數,即可獲得兼具清晰度與小體積的縮略圖。方案 3 為實務專案推薦做法。