The goal is to be able to rotate an image taken by the camera app. My code is based on this rotation and this cropping algorithm. General infos can be found here. The problem occurs only if a big image (e.g. 2 MB) is used and the rotation is done multiple times (e.g. 70x). I'm using an Android tablet with 3 GB of RAM.
This is the place where my code crashes:
public void Rotate()
{
double radians = Math.PI * this.rotationAngle / 180;
float sine = (float)Math.Abs(Math.Sin(radians));
float cosine = (float)Math.Abs(Math.Cos(radians));
int originalWidth = this.originalBitmap.Width;
int originalHeight = this.originalBitmap.Height;
int rotatedWidth = (int)(cosine * originalWidth + sine * originalHeight);
int rotatedHeight = (int)(cosine * originalHeight + sine * originalWidth);
this.rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
using (SKCanvas canvas = new SKCanvas(this.rotatedBitmap))
{
canvas.Clear(SKColors.White);
canvas.Translate(rotatedWidth / 2, rotatedHeight / 2);
canvas.RotateDegrees((float)this.rotationAngle);
canvas.Translate(-originalWidth / 2, -originalHeight / 2);
canvas.DrawBitmap(originalBitmap, new SKPoint());
}
this.InvalidateSurface();
}
It crashes on the line with new SKBitmap()
and the following message:
06-10 10:26:09.255 I/MonoDroid(19721): UNHANDLED EXCEPTION:
06-10 10:26:09.266 I/MonoDroid(19721): System.Exception: Unable to allocate pixels for the bitmap.
06-10 10:26:09.266 I/MonoDroid(19721): at SkiaSharp.SKBitmap..ctor (SkiaSharp.SKImageInfo info, System.Int32 rowBytes) [0x00023] in <0665b4d05b9e46c8a33bb731d6f5db83>:0
06-10 10:26:09.266 I/MonoDroid(19721): at SkiaSharp.SKBitmap..ctor (SkiaSharp.SKImageInfo info) [0x00009] in <0665b4d05b9e46c8a33bb731d6f5db83>:0
06-10 10:26:09.267 I/MonoDroid(19721): at SkiaSharp.SKBitmap..ctor (System.Int32 width, System.Int32 height, SkiaSharp.SKColorType colorType, SkiaSharp.SKAlphaType alphaType) [0x0000b] in <0665b4d05b9e46c8a33bb731d6f5db83>:0
06-10 10:26:09.267 I/MonoDroid(19721): at SkiaSharp.SKBitmap..ctor (System.Int32 width, System.Int32 height, System.Boolean isOpaque) [0x00000] in <0665b4d05b9e46c8a33bb731d6f5db83>:0
06-10 10:26:09.267 I/MonoDroid(19721): at MyApp.PhotoCropperCanvasView.Rotate() [0x0009e] in C:\Users\some-user\Source\MyApp\PhotoCroppingCanvasView.cs:145
Things I tried:
Tried to
Dispose()
it:this.rotatedBitmap?.Dispose(); this.rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
Here it crashes with the first dispose.
Use of
using
:using (SKBitmap newBitMap = new SKBitmap(rotatedWidth, rotatedHeight)) { using (SKCanvas canvas = new SKCanvas(newBitMap)) { canvas.Clear(SKColors.White); canvas.Translate(rotatedWidth / 2, rotatedHeight / 2); canvas.RotateDegrees((float)this.picAngle); canvas.Translate(-originalWidth / 2, -originalHeight / 2); canvas.DrawBitmap(originalBitmap, new SKPoint()); } newBitMap.CopyTo(this.rotatedBitmap); } this.InvalidateSurface();
The same behavior occurs, where I can rotate the picture some times, but after a certain number (e.g. 70x) it crashes the app.
What can I do to have a better memory management? The only thing, which comes up to my mind is to use a minituarized/reduced image, but this will not stop the crash and only delay it.