WPF: Way to take screenshots

c#, screenshot, wpf

Solution

First you'll need to add references for the following namespaces:

using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

Then enumerate your monitors to get the bounding rectangle for all display surfaces and pass that in to the `Graphics.CopyFromScreen()` method call:

private static BitmapSource CopyScreen()
{
    var left = Screen.AllScreens.Min(screen => screen.Bounds.X);
    var top = Screen.AllScreens.Min(screen => screen.Bounds.Y);
    var right = Screen.AllScreens.Max(screen => screen.Bounds.X + screen.Bounds.Width);
    var bottom = Screen.AllScreens.Max(screen => screen.Bounds.Y + screen.Bounds.Height);
    var width = right - left;
    var height = bottom - top;

    using (var screenBmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
    {
        using (var bmpGraphics = Graphics.FromImage(screenBmp))
        {
            bmpGraphics.CopyFromScreen(left, top, 0, 0, new System.Drawing.Size(width, height));
            return Imaging.CreateBitmapSourceFromHBitmap(
                screenBmp.GetHbitmap(),
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
        }
    }
}

Bear in mind though that monitors often don't fit neatly into a single rectangle, particularly if they have different resolution etc, so you might be better snap-shotting the individual screens. Either way, the solution to your problem is to change the coordinates that you were passing in to the `Graphics.CopyFromScreen()` method call.

EDIT: see Demetris Leptos's comment below, the code I've posted in this answer should be calling DeleteObject on the bitmap returned by `screenBmp.GetHbitmap()` so as to avoid a memory leak, as specified in the MSDN documentation.

Problem

Looking to modify the following to take a screenshot off all monitors. I have tried adapting it but my images are blank. Writing it to test.png is for testing. The `byte[]` will be sent to the receiving app. ``` public byte[] Take() { int screenWidth = Convert.ToInt32(SystemParameters.VirtualScreenWidth); int screenHeight = Convert.ToInt32(SystemParameters.VirtualScreenHeight); int screenLeft = Convert.ToInt32(SystemParameters.VirtualScreenLeft); int screenTop = Convert.ToInt32(SystemParameters.VirtualScreenTop); RenderTargetBitmap renderTarget = new RenderTargetBitmap(screenWidth, screenHeight, 96, 96, PixelFormats.Pbgra32); VisualBrush sourceBrush = new VisualBrush(); DrawingVisual drawingVisual = new DrawingVisual(); DrawingContext drawingContext = drawingVisual.RenderOpen(); using (drawingContext) { drawingContext.PushTransform(new ScaleTransform(1, 1)); drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(screenWidth, screenHeight))); } renderTarget.Render(drawingVisual); PngBitmapEncoder pngEncoder = new PngBitmapEncoder(); pngEncoder.Frames.Add(BitmapFrame.Create(renderTarget)); Byte[] _imageArray; using (MemoryStream outputStream = new MemoryStream()) { pngEncoder.Save(outputStream); _imageArray = outputStream.ToArray(); } using (FileStream stream = new FileStream(@"c:\test.png", FileMode.Create, FileAccess.ReadWrite)) { using (BinaryWriter writer = new BinaryWriter(stream)) { writer.Write(_imageArray); } } return _imageArray; } ```

Original source

Related problems