Capturing a screen shot is quite easy but cropping is a different story, or at least appears so. We are attempting to emulate the solution here in Xamarin using SkiaSharp (System.Drawing not supported in Xamarin).
Currently we are able to capture the screenshot and return the image BUT if we crop our image the image returned is all black.
How do we crop a captured screenshot correctly?
NOTE*: image = image.Subset(rec);
under the "crop image" section is how we are trying to crop.
iOS screenshot
public byte[] Capture()
{
var capture = UIScreen.MainScreen.Capture();
using (NSData data = capture.AsPNG())
{
var bytes = new byte[data.Length];
Marshal.Copy(data.Bytes, bytes, 0, Convert.ToInt32(data.Length));
return bytes;
}
}
Droid screenshot
public byte[] Capture()
{
var rootView = context.Window.DecorView.RootView;
using (var screenshot = Bitmap.CreateBitmap(
rootView.Width,
rootView.Height,
Bitmap.Config.Argb8888))
{
var canvas = new Canvas(screenshot);
rootView.Draw(canvas);
using (var stream = new MemoryStream())
{
screenshot.Compress(Bitmap.CompressFormat.Png, 90, stream);
return stream.ToArray();
}
}
}
Attempting to crop captured screenshot
// Use this function to crop a screen shot to a specific element.
public byte[] test(byte[] screenshotData, View element)
{
// locate IntPtr to byte[] of uncropped screenshot
GCHandle gch = GCHandle.Alloc(screenshotData, GCHandleType.Pinned);
IntPtr addr = gch.AddrOfPinnedObject();
// assign initial bounds
SKImageInfo info = new SKImageInfo((int)App.Current.MainPage.Width,
(int)App.Current.MainPage.Height);
// create initial pixel map
using SKPixmap pixmap = new SKPixmap(info, addr);
// Release
gch.Free();
// create bitmap
using SKBitmap bitmap = new SKBitmap();
// assign pixel data
bitmap.InstallPixels(pixmap);
// create surface
using SKSurface surface = SKSurface.Create(info);
// create a canvas for drawing
using SKCanvas canvas = surface.Canvas;
// draw
canvas.DrawBitmap(bitmap, info.Rect);
// get an image subset to save
SKImage image = surface.Snapshot();
SKRectI rec = new SKRectI((int)element.Bounds.Left, (int)element.Bounds.Top,
(int)element.Bounds.Right, (int)element.Bounds.Bottom);
// crop image
image = image.Subset(rec);
byte[] bytes = SKBitmap.FromImage(image).Bytes;
image.Dispose();
return bytes;
}
EDIT: Alternative solution attempt (not working)
// Use this function to crop a screen shot to a specific element.
public byte[] test(byte[] screenshotData, View element)
{
// locate IntPtr to byte[] of uncropped screenshot
GCHandle gch = GCHandle.Alloc(screenshotData, GCHandleType.Pinned);
IntPtr addr = gch.AddrOfPinnedObject();
// assign initial bounds
SKImageInfo info = new SKImageInfo((int)App.Current.MainPage.Width,
(int)App.Current.MainPage.Height);
// create bitmap
SKBitmap bitmap = new SKBitmap();
bitmap.InstallPixels(info, addr);
// boundaries
SKRect cropRect = new SKRect((int)element.Bounds.Left, (int)element.Bounds.Top,
(int)element.Bounds.Right, (int)element.Bounds.Bottom);
SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width,
(int)cropRect.Height);
SKRect dest = new SKRect(0, 0, cropRect.Width, cropRect.Height);
SKRect source = new SKRect(cropRect.Left, cropRect.Top,
cropRect.Right, cropRect.Bottom);
// draw with destination and source rectangles
// to extract a subset of the original bitmap
using SKCanvas canvas = new SKCanvas(croppedBitmap);
canvas.DrawBitmap(bitmap, source, dest);
return croppedBitmap.Bytes;
//return bitmap.Bytes;
}