如何使用图形对象渲染 WPF Hwnd

How to render a WPF Hwnd with Graphics Object

RenderTargetBitmap 之后太慢了。我尝试了一种不同的方法。不幸的是我的尝试没有成功。希望你们中的一些人能弄清楚为什么这段代码不起作用。

  var myPopup = new Popup();
            var child = new Grid() { Background = new VisualBrush(myVisual)};
            myPopup.StaysOpen = false;
            myPopup.Child = child;
            myPopup.IsOpen = false;

            myPopup.Opened += (sender, args) =>
            {
                var source = ((HwndSource)PresentationSource.FromVisual(myPopup.Child));
                var image = new Bitmap(1000,1000);
                using (Graphics gr = Graphics.FromHwnd(source.Handle))
                {
                    var ptr = gr.GetHdc();

                    using (Graphics g = Graphics.FromHdc(ptr))
                    {
                        g.DrawImage(image, new System.Drawing.Point(0, 0));
                    }
                    gr.ReleaseHdc(ptr);
                }
                //The image is just black...
                image.Save("test.png");

                myPopup.IsOpen = false;
            };
            myPopup.IsOpen = true;

恐怕您的代码无法运行。实际上,您正在将一个空图像复制到 Graphics,然后将该图像保存到一个文件中。所以文件是空的。

如果您不想使用RenderTargetBitmap, then you need to use BitBlt功能。

让我们看看如何去做。首先让我们创建一个助手 class 来管理从 Visual 到 Bitmap 的转换:

public static class VisualToBitmapConverter
{
    private enum TernaryRasterOperations : uint
    {
        SRCCOPY = 0x00CC0020,
        SRCPAINT = 0x00EE0086,
        SRCAND = 0x008800C6,
        SRCINVERT = 0x00660046,
        SRCERASE = 0x00440328,
        NOTSRCCOPY = 0x00330008,
        NOTSRCERASE = 0x001100A6,
        MERGECOPY = 0x00C000CA,
        MERGEPAINT = 0x00BB0226,
        PATCOPY = 0x00F00021,
        PATPAINT = 0x00FB0A09,
        PATINVERT = 0x005A0049,
        DSTINVERT = 0x00550009,
        BLACKNESS = 0x00000042,
        WHITENESS = 0x00FF0062,
        CAPTUREBLT = 0x40000000
    }

    [DllImport("gdi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

    public static Bitmap GetBitmap(Visual visual, int width, int height)
    {
        IntPtr source;
        IntPtr destination;

        Bitmap bitmap = new Bitmap(width, height);
        HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(visual);
        using (Graphics graphicsFromVisual = Graphics.FromHwnd(hwndSource.Handle))
        {
            using (Graphics graphicsFromImage = Graphics.FromImage(bitmap))
            {
                source = graphicsFromVisual.GetHdc();
                destination = graphicsFromImage.GetHdc();

                BitBlt(destination, 0, 0, bitmap.Width, bitmap.Height, source, 0, 0, TernaryRasterOperations.SRCCOPY);

                graphicsFromVisual.ReleaseHdc(source);
                graphicsFromImage.ReleaseHdc(destination);
            }
        }

        return bitmap;
    }
}

现在我们可以编写一个简单的 XAML 来测试助手 class:

<Window x:Class="WpfApplication1.MainWindow" Name="win"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="400">

    <StackPanel>
        <Border BorderBrush="DarkGray" BorderThickness="4" CornerRadius="4"
                Background="LightGray" Padding="6" Name="border">
            <Label Content="Copy me to a bitmap file, please" FontSize="20" Foreground="Green"
                   FontStyle="Italic" />
        </Border>
        <Button Content="Save to file" Margin="20" HorizontalAlignment="Center"
                Click="Button_Click" />
    </StackPanel>

</Window>

其代码隐藏:

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Bitmap image = VisualToBitmapConverter.GetBitmap(border,
                (int)border.ActualWidth, (int)border.ActualHeight);

            image.Save(@"C:\YourPath\test.png");
        }
    }
}

如果单击该按钮,您会发现边框及其内容已复制到位图文件中。希望这个方法的速度适合你的目的。