package uts.sdk.modules.masCodeScan import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.ImageFormat import android.graphics.Matrix import android.graphics.Rect import android.graphics.YuvImage import android.media.Image import java.io.ByteArrayOutputStream object YuvFrames { fun imageToBitmap( image: Image, width: Int, height: Int, cropRect: Rect, rotationDegrees: Int ): Bitmap? { return try { val planes = image.planes val yPlane = planes[0] val uPlane = planes[1] val vPlane = planes[2] val yRowStride = yPlane.rowStride val yPixelStride = yPlane.pixelStride val uRowStride = uPlane.rowStride val uPixelStride = uPlane.pixelStride val vRowStride = vPlane.rowStride val vPixelStride = vPlane.pixelStride val nv21Size = width * height * 3 / 2 val nv21 = ByteArray(nv21Size) var destOffset = 0 if (yPixelStride == 1) { for (row in 0 until height) { yPlane.buffer.position(row * yRowStride) yPlane.buffer.get(nv21, destOffset, width) destOffset += width } } else { val yBuffer = yPlane.buffer for (row in 0 until height) { for (col in 0 until width) { nv21[destOffset++] = yBuffer.get(row * yRowStride + col * yPixelStride) } } } var uvOffset = width * height if (uPixelStride == 1 && vPixelStride == 1) { for (row in 0 until height / 2) { vPlane.buffer.position(row * vRowStride) vPlane.buffer.get(nv21, uvOffset + row * width, width / 2) } for (row in 0 until height / 2) { uPlane.buffer.position(row * uRowStride) uPlane.buffer.get(nv21, uvOffset + width / 2 + row * width, width / 2) } } else { val uBuffer = uPlane.buffer val vBuffer = vPlane.buffer for (row in 0 until height / 2) { for (col in 0 until width / 2) { val uvIndex = row * uRowStride + col * uPixelStride nv21[uvOffset++] = vBuffer.get(uvIndex) nv21[uvOffset++] = uBuffer.get(uvIndex) } } } val safeCropRect = Rect(cropRect).apply { left = left.coerceIn(0, width) top = top.coerceIn(0, height) right = right.coerceIn(left, width) bottom = bottom.coerceIn(top, height) } val jpegRect = if (safeCropRect.width() > 0 && safeCropRect.height() > 0) { safeCropRect } else { Rect(0, 0, width, height) } val yuvImage = YuvImage(nv21, ImageFormat.NV21, width, height, null) val baos = ByteArrayOutputStream() yuvImage.compressToJpeg(jpegRect, 85, baos) val jpegData = baos.toByteArray() baos.close() var bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.size) if (bitmap != null && rotationDegrees != 0) { val matrix = Matrix() matrix.postRotate(rotationDegrees.toFloat()) val rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) if (rotated != bitmap) { bitmap.recycle() } bitmap = rotated } bitmap } catch (_: Exception) { null } } fun rectToVisualSpace( rect: Rect, sourceWidth: Int, sourceHeight: Int, rotationDegrees: Int ): Rect { return when (rotationDegrees) { 90 -> Rect( sourceHeight - rect.bottom, rect.left, sourceHeight - rect.top, rect.right ) 180 -> Rect( sourceWidth - rect.right, sourceHeight - rect.bottom, sourceWidth - rect.left, sourceHeight - rect.top ) 270 -> Rect( rect.top, sourceWidth - rect.right, rect.bottom, sourceWidth - rect.left ) else -> Rect(rect) } } }