Image.Save配合EncoderParameters控制JPEG质量是最常用压缩方式,仅适用于JPEG格式,需显式指定JpegCodec和Quality参数(long类型,0–100),默认保存不压缩;缩放应结合高质插值;PNG透明图宜用ImageSharp有损压缩;批量处理须防GDI+句柄泄漏。

用 Image.Save 配合 EncoderParameters 控制 JPEG 质量
这是最常用、效果直接的压缩方式,只适用于 Jpeg 格式。核心是降低质量参数(EncoderParameter 中的 Quality),数值范围 0–100,通常设为 70–85 就能在肉眼难辨失真的前提下显著减小体积。
常见错误:直接调用 image.Save("out.jpg") 不指定编码器,会用默认高质量(接近 100),根本压不动。
- 必须显式创建
JpegCodec并传入EncoderParameters -
Quality是long类型,不是int或float,传错类型会抛ArgumentException - 源图如果是 PNG 或 BMP,先用
Image.FromFile加载再保存为 JPEG,格式转换本身就会大幅降体积
using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices;public static void SaveAsJpegWithQuality(Image source, string path, long quality = 80) { var jpegEncoder = GetEncoder(ImageFormat.Jpeg); var encoderParams = new EncoderParameters(1); encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality); source.Save(path, jpegEncoder, encoderParams); }
private static ImageCodecInfo GetEncoder(ImageFormat format) { var codecs = ImageCodecInfo.GetImageEncoders(); return codecs.FirstOrDefault(c => c.FormatID == format.Guid); }
用 Bitmap 缩放尺寸再压缩,兼顾分辨率与体积
单纯调质量参数压到很低(如 30)会导致明显模糊;而先缩小像素尺寸(比如宽高各缩到 70%),再以中等质量(75)保存,往往获得更优的清晰度/体积比。
注意:缩放不是无损操作,Bitmap 构造时若不指定插值模式,默认用低质量双线性,边缘易发虚。
- 务必设置
Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic - 缩放比例建议用
Math.Max(0.3, Math.Min(0.9, ratio))限制在合理区间,避免过度压缩或无效缩放 - 原始尺寸过大(如 >5000px)时,分两轮缩放(先缩到 2000px 再缩到目标)比单次缩放抗锯齿效果更好
public static Image ResizeImage(Image source, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / source.Width;
var ratioY = (double)maxHeight / source.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int)(source.Width * ratio);
var newHeight = (int)(source.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(newImage))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(source, 0, 0, newWidth, newHeight);
}
return newImage;}
处理 PNG 时别硬转 JPEG:用 ImageSharp 保持透明 + 有损压缩
如果原图是带 Alpha 通道的 PNG,强行用上面的 JPEG 方式会丢失透明背景,变成白底或黑底。这时应优先考虑现代库,比如 ImageSharp,它支持对 PNG 启用有损压缩(类似 JPEG 的质量控制),同时保留透明度。
基于HTML5的图片裁剪插件
基于HTML5的图片裁剪插件,所见即所得的裁剪方式,可生成多张缩略图大小图片,基于HTML5 canvas
绘图实现,支持各种效果的裁剪,当然你如果需要保存图片还是需要后端服务程序裁剪图片,裁剪页面是基于Bootstrap框架实现。
下载
常见误区:以为 PNG 只能无损,其实 ImageSharp 的 PngEncoder 有 CompressionLevel 和实验性 PaletteQuantization,可有效控体积。
- 需安装 NuGet 包:
ImageSharp和ImageSharp.Drawing -
CompressionLevel是 0–11(对应 zlib 级别),设为 6 已有明显压缩效果,且编码速度可接受 - 若允许轻微颜色失真,启用
QuantizeAlpha = true和MaxColors = 256可进一步减小 PNG 体积
using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png;public static async Task SavePngWithCompression(string inputPath, string outputPath, int compressionLevel = 6) { using var image = await Image.LoadAsync(inputPath); var encoder = new PngEncoder { CompressionLevel = (PngCompressionLevel)compressionLevel, QuantizeAlpha = true, MaxColors = 256 }; await image.SaveAsync(outputPath, encoder); }
批量压缩时注意内存和 GDI+ 句柄泄漏
循环处理上百张图时,仅靠 using 不一定能及时释放底层 GDI+ 资源,尤其在 Windows 上容易触发 OutOfMemoryException 或“参数无效”错误——这往往是句柄耗尽的表现,而非真内存不足。
关键点不在代码写法多漂亮,而在资源释放是否真正及时、彻底。
- 对每个
Image实例,确保在using块内完成所有操作,不要跨块复用 - 避免在循环里反复调用
Image.FromFile后不立即释放;改用File.ReadAllBytes+MemoryStream加载,可绕过部分 GDI+ 锁文件问题 - 在 .NET 6+ 中,优先用
ImageSharp替代System.Drawing,它不依赖 GDI+,无句柄泄漏风险
真正麻烦的从来不是“怎么压”,而是压完几百张后程序卡死或报错——那大概率是资源没清干净,而不是算法不对。









