سؤال

وأنا محاولة لتوليد 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 إلى صورة، وأنا استخدم نفس النهج في الجواب أعلاه ويبدو أن تعمل بشكل جيد، المشكلة فقط I ديه، كنت أرغب في ذلك العمل الحقيقي الوقت، لذلك اضطررت لحفر أعمق، وجدت بعض الإشارات حول استخدام نوافذ واجهات برمجة التطبيقات لنسخ محتوى العنصر في صورة نقطية، ثم هذه الصورة النقطية لابد من تحويلها إلى BitmapSource حتى انها صالحة للاستعمال في WPF

وحتى الآن أنه يعمل بشكل جيد، ولكن يبدو أن تسرب الذاكرة (لا متأكدة من ذلك). سأحاول إعادة استخدام مقبض UIElement HWND والكائن نقطية للحصول على أداء أفضل وتسرب الذاكرة (إن وجد)

[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