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 {