You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7中System.Drawing.Imaging保存WebP体积过大及编码器缺失问题

问题描述

我正在使用.NET 7开发,通过System.Drawing.Imaging的以下代码将Bitmap保存为WebP文件:

pictureBox1.Image = image; //image is a Bitmap
image.Save(folderpath, ImageFormat.Webp); 

操作很简单,但保存的640x480图片占用了716KB空间,且画质较差(摄像头图像),和PNG格式占用空间相同。我想知道如何减小WebP文件体积?

更新问题

我参考MSDN代码可调整PNG的质量,但尝试用同样方式设置WebP质量时:

if (capture.IsOpened())
{
    capture.Read(frame);
    image = BitmapConverter.ToBitmap(frame);
    if (pictureBox1.Image != null)
    {
        pictureBox1.Image.Dispose();
    }
    pictureBox1.Image = image;

    ImageCodecInfo myImageCodecInfo;
    System.Drawing.Imaging.Encoder myEncoder;
    EncoderParameter myEncoderParameter;
    EncoderParameters myEncoderParameters;

    myImageCodecInfo = GetEncoder("image/webp");

    myEncoderParameters = new EncoderParameters(1);
    myEncoder = System.Drawing.Imaging.Encoder.Quality;
    // Save the bitmap as a JPEG file with quality level 25.
    myEncoderParameter = new EncoderParameter(myEncoder, 25L);
    myEncoderParameters.Param[0] = myEncoderParameter;
    // and now save it to the file

    image.Save(filename, myImageCodecInfo, myEncoderParameters); 
}

搭配以下方法:

public static ImageCodecInfo GetEncoder(string mimetype)
{
    return ImageCodecInfo.GetImageEncoders().FirstOrDefault(e => e.MimeType == mimetype);
}

却发现ImageCodecInfo.GetImageEncoders()中没有WebP对应的编码器,我无法理解为何Save方法支持保存WebP却找不到该编码器?

解决方案

1. 编码器缺失的原因

.NET 7中System.Drawing.Imaging的ImageCodecInfo.GetImageEncoders()不会返回WebP编码器,因为WebP的支持是依赖Windows 10 1809及以上版本的GDI+扩展实现的,并未被纳入标准编码器枚举列表。Image.Save能保存WebP是底层GDI+原生支持,但未对外暴露编码器信息。

2. 调整WebP质量减小体积的方案

原生System.Drawing无法直接设置WebP编码参数,推荐两种可行方案:

方案一:使用第三方图片处理库(跨平台)

用ImageSharp这类专门的库可以直接控制WebP质量,示例代码:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.PixelFormats;

// 将Bitmap转换为ImageSharp对象
using var stream = new MemoryStream();
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Position = 0;
using var image = Image.Load<Rgba32>(stream);

// 配置WebP编码参数
var webpEncoder = new WebpEncoder
{
    Quality = 25, // 取值0-100,值越小体积越小
    Lossless = false // 非无损压缩才能大幅降体积
};

// 保存为WebP
image.Save("output.webp", webpEncoder);

方案二:调用Windows原生WebP API(仅Windows平台)

通过P/Invoke直接调用系统自带的libwebp.dll,控制编码参数:

// 核心P/Invoke声明
[DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int WebPEncodeBGRA(IntPtr rgba, int width, int height, int stride, float quality, out IntPtr output);

[DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void WebPFree(IntPtr ptr);

// 使用示例
var bitmapData = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), 
    System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

IntPtr webpData;
int dataSize = WebPEncodeBGRA(bitmapData.Scan0, image.Width, image.Height, bitmapData.Stride, 25f, out webpData);

// 将编码后的数据写入文件
byte[] buffer = new byte[dataSize];
System.Runtime.InteropServices.Marshal.Copy(webpData, buffer, 0, dataSize);
File.WriteAllBytes("output.webp", buffer);

// 释放资源
WebPFree(webpData);
image.UnlockBits(bitmapData);

3. 额外优化技巧

  • 若不需要全分辨率,可先缩小图像尺寸再编码
  • 摄像头图像适合用有损压缩,不要开启无损模式
  • 尽量直接从摄像头原始帧数据转换为WebP,减少中间格式转换的损耗

内容的提问来源于stack exchange,提问作者Leandro Bardelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:23:10