Image.Save 转格式时,文件扩展名必须与 ImageFormat 参数匹配,否则生成错误编码数据;需显式指定 PixelFormat 避免 PNG 透明失效;务必调用 Dispose 或 using 释放 GDI 句柄;WebP 仅 .NET 6+ 原生支持。

用 Image.Save 转格式时,文件扩展名和 ImageFormat 必须匹配
很多人以为改个文件后缀(比如把 .jpg 改成 .png)就完成了格式转换,结果打开是乱码或打不开——这是因为 Image.Save 实际编码行为完全取决于传入的 ImageFormat 参数,跟文件名无关。
-
Image.Save("out.png", ImageFormat.Png)→ 正确:PNG 编码,支持透明通道 -
Image.Save("out.png", ImageFormat.Jpeg)→ 错误:生成的是 JPEG 数据,但后缀是 .png,多数看图软件拒绝识别 - 常见陷阱:从磁盘加载图片时用
Image.FromFile,它自动推断格式;但保存时必须显式指定ImageFormat,不能依赖路径后缀
处理 PNG 透明通道丢失?别用 Bitmap 默认构造函数
直接 new Bitmap(width, height) 创建的位图默认是 PixelFormat.Format32bppArgb 吗?不是。它实际是 Format32bppPArgb(预乘 Alpha),且底层像素内存布局可能不兼容 GDI+ 的 PNG 编码器,导致透明区域变黑或半透失效。
- 正确做法:显式指定像素格式
new Bitmap(width, height, PixelFormat.Format32bppArgb) - 更稳妥:从原图克隆
original.Clone(new Rectangle(0,0, w,h), PixelFormat.Format32bppArgb) - 注意:JPG 不支持透明,强行保存带 Alpha 的图会丢弃 alpha 通道(不是报错,而是静默转为不透明白色背景)
批量转图卡顿?Image.Dispose() 漏掉是主因
在循环里反复 Image.FromFile + Save,内存暴涨、速度越来越慢,不是 GC 慢,是没及时释放 GDI 句柄——每个 Image 对象背后绑着一个 Windows GDI bitmap 句柄,不 Dispose() 就一直占着,Windows 有句柄数上限(通常约 10000),超了就抛 OutOfMemoryException。
- 必须配对:每次
Image.FromFile后,Save完立刻调用image.Dispose() - 推荐写法:用
using (var img = Image.FromFile(path)) { img.Save(...); } - 别信“GC 会回收”,GDI 句柄不会等 GC,必须手动释放
WebP 在 .NET 6+ 才原生支持,旧版本得换方案
想用 ImageFormat.Webp?.NET Framework 和 .NET Core 3.1 及更早版本根本不认识这个枚举值,直接编译失败或运行时报 ArgumentException: Invalid parameter。
- .NET 6+:内置支持,可直接用
Image.Save(..., ImageFormat.Webp) - .NET 5 及以下:需引入第三方库,如
ImageSharp(推荐)或libwebpP/Invoke 封装 - 注意:
Image.Save不支持 WebP 的有损/无损/质量参数调节,要用ImageSharp才能控制WebpEncoder.Quality
最常被跳过的细节:不同格式对色彩空间处理不同,比如 CMYK JPG 加载后会被自动转成 RGB,再保存为 PNG 就丢了原始色彩信息——如果业务真依赖精确色域,得自己处理 ICC 配置文件,不是改个格式那么简单。











