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

如何将Drawing.Image转换为Media.ImageSource以实现裁剪图像渲染?

嘿,我之前也遇到过把GDI+的System.Drawing.Image转成WPF的Media.ImageSource的需求,刚好能给你几个靠谱的解决方案:

方案1:通过内存流转换(通用兼容)

这是最通用的方法,不管你的Drawing.Image是Bitmap、Metafile还是其他子类都能适用,原理是把GDI+图像序列化到内存流,再用WPF的BitmapImage加载:

using System.Drawing;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;

// 转换方法
private ImageSource ConvertGdiImageToWpfImageSource(System.Drawing.Image gdiImage)
{
    using (var memoryStream = new MemoryStream())
    {
        // 把GDI+图像保存为PNG格式到内存流(PNG支持透明,也可以选JPEG等)
        gdiImage.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
        memoryStream.Position = 0; // 重置流指针到开头

        var bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad; // 确保流关闭后图像依然可用
        bitmapImage.StreamSource = memoryStream;
        bitmapImage.EndInit();
        
        // 冻结图像提升性能,并且允许跨线程访问(如果需要在非UI线程处理)
        bitmapImage.Freeze();
        return bitmapImage;
    }
}

方案2:直接从像素数据创建(高性能)

如果你的Drawing.Image是System.Drawing.Bitmap类型,这个方法会更高效——直接读取Bitmap的像素缓冲区创建WPF的BitmapSource,跳过序列化/反序列化的开销,适合处理大图像:

private ImageSource ConvertGdiBitmapToWpfImageSource(System.Drawing.Bitmap gdiBitmap)
{
    // 锁定Bitmap的像素数据
    var bitmapData = gdiBitmap.LockBits(
        new System.Drawing.Rectangle(0, 0, gdiBitmap.Width, gdiBitmap.Height),
        System.Drawing.Imaging.ImageLockMode.ReadOnly,
        gdiBitmap.PixelFormat);

    // 根据GDI+像素格式匹配对应的WPF像素格式,这里以常见的32位RGB为例
    var wpfPixelFormat = PixelFormats.Bgr32;
    if (gdiBitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb)
    {
        wpfPixelFormat = PixelFormats.Pbgra32;
    }

    // 创建WPF BitmapSource
    var bitmapSource = BitmapSource.Create(
        bitmapData.Width,
        bitmapData.Height,
        gdiBitmap.HorizontalResolution,
        gdiBitmap.VerticalResolution,
        wpfPixelFormat,
        null,
        bitmapData.Scan0,
        bitmapData.Stride * bitmapData.Height,
        bitmapData.Stride);

    // 解锁Bitmap像素数据
    gdiBitmap.UnlockBits(bitmapData);
    
    bitmapSource.Freeze();
    return bitmapSource;
}

转换后使用ImageDrawing裁剪渲染

拿到ImageSource之后,就可以按你的计划创建ImageDrawing,指定裁剪区域后渲染到DrawingContext了:

// 假设你的原始GDI+图像是gdiImage
ImageSource wpfImage = ConvertGdiImageToWpfImageSource(gdiImage);

// 定义裁剪区域:左上角(10,10),宽150,高150
Rect cropArea = new Rect(10, 10, 150, 150);

// 创建ImageDrawing
var imageDrawing = new ImageDrawing(wpfImage, cropArea);

// 渲染到DrawingContext
drawingContext.DrawDrawing(imageDrawing);

注意事项

  • 像素格式匹配:如果你的图像带透明通道,一定要对应正确的WPF像素格式(比如Pbgra32对应GDI+的Format32bppArgb),否则透明效果会失效。
  • 冻结ImageSource:如果你的转换操作在非UI线程执行,冻结BitmapSource是必须的——WPF的UI元素默认不允许跨线程访问,冻结后的对象是只读且线程安全的。
  • 资源释放:如果你的GDI+图像是从文件或其他资源加载的,记得在使用完后调用Dispose()释放资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Julien Vernay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:20:27