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

ASP.NET 高質量縮略圖生成通用函數:四種模式、插值算法、資源管理與效能優化

     編輯:關於C語言

核心需求

Web 專案頻繁需求:**上傳原圖 → 伺服器生成多種尺寸縮略圖 (列表圖、詳情圖、輪播圖) → 前端按需載入**。關鍵指標:**不變形、清晰度高、記憶體可控、支援多種裁剪模式**。

完整通用函數 (現代化重構)

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

public static class ThumbnailHelper
{
    /// 
    /// 生成高質量縮略圖
    /// 
    /// 原圖物理路徑
    /// 輸出縮略圖物理路徑
    /// 目標寬度
    目標高度
    模式: HW(強制縮放), W(寬固定高自適應), H(高固定寬自適應), Cut(裁剪填滿不變形)
    /// JPEG 品質 1-100 (預設 90)
    /// 輸出格式 (預設 Jpeg)
    public static void MakeThumbnail(
        string originalPath, 
        string thumbnailPath, 
        int width, 
        int height, 
        string mode = "Cut",
        long quality = 90,
        ImageFormat format = null)
    {
        if (!File.Exists(originalPath)) throw new FileNotFoundException("原圖不存在", originalPath);
        if (width <= 0 || height <= 0) throw new ArgumentOutOfRangeException("寬高必須 > 0");

        format ??= ImageFormat.Jpeg;

        using (Image original = Image.FromFile(originalPath))
        {
            int ow = original.Width;
            int oh = original.Height;
            int targetW = width;
            int targetH = height;
            int srcX = 0, srcY = 0, srcW = ow, srcH = oh;

            // 計算來源裁剪區域與目標尺寸
            switch (mode.ToUpperInvariant())
            {
                case "HW": // 強制縮放 (可能變形)
                    break; // 全圖來源、全尺寸目標

                case "W": // 寬固定,高等比
                    targetH = (int)Math.Round(oh * width / (double)ow);
                    break;

                case "H": // 高固定,寬等比
                    targetW = (int)Math.Round(ow * height / (double)oh);
                    break;

                case "CUT": // 裁剪填滿 (不變形,居中裁剪)
                    double targetRatio = (double)width / height;
                    double sourceRatio = (double)ow / oh;

                    if (sourceRatio > targetRatio) // 原圖較寬 → 裁剪左右
                    {
                        srcH = oh;
                        srcW = (int)Math.Round(oh * targetRatio);
                        srcX = (ow - srcW) / 2;
                    }
                    else // 原圖較高 → 裁剪上下
                    {
                        srcW = ow;
                        srcH = (int)Math.Round(ow / targetRatio);
                        srcY = (oh - srcH) / 2;
                    }
                    break;

                default:
                    throw new ArgumentException($"不支援的模式: {mode}");
            }

            // 建立目標位圖
            using (var bitmap = new Bitmap(targetW, targetH, PixelFormat.Format32bppArgb))
            using (var g = Graphics.FromImage(bitmap))
            {
                // 高質量繪圖設定
                g.InterpolationMode = InterpolationMode.HighQualityBicubic; // 雙三次插值 (縮放最佳)
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                
                // 背景透明 (PNG/WebP 需要);JPEG 會填黑,可先填白
                if (format == ImageFormat.Png || format.Guid == ImageFormat.Webp.Guid)
                    g.Clear(Color.Transparent);
                else
                    g.Clear(Color.White);

                // 繪製:來源矩形 → 目標矩形
                g.DrawImage(original, 
                    new Rectangle(0, 0, targetW, targetH), 
                    new Rectangle(srcX, srcY, srcW, srcH), 
                    GraphicsUnit.Pixel);

                // 保存:JPEG 品質控制
                if (format == ImageFormat.Jpeg)
                {
                    var encoderParams = new EncoderParameters(1);
                    encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
                    var jpegCodec = GetEncoderInfo("image/jpeg");
                    bitmap.Save(thumbnailPath, jpegCodec, encoderParams);
                }
                else
                {
                    bitmap.Save(thumbnailPath, format);
                }
            }
        }
    }

    private static ImageCodecInfo GetEncoderInfo(string mimeType)
    {
        return ImageCodecInfo.GetImageEncoders().FirstOrDefault(c => c.MimeType == mimeType);
    }
}

四大模式視覺化對比

模式參數意義輸出尺寸變形適用場景
HW寬、高皆強制完全符合指定 W×H✅ 可能變形固定版面佔位、不介意比例
W指定寬,高自動等比寬=指定,高=計算❌ 保持比例列表圖、卡片寬度固定
H指定高,寬自動等比高=指定,寬=計算❌ 保持比例時間軸、固定高度區塊
Cut指定寬高,**裁剪填滿**完全符合指定 W×H❌ **不變形** (居中裁剪)**頭像、輪播圖、封面圖** 首選

關鍵技術點深度解析

1. 插值算法選擇

  • `HighQualityBicubic` (雙三次):**縮放品質最佳**,適合照片、複雜圖像,計算量較大。
  • `HighQualityBilinear` (雙線性):**速度較快**,品質次之,適合簡單圖形/即時預覽。
  • `NearestNeighbor` (最近鄰):**最快**,適合像素風/QR Code/圖示放大,邊緣鋸齒明顯。
  • **建議**:預設 `HighQualityBicubic`,大圖批次處理可降為 `Bilinear` 平衡效能。

2. JPEG 品質與檔案大小平衡

  • `Encoder.Quality` 範圍 0-100 (長整數)。
  • **75-90** 為黃金區間:肉眼近乎無損、檔案大小適中。
  • >95 檔案暴增、品質提升肉眼難辨;<60 明顯伪影。

3. 記憶體管理鐵律

  • **所有 `Image`、`Bitmap`、`Graphics`、`EncoderParameters` 必須 `using` / `Dispose()`**。
  • `Image.FromFile` **鎖定檔案**直到 Dispose,不可在 using 內再次存取同檔案。
  • 大圖 (如 4000x3000) 解碼佔用 **寬×高×4 bytes ≈ 48MB** 非託管記憶體,**並發處理必須限制併發數** (SemaphoreSlim / Channel)。
  • **串流替代**:`Image.FromStream(stream)` 避免檔案鎖定,配合 `File.OpenRead` 即讀即釋放。

4. GDI+ 併發限制與替代方案

方案優點缺點適用場景
System.Drawing (GDI+)內建、API 熟悉、Windows 相容**非執行緒安全**、大量併發易崩潰、Linux/macOS 需 libgdiplus、效能一般低併發、傳統 .NET Framework、Windows 專用
ImageSharp (SixLabors)**全託管、執行緒安全、跨平台、效能優、API 現代**、支援 WebP/AVIF需 NuGet 套件、API 與 GDI+ 不同**現代 .NET Core/5+ 專案首選**
SkiaSharpGoogle Skia 引擎、極高效能、跨平台、功能豐富 (濾鏡、向量、文字)較大原生庫、學習曲線陡高效能、複雜圖形處理、跨平台
Magick.NET (ImageMagick)格式支援最全 (HEIC/RAW/PSD...)、命令列級功能原生依賴重、部署複雜專業圖像處理管線

ImageSharp 版本範例 (推薦現代專案)

// NuGet: SixLabors.ImageSharp, SixLabors.ImageSharp.Processing
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Jpeg;

public static void MakeThumbnailSharp(string input, string output, int w, int h, string mode = "cut", int quality = 90)
{
    using var img = Image.Load(input);
    var options = new ResizeOptions
    {
        Mode = mode.ToLower() switch
        {
            "hw" => ResizeMode.Stretch,
            "w" => ResizeMode.Max, // 寬固定
            "h" => ResizeMode.Max, // 高固定 (需調整邏輯)
            "cut" => ResizeMode.Crop,
            _ => ResizeMode.Crop
        },
        Sampler = KnownResamplers.Lanczos3 // 高質量重採樣
    };

    if (mode.ToLower() == "w") options.Size = new Size(w, 0);
    else if (mode.ToLower() == "h") options.Size = new Size(0, h);
    else options.Size = new Size(w, h);

    img.Mutate(x => x.Resize(options));
    
    img.Save(output, new JpegEncoder { Quality = quality });
}

部署與效能優化清單

  1. **非同步處理**:上傳後回傳 202 Accepted,背景服務 (Hangfire/BackgroundService) 生成縮略圖,避免阻塞請求執行緒。
  2. **快取策略**:CDN / 輸出快取 / `ETag` / `Cache-Control: public, max-age=31536000`,縮略圖 URL 包含尺寸參數 (`/thumb/w200h200cut/image.jpg`)。
  3. **即時生成 vs 預生成**:流量大預生成所有規格;流量小/規格多用 **即時生成 + 快取落地** (首次請求生成存檔,後續直返靜態檔)。
  4. **記憶體限制**:容器部署設定 `--memory` / `GCHeapHardLimit`,防止大圖解碼 OOM。
  5. **安全驗證**:上傳端驗證 MIME (`image/jpeg`, `image/png`)、Magic Bytes、尺寸上限、檔案大小上限。

總結

高質量縮略圖生成核心在於:**模式選擇 (Cut 為王)、插值算法 (Bicubic/Lanczos)、JPEG 品質 (85-90)、嚴格資源釋放**。**舊專案維護用 GDI+ 封裝函數即可;新專務必遷移至 ImageSharp**,獲得執行緒安全、跨平台、現代 API、更好效能與格式支援。配合**非同步背景生成 + CDN 快取**,構建高效能、可擴展的圖片處理管線。

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