将WPF图像控件保存到文件的最简单方法

15
我在我的WPF应用程序中有一个Image控件,其中包含一张大图像,但该控件本身只有60x150的大小,这意味着它只显示该图像的某个部分。 保存可见部分到文件的最简单方法是什么? 谢谢您的帮助。
[编辑] 最终,我使用在此处找到的代码(在发布此问题之前我无法找到)...
Grid r = new Grid();
        r.Background = new ImageBrush(image2.Source);


    System.Windows.Size sz = new System.Windows.Size(image2.Source.Width, image2.Source.Height);
    r.Measure(sz);
    r.Arrange(new Rect(sz));

    RenderTargetBitmap rtb = new RenderTargetBitmap((int)image2.Source.Width, (int)image2.Source.Height, 96d, 96d, PixelFormats.Default);
    rtb.Render(r);

    BmpBitmapEncoder encoder = new BmpBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(rtb));

    FileStream fs = File.Open(@"C:\lol.png", FileMode.Create);
    encoder.Save(fs);
    fs.Close();
2个回答

20
你可以使用 RenderTargetBitmap 类和 BitmapEncoder
定义这些方法:
void SaveToBmp(FrameworkElement visual, string fileName)
{
    var encoder = new BmpBitmapEncoder();
    SaveUsingEncoder(visual, fileName, encoder);
}

void SaveToPng(FrameworkElement visual, string fileName)
{
    var encoder = new PngBitmapEncoder();
    SaveUsingEncoder(visual, fileName, encoder);
}

// and so on for other encoders (if you want)


void SaveUsingEncoder(FrameworkElement visual, string fileName, BitmapEncoder encoder)
{
    RenderTargetBitmap bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
    bitmap.Render(visual);
    BitmapFrame frame = BitmapFrame.Create(bitmap);
    encoder.Frames.Add(frame);

    using (var stream = File.Create(fileName))
    {
        encoder.Save(stream);
    }
}

如果您将Image控件放置在这样的容器中:

<Grid x:Name="MyGrid">
    <Image Name="MyImage" Stretch="None"></Image>
</Grid>

你只需要这样做:

SaveToPng(MyGrid, "image.png");

否则,当您使用RenderTargetBitmap时,您可以直接传递所需的尺寸:
SaveToPng(MyImage, "image.png");

...

RenderTargetBitmap bitmap = new RenderTargetBitmap(YourWidth, YourHeight, 96, 96, PixelFormats.Pbgra32);

5
谢谢,如果没有一个小问题的话就太好了……保存的图片是全黑的……你有任何想法是怎么发生的或者如何解决吗? - Meh
我已经在VB.NET中完成了一个测试项目: 这里是一个样例,如果有帮助的话; 以及XAML在这里 - gliderkite
@gilderkite 我猜你说的"MyImage"是指WPF中的图像控件,那么是的,我已经尝试过了。 - Meh
好的,尽管您的代码没有出现错误,但它并不能工作。结果我只得到了一张黑色图片。 我的图片是 - system.windows.controls.image - Meh
2
@Capt.Morgan,我知道这是老问题了,但我遇到了同样的问题,你需要像这里解释的那样将渲染控件放在没有边距的父控件上:http://weblog.west-wind.com/posts/2007/Sep/10/Rendering-a-WPF-Container-to-Bitmap - BryanJ
是否有可能保存动态创建且未在UI中显示的控件?因为这样做会得到黑色图像。 - OrLevi

3
我在使用gliderkite的解决方案时遇到了与其他人相同的“黑色”图像问题。 “黑色”图像似乎是由于FrameworkElement的边距导致其在捕获的图像外部呈现。 我在Rick Stahl博客的评论中找到了解决方法。
具体来说,在渲染之前进行测量和排列,使其有机会适应图片中没有边距的事实。 以下是我现在重复使用的用于屏幕截图的静态类。 这是基于gliderkite的答案和Rick Stahl博客上的信息。
public static class ScreenCapture
{
    public static void SaveToBmp(FrameworkElement visual, string fileName)
    {
        var encoder = new BmpBitmapEncoder();
        SaveUsingEncoder(visual, fileName, encoder);
    }

    public static void SaveToPng(FrameworkElement visual, string fileName)
    {
        var encoder = new PngBitmapEncoder();
        SaveUsingEncoder(visual, fileName, encoder);
    }

    public static void SaveToJpeg(FrameworkElement visual, string fileName)
    {
        var encoder = new JpegBitmapEncoder();
        SaveUsingEncoder(visual, fileName, encoder);
    }

    private static void SaveUsingEncoder(FrameworkElement visual, string fileName, BitmapEncoder encoder)
    {
        RenderTargetBitmap bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
        Size visualSize = new Size(visual.ActualWidth, visual.ActualHeight);
        visual.Measure(visualSize);
        visual.Arrange(new Rect(visualSize));
        bitmap.Render(visual);
        BitmapFrame frame = BitmapFrame.Create(bitmap);
        encoder.Frames.Add(frame);

        using (var stream = File.Create(fileName))
        {
            encoder.Save(stream);
        }
    }
}

我尝试了其他方法,但渲染图像的宽度和高度总是太小,这意味着我的内容在图像底部和右侧被裁剪。然而,使用这种方法,我得到了我期望的确切尺寸。不知道为什么... - Kevin Lee Garner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接