简体   繁体   English

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

[英]How to render a WPF Hwnd with Graphics Object

After the RenderTargetBitmap is much too slow. 之后,RenderTargetBitmap太慢了。 I tried a different approach. 我尝试了另一种方法。 Unfortunately my attempt was not successful. 不幸的是,我的尝试没有成功。 Hopefully some of you guys can figure out why this code is not working. 希望你们中的一些人能弄清楚为什么此代码不起作用。

  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;

I am afraid that your code cannot work. 恐怕您的代码无法正常工作。 Indeed you are copying an empty image to a Graphics and then you are saving that image to a file. 实际上,您是将一个空图像复制到Graphics ,然后将该图像保存到文件。 So the file is empty. 因此该文件为空。

If you do not want to use RenderTargetBitmap , then you need to use BitBlt function. 如果您不想使用RenderTargetBitmap ,则需要使用BitBlt函数。

Let's see how to do it. 让我们来看看如何做。 First of all let's create an helper class which manages the conversion from Visual to Bitmap: 首先,让我们创建一个帮助程序类,该类管理从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;
    }
}

Now we can write a simple XAML just for testing the helper class: 现在我们可以编写一个简单的XAML来测试助手类:

<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>

With its code-behind: 后面有代码:

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");
        }
    }
}

If you click the button, you will find the Border and its content copied into the Bitmap file. 如果单击该按钮,将发现Border及其内容已复制到Bitmap文件中。 I hope the speed of this method is suitable for your pourpose. 我希望这种方法的速度适合您的目的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM