Sử dụng System.Drawing.Common (Windows) hoặc ImageSharp (cross-platform) để resize ảnh.
Cách 1: System.Drawing.Common (Chỉ Windows / Linux với libgdiplus)
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public static void ResizeImage(string inputPath, string outputPath, int maxWidth, int maxHeight, long quality = 85L)
{
using var original = Image.FromFile(inputPath);
// Tính kích thước mới giữ aspect ratio
var newSize = CalculateNewSize(original.Width, original.Height, maxWidth, maxHeight);
using var resized = new Bitmap(newSize.Width, newSize.Height);
using var graphics = Graphics.FromImage(resized);
// Chất lượng cao
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(original, 0, 0, newSize.Width, newSize.Height);
// Encoder parameters cho JPEG quality
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
var jpegCodec = GetEncoderInfo("image/jpeg");
resized.Save(outputPath, jpegCodec, encoderParams);
}
static Size CalculateNewSize(int origW, int origH, int maxW, int maxH)
{
double ratio = Math.Min((double)maxW / origW, (double)maxH / origH);
return new Size((int)(origW * ratio), (int)(origH * ratio));
}
static ImageCodecInfo GetEncoderInfo(string mimeType)
{
return ImageCodecInfo.GetImageEncoders().FirstOrDefault(c => c.MimeType == mimeType);
}
Cách 2: ImageSharp (Cross-platform, khuyến nghị cho .NET Core/5+)
// NuGet: SixLabors.ImageSharp
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Jpeg;
public static void ResizeImageSharp(string inputPath, string outputPath, int maxWidth, int maxHeight, int quality = 85)
{
using var image = Image.Load(inputPath);
image.Mutate(x => x.Resize(new ResizeOptions
{
Mode = ResizeMode.Max, // Giữ aspect ratio, fit trong maxWidth x maxHeight
Size = new Size(maxWidth, maxHeight)
}));
image.Save(outputPath, new JpegEncoder { Quality = quality });
}
Cách 3: SkiaSharp (Cross-platform, hiệu năng cao)
// NuGet: SkiaSharp
using SkiaSharp;
public static void ResizeSkia(string inputPath, string outputPath, int maxWidth, int maxHeight, int quality = 85)
{
using var inputStream = File.OpenRead(inputPath);
using var original = SKBitmap.Decode(inputStream);
var newSize = CalculateNewSize(original.Width, original.Height, maxWidth, maxHeight);
using var resized = original.Resize(new SKImageInfo(newSize.Width, newSize.Height), SKFilterQuality.High);
using var image = SKImage.FromBitmap(resized);
using var data = image.Encode(SKEncodedImageFormat.Jpeg, quality);
using var outputStream = File.OpenWrite(outputPath);
data.SaveTo(outputStream);
}
So sánh thư viện
| Thư viện | Platform | Hiệu năng | Tính năng | Khuyến nghị |
|---|---|---|---|---|
| System.Drawing.Common | Windows (Linux cần libgdiplus) | Trung bình | Cơ bản | Legacy WinForms/WPF |
| ImageSharp | Cross-platform (managed 100%) | Tốt | Đầy đủ, fluent API | ⭐ Mới, web, cloud |
| SkiaSharp | Cross-platform (native Skia) | Rất tốt | Nâng cao, 2D graphics | High perf, mobile, game |
| Magick.NET | Cross-platform (ImageMagick) | Rất tốt | Rất đầy đủ (100+ format) | Complex processing |
Lưu ý quan trọng
- Dispose đúng cách: Image, Graphics, Bitmap, Stream đều implement IDisposable -> dùng
using. - Aspect ratio: Luôn giữ tỷ lệ để không biến dạng ảnh.
- Memory: Ảnh lớn -> load vào memory -> OOM. Dùng stream, decode bounds trước (SkiaSharp/ImageSharp hỗ trợ).
- EXIF Orientation: Ảnh từ điện thoại có thể xoay. ImageSharp/SkiaSharp tự handle, System.Drawing cần code thêm.