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

View file

@ -18,21 +18,23 @@ class TiffRegionFetcher internal constructor(
page: Int = 0,
result: MethodChannel.Result,
) {
val resolver = context.contentResolver
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 {
inDirectoryNumber = page
inSampleSize = sampleSize
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) {
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) {
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) {
val resolver = activity.contentResolver
try {
var dirCount = 0
resolver.openFileDescriptor(uri, "r")?.use { descriptor ->
val options = TiffBitmapFactory.Options().apply {
var fd = resolver.openFileDescriptor(uri, "r")?.detachFd()
if (fd == null) {
error("streamImage-tiff-fd", "failed to get file descriptor for uri=$uri", null)
return
}
var options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
dirCount = options.outDirectoryCount
}
TiffBitmapFactory.decodeFileDescriptor(fd, options)
val dirCount = options.outDirectoryCount
// TODO TLAD handle multipage TIFF
if (dirCount > page) {
resolver.openFileDescriptor(uri, "r")?.use { descriptor ->
val options = TiffBitmapFactory.Options().apply {
fd = resolver.openFileDescriptor(uri, "r")?.detachFd()
if (fd == null) {
error("streamImage-tiff-fd", "failed to get file descriptor for uri=$uri", null)
return
}
options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = false
inDirectoryNumber = page
}
val bitmap = TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
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) {
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
// determine sample size
var fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
if (fd == null) {
callback.onLoadFailed(Exception("null file descriptor"))
return
}
var sampleSize = 1
context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor ->
val options = TiffBitmapFactory.Options().apply {
var options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = true
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
TiffBitmapFactory.decodeFileDescriptor(fd, options)
val imageWidth = options.outWidth
val imageHeight = options.outHeight
if (imageHeight > height || imageWidth > width) {
@ -61,17 +65,18 @@ internal class TiffThumbnailFetcher(val model: TiffThumbnail, val width: Int, va
sampleSize *= 2
}
}
}
// decode
val bitmap = context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor ->
val options = TiffBitmapFactory.Options().apply {
fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd()
if (fd == null) {
callback.onLoadFailed(Exception("null file descriptor"))
return
}
options = TiffBitmapFactory.Options().apply {
inJustDecodeBounds = false
inSampleSize = sampleSize
}
TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options)
}
val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options)
if (bitmap == null) {
callback.onLoadFailed(Exception("null bitmap"))
} else {

View file

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