@capacitor/camera - Android: `BitmapFactory.decodeFile` without `inSampleSize` decodes the full-resolution bitmap in `IonCameraFlow`
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 76/100
Direzione di ricerca
Start in IonCameraFlow.kt at handleMediaResult, including the lines around 726 and 806, then inspect LegacyCameraFlow.java at processPickedImage and processPickedImages. Compare these decode calls with IONCAMRImageEditorView.decodeSampledBitmapFromUri and run the reported multi-image reproduction. Done means image validation no longer allocates full-resolution pixels unnecessarily and requested resizing still behaves correctly.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Bug Report
Plugin(s)
@capacitor/camera 8.2.4 (also 8.2.2), @capacitor/core 8.5.2, Android targetSdk 36
Capacitor Version
$ npx cap doctor
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 8.5.2
@capacitor/core: 8.5.2
@capacitor/android: 8.5.2
@capacitor/ios: 8.5.2
Installed Dependencies:
@capacitor/cli: 8.5.2
@capacitor/android: 8.5.2
@capacitor/core: 8.5.2
@capacitor/ios: 8.5.2
[success] Android looking great! 👌
Platform(s)
Android
Current Behavior
IonCameraFlow.kt handleMediaResult calls BitmapFactory.decodeFile(mediaResult.uri) (line ~726, and again ~806) with no BitmapFactory.Options. On a 12 MP photo that allocates roughly 48 MB as ARGB_8888. LegacyCameraFlow.java does the same with decodeStream.
Expected Behavior
The decode should not allocate pixel memory it never uses.
In both places the decoded Bitmap is used only as a null check — "is this file an
image?". The very next line, ImageUtils.getExifData(context, bitmap, uri), reads the EXIF
from the uri and ignores the bitmap argument entirely. So a bounds-only decode
(inJustDecodeBounds = true) answers the same question for a few bytes instead of ~48 MB.
Where a bitmap really is needed later, BitmapFactory.Options.inSampleSize should be
computed from the requested width/height before the full decode — which the library
already knows how to do: IONCAMRImageEditorView.decodeSampledBitmapFromUri does exactly
that. These call sites bypass it.
Code Reproduction
No special app is needed — any Capacitor app with the plugin reproduces it:
npm i @capacitor/camera@8.2.4 && npx cap sync android- Call
Camera.pickImages({ quality: 90, width: 2400, height: 2400 })and choose three
12 MP photos (4000×3000). - Watch the heap in Android Studio's Memory Profiler, or
adb shell dumpsys meminfo <package> | grep -i "Native Heap"before and during the pick.
Each picked photo shows a transient allocation of roughly width × height × 4 bytes —
about 48 MB per 12 MP image — before any resizing happens. Passing a smaller width/
height does not prevent it: the full decode happens first.
A breakpoint on IonCameraFlow.handleMediaResult shows the bitmap local going unused
after the null check.
Other Technical Details
@capacitor/camera8.2.4 (and 8.2.2 — I unpacked both npm tarballs and compared; the
decode is identical)io.ionic.libs:ioncamera-android1.0.2, the newest on Maven Central, which the plugin
pins- Android targetSdk 36, AGP 8.13.0, Gradle 8.14.3
- Affected lines:
IonCameraFlow.kt~726 (handleMediaResult) and ~806 (the multi-pick
path);LegacyCameraFlow.javausesBitmapFactory.decodeStreamwithoutinSampleSize
inprocessPickedImage/processPickedImages
Additional Context
Google Play reports this. The Play Console flags it as a bitmap-downsampling
recommendation with the obfuscated symbols w4.k.c, w4.k.l, w4.m.d, and names these
entry points in the deprecated-API section:
com.capacitorjs.plugins.camera.LegacyCameraFlow.processPickedImage/processPickedImagesio.ionic.libs.ioncameralib.view.IONCAMRImageEditorView.decodeSampledBitmapFromUri/loadBitmapSafelyio.ionic.libs.ioncameralib.helper.IONCAMRImageHelper.getBitmapForInputStream/decodeFileio.ionic.libs.ioncameralib.helper.IONCAMRMediaHelper.getImageResolution
This has a deadline. Google's August 2026 app-quality post makes bitmap memory a
bad-behaviour threshold enforced from February 2027, alongside anonymous RSS + swap.
Apps over the threshold can lose visibility.
Why it bites us. Our app scans multi-page recipes, so a session decodes one full-size
bitmap per page. On a low-RAM device the WebView renderer is killed mid-scan.
Workaround we ship, via patch-package on IonCameraFlow.kt — happy to send this as a PR:
// was: val bitmap = BitmapFactory.decodeFile(mediaResult.uri)
// if (bitmap == null) { sendError(IONCAMRError.PROCESS_IMAGE_ERROR); return }
val bounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }
BitmapFactory.decodeFile(mediaResult.uri, bounds)
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) {
sendError(IONCAMRError.PROCESS_IMAGE_ERROR)
return
}
val exif = ImageUtils.getExifData(context, null, uri)
Verified on an Android emulator: camera capture, gallery pick and a three-page recipe scan
of 4000×3000 JPEGs all behave identically, with no error and no crash.
Note ioncamera-android is shipped as an AAR, so the IONCAMR* call sites above cannot be
patched this way — only an upstream fix reaches them.
- Lingua principale
- Java
- Stelle
- 678
- Fork
- 688
- Merge medio
- 8g 18h
- PR unite (30g)
- 1
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di ionic-team/capacitor-plugins
-
platform: ios
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
ionic-team/capacitor-plugins#2595 ·
-
platform: android triage
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
ionic-team/capacitor-plugins#2593 ·
-
platform: ios
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
ionic-team/capacitor-plugins#2565 ·
-
triage
Difficoltà 3/5 1-2 giorni Idoneità per principianti 58/100
ionic-team/capacitor-plugins#2563 ·
-
platform: android platform: ios platform: web
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
ionic-team/capacitor-plugins#2554 ·
Tutte le issue di ionic-team/capacitor-plugins
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
infinispan/infinispan#18150 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
-
untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
opensearch-project/k-NN#3597 ·
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100