Android-YUV转Bitmap

这里以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)
    }

renderscript-toolkit库实现

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)
}

其他

Built with Hugo
主题 StackJimmy 设计