I'm trying to grab a screenshot and save it on disk using Xamarin and C# on Mac. I wrote the code below:
public static void TakeScreenshotAndSaveToDisk(string path)
{
var fullScreenBounds = NSScreen.MainScreen.Frame;
IntPtr ptr = CGWindowListCreateImage(fullScreenBounds, CGWindowListOption.OnScreenAboveWindow, 0, CGWindowImageOption.Default);
var cgImage = new CGImage(ptr);
var fileURL = new NSUrl(path, false);
var imageDestination = CGImageDestination.Create(new CGDataConsumer(fileURL), UTType.PNG, 1);
imageDestination.AddImage(cgImage);
imageDestination.Close();
imageDestination.Dispose();
fileURL.Dispose();
cgImage.Dispose();
}
The method executes and the file appears at the correct location. If I try to open it, it will show blank. If I click "Get Info" on the file it will not show a preview. After I close my app, the image can be opened and "Get Info" shows the preview.
What am I doing wrong here? It seems to me that the resources are not released even though I call Dispose() on the objects.
Thanks.
The CGImageDestination.Create
method has 3 different signatures, if you use the one that accepts a NSUrl instead of a CGDataConsumer
you should be good.
var imageDestination = CGImageDestination.Create(fileURL, UTType.PNG, 1);
With this one you don't need to create a CGDataConsumer
but if you really want/need to
var dataConsumer = new CGDataConsumer(fileURL);
var imageDestination = CGImageDestination.Create(dataConsumer, UTType.PNG, 1);
imageDestination.AddImage(cgImage);
imageDestination.Close();
dataConsumer.Dispose();
Just make sure to dispose the instance once you have saved the file.
With the using
approach:
using (var dataConsumer = new CGDataConsumer(fileURL))
{
var imageDestination = CGImageDestination.Create(dataConsumer, UTType.PNG, 1);
imageDestination.AddImage(cgImage);
imageDestination.Close();
}
Note: for the CGImageDestination
you don't need to manually dispose, the Close
method will also dispose the object (based on the documentation).
public Boolean Close ()
Writes the images to the destination and disposes the object.
Hope this helps.-
I may be late into this but have just implemented this Swift algorithm with Xamarin.Mac, and can be consumed in a head-less mode too:
https://gist.github.com/MarcosCobena/b4768bacc1a112a4f38a9d11a19f1251
It relies on "new" CoreGraphics bindings (some were already present in Xamarin.Mac, but internal or private) to detect displays and enumerate them. Finally, it takes one screenshot per display, saving it as PNG in a given path.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With