Вопрос

Я пытаюсь сгенерировать BitmapFrame , основанный на 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);
}

Для целей тестирования и отладки я использую дополнительную функцию, которая создает простой StackFrame, который должен создать допустимый визуальный элемент, который может быть представлен:

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

По какой-то причине VisualBrush не отображается в функции DrawRetangle (...). Я вижу зеленую границу, но больше ничего. Кроме того, если я заменю VisualBrush стандартной кистью, он прекрасно работает:

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

Заранее спасибо!

Это было полезно?

Решение

Посмотрите на это для альтернативного способа создания BitmapSource из UIElement :

Тема MSDN

Я также пытался заставить VisualBrush работать без какой-либо удачи, которая привела меня к этой теме.

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

Другие советы

У меня раньше была такая же проблема, я хотел скопировать содержимое UIElement в изображение, я использовал тот же подход в ответе выше, и, похоже, он работает нормально, только у меня есть проблема, Я хотел, чтобы он работал в режиме реального времени, поэтому мне пришлось копать глубже, я нашел несколько ссылок об использовании Windows API для копирования содержимого элемента в растровое изображение, а затем это растровое изображение должно быть преобразовано в BitmapSource так что его можно использовать в WPF

Пока все работает нормально, но, похоже, происходит утечка памяти (не уверен в этом). Я попытаюсь повторно использовать дескриптор hwnd UIElement и объект растрового изображения для повышения производительности и утечки памяти (если она существует)

[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;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top