I know there are a lot of articles about using the camera out there but sadly nothing helped me out.
My project seemed to be simple: Take a photo (don't save it), crop a part and create a new image from it (don't save it) and use this for further calculations.
My written code already worked fine at the emulator but fails at my Galaxy phone.
I used the CameraView of the Xamarin.CommunityToolkit:
xmlns:xct="clr-namespace:Xamarin.CommunityToolkit.UI.Views;assembly=Xamarin.CommunityToolkit"
<xct:CameraView x:Name="xctCameraView"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
CaptureMode="Photo"
MediaCaptured="MediaCaptured"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
IsVisible="True" />
In the MediaCaptured event I want to work with the captured photo:
private void MediaCaptured(object sender, MediaCapturedEventArgs e)
{
var imageData = e.ImageData;
var cropRectSize = overlayView.GetOverlayRectSize();
var resultImage = GetCroppedImage(imageData, cropRectSize);
if (resultImage != null)
{
...
var image = SKImage.FromPixels(resultImage.PeekPixels());
var encoded = image.Encode();
var stream = encoded.AsStream();
imgView.Source = ImageSource.FromStream(() => stream);
}
}
Here is the void where the error on my Galaxy phone appeared (originally I used "using" with all disposable objects below with the same result):
private SKBitmap GetCroppedImage(byte[] imageData, float[] cropRectSize)
{
if (cropRectSize.Length != 2)
return null;
var cropRectWidth = cropRectSize[0];
var cropRectHeight = cropRectSize[1];
var memStream = new MemoryStream(imageData);
var bitmap = SKBitmap.Decode(memStream); // <= here it failes (*)
var imageWidthMid = bitmap.Width / 2;
var imageHeightMid = bitmap.Height / 2;
var cropRect = new Xamarin.Forms.Rectangle(imageWidthMid - cropRectWidth / 2,
imageHeightMid - cropRectHeight / 2,
cropRectWidth, cropRectHeight);
SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width,
(int)cropRect.Height);
SKRect dest = new SKRect(0, 0, (float)cropRect.Width, (float)cropRect.Height);
SKRect source = new SKRect((float)cropRect.Left, (float)cropRect.Top,
(float)cropRect.Right, (float)cropRect.Bottom);
var canvas = new SKCanvas(croppedBitmap);
canvas.DrawBitmap(bitmap, source, dest);
return croppedBitmap;
}
(*) The catched error is as follows:
Value cannot be null.
Parameter name: buffer
at SkiaSharp.SKManagedStream.OnReadManagedStream(System.IntPtr buffer, System.IntPtr size) [0x0000d] in <...>:0
at SkiaSharp.SKManagedStream.OnRead(System.IntPtr size) [0x00006] in <...>:0
at SkiaSharp.SKAbstractManagedStream.ReadInternal (System.IntPtr s, System.Void* context, System.Void* buffer, System.IntPtr size) [0x00015] in <...>:0
at (wrapper native-to-managed) SkiaSharp.SKAbstractManagedStream.ReadInternal(intptr,void*,void*,intptr)
at (wrapper native-to-managed) SkiaSharp.SkiaApi.sk_codec_new_from_stream(intptr,SkiaSharp.SKCodecResult*)
at SkiaSharp.SKCodec.Create (SkiaSharp.SKStream stream, SkiaSharp.SKCodecResult& result) [0x0003b] in <...>:0
at SkiaSharp.SKCodec.Create (System.IO.Stream stream, SkiaSharp.SKCodecResult& result) [0x00006] in <...>:0
at SkiaSharp.SKCodec.Create (System.IO.Stream stream) [0x00000] in <...>:0
at SkiaSharp.SKBitmap.Decode (System.IO.Stream stream) [0x0000e] in <...>:0
at GetCroppedImage(System.Byte[] imageData, System.Single[] cropRectSize [0x00049]) in <...>:0
Any help would be very appreciated!
Thanks in advance! Sebastian.
CodePudding user response:
Looks like a typo. In your MediaCaptured
method you have:
var imageData = e.ImageData;
var cropRectSize = overlayView.GetOverlayRectSize();
var resultImage = GetCroppedImage(_imageData, cropRectSize);
You never use imageData
, but rather use _imageData
, which is probably the cause of the null reference.
CodePudding user response:
It is a SkyiaSharp issue and seems to appear on Samsung phones:
https://github.com/mono/SkiaSharp/issues/1551
There is a workaround out there. After changing my GetCroppedImage void to
private SKBitmap GetCroppedImage(Stream stream, float[] cropRectSize)
{
if (cropRectSize.Length != 2)
return null;
var cropRectWidth = cropRectSize[0];
var cropRectHeight = cropRectSize[1];
using (var inputStream = new SKManagedStream(stream))
{
using (var inputData = SKData.Create(inputStream))
{
var bitmap = SKBitmap.Decode(inputData);
var imageWidthMid = bitmap.Width / 2;
var imageHeightMid = bitmap.Height / 2;
var cropRect = new Xamarin.Forms.Rectangle(imageWidthMid - cropRectWidth / 2,
imageHeightMid - cropRectHeight / 2,
cropRectWidth, cropRectHeight);
SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width,
(int)cropRect.Height);
SKRect dest = new SKRect(0, 0, (float)cropRect.Width, (float)cropRect.Height);
SKRect source = new SKRect((float)cropRect.Left, (float)cropRect.Top,
(float)cropRect.Right, (float)cropRect.Bottom);
var canvas = new SKCanvas(croppedBitmap);
canvas.DrawBitmap(bitmap, source, dest);
return croppedBitmap;
}
}
}
It is perfectly working now!
Regards. Sebastian.