问题
After the RenderTargetBitmap is much too slow. 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;
回答1:
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. So the file is empty.
If you do not want to use RenderTargetBitmap, then you need to use BitBlt function.
Let's see how to do it. First of all let's create an helper class which manages the conversion from Visual to 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:
<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. I hope the speed of this method is suitable for your pourpose.
来源:https://stackoverflow.com/questions/32505712/how-to-render-a-wpf-hwnd-with-graphics-object