diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt index 91f0486d0..1119e62e3 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt @@ -240,26 +240,29 @@ class DebugHandler(private val context: Context) : MethodCallHandler { try { val metadataMap = HashMap() - var dirCount: Int? = null - context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> - val options = TiffBitmapFactory.Options().apply { - inJustDecodeBounds = true - } - TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) - metadataMap["0"] = tiffOptionsToMap(options) - dirCount = options.outDirectoryCount + var 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 { - inJustDecodeBounds = true - inDirectoryNumber = i - } - TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) - metadataMap["$i"] = tiffOptionsToMap(options) - } + var options = TiffBitmapFactory.Options().apply { + inJustDecodeBounds = true + } + TiffBitmapFactory.decodeFileDescriptor(fd, options) + metadataMap["0"] = tiffOptionsToMap(options) + 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 } + options = TiffBitmapFactory.Options().apply { + inJustDecodeBounds = true + inDirectoryNumber = i + } + TiffBitmapFactory.decodeFileDescriptor(fd, options) + metadataMap["$i"] = tiffOptionsToMap(options) } result.success(metadataMap) } catch (e: Exception) { diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt index 1c88245bb..2d17f62d6 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/TiffRegionFetcher.kt @@ -18,20 +18,22 @@ class TiffRegionFetcher internal constructor( page: Int = 0, result: MethodChannel.Result, ) { - val resolver = context.contentResolver try { - resolver.openFileDescriptor(uri, "r")?.use { descriptor -> - 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) - 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) - } + 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(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) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ImageByteStreamHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ImageByteStreamHandler.kt index eceb88bce..d14ab3a4e 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ImageByteStreamHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ImageByteStreamHandler.kt @@ -139,28 +139,33 @@ 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 { - inJustDecodeBounds = true - } - TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) - dirCount = options.outDirectoryCount + 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(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 { - inJustDecodeBounds = false - inDirectoryNumber = page - } - val bitmap = TiffBitmapFactory.decodeFileDescriptor(descriptor.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) - } + 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(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) { diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/decoder/TiffThumbnailGlideModule.kt b/android/app/src/main/kotlin/deckers/thibault/aves/decoder/TiffThumbnailGlideModule.kt index 060b312f6..4ee15e9b4 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/decoder/TiffThumbnailGlideModule.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/decoder/TiffThumbnailGlideModule.kt @@ -48,30 +48,35 @@ 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 { - inJustDecodeBounds = true - } - TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) - val imageWidth = options.outWidth - val imageHeight = options.outHeight - if (imageHeight > height || imageWidth > width) { - while (imageHeight / (sampleSize * 2) > height && imageWidth / (sampleSize * 2) > width) { - sampleSize *= 2 - } + var options = TiffBitmapFactory.Options().apply { + inJustDecodeBounds = true + } + TiffBitmapFactory.decodeFileDescriptor(fd, options) + val imageWidth = options.outWidth + val imageHeight = options.outHeight + if (imageHeight > height || imageWidth > width) { + while (imageHeight / (sampleSize * 2) > height && imageWidth / (sampleSize * 2) > width) { + sampleSize *= 2 } } // decode - val bitmap = context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> - val options = TiffBitmapFactory.Options().apply { - inJustDecodeBounds = false - inSampleSize = sampleSize - } - TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) + 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 + } + val bitmap = TiffBitmapFactory.decodeFileDescriptor(fd, options) if (bitmap == null) { callback.onLoadFailed(Exception("null bitmap")) } else { diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceImageEntry.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceImageEntry.kt index 304ff9acb..2e963ae6a 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceImageEntry.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceImageEntry.kt @@ -249,14 +249,13 @@ class SourceImageEntry { private fun fillByTiffDecode(context: Context) { try { - context.contentResolver.openFileDescriptor(uri, "r")?.use { descriptor -> - val options = TiffBitmapFactory.Options().apply { - inJustDecodeBounds = true - } - TiffBitmapFactory.decodeFileDescriptor(descriptor.fd, options) - width = options.outWidth - height = options.outHeight + val fd = context.contentResolver.openFileDescriptor(uri, "r")?.detachFd() ?: return + val options = TiffBitmapFactory.Options().apply { + inJustDecodeBounds = true } + TiffBitmapFactory.decodeFileDescriptor(fd, options) + width = options.outWidth + height = options.outHeight } catch (e: Exception) { // ignore }