Capture the Screen into a Bitmap
Asked Answered
D

7

74

I want to capture the screen in my code to get an image - like using the 'print screen' button on the keyboard .

Does anyone have an idea how to do this? I have no starting point.

Deed answered 12/12, 2008 at 14:57 Comment(0)
L
122

You can use the Graphics.CopyFromScreen() method.

//Create a new bitmap.
var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                               Screen.PrimaryScreen.Bounds.Height,
                               PixelFormat.Format32bppArgb);

// Create a graphics object from the bitmap.
var gfxScreenshot = Graphics.FromImage(bmpScreenshot);

// Take the screenshot from the upper left corner to the right bottom corner.
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                            Screen.PrimaryScreen.Bounds.Y,
                            0,
                            0,
                            Screen.PrimaryScreen.Bounds.Size,
                            CopyPixelOperation.SourceCopy);

// Save the screenshot to the specified path that the user has chosen.
bmpScreenshot.Save("Screenshot.png", ImageFormat.Png);
Lelahleland answered 12/12, 2008 at 15:4 Comment(4)
Your answer is incorrect please update it with ( g.CopyFromScreen( 0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);Pennywise
Yes, take a look at the .NET Screen object to get the other screens. Notice in the above call i use Screen.PrimaryScreen to get the primary screen? You can use Screen.AllScreens to get an array of them all. Screen.AllScreens[n].Bounds.Width etc...Lelahleland
Here we are in 2016 and this still works perfectly. Thanks!Gleanings
if change display setting Change the size of all items to larger, the code can only capture part of the screen. how to solve?Date
C
13

I had two problems with the accepted answer.

  1. It doesn't capture all screens in a multi-monitor setup.
  2. The width and height returned by the Screen class are incorrect when display scaling is used and your application is not declared per monitor dpiAware.

Here's my updated solution using the Screen.AllScreens static property and calling EnumDisplaySettings using p/invoke to get the real screen resolution.

using System.Runtime.InteropServices;

const int ENUM_CURRENT_SETTINGS = -1;

foreach (Screen screen in Screen.AllScreens)
{
    var dm = new DEVMODE();
    dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
    EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);

    using var bmp = new Bitmap(dm.dmPelsWidth, dm.dmPelsHeight);
    using var g = Graphics.FromImage(bmp);

    g.CopyFromScreen(dm.dmPositionX, dm.dmPositionY, 0, 0, bmp.Size);
    bmp.Save(screen.DeviceName.Split('\\').Last() + ".png");
}

[DllImport("user32.dll")]
static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
    private const int CCHDEVICENAME = 0x20;
    private const int CCHFORMNAME = 0x20;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
    public string dmDeviceName;
    public short dmSpecVersion;
    public short dmDriverVersion;
    public short dmSize;
    public short dmDriverExtra;
    public int dmFields;
    public int dmPositionX;
    public int dmPositionY;
    public ScreenOrientation dmDisplayOrientation;
    public int dmDisplayFixedOutput;
    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
    public string dmFormName;
    public short dmLogPixels;
    public int dmBitsPerPel;
    public int dmPelsWidth;
    public int dmPelsHeight;
    public int dmDisplayFlags;
    public int dmDisplayFrequency;
    public int dmICMMethod;
    public int dmICMIntent;
    public int dmMediaType;
    public int dmDitherType;
    public int dmReserved1;
    public int dmReserved2;
    public int dmPanningWidth;
    public int dmPanningHeight;
}

References:

https://mcmap.net/q/271030/-detect-if-non-dpi-aware-application-has-been-scaled-virtualized http://pinvoke.net/default.aspx/user32/EnumDisplaySettings.html?diff=y

Chauffer answered 29/1, 2019 at 16:29 Comment(0)
A
8
// Use this version to capture the full extended desktop (i.e. multiple screens)

Bitmap screenshot = new Bitmap(SystemInformation.VirtualScreen.Width, 
                               SystemInformation.VirtualScreen.Height, 
                               PixelFormat.Format32bppArgb);
Graphics screenGraph = Graphics.FromImage(screenshot);
screenGraph.CopyFromScreen(SystemInformation.VirtualScreen.X, 
                           SystemInformation.VirtualScreen.Y, 
                           0, 
                           0, 
                           SystemInformation.VirtualScreen.Size, 
                           CopyPixelOperation.SourceCopy);

screenshot.Save("Screenshot.png", System.Drawing.Imaging.ImageFormat.Png);
Alopecia answered 20/8, 2014 at 15:23 Comment(2)
Your code doesn't out put a proper image. Is it supposed to be a JPEG or a PNG?Cottle
Works well, but there is a general UI freeze. Incompatible for projects (as mine) which need to analyze screen 10-20 times per second.Durward
H
1

Try this code

Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics gr = Graphics.FromImage(bmp);
gr.CopyFromScreen(0, 0, 0, 0, bmp.Size);
pictureBox1.Image = bmp;
bmp.Save("img.png",System.Drawing.Imaging.ImageFormat.Png);
Hesky answered 4/2, 2017 at 8:0 Comment(0)
M
0
Bitmap memoryImage;
//Set full width, height for image
memoryImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                       Screen.PrimaryScreen.Bounds.Height,
                       PixelFormat.Format32bppArgb);
Size s = new Size(memoryImage.Width, memoryImage.Height);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
memoryGraphics.CopyFromScreen(0, 0, 0, 0, s);
string str = "";
try
{
    str = string.Format(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +
          @"\Screenshot.png");//Set folder to save image
}
catch { };
memoryImage.save(str);
Murchison answered 28/9, 2017 at 4:37 Comment(1)
It is recommended to add some explanation to your code so that people reading your answer would understand better and easier.Singleminded
K
0

I had been wondering how to do the same thing in FORTRAN to save me a bunch of manual intervention using PrintScreen, paste to Paint etc. I just figured out how: I read the pixels using GETPIXEL_RGB for any section of the screen I want, and, having prepared a .bmp header and written it to the .bmp file, follow by writing the pixel data. However, I don't think it's going to capture 10 to 20 sctre

Kilter answered 21/4, 2022 at 12:43 Comment(0)
K
0

Multi Screen Capture Program by Smitty

The Form has
CheckBox2 - Checkbox - Button Style - Anchor = Top, Left
CB1 - ComboBox - Font size = 20 - Text = 1 - Anchor = Top, Left
PB1 - PictureBox - SizeMode = StretchImage - Anchor = Top, Right, Bottom, Left

This is the module1.vb code

Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.Media
Imports System.Threading
Imports System.Management
Imports System.Runtime.InteropServices

Module Mod1
    Dim x As Integer = Screen.AllScreens.Count
    Public mon(x) As ScreenSpecs
    <DllImport("gdi32.dll")>
    Public Function GetDeviceCaps(ByVal hDC As IntPtr, ByVal nIndex As Integer) As Integer
    End Function

    <DllImport("gdi32.dll", SetLastError:=True, CharSet:=CharSet.Ansi)>
    Public Function CreateDC(<MarshalAs(UnmanagedType.LPStr)> lpszDriver As String,
          <MarshalAs(UnmanagedType.LPStr)> lpszDevice As String,
          <MarshalAs(UnmanagedType.LPStr)> lpszOutput As String,
          lpInitData As IntPtr) As IntPtr
    End Function
    Public Function BeforeLast(value As String, a As String) As String
        If value = Nothing Then
            Return value
            Exit Function
        End If
        Dim posA As Integer = value.LastIndexOf(a)
        If posA = -1 Then Return ""
        Return value.Substring(0, posA)
    End Function
    Public Function BeforeFirst(value As String, a As String) As String
        If value = Nothing Then
            Return value
            Exit Function
        End If
        Dim posA As Integer = value.IndexOf(a)
        If posA = -1 Then Return ""
        Return value.Substring(0, posA)
    End Function
    Public Function AfterFirst(value As String, a As String) As String
        If value = Nothing Then
            Return value
            Exit Function
        End If
        Dim posA As Integer = value.IndexOf(a)
        If posA = -1 Then Return ""
        Dim adjustedPosA As Integer = posA + a.Length
        If adjustedPosA >= value.Length Then Return ""
        Return value.Substring(adjustedPosA)
    End Function
    Public Function AfterLast(value As String, a As String) As String
        If value = Nothing Then
            Return value
            Exit Function
        End If
        Dim posA As Integer = value.LastIndexOf(a)
        If posA = -1 Then Return ""
        Dim adjustedPosA As Integer = posA + a.Length
        If adjustedPosA >= value.Length Then Return ""
        Return value.Substring(adjustedPosA)
    End Function

    Public Function GrabScreen(Index As Integer) As Bitmap
        Dim MonWidth As Integer = mon(Index).Width
        Dim MonHeight As Integer
        If Form1.CheckBox2.Checked Then
            MonHeight = mon(Index).Height
        Else
            MonHeight = mon(Index).HeightNtb
        End If
        Dim screenSize As Size = New Size(MonWidth, MonHeight)
        Dim screenGrab As New Bitmap(MonWidth, MonHeight)
        Dim g As Graphics = Graphics.FromImage(screenGrab)
        g.CopyFromScreen(New Point(mon(Index).XStart, mon(Index).YStart), New Point(0, 0), screenSize)
        Return screenGrab
    End Function

    Public Function GetScalleFactor(index As Integer) As Double
        Dim desktop As IntPtr = CreateDC(Screen.AllScreens(index).DeviceName, Nothing, Nothing, IntPtr.Zero)
        Return GetDeviceCaps(desktop, 118) / GetDeviceCaps(desktop, 8)
    End Function

End Module

This is the ScreenSpec.vb Class I created

Public Class ScreenSpecs
    Private BPPValue As Integer
    Private IndexValue As Integer
    Private NameValue As String
    Private WidthValue As Integer
    Private HeightValue As Integer
    Private HeightNtbValue As Integer
    Private ScaleValue As Double
    Private XStartValue As Integer
    Private YStartValue As Integer
    Public Property BPP() As Integer
        Get
            ' Gets the property value.
            Return BPPValue
        End Get
        Set(ByVal Value As Integer)
            ' Sets the property value.
            BPPValue = Value
        End Set
    End Property
    Public Property Index() As Integer
        Get
            ' Gets the property value.
            Return IndexValue
        End Get
        Set(ByVal Value As Integer)
            ' Sets the property value.
            IndexValue = Value
        End Set
    End Property
    Public Property Name() As String
        Get
            ' Gets the property value.
            Return NameValue
        End Get
        Set(ByVal Value As String)
            ' Sets the property value.
            NameValue = Value
        End Set
    End Property
    Public Property Width() As String
        Get
            ' Gets the property value.
            Return WidthValue
        End Get
        Set(ByVal Value As String)
            ' Sets the property value.
            WidthValue = Value
        End Set
    End Property
    Public Property Height() As String
        Get
            ' Gets the property value.
            Return HeightValue
        End Get
        Set(ByVal Value As String)
            ' Sets the property value.
            HeightValue = Value
        End Set
    End Property
    Public Property HeightNtb() As String
        Get
            ' Gets the property value.
            Return HeightNtbValue
        End Get
        Set(ByVal Value As String)
            ' Sets the property value.
            HeightNtbValue = Value
        End Set
    End Property
    Public Property Scale() As Double
        Get
            ' Gets the property value.
            Return ScaleValue
        End Get
        Set(ByVal Value As Double)
            ' Sets the property value.
            ScaleValue = Value
        End Set
    End Property
    Public Property XStart() As String
        Get
            ' Gets the property value.
            Return XStartValue
        End Get
        Set(ByVal Value As String)
            ' Sets the property value.
            XStartValue = Value
        End Set
    End Property
    Public Property YStart() As String
        Get
            ' Gets the property value.
            Return YStartValue
        End Get
        Set(ByVal Value As String)
            ' Sets the property value.
            YStartValue = Value
        End Set
    End Property
End Class

This is the Form1.vb code

Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
Imports System.Threading

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        On Error Resume Next
        CB1.Items.Clear()
        Dim x As Integer
        Dim MonH As Integer
        Dim MonHtb As Integer
        Dim MonW As Integer
        For x = 0 To (UBound(Screen.AllScreens))
            mon(x) = New ScreenSpecs()
            mon(x).Index = x
            mon(x).Name = Screen.AllScreens(x).DeviceName.ToString
            mon(x).BPP = Screen.AllScreens(x).BitsPerPixel
            MonH = Screen.AllScreens(x).Bounds.Size.Height.ToString
            MonHtb = Screen.AllScreens(x).WorkingArea.Size.Height.ToString
            MonW = Screen.AllScreens(x).Bounds.Size.Width.ToString
            mon(x).Scale = GetScalleFactor(x)
            mon(x).Height = (MonH * mon(x).Scale)
            mon(x).HeightNtb = (MonHtb * mon(x).Scale)
            mon(x).Width = (MonW * mon(x).Scale)
            mon(x).XStart = Screen.AllScreens(x).Bounds.Location.X.ToString
            mon(x).YStart = Screen.AllScreens(x).Bounds.Location.Y.ToString
            CB1.Items.Add((x + 1))
        Next
    End Sub

    Private Sub PB1_Click(sender As Object, e As EventArgs) Handles PB1.Click
        PB1.Image = GrabScreen((Int(CB1.Text) - 1))
    End Sub

    Private Sub CheckBox2_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox2.CheckedChanged
        If CheckBox2.Checked = False Then
            CheckBox2.Text = "No Taskbar"
            CheckBox2.BackColor = Color.Pink
        Else
            CheckBox2.Text = "Show Taskbar"
            CheckBox2.BackColor = Color.LightGreen
        End If
    End Sub

    Private Sub CB1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CB1.SelectedIndexChanged
        Dim MonSpec As String = ""
        Dim x As Integer = sender.SelectedIndex
        Me.Text = "Monitor Number " & mon(x).Index & " - BitsPerPixel = " & mon(x).BPP & " - Scaling Factor = " & mon(x).Scale & " - Width = " & mon(x).Width & " - Height = " & mon(x).Height & " - X-Start = " & mon(x).XStart & " - Y-Start = " & mon(x).YStart
    End Sub
End Class

When program starts it will find all monitors and list them in ComboBox. Set ComboBox to monitor number you want and single-click PictureBox. Your selected monitor will be captured in the PictureBox. The CheckBox is used as a (Show Task Bar/Hide Task Bar). Also as you switch ComboBox the selected monitors specs will show in the forms title bar.

Made change to the picturebox click which will hide the screenshot program.

Private Sub PB1_Click(sender As Object, e As EventArgs) Handles PB1.Click
    Me.SendToBack()
    Application.DoEvents()
    PB1.Image = GrabScreen((Int(CB1.Text) - 1))
    Application.DoEvents()
    Me.BringToFront()
End Sub
Kaffraria answered 23/3 at 5:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.