Captura de pantalla de la ventana activa?

175

Estoy haciendo una aplicación de captura de pantalla y todo va bien. Todo lo que necesito hacer es capturar la ventana activa y tomar una captura de pantalla de esta ventana activa. ¿Alguien sabe cómo puedo hacer esto?

usuario
fuente
17
¿"Ventana activa" significa la ventana activa de SU aplicación o la ventana que estaría activa si su aplicación estuviera oculta?
Corey Trager

Respuestas:

151
ScreenCapture sc = new ScreenCapture();
// capture entire screen, and save it to a file
Image img = sc.CaptureScreen();
// display image in a Picture control named imageDisplay
this.imageDisplay.Image = img;
// capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);

http://www.developerfusion.com/code/4630/capture-a-screen-shot/

joe
fuente
77
Ya sé cómo capturar una captura de pantalla estándar. Solo necesito saber cómo capturar la ventana activa.
usuario
3
Gran solución! Gracias por el enlace.
Matthew M.
66
@joe obtengo un error GDI + cuando intento ejecutar el código anterior. el error ocurre en la clase ScreenCpature al guardar imágenes.
hurnhu
2
¡Excelente! Quería capturar el contenido de un panel en mi aplicación. Así que hice sc.CaptureWindowToFile (panel1.Handle, "c: \ temp.jpg", imageformat.jpg) y ¡listo!
D. Kermott
2
En resolución HD con elementos de interfaz de Windows con zoom, esta clase no captura toda la pantalla.
Yeronimo
223
Rectangle bounds = Screen.GetBounds(Point.Empty);
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
    using(Graphics g = Graphics.FromImage(bitmap))
    {
         g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }
    bitmap.Save("test.jpg", ImageFormat.Jpeg);
}

para capturar el uso actual de la ventana

 Rectangle bounds = this.Bounds;
 using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
 {
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(new Point(bounds.Left,bounds.Top), Point.Empty, bounds.Size);
    }
    bitmap.Save("C://test.jpg", ImageFormat.Jpeg);
 }
Arsen Mkrtchyan
fuente
¡Ordenado! Pensé que tendrías que usar el WinAPI. ¿Sabes si esto se implementa en Mono?
Lucas Jones
Esto solo me da una captura de pantalla normal. ¿No tengo que usar el WinAPI?
usuario
Hola, ¿puedo saber cómo hacer capturas de pantalla en vb web form aspx?
beny lim
Hola @benylim, mira esto ( stackoverflow.com/questions/701798/… ) y esto ( social.msdn.microsoft.com/Forums/en/netfxjscript/thread/… ), espero que esto ayude
Arsen Mkrtchyan
¿Isitz solo puede hacer con Java Script?
beny lim
29

Sugiero la próxima solución para capturar cualquier ventana activa actual (no solo nuestra aplicación C #) o la pantalla completa con la determinación de la posición del cursor en relación con la esquina superior izquierda de la ventana o pantalla, respectivamente:

public enum enmScreenCaptureMode
{
    Screen,
    Window
}

class ScreenCapturer
{
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

    [StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    public Bitmap Capture(enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window)
    {
        Rectangle bounds;

        if (screenCaptureMode == enmScreenCaptureMode.Screen)
        {
            bounds = Screen.GetBounds(Point.Empty);
            CursorPosition = Cursor.Position;
        }
        else
        {
            var foregroundWindowsHandle = GetForegroundWindow();
            var rect = new Rect();
            GetWindowRect(foregroundWindowsHandle, ref rect);
            bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
            CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
        }

        var result = new Bitmap(bounds.Width, bounds.Height);

        using (var g = Graphics.FromImage(result))
        {
            g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
        }

        return result;
    }

    public Point CursorPosition
    {
        get;
        protected set;
    }
}
Ivan Kochurkin
fuente
¿Por qué necesitamos declarar nuestra propia estructura de rectángulo en lugar de utilizar System.Drawing.Rectangle? ¿Es solo para que podamos agregar un atributo? ¿Sabes si también deberíamos hacer esto para la estructura Point?
Caster Troy
@ Alex, traté de reemplazar mi Rectsistema Rectangle, pero después de eso la función GetWindowRectdevolvió un rectángulo incorrecto. En lugar de Righty Top, establece Widthy Heightdel rectángulo de salida.
Ivan Kochurkin el
1
Una advertencia: la ventana de primer plano no es necesariamente la ventana de la aplicación desde la que se llama. Para una aplicación WPF de una sola ventana que var thisWindowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
usarías
23

Aquí hay un fragmento para capturar el escritorio o la ventana activa. No tiene referencia a Windows Forms.

public class ScreenCapture
{
    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetDesktopWindow();

    [StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }   

    [DllImport("user32.dll")]
    private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

    public static Image CaptureDesktop()
    {
        return CaptureWindow(GetDesktopWindow());
    }

    public static Bitmap CaptureActiveWindow()
    {
        return CaptureWindow(GetForegroundWindow());
    }

    public static Bitmap CaptureWindow(IntPtr handle)
    {
        var rect = new Rect();
        GetWindowRect(handle, ref rect);
        var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
        var result = new Bitmap(bounds.Width, bounds.Height);

        using (var graphics = Graphics.FromImage(result))
        {
            graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
        }

        return result;
    }
}

Cómo capturar toda la pantalla:

var image = ScreenCapture.CaptureDesktop();
image.Save(@"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);

Cómo capturar la ventana activa:

var image = ScreenCapture.CaptureActiveWindow();
image.Save(@"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);

Originalmente encontrado aquí: http://www.snippetsource.net/Snippet/158/capture-screenshot-in-c

Christian Moser
fuente
Muchas gracias Christian por este gran fragmento. ¡Me ayudó mucho!
casaout
Esto funciona muy bien, pero no funciona si el usuario tiene un ajuste de escala en esa pantalla (es decir, el 125% corta los lados izquierdo e inferior)
russelrillema
12

El código de KvanTTT funcionó muy bien. Lo extendí un poco para permitir un poco más de flexibilidad en el formato de guardado, así como la capacidad de guardar mediante hWnd, .NET Control / Form. Puede obtener un mapa de bits o guardarlo en un archivo, con algunas opciones.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MosaiqPerformanceMonitor {
     public enum CaptureMode {
          Screen, Window
     }

     public static class ScreenCapturer {
          [DllImport("user32.dll")]
          private static extern IntPtr GetForegroundWindow();

          [DllImport("user32.dll")]
          private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);

          [StructLayout(LayoutKind.Sequential)]
          private struct Rect {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
          }

          [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
          public static extern IntPtr GetDesktopWindow();

          /// <summary> Capture Active Window, Desktop, Window or Control by hWnd or .NET Contro/Form and save it to a specified file.  </summary>
          /// <param name="filename">Filename.
          /// <para>* If extension is omitted, it's calculated from the type of file</para>
          /// <para>* If path is omitted, defaults to %TEMP%</para>
          /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
          /// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
          /// <param name="format">Optional file save mode.  Default is PNG</param>
          public static void CaptureAndSave(string filename, CaptureMode mode = CaptureMode.Window, ImageFormat format = null) {
                ImageSave(filename, format, Capture(mode));
          }

          /// <summary> Capture a specific window (or control) and save it to a specified file.  </summary>
          /// <param name="filename">Filename.
          /// <para>* If extension is omitted, it's calculated from the type of file</para>
          /// <para>* If path is omitted, defaults to %TEMP%</para>
          /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
          /// <param name="handle">hWnd (handle) of the window to capture</param>
          /// <param name="format">Optional file save mode.  Default is PNG</param>
          public static void CaptureAndSave(string filename, IntPtr handle, ImageFormat format = null) {
                ImageSave(filename, format, Capture(handle));
          }

          /// <summary> Capture a specific window (or control) and save it to a specified file.  </summary>
          /// <param name="filename">Filename.
          /// <para>* If extension is omitted, it's calculated from the type of file</para>
          /// <para>* If path is omitted, defaults to %TEMP%</para>
          /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
          /// <param name="c">Object to capture</param>
          /// <param name="format">Optional file save mode.  Default is PNG</param>
          public static void CaptureAndSave(string filename, Control c, ImageFormat format = null) {
                ImageSave(filename, format, Capture(c));
          }
          /// <summary> Capture the active window (default) or the desktop and return it as a bitmap </summary>
          /// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
          public static Bitmap Capture(CaptureMode mode = CaptureMode.Window) {
                return Capture(mode == CaptureMode.Screen ? GetDesktopWindow() : GetForegroundWindow());
          }

          /// <summary> Capture a .NET Control, Form, UserControl, etc. </summary>
          /// <param name="c">Object to capture</param>
          /// <returns> Bitmap of control's area </returns>
          public static Bitmap Capture(Control c) {
                return Capture(c.Handle);
          }


          /// <summary> Capture a specific window and return it as a bitmap </summary>
          /// <param name="handle">hWnd (handle) of the window to capture</param>
          public static Bitmap Capture(IntPtr handle) {
                Rectangle bounds;
                var rect = new Rect();
                GetWindowRect(handle, ref rect);
                bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
                CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);

                var result = new Bitmap(bounds.Width, bounds.Height);
                using (var g = Graphics.FromImage(result))
                     g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);

                return result;
          }

          /// <summary> Position of the cursor relative to the start of the capture </summary>
          public static Point CursorPosition;


          /// <summary> Save an image to a specific file </summary>
          /// <param name="filename">Filename.
          /// <para>* If extension is omitted, it's calculated from the type of file</para>
          /// <para>* If path is omitted, defaults to %TEMP%</para>
          /// <para>* Use %NOW% to put a timestamp in the filename</para></param>
          /// <param name="format">Optional file save mode.  Default is PNG</param>
          /// <param name="image">Image to save.  Usually a BitMap, but can be any
          /// Image.</param>
          static void ImageSave(string filename, ImageFormat format, Image image) {
                format = format ?? ImageFormat.Png;
                if (!filename.Contains("."))
                     filename = filename.Trim() + "." + format.ToString().ToLower();

                if (!filename.Contains(@"\"))
                     filename = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? @"C:\Temp", filename);

                filename = filename.Replace("%NOW%", DateTime.Now.ToString("[email protected]"));
                image.Save(filename, format);
          }
     }
}
Wade Hatler
fuente
Grandes habilidades refactorias!
Ahmed Alejo
Parte superior del código, lo hice funcionar sin problemas y era justo lo que estaba buscando. Gracias por compartir.
Hugo Yates
1

Un pequeño ajuste al método estático vacío ImageSave () le dará la opción de guardarlo. El crédito va a Microsoft (http://msdn.microsoft.com/en-us/library/sfezx97z.aspx)

static void ImageSave(string filename, ImageFormat format, Image image, SaveFileDialog saveFileDialog1)
    { 
        saveFileDialog1.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif";
        saveFileDialog1.Title = "Enregistrer un image";
        saveFileDialog1.ShowDialog();

        // If the file name is not an empty string open it for saving.
        if (saveFileDialog1.FileName != "")
        {
            // Saves the Image via a FileStream created by the OpenFile method.
            System.IO.FileStream fs =
               (System.IO.FileStream)saveFileDialog1.OpenFile();
            // Saves the Image in the appropriate ImageFormat based upon the
            // File type selected in the dialog box.
            // NOTE that the FilterIndex property is one-based.
            switch (saveFileDialog1.FilterIndex)
            {
                case 1:
                    image.Save(fs,
                       System.Drawing.Imaging.ImageFormat.Jpeg);
                    break;

                case 2:
                    image.Save(fs,
                       System.Drawing.Imaging.ImageFormat.Bmp);
                    break;

                case 3:
                    image.Save(fs,
                       System.Drawing.Imaging.ImageFormat.Gif);
                    break;
            }

            fs.Close();
        }



    }

Su evento button_click debe codificarse de esta manera ...

private void btnScreenShot_Click(object sender, EventArgs e)
    {

        SaveFileDialog saveFileDialog1 = new SaveFileDialog();


        ScreenCapturer.CaptureAndSave(filename, mode, format, saveFileDialog1);

    }//
Junior CSharp
fuente
1

Si desea usar código administrado: Esto capturará cualquier ventana a través de ProcessId.

Usé lo siguiente para activar la ventana.

Microsoft.VisualBasic.Interaction.AppActivate(ProcessId);
Threading.Thread.Sleep(20);

Usé la pantalla de impresión para capturar una ventana.

SendKeys.SendWait("%{PRTSC}");
Threading.Thread.Sleep(40);
IDataObject objData = Clipboard.GetDataObject();
Klaus Heinrich
fuente
1

Utiliza el siguiente código:

            // Shot size = screen size
            Size shotSize = Screen.PrimaryScreen.Bounds.Size;

            // the upper left point in the screen to start shot
            // 0,0 to get the shot from upper left point
            Point upperScreenPoint = new Point(0, 0);

            // the upper left point in the image to put the shot
            Point upperDestinationPoint = new Point(0, 0);

            // create image to get the shot in it
            Bitmap shot = new Bitmap(shotSize.Width, shotSize.Height);

            // new Graphics instance 
            Graphics graphics = Graphics.FromImage(shot);

            // get the shot by Graphics class 
            graphics.CopyFromScreen(upperScreenPoint, upperDestinationPoint, shotSize);

            // return the image
            pictureBox1.Image = shot;
Muhanned F.Obaid
fuente
0

Basado en la respuesta de ArsenMkrt, pero esta le permite capturar un control en su formulario (por ejemplo, estoy escribiendo una herramienta que tiene un control WebBrowser y desea capturar solo su pantalla). Tenga en cuenta el uso del método PointToScreen:

//Project: WebCapture
//Filename: ScreenshotUtils.cs
//Author: George Birbilis (http://zoomicon.com)
//Version: 20130820

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

namespace WebCapture
{
  public static class ScreenshotUtils
  {

    public static Rectangle Offseted(this Rectangle r, Point p)
    {
      r.Offset(p);
      return r;
    }

    public static Bitmap GetScreenshot(this Control c)
    {
      return GetScreenshot(new Rectangle(c.PointToScreen(Point.Empty), c.Size));
    }

    public static Bitmap GetScreenshot(Rectangle bounds)
    {
      Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
      using (Graphics g = Graphics.FromImage(bitmap))
        g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
      return bitmap;
    }

    public const string DEFAULT_IMAGESAVEFILEDIALOG_TITLE = "Save image";
    public const string DEFAULT_IMAGESAVEFILEDIALOG_FILTER = "PNG Image (*.png)|*.png|JPEG Image (*.jpg)|*.jpg|Bitmap Image (*.bmp)|*.bmp|GIF Image (*.gif)|*.gif";

    public const string CUSTOMPLACES_COMPUTER = "0AC0837C-BBF8-452A-850D-79D08E667CA7";
    public const string CUSTOMPLACES_DESKTOP = "B4BFCC3A-DB2C-424C-B029-7FE99A87C641";
    public const string CUSTOMPLACES_DOCUMENTS = "FDD39AD0-238F-46AF-ADB4-6C85480369C7";
    public const string CUSTOMPLACES_PICTURES = "33E28130-4E1E-4676-835A-98395C3BC3BB";
    public const string CUSTOMPLACES_PUBLICPICTURES = "B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5";
    public const string CUSTOMPLACES_RECENT = "AE50C081-EBD2-438A-8655-8A092E34987A";

    public static SaveFileDialog GetImageSaveFileDialog(
      string title = DEFAULT_IMAGESAVEFILEDIALOG_TITLE, 
      string filter = DEFAULT_IMAGESAVEFILEDIALOG_FILTER)
    {
      SaveFileDialog dialog = new SaveFileDialog();

      dialog.Title = title;
      dialog.Filter = filter;


      /* //this seems to throw error on Windows Server 2008 R2, must be for Windows Vista only
      dialog.CustomPlaces.Add(CUSTOMPLACES_COMPUTER);
      dialog.CustomPlaces.Add(CUSTOMPLACES_DESKTOP);
      dialog.CustomPlaces.Add(CUSTOMPLACES_DOCUMENTS);
      dialog.CustomPlaces.Add(CUSTOMPLACES_PICTURES);
      dialog.CustomPlaces.Add(CUSTOMPLACES_PUBLICPICTURES);
      dialog.CustomPlaces.Add(CUSTOMPLACES_RECENT);
      */

      return dialog;
    }

    public static void ShowSaveFileDialog(this Image image, IWin32Window owner = null)
    {
      using (SaveFileDialog dlg = GetImageSaveFileDialog())
        if (dlg.ShowDialog(owner) == DialogResult.OK)
          image.Save(dlg.FileName);
    }

  }
}

Al tener el objeto Bitmap, simplemente puede llamar Guardar en él

private void btnCapture_Click(object sender, EventArgs e)
{
  webBrowser.GetScreenshot().Save("C://test.jpg", ImageFormat.Jpeg);
}

Lo anterior asume que el GC tomará el mapa de bits, pero tal vez sea mejor asignar el resultado de someControl.getScreenshot () a una variable de mapa de bits, luego deseche esa variable manualmente cuando termine con cada imagen, especialmente si está haciendo esto a menudo ( supongamos que tiene una lista de páginas web que desea cargar y guardar capturas de pantalla de ellas):

private void btnCapture_Click(object sender, EventArgs e)
{
  Bitmap bitmap = webBrowser.GetScreenshot();
  bitmap.ShowSaveFileDialog();
  bitmap.Dispose(); //release bitmap resources
}

Aún mejor, podría emplear una cláusula de uso, que tiene el beneficio adicional de liberar los recursos de mapa de bits incluso en el caso de que ocurra una excepción dentro del bloque de uso (hijo):

private void btnCapture_Click(object sender, EventArgs e)
{
  using(Bitmap bitmap = webBrowser.GetScreenshot())
    bitmap.ShowSaveFileDialog();
  //exit from using block will release bitmap resources even if exception occured
}

Actualizar:

Ahora la herramienta WebCapture está implementada con ClickOnce ( http://gallery.clipflair.net/WebCapture ) desde la web (también tiene un buen soporte de actualización automática gracias a ClickOnce) y puede encontrar su código fuente en https://github.com/Zoomicon / ClipFlair / tree / master / Server / Tools / WebCapture

George Birbilis
fuente