C# 图片压缩方法 C#如何实现图片大小压缩

来源:这里教程网 时间:2026-02-21 17:40:08 作者:

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;
<p>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);
}</p><p>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);
<pre class='brush:php;toolbar:false;'>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 的质量控制),同时保留透明度。

常见误区:以为 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;
<p>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+,无句柄泄漏风险

真正麻烦的从来不是“怎么压”,而是压完几百张后程序卡死或报错——那大概率是资源没清干净,而不是算法不对。

相关推荐