在C#桌面与后台服务开发中,图片格式转换是高频需求,例如把用户上传的BMP转成体积更小的JPG,或将截图保存为支持透明的PNG。核心类位于System.Drawing命名空间,通过Bitmap和ImageFormat配合编码器完成。理解不同格式的编码器参数,才能避免画质受损或内存异常。

一、基础转换:使用Save与ImageFormat
最直观的方式是调用Bitmap的Save方法并指定目标ImageFormat。ImageFormat类提供了静态属性如Jpeg、Png、Bmp、Gif,直接映射系统内置格式。这种方式代码简单,适合对输出质量无精细要求的场景。
下面的示例读取一个BMP文件,将其转换为PNG并保存。注意using语句确保Bitmap资源被释放,否则GDI+对象泄漏会引发后续绘图失败。转换本身不修改原图,而是按目标格式编码新文件。
using System.Drawing;
using System.Drawing.Imaging;
// 加载源图片(BMP格式)
using (Bitmap srcBmp = new Bitmap("source.bmp"))
{
// 直接以PNG格式保存,保留透明通道
srcBmp.Save("output.png", ImageFormat.Png);
}
// 转为JPG,使用默认质量
using (Bitmap srcBmp = new Bitmap("source.bmp"))
{
srcBmp.Save("output.jpg", ImageFormat.Jpeg);
}
这种写法在JPG转换时采用系统默认压缩质量(约70%),若源图含透明度,JPG不支持alpha,区域会被填成黑色。PNG虽无损且支持透明,但体积通常数倍于JPG。因此基础转换只适用于快速导出,生产环境应控制参数。
二、带质量参数的JPG转换
JPG是有损格式,压缩质量直接影响清晰度和文件大小。C#通过ImageCodecInfo定位JPEG编码器,再用EncoderParameters包裹一个EncoderParameter,指定Quality数值(0-100)。该方式能平衡画质与存储。
实践中需先遍历ImageCodecInfo.GetImageEncoders(),匹配MimeType为image/jpeg的编码器。若每次转换都遍历会有微小开销,可缓存编码器实例。以下代码演示如何以85质量保存JPG,并说明参数构造逻辑。
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
public static void ConvertToJpgWithQuality(string srcPath, string destPath, long quality)
{
using (Bitmap bmp = new Bitmap(srcPath))
{
ImageCodecInfo jpgEncoder = ImageCodecInfo.GetImageEncoders()
.First(c => c.MimeType == "image/jpeg");
EncoderParameters ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(Encoder.Quality, quality);
bmp.Save(destPath, jpgEncoder, ep);
}
}
// 调用:以85质量转换
ConvertToJpgWithQuality("input.bmp", "result.jpg", 85);
质量参数过低(如低于50)会出现明显块状伪影,过高(如100)则文件接近无损、失去压缩意义。一般Web展示用75-85即可。另外,EncoderParameter的Value必须是long类型,传入int会被装箱导致运行时异常,这是常见疏忽。
三、PNG与WEBP等格式的处理差异
PNG属于无损格式,Save时无需质量参数,但可通过EncoderParameters设置压缩级别(Encoder.Compression)。WEBP在旧版.NET Framework中并非原生支持,需借助System.Drawing.Common的扩展或第三方库;.NET Core 3.0后部分平台支持,但仍建议用ImageCodecInfo确认可用性。
下例展示如何检测系统是否支持某格式编码器,避免调用Save时抛出UnsupportedImageFormatException。对于不支持的格式,应提示用户或引入Native库。
using System.Drawing.Imaging;
using System.Linq;
public static bool IsFormatSupported(string mimeType)
{
return ImageCodecInfo.GetImageEncoders()
.Any(c => c.MimeType == mimeType);
}
// 检查WEBP
bool webpOk = IsFormatSupported("image/webp");
若环境支持WEBP,其编码器参数可设质量与透明度,体积通常比JPG小30%且支持透明,非常适合前端资源。但在Windows Server无桌面体验包时,System.Drawing常受限,此时应改用ImageSharp等跨平台库,原理类似但API更现代。
四、批量转换与资源释放要点
批量处理图片时,必须对每个Bitmap使用using或显式Dispose,GDI+句柄数量受限,泄漏会触发“内存不足”假异常。建议封装统一转换方法,根据目标后缀选择编码器与参数。
下面的辅助方法通过文件扩展名路由到不同保存逻辑,并统一捕获异常。实际项目中可加入缩放、水印等前置处理,但格式转换应作为最后一步,减少重复编码。
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
public static void ConvertByExtension(string src, string dest)
{
using (Bitmap bmp = new Bitmap(src))
{
string ext = Path.GetExtension(dest).ToLower();
if (ext == ".jpg" || ext == ".jpeg")
{
var enc = ImageCodecInfo.GetImageEncoders()
.First(c => c.MimeType == "image/jpeg");
var ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(Encoder.Quality, 80L);
bmp.Save(dest, enc, ep);
}
else if (ext == ".png")
{
bmp.Save(dest, ImageFormat.Png);
}
else
{
bmp.Save(dest, ImageFormat.Bmp);
}
}
}
综上,C#转换图片格式并不复杂,关键在选对编码器、设好参数、管好资源。简单场景用ImageFormat直接Save,严谨场景用ImageCodecInfo加EncoderParameters。面对WEBP等新格式,先检测支持度再决定方案,才能写出稳定高效的转换工具。
C#_image_convertSystem_DrawingImageFormat修改时间:2026-08-01 23:39:48