問題現象
使用 Graphics.DrawImage 放大圖片時,預設插值模式為 InterpolationMode.Default (雙三次插值),導致:
- 邊緣模糊、鋸齒明顯
- 像素風格圖片 (像素藝術、遊戲素材) 失去銳利邊緣
- 放大後圖片左上角缺少半個像素 (座標偏移問題)
解決方案:最近鄰居插值 + 半像素偏移
using System.Drawing;
using System.Drawing.Drawing2D;
public static Bitmap ScaleImageNearestNeighbor(Image source, int scaleFactor) {
int newWidth = source.Width * scaleFactor;
int newHeight = source.Height * scaleFactor;
Bitmap result = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(result)) {
// 關鍵 1:最近鄰居插值 - 保留硬邊緣,適合像素圖
g.InterpolationMode = InterpolationMode.NearestNeighbor;
// 關鍵 2:半像素偏移 - 修正左上角缺失半像素問題
g.PixelOffsetMode = PixelOffsetMode.Half;
// 可選:關閉抗鋸齒以獲得純淨像素風格
g.SmoothingMode = SmoothingMode.None;
g.DrawImage(source, 0, 0, newWidth, newHeight);
}
return result;
}
插值模式比較
| 模式 | 適用場景 | 特點 |
NearestNeighbor | 像素藝術、遊戲素材、QR Code、條碼 | 無模糊、邊緣銳利、放大呈現方塊狀 |
Bilinear | 一般照片縮小 | 速度快、品質中等 |
Bicubic (Default) | 一般照片放大 | 平滑、但邊緣軟化 |
HighQualityBicubic | 高品質照片放大 | 最佳平滑度、運算最慢 |
像素偏移模式說明
| 模式 | 行為 |
Default | 座標對齊像素網格左上角,放大時產生半像素偏移 |
Half | 座標偏移 0.5 像素,使像素中心對齊,修正邊界缺失 |
HighQuality | 高品質下採樣時使用 |
完整封裝工具類別
public static class ImageScaler {
public enum ScaleMode {
PixelArt, // 像素風格:NearestNeighbor + Half
Photo, // 照片:HighQualityBicubic
Fast, // 快速:Bilinear
}
public static Bitmap Scale(Image source, int targetWidth, int targetHeight, ScaleMode mode = ScaleMode.Photo) {
Bitmap result = new Bitmap(targetWidth, targetHeight);
using (Graphics g = Graphics.FromImage(result)) {
switch (mode) {
case ScaleMode.PixelArt:
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.SmoothingMode = SmoothingMode.None;
break;
case ScaleMode.Photo:
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
break;
case ScaleMode.Fast:
g.InterpolationMode = InterpolationMode.Bilinear;
break;
}
g.DrawImage(source, 0, 0, targetWidth, targetHeight);
}
return result;
}
// 等比例縮放
public static Bitmap ScaleByFactor(Image source, int factor, ScaleMode mode = ScaleMode.Photo) {
return Scale(source, source.Width * factor, source.Height * factor, mode);
}
}
使用範例
// 像素圖放大 8 倍
using (Image pixelArt = Image.FromFile("sprite.png")) {
Bitmap scaled = ImageScaler.ScaleByFactor(pixelArt, 8, ImageScaler.ScaleMode.PixelArt);
scaled.Save("sprite_8x.png", ImageFormat.Png);
}
// 照片高品質放大 2 倍
using (Image photo = Image.FromFile("photo.jpg")) {
Bitmap scaled = ImageScaler.ScaleByFactor(photo, 2, ImageScaler.ScaleMode.Photo);
scaled.Save("photo_2x.jpg", ImageFormat.Jpeg);
}