2009-05-06 20 views
3

Ich versuche ein BitmapFrame zu generieren, das auf einem UIElement basiert. Hier ist meine Funktion:Erzeuge BitmapSource von UIElement

private BitmapFrame RenderToBitmap2() 
{ 
    RenderTargetBitmap renderBitmap = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32); 

    DrawingVisual drawingVisual = new DrawingVisual(); 
    DrawingContext drawingContext = drawingVisual.RenderOpen(); 
    VisualBrush aVisualBrush = new VisualBrush(GenerateTestStackPanel()); 
    drawingContext.DrawRectangle(aVisualBrush, new Pen(Brushes.Green, 2), new Rect(new Size(150, 150))); 

    drawingContext.Close(); 

    renderBitmap.Render(drawingVisual); 

    return BitmapFrame.Create(renderBitmap); 
} 

Zum Testen und Debuggen, ich bin eine zusätzliche Funktion, die eine einfache Stackframe erzeugt, dass sollte ein gültiges visuelles Element erstellen, die dargestellt werden können:

private StackPanel GenerateTestStackPanel() 
{ 
    // Create a red Ellipse. 
    Ellipse myEllipse = new Ellipse(); 

    myEllipse.Fill = Brushes.Green; 
    myEllipse.StrokeThickness = 2; 
    myEllipse.Stroke = Brushes.Black; 

    // Set the width and height of the Ellipse. 
    myEllipse.Width = 200; 
    myEllipse.Height = 200; 
    // Add the Ellipse to the StackPanel. 
    StackPanel myStackPanel = new StackPanel(); 
    myStackPanel.Children.Add(myEllipse); 
    return myStackPanel; 
} 

Aus irgendeinem Grund wird VisualBrush in der Funktion DrawRetangle (...) nicht gerendert. Ich kann die grüne Grenze sehen, aber sonst nichts. Darüber hinaus, wenn ich die VisualBrush mit einem Standard-Pinsel tauschen, es funktioniert super:

drawingContext.DrawRectangle(Brushes.Plum, new Pen(Brushes.Green, 2), new Rect(new Size(150, 150))); 

Vielen Dank im Voraus!

Antwort

4

Werfen Sie einen Blick auf diese für eine alternative Art und Weise ein BitmapSource von einem UIElement zu erstellen:

MSDN Thread

Ich habe auch die VisualBrush ohne Erfolg zur Arbeit zu kommen versucht, die mich auf diesen Thread gebracht .

public static BitmapSource CreateBitmapSourceFromVisual(
    Double width, 
    Double height, 
    Visual visualToRender, 
    Boolean undoTransformation) 
    { 
     if (visualToRender == null) 
     { 
      return null; 
     } 
     RenderTargetBitmap bmp = new RenderTargetBitmap((Int32)Math.Ceiling(width), 
      (Int32)Math.Ceiling(height), 96, 96, PixelFormats.Pbgra32); 

     if (undoTransformation) 
     { 
      DrawingVisual dv = new DrawingVisual(); 
      using (DrawingContext dc = dv.RenderOpen()) 
      { 
       VisualBrush vb = new VisualBrush(visualToRender); 
       dc.DrawRectangle(vb, null, new Rect(new Point(), new Size(width, height))); 
      } 
      bmp.Render(dv); 
     } 
     else 
     { 
      bmp.Render(visualToRender); 
     } 
     return bmp; 
    } 
3

ich vor das gleiche Problem hatte ich einen Gehalt von UIElement auf ein Bild, habe ich den gleichen Ansatz in der Antwort oben, und es scheint zu funktionieren, nur Problem, das ich habe, wollte ich es kopieren wollte Um in Echtzeit arbeiten zu können, musste ich genauer nachgehen. Ich fand einige Referenzen über die Verwendung von Windows-APIs, um den Inhalt des Elements in ein Bitmap zu kopieren, und dann muss dieses Bitmap in konvertiert werden, damit es in WPF

verwendbar ist

soweit funktioniert es gut, aber es scheint Speicher auslaufen (nicht sicher darüber). Ich werde versuchen, die UIElement HWND Handle und das Bitmap-Objekt für eine bessere Leistung und das Speicherleck (wenn es existiert)

[DllImport("gdi32.dll")] 
private static extern bool BitBlt(
    IntPtr hdcDest, // handle to destination DC 
    int nXDest, // x-coord of destination upper-left corner 
    int nYDest, // y-coord of destination upper-left corner 
    int nWidth, // width of destination rectangle 
    int nHeight, // height of destination rectangle 
    IntPtr hdcSrc, // handle to source DC 
    int nXSrc, // x-coordinate of source upper-left corner 
    int nYSrc, // y-coordinate of source upper-left corner 
    System.Int32 dwRop // raster operation code 
); 

[DllImport("User32.dll")] 
public extern static System.IntPtr GetDC(System.IntPtr hWnd); 

[DllImport("User32.dll")] 
public extern static int ReleaseDC(System.IntPtr hWnd, System.IntPtr hDC); //modified to include hWnd 

//[DllImport("gdi32.dll")] 
//[return: MarshalAs(UnmanagedType.Bool)] 
//internal static extern bool DeleteObject(IntPtr hObject); 

private static Bitmap GetBitmapFromControl(Window element, int width, int height) 
{ 
    HwndSource hWnd = (HwndSource)HwndSource.FromVisual(element); 
    System.IntPtr srcDC = GetDC(hWnd.Handle); 

    Bitmap bm = new Bitmap(width, height); 
    Graphics g = Graphics.FromImage(bm); 
    System.IntPtr bmDC = g.GetHdc(); 
    BitBlt(bmDC, 0, 0, bm.Width, bm.Height, srcDC, 0, 0, 0x00CC0020 /*SRCCOPY*/); 
    ReleaseDC(hWnd.Handle, srcDC); 
    g.ReleaseHdc(bmDC); 
    g.Dispose(); 

    return bm; 
} 

public static BitmapSource ToWpfBitmap(this Bitmap bitmap) 
{ 
    using (MemoryStream stream = new MemoryStream()) 
    { 
     bitmap.Save(stream, ImageFormat.Bmp); 

     stream.Position = 0; 
     BitmapImage result = new BitmapImage(); 
     result.BeginInit(); 
     // According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed." 
     // Force the bitmap to load right now so we can dispose the stream. 
     result.CacheOption = BitmapCacheOption.OnLoad; 
     result.StreamSource = stream; 
     result.EndInit(); 
     result.Freeze(); 


     //DeleteObject(bitmap.GetHbitmap()); 
     bitmap.Dispose(); 

     return result; 
    } 
} 
wieder zu verwenden