简体   繁体   English

如何使用Mono C#截取屏幕截图?

[英]How to take a screenshot with Mono C#?

I'm trying to use use code get a screenshot in Mono C# but I'm getting a System.NotImplementedException when I call CopyFromScreen . 我正在尝试使用代码在Mono C#中获取屏幕截图,但是当我调用CopyFromScreen时,我收到了System.NotImplementedException。 My code works with .NET, so is there an alternate way of getting a screenshot using Mono? 我的代码适用于.NET,那么是否有另一种使用Mono获取屏幕截图的方法?

Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap as Image);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
bitmap.Save(memoryStream, imageFormat);
bitmap.Save(@"\tmp\screenshot.png", ImageFormat.Png);

I am using Mono JIT compiler version 2.4.2.3 (Debian 2.4.2.3+dfsg-2) 我使用的是Mono JIT编译器版本2.4.2.3(Debian 2.4.2.3 + dfsg-2)

UPDATE: Mono cannot take screenshots. 更新:Mono无法截屏。 Sad. 伤心。 Lame. 瘸。

I guess an alternative would be using gtk# to get a screenshot. 我想另一种方法是使用gtk#来获取截图。 You would need to create a mono project with GTK# support, after that following code should execute: 在执行以下代码之后,您需要创建一个带有GTK#支持的单声道项目:

Gdk.Window window = Gdk.Global.DefaultRootWindow;
if (window!=null)
{           
    Gdk.Pixbuf pixBuf = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, false, 8, 
                                       window.Screen.Width, window.Screen.Height);          
    pixBuf.GetFromDrawable(window, Gdk.Colormap.System, 0, 0, 0, 0, 
                           window.Screen.Width, window.Screen.Height);          
    pixBuf.ScaleSimple(400, 300, Gdk.InterpType.Bilinear);
    pixBuf.Save("screenshot0.jpeg", "jpeg");
}

you could also use P\\Invoke and call GTK functions directly. 你也可以使用P \\ Invoke直接调用GTK函数。

hope this helps, regards 希望这有帮助,问候

We had the same problem when we needed to take screenshots with Mono on Linux and OS X in the same software. 当我们需要在同一软件中使用Linux和OS X上的Mono屏幕截图时,我们遇到了同样的问题。

Actually, you can use CopyFromScreen on Mono on Linux. 实际上,您可以在Linux上使用Mono上的CopyFromScreen However you need to install mono-complete package, which includes System.Drawing. 但是,您需要安装mono-complete软件包,其中包括System.Drawing。

For OS X the most reliable way is to Process.Start the screencapture command line tool. 对于OS X ,最可靠的方法是Process.Start screencapture命令行工具。 It is present there by default. 它默认出现在那里。

For Linux , to make it reliable, one can use either import command line from ImageMagic (you'll need to make it a dependency in this case), or force dependency on mono-complete package which includes System.Drawing. 对于Linux ,要使其可靠,可以使用ImageMagic中的任一import命令行(在这种情况下您需要使其成为依赖项),或者强制依赖包含System.Drawing的mono-complete包。 Gtk# approach is unreliable according to our tests and may provide blank screens or fail with exception (and we take thousands of screenshots on various machines every day). 根据我们的测试,Gtk#方法是不可靠的,并且可能提供空白屏幕或异常失败(我们每天在各种机器上拍摄数千个屏幕截图)。

Another thing is that when you need to capture multiple displays in one screenshot, you have to properly align separate screenshots after taking those separately via CopyFromScreen. 另一件事是,当您需要在一个屏幕截图中捕获多个显示时,您必须在通过CopyFromScreen单独拍摄之后正确对齐单独的屏幕截图。

So we have this solution so far: 所以到目前为止我们有这个解决方案

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace Pranas
{
    /// <summary>
    ///     ScreenshotCapture
    /// </summary>
    public static class ScreenshotCapture
    {
        #region Public static methods

        /// <summary>
        ///     Capture screenshot to Image object
        /// </summary>
        /// <param name="onlyPrimaryScreen">Create screen only from primary screen</param>
        /// <returns></returns>
        public static Image TakeScreenshot(bool onlyPrimaryScreen = false)
        {
            try
            {
                return WindowsCapture(onlyPrimaryScreen);
            }
            catch (Exception)
            {
                return OsXCapture(onlyPrimaryScreen);
            }
        }

        #endregion

        #region  Private static methods

        //private static Image ImageMagicCapture(bool onlyPrimaryScreen)
        //{
        //  return ExecuteCaptureProcess("import", "-window root ");
        //}

        private static Image OsXCapture(bool onlyPrimaryScreen)
        {
            var data = ExecuteCaptureProcess(
                "screencapture",
                string.Format("{0} -T0 -tpng -S -x", onlyPrimaryScreen ? "-m" : ""));
            return data;
        }


        /// <summary>
        ///     Start execute process with parameters
        /// </summary>
        /// <param name="execModule">Application name</param>
        /// <param name="parameters">Command line parameters</param>
        /// <returns>Bytes for destination image</returns>
        private static Image ExecuteCaptureProcess(string execModule, string parameters)
        {
            var imageFileName = Path.Combine(Path.GetTempPath(), string.Format("screenshot_{0}.jpg", Guid.NewGuid()));

            var process = Process.Start(execModule, string.Format("{0} {1}", parameters, imageFileName));
            if (process == null)
            {
                throw new InvalidOperationException(string.Format("Executable of '{0}' was not found", execModule));
            }
            process.WaitForExit();

            if (!File.Exists(imageFileName))
            {
                throw new InvalidOperationException(string.Format("Failed to capture screenshot using {0}", execModule));
            }

            try
            {
                return Image.FromFile(imageFileName);
            }
            finally
            {
                File.Delete(imageFileName);
            }
        }

        /// <summary>
        ///     Capture screenshot with .NET standard implementation
        /// </summary>
        /// <param name="onlyPrimaryScreen"></param>
        /// <returns>Return bytes of screenshot image</returns>
        private static Image WindowsCapture(bool onlyPrimaryScreen)
        {
            if (onlyPrimaryScreen) return ScreenCapture(Screen.PrimaryScreen);
            var bitmaps = (Screen.AllScreens.OrderBy(s => s.Bounds.Left).Select(ScreenCapture)).ToArray();
            return CombineBitmap(bitmaps);
        }

        /// <summary>
        ///     Create screenshot of single display
        /// </summary>
        /// <param name="screen"></param>
        /// <returns></returns>
        private static Bitmap ScreenCapture(Screen screen)
        {
            var bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height, PixelFormat.Format32bppArgb);

            using (var graphics = Graphics.FromImage(bitmap))
            {
                graphics.CopyFromScreen(
                    screen.Bounds.X,
                    screen.Bounds.Y,
                    0,
                    0,
                    screen.Bounds.Size,
                    CopyPixelOperation.SourceCopy);
            }

            return bitmap;
        }

        /// <summary>
        ///     Combine images into one bitmap
        /// </summary>
        /// <param name="images"></param>
        /// <returns>Combined image</returns>
        private static Image CombineBitmap(ICollection<Image> images)
        {
            Image finalImage = null;

            try
            {
                var width = 0;
                var height = 0;

                foreach (var image in images)
                {
                    width += image.Width;
                    height = image.Height > height ? image.Height : height;
                }

                finalImage = new Bitmap(width, height);

                using (var g = Graphics.FromImage(finalImage))
                {
                    g.Clear(Color.Black);

                    var offset = 0;
                    foreach (var image in images)
                    {
                        g.DrawImage(image,
                            new Rectangle(offset, 0, image.Width, image.Height));
                        offset += image.Width;
                    }
                }
            }
            catch (Exception ex)
            {
                if (finalImage != null)
                    finalImage.Dispose();
                throw ex;
            }
            finally
            {
                //clean up memory
                foreach (var image in images)
                {
                    image.Dispose();
                }
            }

            return finalImage;
        }

        #endregion
    }
}

Or install it via NuGet ( disclaimer: I'm the author ): 或者通过NuGet安装它( 免责声明:我是作者 ):

PM> Install-Package Pranas.ScreenshotCapture

We use it heavily in our product on many setups, so we periodically improve the code and put notes into blog . 我们在许多设置中大量使用它,因此我们会定期改进代码并将注释放入博客中

使用Mono 2.4.4,您可以在没有 GTK#的情况下获得整个屏幕:

public static class MonoScreenShooter { public static void TakeScreenshot(string filePath) { using (Bitmap bmpScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)) { using (Graphics g = Graphics.FromImage(bmpScreenCapture)) { g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, bmpScreenCapture.Size, CopyPixelOperation.SourceCopy); } bmpScreenCapture.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg); } } } }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM