这里以CameraX中ImageProxy为例说明YUV转Bitmap实现。
获取YUV数据
在ImageProxy里通过Image.getPlanes()方法获得包含YUV数据的数组。
1
2
3
4
5
6
7
8
9
|
/**
* Get the array of pixel planes for this Image. The number of planes is
* determined by the format of the Image. The application will get an empty
* array if the image format is {@link android.graphics.ImageFormat#PRIVATE
* PRIVATE}, because the image pixel data is not directly accessible. The
* application can check the image format by calling
* {@link Image#getFormat()}.
*/
public abstract Plane[] getPlanes();
|
Planes数组合并成字节数组:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
val _image = image ?: return null
val _planes = image!!.planes
val yBuffer = _planes[0].buffer
val uBuffer = _planes[1].buffer
val vBuffer = _planes[2].buffer
val ySize = yBuffer.remaining()
val uSize = uBuffer.remaining()
val vSize = vBuffer.remaining()
val nv21 = ByteArray(ySize + uSize + vSize)
yBuffer.get(nv21, 0, ySize)
vBuffer.get(nv21, ySize, vSize)
uBuffer.get(nv21, ySize + vSize, uSize)
|
YuvImage实现
1
2
3
4
5
6
7
|
var bitmap: Bitmap? = null
val yuvImage = YuvImage(nv21, ImageFormat.NV21, _image.width, _image.height, null)
ByteArrayOutputStream().use { outStream ->
yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 50, outStream)
val imageBytes = outStream.toByteArray()
bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
}
|
Android 12 之前可以用renderscript实现更高效的版本。但是由于Android 12之后官方已经废弃了renderscript,所以这里不做介绍。在废弃renderscript的同时,官方放出了renderscript-toolkit库以替代renderscript部分功能。
1
|
val bitmap = Toolkit.yuvToRgbBitmap(nv21, _image.width, _image.height, YuvFormat.NV21)
|
旋转
通过上面方法可以得到原始bitmap,但是实际情况是图片数据有旋转角度,所以还要做一步旋转操作才能是正常的看到的图片。
需要旋转的角度就是ImageProxy.imageInfo.rotationDegrees
。
添加Bitmap的Kotlin扩展函数:
1
2
3
4
5
6
|
fun Bitmap.rotate(rotationDegrees: Float): Bitmap {
val matrix = Matrix()
matrix.postRotate(rotationDegrees)
return Bitmap.createBitmap(this, 0, 0, width, height, matrix, true)
}
|
其他