137 lines
4.6 KiB
Kotlin
137 lines
4.6 KiB
Kotlin
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)
|
|
}
|
|
}
|
|
}
|