Generate BitmapSource from UIElement

前端 未结 2 1975
孤城傲影
孤城傲影 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;
        }
    }
    

提交回复
热议问题