首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

C# 產生不失真縮圖的通用方法(等比縮放 + 高品質插值)

     編輯:ASP.NET 基礎

核心需求

  • 保持原圖長寬比,不拉伸變形。
  • 指定最大寬/高,自動計算目標尺寸。
  • 使用高品質雙三次插值,減少鋸齒。
  • 支援實體路徑與虛擬路徑(`Server.MapPath`)雙模式。

完整可重複使用類別

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Web;

public class ThumbnailHelper
{
    /// 
    /// 產生縮圖並儲存為 JPEG
    /// 
    /// 原圖路徑(虛擬或實體)
    /// 輸出路徑(虛擬或實體)
    /// 最大寬度
    /// 最大高度
    /// JPEG 品質 1-100,預設 90
    /// 是否成功
    public static bool Generate(string sourcePath, string destPath, int maxWidth, int maxHeight, int quality = 90)
    {
        try
        {
            // 1. 解析實體路徑
            string srcPhysical = ResolvePhysicalPath(sourcePath);
            string destPhysical = ResolvePhysicalPath(destPath);

            if (!File.Exists(srcPhysical)) return false;

            using (Image src = Image.FromFile(srcPhysical))
            {
                // 2. 計算等比尺寸
                Size newSize = CalcProportionalSize(src.Width, src.Height, maxWidth, maxHeight);
                if (newSize.Width >= src.Width && newSize.Height >= src.Height)
                {
                    // 原圖已小於限制,直接複製
                    File.Copy(srcPhysical, destPhysical, true);
                    return true;
                }

                // 3. 繪製高品質縮圖
                using (Bitmap bmp = new Bitmap(newSize.Width, newSize.Height))
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    g.DrawImage(src, 0, 0, newSize.Width, newSize.Height);

                    // 4. 以指定品質儲存 JPEG
                    var encoder = GetEncoder(ImageFormat.Jpeg);
                    var eps = new EncoderParameters(1);
                    eps.Param[0] = new EncoderParameter(Encoder.Quality, (long)quality);
                    bmp.Save(destPhysical, encoder, eps);
                }
            }
            return true;
        }
        catch
        {
            // 實務請記錄 Log
            return false;
        }
    }

    private static Size CalcProportionalSize(int srcW, int srcH, int maxW, int maxH)
    {
        double ratio = Math.Min((double)maxW / srcW, (double)maxH / srcH);
        return new Size((int)(srcW * ratio), (int)(srcH * ratio));
    }

    private static string ResolvePhysicalPath(string path)
    {
        if (HttpContext.Current != null && !Path.IsPathRooted(path))
            return HttpContext.Current.Server.MapPath(path);
        return path;
    }

    private static ImageCodecInfo GetEncoder(ImageFormat format)
    {
        return ImageCodecInfo.GetImageDecoders()
            .FirstOrDefault(c => c.FormatID == format.Guid);
    }
}

呼叫範例

// 在 .aspx.cs 或 .ashx 中
bool ok = ThumbnailHelper.Generate(
    "~/Uploads/photo.jpg",   // 來源虛擬路徑
    "~/Thumbs/photo_300.jpg", // 目標虛擬路徑
    300, 300,                 // 最大 300x300
    90                        // 品質 90
);

常見坑點與解決

問題原因解決
GIF 透明背景變黑直接 DrawImage 不處理透明通道建立 Bitmap 時指定 `PixelFormat.Format32bppArgb`,並 `g.Clear(Color.Transparent)`
大圖 OutOfMemoryException一次載入完整像素陣列改用 `Image.GetThumbnailImageAbort` 回呼或分塊處理;或限制最大像素數(如 4000x4000)
儲存後檔案被鎖定`Image.FromFile` 鎖定檔案改用 `using (var fs = new FileStream(...)) { Image.FromStream(fs); }` 或 `File.Copy` 到暫存檔再載入

.NET Core / .NET 6+ 遷移提示

`System.Drawing.Common` 在非 Windows 平台僅支援基本功能,建議改用 ImageSharp 或 Magick.NET 取得跨平台高效能影像處理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved