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

C# 產生圖片縮圖完整指南:GetThumbnailImage、高畫質縮放、比例保持、記憶體管理

     編輯:關於C語言

核心 API 比較

方法命名空間畫質效能特點
Image.GetThumbnailImageSystem.Drawing低 (內建縮放演算法簡單)極快 (原生 GDI+)無需額外程式碼、支援回呼取消
Graphics.DrawImage + InterpolationMode.HighQualityBicubicSystem.Drawing高 (雙三次插值)中等完整控制插值模式、可加銳化
Bitmap.Clone + 縮放System.Drawing中快適用裁切後縮放
ImageSharp / SkiaSharpNuGet 套件最高 (Lanczos、Mitchell、Catmull-Rom)好 (純 managed、跨平台)伺服器端/容器/無 GDI+ 環境首選

方案一:GetThumbnailImage 簡易版 (原文改良)

public static void CreateThumbnailSimple(string sourcePath, string destPath, int maxWidth, int maxHeight, long quality = 85L)
{
    using var srcImage = Image.FromFile(sourcePath);
    // 計算目標尺寸 (保持比例)
    var (thumbW, thumbH) = CalculateDimensions(srcImage.Width, srcImage.Height, maxWidth, maxHeight);

    // GetThumbnailImage 回呼 (必須回傳 false 繼續)
    Image.GetThumbnailImageAbort callback = () => false;
    using var thumbnail = srcImage.GetThumbnailImage(thumbW, thumbH, callback, IntPtr.Zero);
    
    // 儲存為 JPEG 並指定品質
    var encoderParams = new EncoderParameters(1);
    encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
    var jpegCodec = GetEncoderInfo("image/jpeg");
    thumbnail.Save(destPath, jpegCodec, encoderParams);
}

private static (int w, int h) CalculateDimensions(int srcW, int srcH, int maxW, int maxH)
{
    double ratio = Math.Min((double)maxW / srcW, (double)maxH / srcH);
    if (ratio >= 1) return (srcW, srcH); // 原圖較小,不放大
    return ((int)(srcW * ratio), (int)(srcH * ratio));
}

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

方案二:Graphics 高畫質縮放 (推薦桌面應用)

public static void CreateThumbnailHighQuality(string sourcePath, string destPath, int maxWidth, int maxHeight, long quality = 90L)
{
    using var srcImage = Image.FromFile(sourcePath);
    var (thumbW, thumbH) = CalculateDimensions(srcImage.Width, srcImage.Height, maxWidth, maxHeight);

    using var bitmap = new Bitmap(thumbW, thumbH);
    bitmap.SetResolution(srcImage.HorizontalResolution, srcImage.VerticalResolution);

    using var g = Graphics.FromImage(bitmap);
    // 高畫質設定
    g.InterpolationMode = InterpolationMode.HighQualityBicubic; // 雙三次插值
    g.SmoothingMode = SmoothingMode.HighQuality;
    g.PixelOffsetMode = PixelOffsetMode.HighQuality;
    g.CompositingQuality = CompositingQuality.HighQuality;

    // 繪製 (來源矩形 → 目標矩形)
    g.DrawImage(srcImage, 0, 0, thumbW, thumbH);

    // 可選:銳化濾鏡 (Unsharp Mask) 提升銳度
    // ApplyUnsharpMask(bitmap);

    SaveJpeg(bitmap, destPath, quality);
}

private static void SaveJpeg(Image img, string path, long quality)
{
    var eps = new EncoderParameters(1);
    eps.Param[0] = new EncoderParameter(Encoder.Quality, quality);
    var codec = ImageCodecInfo.GetImageEncoders().First(c => c.MimeType == "image/jpeg");
    img.Save(path, codec, eps);
}

方案三:ImageSharp 跨平台高效能版 (推薦 ASP.NET Core / Linux 容器)


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

public static async Task CreateThumbnailImageSharpAsync(string sourcePath, string destPath, int maxWidth, int maxHeight, int quality = 85)
{
    using var image = await Image.LoadAsync(sourcePath);
    image.Mutate(x => x.Resize(new ResizeOptions
    {
        Mode = ResizeMode.Max,           // 保持比例、不放大
        Size = new Size(maxWidth, maxHeight),
        Sampler = KnownResamplers.Lanczos3 // 高畫質 Lanczos 3-lobes
    }));

    await image.SaveAsync(destPath, new JpegEncoder { Quality = quality });
}

方案四:批次處理與記憶體優化

public static async Task BatchCreateThumbnailsAsync(string sourceDir, string destDir, int maxSize, int maxDegreeOfParallelism = 4)
{
    Directory.CreateDirectory(destDir);
    var files = Directory.GetFiles(sourceDir, "*.*", SearchOption.TopDirectoryOnly)
        .Where(f => IsImageFile(f)).ToList();

    var options = new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism };
    await Parallel.ForEachAsync(files, options, async (file, ct) =>
    {
        try
        {
            string destFile = Path.Combine(destDir, Path.GetFileNameWithoutExtension(file) + "_thumb.jpg");
            // 根據環境選擇實作
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                CreateThumbnailHighQuality(file, destFile, maxSize, maxSize);
            else
                await CreateThumbnailImageSharpAsync(file, destFile, maxSize, maxSize);
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"縮圖失敗 {file}: {ex.Message}");
        }
    });
}

private static bool IsImageFile(string path)
{
    string ext = Path.GetExtension(path).ToLowerInvariant();
    return ext is ".jpg" or ".jpeg" or ".png" or ".bmp" or ".gif" or ".tiff" or ".webp";
}

常見問題與解決

問題原因解決
縮圖模糊/鋸齒GetThumbnailImage 使用低品質縮放改用 Graphics.HighQualityBicubic 或 ImageSharp Lanczos3
GDI+ 一般性錯誤 / OutOfMemory圖片過大 (如 100MP 以上)、檔案損毀、CMYK JPEG 不支援先檢查尺寸、嘗試 ImageSharp (無尺寸限制)、轉檔為 RGB
縮圖比例變形寬高皆強制指定未保持比例使用 CalculateDimensions 或 ResizeMode.Max
透明背景變黑PNG/GIF 透明通道在 JPEG 儲存遺失儲存為 PNG、或合成白背景後存 JPEG
EXIF 方向標籤未套用手機照片含 Orientation 標籤,GDI+ 不自動旋轉ImageSharp 自動處理、或手動讀 EXIF 旋轉
ASP.NET Core Linux 容器報錯System.Drawing 依賴 libgdiplus,非原生支援改用 ImageSharp/SkiaSharp 純 managed 實作

效能基準 (測試環境: i7-12700H, 1920x1080 → 300x300, 100 張 JPEG)

GetThumbnailImage:     ~1.2 秒 (最快,畫質最低)
Graphics Bicubic:      ~2.8 秒 (畫質佳,CPU 密集)
ImageSharp Lanczos3:   ~3.5 秒 (畫質最佳,純 managed)
SkiaSharp Lanczos3:    ~2.5 秒 (需原生庫,跨平台最佳平衡)

選型建議

  • WinForms/WPF 桌面應用、小量縮圖:Graphics.HighQualityBicubic 畫質/速度平衡佳。
  • ASP.NET Core / Linux 容器 / 雲端服務:ImageSharp 純 managed、無原生相依、支援最新影像格式 (AVIF, WebP, HEIC)。
  • 高效能批次處理、需原生加速:SkiaSharp (Skia 圖形引擎,Chrome/Firefox 同款)。
  • 極簡單需求、相容 .NET Framework 2.0+:GetThumbnailImage 一行搞定。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved