0

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:

  1. Tried to Dispose() it:

    this.rotatedBitmap?.Dispose();
    this.rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
    

    Here it crashes with the first dispose.

  2. 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.

testing
  • 19,681
  • 50
  • 236
  • 417

1 Answers1

0

Because I didn't receive any feedback I did what I could and this is the use of the reduced image. With this the app is more stable, but it doesn't 100% fix the issue.

The rotation algorithm stayed the same and for resizing the image I found this worked the best, because it reduces my image from ~2 MB to ~50 KB. Before I tried to use the sample implementation from Android, but I didn't get the efficiency like the FFImageLoading library does. With another resizing algorithm I also didn't get the smoothness in resizing. As for the sizes I used the current page width, which seems to be ok for portrait and landscape position.

testing
  • 19,681
  • 50
  • 236
  • 417