Как сделать скриншот с Mono C #? - PullRequest
4 голосов
/ 27 апреля 2010

Я пытаюсь использовать код для получения снимка экрана в Mono C #, но при вызове CopyFromScreen я получаю исключение System.NotImplementedException. Мой код работает с .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);

Я использую Mono JIT-компилятор версии 2.4.2.3 (Debian 2.4.2.3 + dfsg-2)

ОБНОВЛЕНИЕ: Mono не может делать скриншоты. Печальный. Lame.

Ответы [ 3 ]

4 голосов
/ 01 мая 2010

Я полагаю, что альтернативой будет использование gtk # для получения скриншота. Вам необходимо создать моно-проект с поддержкой 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");
}

Вы также можете использовать P \ Invoke и напрямую вызывать функции GTK.

надеюсь, это поможет, с уважением

2 голосов
/ 20 января 2015

У нас была такая же проблема, когда нам нужно было делать скриншоты с Mono в Linux и OS X в одном программном обеспечении.

На самом деле, вы можете использовать CopyFromScreen в Mono в Linux. Однако вам необходимо установить моно-полный пакет, который включает System.Drawing.

Для OS X наиболее надежным способом является обработка. Запустите инструмент командной строки screencapture. Он присутствует там по умолчанию.

Для Linux , чтобы сделать его надежным, можно использовать либо import командную строку из ImageMagic (в этом случае вам потребуется сделать ее зависимой), либо принудительную зависимость от mono-complete пакет, который включает System.Drawing. Подход Gtk # ненадежен в соответствии с нашими тестами и может привести к появлению пустых экранов или сбою без исключения (и мы ежедневно делаем тысячи снимков экрана на разных машинах).

Другое дело, что когда вам нужно захватить несколько дисплеев на одном скриншоте, вы должны правильно выровнять отдельные скриншоты после того, как снимаете их отдельно с помощью CopyFromScreen.

Итак, у нас пока есть это решение:

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
    }
}

Или установите его через NuGet ( отказ от ответственности: я автор ):

PM> Install-Package Pranas.ScreenshotCapture

Мы интенсивно используем его в нашем продукте во многих настройках, поэтому мы периодически улучшаем код и помещаем заметки в blog .

0 голосов
/ 15 сентября 2014

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...