Image.FromFile存在文件锁问题,应改用FileStream+FromStream;缩放需设置HighQualityBicubic、Half偏移和抗锯齿;JPEG保存须用EncoderParameters控质量;超大图推荐ImageSharp或Bitmap(Size)构造函数;需手动处理DPI与EXIF。

用 Image.FromFile 读取图片时要注意文件锁问题
直接调用 Image.FromFile("xxx.jpg") 会以只读+独占方式打开文件,后续若想覆盖保存或被其他进程访问就会失败,常见报错是 System.IO.IOException: The process cannot access the file...。实际项目中更稳妥的做法是先用 FileStream 打开再构造 Image:
- 使用
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); - 再调用
Image.FromStream(fs),这样流关闭后文件就释放了 - 如果只是读取元数据(比如尺寸),可用
ImageCodecInfo.GetImageDecoders()配合小缓冲区解析,避免加载整图
用 Graphics.DrawImage 缩放图片要设好插值和像素模式
单纯用 new Bitmap(width, height) 创建目标画布,再用 Graphics.FromImage 绘制原图,缩放质量取决于绘图设置。默认的 Graphics.InterpolationMode 是 Low,边缘锯齿明显;PixelOffsetMode 不设也会导致模糊偏移。
- 务必设置
g.InterpolationMode = InterpolationMode.HighQualityBicubic; - 加上
g.PixelOffsetMode = PixelOffsetMode.Half;消除1像素偏移 - 启用抗锯齿:
g.SmoothingMode = SmoothingMode.HighQuality; - 注意:
DrawImage的重载很多,推荐用带Rectangle目标区域 +Rectangle源区域的版本,控制裁剪与拉伸逻辑
保存为 JPEG 时用 EncoderParameters 控制压缩质量
直接调用 bitmap.Save("out.jpg", ImageFormat.Jpeg) 用的是系统默认质量(通常约75%),但这个值不可控。要精确设定,必须通过 ImageCodecInfo 查找 JPEG 编码器,并传入 EncoderParameters:
- 用
ImageCodecInfo codec = GetEncoderInfo("image/jpeg");获取编码器 - 构造
EncoderParameters,其中Encoder.Quality参数值为 0–100 的long - 特别注意:参数数组长度必须为1,且
EncoderParameter的Guid必须匹配编码器支持的选项,否则静默失败或抛异常 - 示例关键行:
params.Param[0] = new EncoderParameter(Encoder.Quality, 92L);
处理超大图片时别用 Bitmap 全量加载
一张 8000×6000 的 24 位 BMP 加载进内存要近 140MB,容易触发 OutOfMemoryException,尤其在 x86 进程里。不是所有缩放都必须走 GDI+ 全图解码。
- 对 JPEG/PNG,可考虑用
ImageSharp库(纯托管、内存友好),支持流式解码和采样缩放 - 若坚持用原生 API,可用
Bitmap(Image, Size)构造函数配合Size参数做快速等比缩略——它内部可能跳过完整解码 - 真正需要精确控制(如保留 EXIF、ICC 配置)时,得用
WIC(Windows Imaging Component)API,但需 P/Invoke 或封装库如WindowsAPICodePack
Bitmap 默认不复制原图的 HorizontalResolution/VerticalResolution,EXIF 方向标记(Orientation tag)也直接丢弃。如果业务涉及打印或移动端展示,这两点必须手动处理。










