在2018年有效裁剪和缩放位图?

时间:2018-09-01 17:26:17

标签: android bitmap android-glide bitmapfactory

我们在产品中使用位图时遇到困难。我们的目标是快速拍照并立即显示/裁剪。问题是-图像必须具有良好的质量,并且必须快速,良好地裁剪。我亲自尝试了下面的代码,它确实将内存使用量减少了2-3倍。尽管如此,我们还是想知道更有效的方法。我们是否应该始终在自定义帧处理(使用Fotoapparat库,因为它能够有效显示全屏相机View的能力)和ImageView之间传输imageArray []而不是实际的位图? 我们愿意使用Glide或任何其他工具进行裁剪,或者加载位图(如果这样做会更有效)。我们当前的用于从cameraView框架中检索图像的代码(这将使使用减少2-3倍):

ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 50, out);
byte[] imageBytes = out.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
options.inSampleSize = calculateInSampleSize(options, (int)(width/1.5),(int)(height/1.5));
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);

然后我们使用以下方法裁剪此位图(在2018年这似乎效率不高):

resizedbitmap = Bitmap.createBitmap(original, 0,0,width, height);

另外,线程呢?是否应该使用AsyncTask,Executors或其他任何方式来裁剪/显示位图?我个人一直使用RxJava,但是我们的核心产品必须尽可能轻巧:)

1 个答案:

答案 0 :(得分:1)

替代项

如果您的API级别为10+,则可以选择使用BitmapRegionDecoder,它一步一步进行裁剪和下采样,可能是在本地进行的。

作为一种完全不同的方法,您还可以尝试将data直接转换为Bitmap,然后使用Canvas将原始位图的一部分绘制到新的裁剪版本上,通过Canvas的转换矩阵进行缩放。

质量

  

图像必须具有良好的质量,并且必须快速,良好地裁剪。

压缩为quality=50的第一步,您正在丢失大量信息。然后,当您创建新的位图时,您将进行放大,这也会影响质量。在我看来,只有在生成的图像实际上较小的情况下,裁切才有意义。

效率

  

然后我们使用以下方法裁剪此位图(在2018年这似乎效率不高)

考虑一下:您真的需要位图精确到大小吗?最好将位图保留为裁剪后的大小,将较小的位图保留在内存中,然后将较小的位图上载到GPU,然后让GPU渲染进行缩放。 View可能与Bitmap的大小不匹配,所以还是会发生这种情况。

滑行

Glide的核心功能几乎与您的代码(YUV位除外)相同。请参见Downsampler,不同之处在于它可用于许多输入源,格式和API级别,因此大小也不同。

  

我们的核心产品必须尽可能轻巧:)

包括图像加载库并强迫用户也包括在内与此相反。但是同时您真的想重新发明轮子并编写自己的图像加载库吗?例如,Glide有很多部件可以替换为自定义行为。

在我的应用中,我有一个摄像头->用户裁剪选择->裁剪了较小的位图流。除了使用磁盘而不是ByteArrayOutputStream之外,我做了一些与您类似的事情,因为输入可能非常庞大,并且需要将两次插入内存中,而这无法保证。