Skip to content

Instantly share code, notes, and snippets.

@MarcosCobena
Created August 28, 2018 10:37
Show Gist options
  • Save MarcosCobena/b4768bacc1a112a4f38a9d11a19f1251 to your computer and use it in GitHub Desktop.
Save MarcosCobena/b4768bacc1a112a4f38a9d11a19f1251 to your computer and use it in GitHub Desktop.
A workaround to take screenshots under macOS when Gtk# crashes doing the same (https://github.com/mono/gtk-sharp/issues/236)
using System;
using System.Runtime.InteropServices;
using AppKit;
using CoreGraphics;
using Foundation;
using ImageIO;
using MobileCoreServices;
namespace ScreenshotDemo
{
// NOTE Follow https://docs.microsoft.com/es-es/xamarin/mac/app-fundamentals/console to include Xamarin.Mac head-less dependencies
public static class MacOSScreenshot
{
private const string _appServicesPath =
"/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices";
// https://developer.apple.com/documentation/coregraphics/1454603-cggetactivedisplaylist
[DllImport(_appServicesPath, EntryPoint = "CGGetActiveDisplayList")]
private static extern int CGGetActiveDisplayList(int maxDisplays, int[] activeDisplays, out int displayCount);
// https://developer.apple.com/documentation/coregraphics/1455691-cgdisplaycreateimage
[DllImport(_appServicesPath, EntryPoint = "CGDisplayCreateImage")]
private static extern /* CGImageRef */ IntPtr CGDisplayCreateImage(int displayId);
// Based on: https://stackoverflow.com/a/40864231
public static void Take()
{
NSApplication.Init();
var result = CGGetActiveDisplayList(0, null, out int displayCount);
// https://developer.apple.com/documentation/coregraphics/cgerror/success
if (result != 0)
{
Console.WriteLine("Error retrieving the displays count.");
return;
}
var allocated = displayCount;
// CGDirectDisplayID is an Int32: https://developer.apple.com/documentation/coregraphics/cgdirectdisplayid
var activeDisplays = new int[allocated]; // UnsafeMutablePointer<CGDirectDisplayID>.allocate(capacity: allocated)
result = CGGetActiveDisplayList(displayCount, activeDisplays, out displayCount);
if (result != 0)
{
Console.WriteLine("Error retrieving the displays list.");
return;
}
for (int i = 0; i < displayCount; i++)
{
var handle = CGDisplayCreateImage(activeDisplays[i]);
var screenShot = new CGImage(handle);
//let bitmapRep = NSBitmapImageRep(cgImage: screenShot)
//let jpegData = bitmapRep.representation(using: NSBitmapImageFileType.JPEG, properties: [:])!
#if DEBUG
Save(screenShot, $"/Users/marcos/Desktop/screenshot-{i}");
#endif
}
}
// It returns 1x1 px screenshots :-S
// Based on: https://stackoverflow.com/q/45714609
// public static void Take()
// {
// var screens = NSScreen.Screens;
// for (int i = 0; i < screens.Length; i++)
// {
// var item = screens[i];
// var screenshot = CGImage.ScreenImage(i, item.Frame);
//#if DEBUG
// Save(screenshot, $"/Users/marcos/Desktop/screenshot-{i}");
//#endif
// }
//}
#if DEBUG
private static void Save(CGImage screenshot, string filename)
{
var imageFormat = UTType.PNG;
var fileURL = new NSUrl($"{filename}.{imageFormat.ToString().ToLowerInvariant()}", false);
using (var dataConsumer = new CGDataConsumer(fileURL))
{
var imageDestination = CGImageDestination.Create(dataConsumer, imageFormat, 1);
imageDestination.AddImage(screenshot);
imageDestination.Close();
}
}
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment