QrCodeFromFileScanner: more efficiently downscale images and release memory
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
@@ -29,7 +29,6 @@ class QrCodeFromFileScanner(
|
|||||||
private val contentResolver: ContentResolver,
|
private val contentResolver: ContentResolver,
|
||||||
private val reader: Reader,
|
private val reader: Reader,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private fun scanBitmapForResult(source: Bitmap): Result {
|
private fun scanBitmapForResult(source: Bitmap): Result {
|
||||||
val width = source.width
|
val width = source.width
|
||||||
val height = source.height
|
val height = source.height
|
||||||
@@ -40,55 +39,28 @@ class QrCodeFromFileScanner(
|
|||||||
return reader.decode(bBitmap, mapOf(DecodeHintType.TRY_HARDER to true))
|
return reader.decode(bBitmap, mapOf(DecodeHintType.TRY_HARDER to true))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downscaleBitmap(source: Bitmap, scaledSize: Int): Bitmap {
|
|
||||||
|
|
||||||
val originalWidth = source.width
|
|
||||||
val originalHeight = source.height
|
|
||||||
|
|
||||||
var newWidth = -1
|
|
||||||
var newHeight = -1
|
|
||||||
val multFactor: Float
|
|
||||||
|
|
||||||
when {
|
|
||||||
originalHeight > originalWidth -> {
|
|
||||||
newHeight = scaledSize
|
|
||||||
multFactor = originalWidth.toFloat() / originalHeight.toFloat()
|
|
||||||
newWidth = (newHeight * multFactor).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
originalWidth > originalHeight -> {
|
|
||||||
newWidth = scaledSize
|
|
||||||
multFactor = originalHeight.toFloat() / originalWidth.toFloat()
|
|
||||||
newHeight = (newWidth * multFactor).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
originalHeight == originalWidth -> {
|
|
||||||
newHeight = scaledSize
|
|
||||||
newWidth = scaledSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Bitmap.createScaledBitmap(source, newWidth, newHeight, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doScan(data: Uri): Result {
|
private fun doScan(data: Uri): Result {
|
||||||
Log.d(TAG, "Starting to scan an image: $data")
|
Log.d(TAG, "Starting to scan an image: $data")
|
||||||
contentResolver.openInputStream(data).use { inputStream ->
|
contentResolver.openInputStream(data).use { inputStream ->
|
||||||
val originalBitmap = BitmapFactory.decodeStream(inputStream)
|
var bitmap: Bitmap? = null
|
||||||
?: throw IllegalArgumentException("Can't decode stream to Bitmap")
|
var firstException: Throwable? = null
|
||||||
|
for (i in arrayOf(1, 2, 4, 8, 16, 32, 64, 128)) {
|
||||||
return try {
|
try {
|
||||||
scanBitmapForResult(originalBitmap).also {
|
val options = BitmapFactory.Options()
|
||||||
Log.d(TAG, "Found result in original image")
|
options.inSampleSize = i
|
||||||
|
bitmap = BitmapFactory.decodeStream(inputStream, null, options)
|
||||||
|
?: throw IllegalArgumentException("Can't decode stream for bitmap")
|
||||||
|
return scanBitmapForResult(bitmap)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
bitmap?.recycle()
|
||||||
|
System.gc()
|
||||||
|
Log.e(TAG, "Original image scan at scale factor $i finished with error: $e")
|
||||||
|
if (firstException == null)
|
||||||
|
firstException = e
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
|
||||||
Log.e(TAG, "Original image scan finished with error: $e, will try downscaled image")
|
|
||||||
val scaleBitmap = downscaleBitmap(originalBitmap, 500)
|
|
||||||
scanBitmapForResult(originalBitmap).also { scaleBitmap.recycle() }
|
|
||||||
} finally {
|
|
||||||
originalBitmap.recycle()
|
|
||||||
}
|
}
|
||||||
|
throw Exception(firstException)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user