fixed crash when loading TIFF on Android 11

This commit is contained in:
Thibault Deckers 2021-01-04 20:55:52 +09:00
parent 7281eaff06
commit 276743bc64
5 changed files with 88 additions and 74 deletions

View file

@ -240,26 +240,29 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
try { try {
val metadataMap = HashMap<String, FieldMap>() val metadataMap = HashMap<String, FieldMap>()
var dirCount: Int? = null var fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> if (fd == null) {
val options = TiffBitmapFactory.Options().apply { result.error("getTiffStructure-fd", "failed to get file descriptor", null)
inJustDecodeBounds = true return
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
metadataMap["0"] = tiffOptionsToMap(options)
dirCount = options.outDirectoryCount
} }
if (dirCount != null) { var options = TiffBitmapFactory.Options().apply {
for (i in 1 until dirCount!!) { inJustDecodeBounds = true
context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> }
val options = TiffBitmapFactory.Options().apply { TiffBitmapFactory.decodeFileDescriptor(fd, options)
inJustDecodeBounds = true metadataMap["0"] = tiffOptionsToMap(options)
inDirectoryNumber = i val dirCount = options.outDirectoryCount
} for (i in 1 until dirCount) {
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
metadataMap["$i"] = tiffOptionsToMap(options) if (fd == null) {
} result.error("getTiffStructure-fd", "failed to get file descriptor", null)
return
} }
options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true
inDirectoryNumber = i
}
TiffBitmapFactory.decodeFileDescriptor(fd, options)
metadataMap["$i"] = tiffOptionsToMap(options)
} }
result.success(metadataMap) result.success(metadataMap)
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -18,20 +18,22 @@ class TiffRegionFetcher internal constructor(
page: Int = 0, page: Int = 0,
result: MethodChannel.Result, result: MethodChannel.Result,
) { ) {
val resolver = context.contentResolver
try { try {
resolver.openFileDescriptor(uri, "r")?.use { descriptor -> val fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
val options = TiffBitmapFactory.Options().apply { if (fd == null) {
inDirectoryNumber = page result.error("getRegion-tiff-fd", "failed to get file descriptor for uri=$uri", null)
inSampleSize = sampleSize return
inDecodeArea = DecodeArea(regionRect.left, regionRect.top, regionRect.width(), regionRect.height()) }
} val options = TiffBitmapFactory.Options().apply {
val bitmap = TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) inDirectoryNumber = page
if (bitmap != null) { inSampleSize = sampleSize
result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true)) inDecodeArea = DecodeArea(regionRect.left, regionRect.top, regionRect.width(), regionRect.height())
} else { }
result.error("getRegion-tiff-null", "failed to decode region for uri=$uri page=$page regionRect=$regionRect", null) val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
} if (bitmap != null) {
result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} else {
result.error("getRegion-tiff-null", "failed to decode region for uri=$uri page=$page regionRect=$regionRect", null)
} }
} catch (e: Exception) { } catch (e: Exception) {
result.error("getRegion-tiff-read-exception", "failed to read from uri=$uri page=$page regionRect=$regionRect", e.message) result.error("getRegion-tiff-read-exception", "failed to read from uri=$uri page=$page regionRect=$regionRect", e.message)

View file

@ -139,28 +139,33 @@ class ImageByteStreamHandler(private val activity: Activity, private val argumen
private fun streamTiffImage(uri: Uri, page: Int = 0) { private fun streamTiffImage(uri: Uri, page: Int = 0) {
val resolver = activity.contentResolver val resolver = activity.contentResolver
try { try {
var dirCount = 0 var fd = resolver.openFileDescriptor(uri, "r")?.detachFd()
resolver.openFileDescriptor(uri, "r")?.use { descriptor -> if (fd == null) {
val options = TiffBitmapFactory.Options().apply { error("streamImage-tiff-fd", "failed to get file descriptor for uri=$uri", null)
inJustDecodeBounds = true return
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
dirCount = options.outDirectoryCount
} }
var options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true
}
TiffBitmapFactory.decodeFileDescriptor(fd, options)
val dirCount = options.outDirectoryCount
// TODO TLAD handle multipage TIFF // TODO TLAD handle multipage TIFF
if (dirCount > page) { if (dirCount > page) {
resolver.openFileDescriptor(uri, "r")?.use { descriptor -> fd = resolver.openFileDescriptor(uri, "r")?.detachFd()
val options = TiffBitmapFactory.Options().apply { if (fd == null) {
inJustDecodeBounds = false error("streamImage-tiff-fd", "failed to get file descriptor for uri=$uri", null)
inDirectoryNumber = page return
} }
val bitmap = TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) options = TiffBitmapFactory.Options().apply {
if (bitmap != null) { inJustDecodeBounds = false
success(bitmap.getBytes(canHaveAlpha = true, recycle = true)) inDirectoryNumber = page
} else { }
error("streamImage-tiff-null", "failed to get tiff image (dir=$page) from uri=$uri", null) val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
} if (bitmap != null) {
success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} else {
error("streamImage-tiff-null", "failed to get tiff image (dir=$page) from uri=$uri", null)
} }
} }
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -48,30 +48,35 @@ internal class TiffThumbnailFetcher(val model: TiffThumbnail, val width: Int, va
val uri = model.uri val uri = model.uri
// determine sample size // determine sample size
var fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
if (fd == null) {
callback.onLoadFailed(Exception("null file descriptor"))
return
}
var sampleSize = 1 var sampleSize = 1
context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> var options = TiffBitmapFactory.Options().apply {
val options = TiffBitmapFactory.Options().apply { inJustDecodeBounds = true
inJustDecodeBounds = true }
} TiffBitmapFactory.decodeFileDescriptor(fd, options)
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) val imageWidth = options.outWidth
val imageWidth = options.outWidth val imageHeight = options.outHeight
val imageHeight = options.outHeight if (imageHeight > height || imageWidth > width) {
if (imageHeight > height || imageWidth > width) { while (imageHeight / (sampleSize * 2) > height && imageWidth / (sampleSize * 2) > width) {
while (imageHeight / (sampleSize * 2) > height && imageWidth / (sampleSize * 2) > width) { sampleSize *= 2
sampleSize *= 2
}
} }
} }
// decode // decode
val bitmap = context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
val options = TiffBitmapFactory.Options().apply { if (fd == null) {
inJustDecodeBounds = false callback.onLoadFailed(Exception("null file descriptor"))
inSampleSize = sampleSize return
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
} }
options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = false
inSampleSize = sampleSize
}
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
if (bitmap == null) { if (bitmap == null) {
callback.onLoadFailed(Exception("null bitmap")) callback.onLoadFailed(Exception("null bitmap"))
} else { } else {

View file

@ -249,14 +249,13 @@ class SourceImageEntry {
private fun fillByTiffDecode(context: Context) { private fun fillByTiffDecode(context: Context) {
try { try {
context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> val fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd() ?: return
val options = TiffBitmapFactory.Options().apply { val options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true inJustDecodeBounds = true
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
width = options.outWidth
height = options.outHeight
} }
TiffBitmapFactory.decodeFileDescriptor(fd, options)
width = options.outWidth
height = options.outHeight
} catch (e: Exception) { } catch (e: Exception) {
// ignore // ignore
} }