diff --git a/CHANGELOG.md b/CHANGELOG.md index 3922d2d3e..23c3e161f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Fixed + +- crash when decoding large region + ## [v1.10.7] - 2024-03-12 ### Added diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt index 2cf30d200..9d319e7db 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/RegionFetcher.kt @@ -12,7 +12,9 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.request.RequestOptions import deckers.thibault.aves.decoder.MultiPageImage import deckers.thibault.aves.utils.BitmapRegionDecoderCompat +import deckers.thibault.aves.utils.BitmapUtils.ARGB_8888_BYTE_SIZE import deckers.thibault.aves.utils.BitmapUtils.getBytes +import deckers.thibault.aves.utils.MemoryUtils import deckers.thibault.aves.utils.MimeTypes import deckers.thibault.aves.utils.StorageUtils import io.flutter.plugin.common.MethodChannel @@ -73,7 +75,7 @@ class RegionFetcher internal constructor( BitmapRegionDecoderCompat.newInstance(input) } if (newDecoder == null) { - result.error("getRegion-read-null", "failed to open file for mimeType=$mimeType uri=$uri regionRect=$regionRect", null) + result.error("fetch-read-null", "failed to open file for mimeType=$mimeType uri=$uri regionRect=$regionRect", null) return } currentDecoderRef = LastDecoderRef(uri, newDecoder) @@ -96,14 +98,22 @@ class RegionFetcher internal constructor( regionRect } + // use `Long` as rect size could be unexpectedly large and go beyond `Int` max + val targetBitmapSizeBytes: Long = ARGB_8888_BYTE_SIZE.toLong() * effectiveRect.width() * effectiveRect.height() / sampleSize + if (!MemoryUtils.canAllocate(targetBitmapSizeBytes)) { + // decoding a region that large would yield an OOM when creating the bitmap + result.error("fetch-large-region", "Region too large for uri=$uri regionRect=$regionRect", null) + return + } + val bitmap = decoder.decodeRegion(effectiveRect, options) if (bitmap != null) { result.success(bitmap.getBytes(MimeTypes.canHaveAlpha(mimeType), recycle = true)) } else { - result.error("getRegion-null", "failed to decode region for uri=$uri regionRect=$regionRect", null) + result.error("fetch-null", "failed to decode region for uri=$uri regionRect=$regionRect", null) } } catch (e: Exception) { - result.error("getRegion-read-exception", "failed to initialize region decoder for uri=$uri regionRect=$regionRect", e.message) + result.error("fetch-read-exception", "failed to initialize region decoder for uri=$uri regionRect=$regionRect", e.message) } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt index 882844c6e..2c18d004a 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/fetchers/SvgRegionFetcher.kt @@ -11,6 +11,7 @@ import com.caverock.androidsvg.RenderOptions import com.caverock.androidsvg.SVG import com.caverock.androidsvg.SVGParseException import deckers.thibault.aves.metadata.SvgHelper.normalizeSize +import deckers.thibault.aves.utils.BitmapUtils.ARGB_8888_BYTE_SIZE import deckers.thibault.aves.utils.BitmapUtils.getBytes import deckers.thibault.aves.utils.MemoryUtils import deckers.thibault.aves.utils.StorageUtils @@ -116,8 +117,4 @@ class SvgRegionFetcher internal constructor( val uri: Uri, val svg: SVG, ) - - companion object { - const val ARGB_8888_BYTE_SIZE = 4 - } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/BitmapUtils.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/BitmapUtils.kt index 9d51d4008..95999d60e 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/BitmapUtils.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/BitmapUtils.kt @@ -20,6 +20,8 @@ object BitmapUtils { private val freeBaos = ArrayList() private val mutex = Mutex() + const val ARGB_8888_BYTE_SIZE = 4 + suspend fun Bitmap.getBytes(canHaveAlpha: Boolean = false, quality: Int = 100, recycle: Boolean): ByteArray? { val stream: ByteArrayOutputStream mutex.withLock {