2015-09-10 2 views
2

После того, как RenderTargetBitmap работает слишком медленно. Я попробовал другой подход. К сожалению, моя попытка не была успешной. Надеюсь, некоторые из вас, ребята, могут понять, почему этот код не работает.Как визуализировать WPF Hwnd с помощью графического объекта

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; 
+0

Что не работает? Вы получаете ошибку, вы получаете неправильные результаты, все еще не счастливы с производительностью ... – sous2817

+0

Ошибка. Он просто выглядит как графический объект пуст и рисует пустое изображение. – Andreas

+0

Зачем этот вопрос? ^^ – Andreas

ответ

3

Боюсь, что ваш код не может работать. Действительно, вы копируете пустой образ в Graphics, а затем сохраняете это изображение в файл. Таким образом, файл пуст.

Если вы не хотите использовать RenderTargetBitmap, вам необходимо использовать функцию BitBlt.

Давайте посмотрим, как это сделать. Прежде всего давайте создадим вспомогательный класс, который управляет преобразованием из Визуальных в 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 только для тестирования вспомогательного класса:

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

Если вы нажмете кнопку, вы найдете Границу и ее содержимое скопировано в файл растрового изображения. Я надеюсь, что скорость этого метода подходит для вашей наживки.

+0

К сожалению, он захватывает также наложения элемента управления, но мы можем поместить границу в всплывающее окно воздушного пространства, чтобы захватить его hwnd. – Andreas

Смежные вопросы