我正在尝试使用代码在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无法截屏。伤心。跛。
答案 0 :(得分:4)
我想另一种方法是使用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函数。
希望这有帮助,尊重
答案 1 :(得分:2)
当我们需要在同一软件中使用Linux和OS X上的Mono屏幕截图时,我们遇到了同样的问题。
实际上,您可以在Linux上的Mono上使用CopyFromScreen
。但是,您需要安装mono-complete软件包,其中包括System.Drawing。
对于 OS X ,最可靠的方法是Process.Start screencapture
命令行工具。它默认出现在那里。
对于 Linux ,为了使其可靠,可以使用ImageMagic中的import
命令行(在这种情况下你需要使它成为依赖项),或强制使用依赖于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。
答案 2 :(得分:0)
使用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);
}
}
}
}