Screenshot des aktiven Fensters aufnehmen?

174

Ich mache eine Bildschirmaufnahme-Anwendung und alles läuft gut. Ich muss nur das aktive Fenster erfassen und einen Screenshot dieses aktiven Fensters machen. Weiß jemand, wie ich das machen kann?

Benutzer
quelle
17
Bedeutet "aktives Fenster" das aktive Fenster IHRER App oder das Fenster, das aktiv wäre, wenn Ihre App ausgeblendet wäre?
Corey Trager

Antworten:

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
quelle
7
Ich weiß bereits, wie man einen Standard-Screenshot aufnimmt. Ich muss nur wissen, wie man das aktive Fenster erfasst.
Benutzer
3
Tolle Lösung! Danke für den Link.
Matthew M.
6
@ Joe Ich bekomme einen GDI + Fehler, wenn ich versuche, über Code zu laufen. Der Fehler tritt in der ScreenCpature-Klasse beim Speichern von Bildern auf.
Hurnhu
2
Ausgezeichnet! Ich wollte den Inhalt eines Panels in meiner App erfassen. Also habe ich sc.CaptureWindowToFile (panel1.Handle, "c: \ temp.jpg", imageformat.jpg) und voila gemacht!
D. Kermott
2
Bei HD-Auflösung mit gezoomten Windows-Schnittstellenelementen erfasst diese Klasse nicht den gesamten Bildschirm.
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);
}

zur Erfassung der aktuellen Fensterverwendung

 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
quelle
Ordentlich! Ich dachte, Sie müssten die WinAPI verwenden. Wissen Sie, ob dies auf Mono implementiert ist?
Lucas Jones
Dies gibt mir nur einen normalen Screenshot. Muss ich die WinAPI nicht verwenden?
Benutzer
Hallo, kann ich wissen, wie man Screenshots in vb Web Form Aspx macht?
Beny Lim
Hallo @benylim, werfen Sie einen Blick darauf ( stackoverflow.com/questions/701798/… ) und dies ( social.msdn.microsoft.com/Forums/en/netfxjscript/thread/… ), hoffe dies hilft
Arsen Mkrtchyan
Isitz kann nur mit Java-Skript tun?
Beny Lim
29

Ich schlage die nächste Lösung für die Erfassung eines aktuell aktiven Fensters (nicht nur unserer C # -Anwendung) oder des gesamten Bildschirms mit Cursorpositionsbestimmung relativ zur linken oberen Ecke des Fensters bzw. Bildschirms vor:

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
quelle
Warum müssen wir unsere eigene Rechteckstruktur deklarieren, anstatt System.Drawing.Rectangle zu verwenden? Ist es nur so, dass wir ein Attribut hinzufügen können? Wissen Sie, ob wir dies auch für die Punktstruktur tun sollten?
Caster Troy
@Alex, ich habe versucht, meine Rectdurch System zu ersetzen Rectangle, aber danach hat die Funktion ein GetWindowRectfalsches Rechteck zurückgegeben. Statt Rightund Topes festgelegt Widthund Heightder Ausgang Rechteck.
Ivan Kochurkin
1
Eine Einschränkung: Das Vordergrundfenster ist nicht unbedingt das Fenster der Anwendung, von der aus es aufgerufen wird. Für eine WPF-App mit einem einzigen Fenster würden Sie var thisWindowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle;stattdessen verwenden
am
23

Hier ist ein Ausschnitt, mit dem Sie entweder den Desktop oder das aktive Fenster erfassen können. Es enthält keinen Verweis auf 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;
    }
}

So erfassen Sie den gesamten Bildschirm:

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

So erfassen Sie das aktive Fenster:

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

Ursprünglich hier gefunden: http://www.snippetsource.net/Snippet/158/capture-screenshot-in-c

Christian Moser
quelle
Vielen Dank Christian für diesen tollen Ausschnitt. Es hat mir sehr geholfen!
Casaout
Dies funktioniert gut, funktioniert aber nicht, wenn der Benutzer die Skalierung auf dieser Anzeige eingestellt hat (dh 125% schneiden die linke und untere Seite ab)
russelrillema
12

Der Code von KvanTTT hat großartig funktioniert. Ich habe es ein wenig erweitert, um ein wenig mehr Flexibilität beim Speichern des Formats sowie die Möglichkeit zum Speichern mit hWnd, .NET Control / Form zu ermöglichen. Mit einigen Optionen können Sie eine Bitmap abrufen oder in einer Datei speichern.

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
quelle
Großartige Fertigungsfähigkeiten!
Ahmed Alejo
Top Code, hat es ohne Probleme zum Laufen gebracht und es war genau das, wonach ich gesucht habe. Ich danke Ihnen für das Teilen.
Hugo Yates
1

Durch eine kleine Änderung der Methode static void ImageSave () erhalten Sie die Option, wo Sie sie speichern können. Das Guthaben geht an 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();
        }



    }

Ihr button_click-Ereignis sollte ungefähr so ​​codiert sein ...

private void btnScreenShot_Click(object sender, EventArgs e)
    {

        SaveFileDialog saveFileDialog1 = new SaveFileDialog();


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

    }//
Junior CSharp
quelle
1

Wenn Sie verwalteten Code verwenden möchten: Dadurch wird jedes Fenster über die ProcessId erfasst.

Ich habe Folgendes verwendet, um das Fenster zu aktivieren.

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

Ich habe den Druckbildschirm verwendet, um ein Fenster aufzunehmen.

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

Verwenden Sie den folgenden Code:

            // 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
quelle
0

Basierend auf der Antwort von ArsenMkrt, aber mit dieser können Sie ein Steuerelement in Ihrem Formular erfassen (ich schreibe beispielsweise ein Tool, das ein WebBrowser-Steuerelement enthält und nur dessen Anzeige erfassen möchte). Beachten Sie die Verwendung der PointToScreen-Methode:

//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);
    }

  }
}

Mit dem Bitmap-Objekt können Sie einfach Speichern aufrufen

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

Oben wird davon ausgegangen, dass der GC die Bitmap abruft. Vielleicht ist es jedoch besser, das Ergebnis von someControl.getScreenshot () einer Bitmap-Variablen zuzuweisen und diese Variable dann manuell zu entsorgen, wenn Sie mit jedem Bild fertig sind, insbesondere wenn Sie dies häufig tun ( Angenommen, Sie haben eine Liste von Webseiten, die Sie laden und Screenshots davon speichern möchten.

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

Noch besser ist, dass eine using-Klausel verwendet werden könnte, die den zusätzlichen Vorteil hat, dass die Bitmap-Ressourcen auch im Falle einer Ausnahme innerhalb des using (child) -Blocks freigegeben werden:

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
}

Aktualisieren:

Jetzt wird das WebCapture-Tool von ClickOnce ( http://gallery.clipflair.net/WebCapture ) aus dem Web bereitgestellt ( dank ClickOnce bietet es auch eine gute Unterstützung für die automatische Aktualisierung). Den Quellcode finden Sie unter https://github.com/Zoomicon / ClipFlair / tree / master / Server / Tools / WebCapture

George Birbilis
quelle