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,27 +240,30 @@ 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)
return
}
var options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true inJustDecodeBounds = true
} }
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) TiffBitmapFactory.decodeFileDescriptor(fd, options)
metadataMap["0"] = tiffOptionsToMap(options) metadataMap["0"] = tiffOptionsToMap(options)
dirCount = options.outDirectoryCount val dirCount = options.outDirectoryCount
for (i in 1 until dirCount) {
fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
if (fd == null) {
result.error("getTiffStructure-fd", "failed to get file descriptor", null)
return
} }
if (dirCount != null) { options = TiffBitmapFactory.Options().apply {
for (i in 1 until dirCount!!) {
context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor ->
val options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true inJustDecodeBounds = true
inDirectoryNumber = i inDirectoryNumber = i
} }
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) TiffBitmapFactory.decodeFileDescriptor(fd, options)
metadataMap["$i"] = tiffOptionsToMap(options) metadataMap["$i"] = tiffOptionsToMap(options)
} }
}
}
result.success(metadataMap) result.success(metadataMap)
} catch (e: Exception) { } catch (e: Exception) {
result.error("getTiffStructure-read", "failed to read tiff", e.message) result.error("getTiffStructure-read", "failed to read tiff", e.message)

View file

@ -18,21 +18,23 @@ 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()
if (fd == null) {
result.error("getRegion-tiff-fd", "failed to get file descriptor for uri=$uri", null)
return
}
val options = TiffBitmapFactory.Options().apply { val options = TiffBitmapFactory.Options().apply {
inDirectoryNumber = page inDirectoryNumber = page
inSampleSize = sampleSize inSampleSize = sampleSize
inDecodeArea = DecodeArea(regionRect.left, regionRect.top, regionRect.width(), regionRect.height()) inDecodeArea = DecodeArea(regionRect.left, regionRect.top, regionRect.width(), regionRect.height())
} }
val bitmap = TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
if (bitmap != null) { if (bitmap != null) {
result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true)) result.success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} else { } else {
result.error("getRegion-tiff-null", "failed to decode region for uri=$uri page=$page regionRect=$regionRect", null) 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,30 +139,35 @@ 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)
return
}
var options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true inJustDecodeBounds = true
} }
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) TiffBitmapFactory.decodeFileDescriptor(fd, options)
dirCount = options.outDirectoryCount 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) {
error("streamImage-tiff-fd", "failed to get file descriptor for uri=$uri", null)
return
}
options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = false inJustDecodeBounds = false
inDirectoryNumber = page inDirectoryNumber = page
} }
val bitmap = TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
if (bitmap != null) { if (bitmap != null) {
success(bitmap.getBytes(canHaveAlpha = true, recycle = true)) success(bitmap.getBytes(canHaveAlpha = true, recycle = true))
} else { } else {
error("streamImage-tiff-null", "failed to get tiff image (dir=$page) from uri=$uri", null) error("streamImage-tiff-null", "failed to get tiff image (dir=$page) from uri=$uri", null)
} }
} }
}
} catch (e: Exception) { } catch (e: Exception) {
error("streamImage-tiff-exception", "failed to get image from uri=$uri", toErrorDetails(e)) error("streamImage-tiff-exception", "failed to get image from uri=$uri", toErrorDetails(e))
} }

View file

@ -48,12 +48,16 @@ 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(descriptor.fd, options) TiffBitmapFactory.decodeFileDescriptor(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) {
@ -61,17 +65,18 @@ internal class TiffThumbnailFetcher(val model: TiffThumbnail, val width: Int, va
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) {
callback.onLoadFailed(Exception("null file descriptor"))
return
}
options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = false inJustDecodeBounds = false
inSampleSize = sampleSize inSampleSize = sampleSize
} }
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) 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) TiffBitmapFactory.decodeFileDescriptor(fd, options)
width = options.outWidth width = options.outWidth
height = options.outHeight height = options.outHeight
}
} catch (e: Exception) { } catch (e: Exception) {
// ignore // ignore
} }