我们的产品中的位图有问题。我们的目标是快速拍照并立即显示/裁剪。问题是 - 图像必须质量好,必须快速裁剪。我亲自尝试了下面的代码,它确实减少了大约2-3倍的内存使用量。不过,我们想知道更有效的方式。我们是否应始终在我们的自定义帧处理(使用Fotoapparat库,因为它能够有效显示全屏摄像机视图)和ImageViews之间传输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);
然后我们用下面的方法裁剪这个Bitmap(这在2018年似乎效率低下):
resizedbitmap = Bitmap.createBitmap(original, 0,0,width, height);
还有,线程怎么样?我们应该使用AsyncTask,Executors或任何其他方式来裁剪/显示位图吗?我个人总是使用RxJava,但我们的核心产品必须尽可能轻量级:)
如果您使用的是API等级10+,您可以选择使用BitmapRegionDecoder
,它可以在一步中进行裁剪和下采样,可能是原生的。
作为一种完全不同的方法,您还可以尝试将data
直接转换为Bitmap
,然后使用Canvas
将原始Bitmap的某些部分绘制到新的裁剪版本上,通过Canvas的转换矩阵进行缩放。
图像必须具有良好的质量,必须快速裁剪。
你压缩到quality=50
的第一步,你丢失了很多信息。然后,当您创建新的位图时,您会进行向上扩展,这也会影响质量;在我看来,如果生成的图像实际上更小,裁剪才有意义。
然后我们用下面的方法裁剪这个位图(这在2018年似乎效率低下)
考虑一下:你真的需要Bitmap是确切的大小吗?将Bitmap保留为裁剪大小,在内存中使用较小的Bitmap,将较小的Bitmap上传到GPU并让GPU渲染进行缩放可能要好得多。 View
可能与Bitmap
尺寸不匹配,所以无论如何都会发生这种情况。
Glide几乎与你的代码(YUV位除外)的核心相同。请参阅Downsampler
,区别在于它适用于许多输入源,格式和API级别,因此大小不同。
我们的核心产品必须尽可能轻巧:)
包括图像加载库并强制用户包含它也违背了这一点。但与此同时,您是否真的想重新发明轮子并编写自己的图像加载库?例如,Glide有很多可以替换自定义行为的部分。
在我的应用程序中,我有一个摄像头 - >用户裁剪选择 - >裁剪较小的位图流程。我做了类似于你的事情,除了使用磁盘而不是ByteArrayOutputStream
,因为输入可能是巨大的,它需要适合两次内存,这是无法保证的。