Generate BitmapSource from UIElement

前端 未结 2 1977
孤城傲影
孤城傲影 2021-02-11 00:36

I am attempting to generate a BitmapFrame that is based on a UIElement. Here is my function:

private BitmapFrame RenderToBitmap2()
{
           


        
相关标签:
2条回答
  • 2021-02-11 01:02

    I had the same issue before, I wanted to copy content of a UIElement to an image, I used the same approach in the answer above and it seems to work fine, only problem I has, I wanted it to work real-time, so I had to dig deeper, I found some references about using windows APIs to copy the content of the element into a Bitmap, and then this bitmap has to be converted into a BitmapSource so it's usable in WPF

    so far it works fine, but it seems to leak memory (not sure about this). I will try to re-use the UIElement hwnd Handle and the bitmap object for better performance and the memory leak (if it exists)

    [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;
        }
    }
    
    0 讨论(0)
  • 2021-02-11 01:05

    Take a look at this for an alternate way to create a BitmapSource from a UIElement:

    MSDN Thread

    I have also been trying to get the VisualBrush to work without any luck which brought me to this thread.

    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;
        }
    
    0 讨论(0)
提交回复
热议问题