SkiaSharp:多次旋转大图片而不会因为内存管理而导致应用程序崩溃
SkiaSharp: rotate big picture multiple times without crashing the app because of memory management
目标是能够旋转相机应用拍摄的图像。我的代码基于 this rotation and this cropping algorithm. General infos can be found here。仅当使用大图像(例如 2 MB)并且多次旋转(例如 70x)时才会出现此问题。我正在使用具有 3 GB RAM 的 Android 平板电脑。
这是我的代码崩溃的地方:
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();
}
它在 new SKBitmap()
和以下消息的行上崩溃:
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
我尝试过的事情:
试过Dispose()
它:
this.rotatedBitmap?.Dispose();
this.rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
第一次处理时崩溃。
使用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();
出现相同的行为,我可以将图片旋转几次,但在一定数量(例如 70x)后应用程序崩溃。
我该怎么做才能获得更好的内存管理?我唯一想到的是使用 minituarized/reduced 图像,但这不会阻止崩溃,只会延迟崩溃。
因为我没有收到任何反馈,所以我做了我能做的,这就是缩小图像的使用。有了这个应用程序更稳定,但它并不能 100% 解决问题。
旋转算法保持不变,我发现 调整图像大小效果最好,因为它将我的图像从 ~2 MB 减少到 ~50 KB。在我尝试使用 Android 中的示例实现之前,我没有获得像 FFImageLoading
库那样的效率。使用另一种调整大小算法,我也没有得到调整大小的平滑度。至于尺寸,我使用了当前的页面宽度,纵向和横向位置似乎都可以。
目标是能够旋转相机应用拍摄的图像。我的代码基于 this rotation and this cropping algorithm. General infos can be found here。仅当使用大图像(例如 2 MB)并且多次旋转(例如 70x)时才会出现此问题。我正在使用具有 3 GB RAM 的 Android 平板电脑。
这是我的代码崩溃的地方:
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();
}
它在 new SKBitmap()
和以下消息的行上崩溃:
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
我尝试过的事情:
试过
Dispose()
它:this.rotatedBitmap?.Dispose(); this.rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight);
第一次处理时崩溃。
使用
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();
出现相同的行为,我可以将图片旋转几次,但在一定数量(例如 70x)后应用程序崩溃。
我该怎么做才能获得更好的内存管理?我唯一想到的是使用 minituarized/reduced 图像,但这不会阻止崩溃,只会延迟崩溃。
因为我没有收到任何反馈,所以我做了我能做的,这就是缩小图像的使用。有了这个应用程序更稳定,但它并不能 100% 解决问题。
旋转算法保持不变,我发现 FFImageLoading
库那样的效率。使用另一种调整大小算法,我也没有得到调整大小的平滑度。至于尺寸,我使用了当前的页面宽度,纵向和横向位置似乎都可以。