C# ImageSharp图片处理 C#如何使用ImageSharp加载、编辑和保存图片文件

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

ImageSharp 加载图片时文件路径或流没释放会报错

常见错误是

System.IO.IOException: The process cannot access the file because it is being used by another process
,本质是
Image.Load
后没调用
Dispose()
,或用
using
包裹时提前把文件流关了。ImageSharp 的
Image
是 IDisposable,必须显式释放资源。

正确做法是始终用

using
块加载并处理:

using var image = Image.Load("input.jpg"); // 自动调用 Dispose()
image.Mutate(x => x.Resize(800, 600));
image.Save("output.jpg");
不要手动 new FileStream 并传给
Image.Load(stream)
后还自己
stream.Close()
—— 这会让后续
Save()
失败
如果必须复用流(比如从 HTTP 响应读取),用
Image.Load<rgba32>(stream)</rgba32>
并确保流生命周期覆盖整个图像操作
加载 WebP、AVIF 等格式需额外安装对应编码器包(如
SixLabors.ImageSharp.WebP
),否则抛
NotSupportedException

Resize 和 Crop 参数不匹配导致图像拉伸或裁剪偏移

Resize()
默认使用
ResizeMode.Stretch
,直接填宽高会强制拉伸;而
Crop()
默认按左上角裁剪,不加
Rectangle
AnchorPosition
容易切掉关键内容。

常用组合写法:

image.Mutate(x => x
    .Resize(new ResizeOptions
    {
        Size = new Size(1200, 800),
        Mode = ResizeMode.Max // 保持比例,缩放到最大边匹配
    })
    .Crop(new Rectangle(100, 50, 800, 600)) // 显式指定区域
);
ResizeMode.Crop
先等比缩放再居中裁剪,适合头像生成
ResizeMode.Pad
缩放后留黑边,需配合
PadColor
设置背景色
Crop()
Rectangle
时坐标原点在左上角,不是中心;要居中裁剪建议用
Clone().Crop(centerRect)
配合
image.Bounds()
计算

Save 保存为 JPEG 时质量控制和颜色空间问题

默认

Save("x.jpg")
用的是
JpegEncoder
的默认质量(95)和 RGB 模式,但部分老设备或打印系统要求 CMYK 或更低质量(如 75)。直接写文件名不指定编码器,就无法控制这些参数。

必须显式传入

JpegEncoder
实例:

var encoder = new JpegEncoder
{
    Quality = 82,
    ColorType = JpegColorType.Rgb // 不要设为 Cmyk(ImageSharp 目前不支持 CMYK 编码)
};
image.Save("output.jpg", encoder);
ImageSharp v3 不支持 CMYK 输出,若需 CMYK 应改用
Magick.NET
或预处理转换
WebP 保存需设置
Quality
UseAnimation
(动图才开),否则静图可能体积反而更大
保存 PNG 时若含透明通道但目标平台不支持(如某些 CMS),可先
image.Mutate(x => x.BackgroundColor(Rgba32.White))
填白底

并发处理多张图片时内存暴涨甚至 OOM

ImageSharp 默认使用托管内存(

Memory<byte></byte>
),单张大图(如 5000×4000)解码后可能占 80MB+ 内存;并发 10 张不释放,很容易触发 GC 压力或
OutOfMemoryException

关键应对点:

务必每个
Image
实例都走
using
,哪怕只是读尺寸:
using var img = Image.Load(...); var size = img.Size;
避免在 ASP.NET Core 中把
Image
存进静态集合或缓存——它不是线程安全的,且不释放就一直占内存
批量处理时加限流:用
SemaphoreSlim
控制同时最多解码 3–4 张,比无脑
Parallel.ForEach
更稳
对只读元数据场景(如提取 EXIF),用
Image.Identify()
替代
Load()
,内存占用低两个数量级

最常被忽略的是:以为

image.Dispose()
只影响像素数据,其实它还会释放内部缓存的 ICC 配置文件、EXIF 解析结果等——漏掉就等于悄悄泄漏几 MB。

相关推荐