A snapshot is not a live video stream
CameraScreen binds preview and image capture to the screen lifecycle. Camera permission is requested when the user reaches this feature. The shutter is enabled only after the preview reports streaming; this rule was added after a UI test exposed capture before camera readiness. The app captures only on a deliberate tap. Returning from another screen should not start inference by itself.
Photo Picker is an alternate input. The selected URI is copied into app-private storage while the app has access; long-lived story state references the private file, not an assumption that an external URI stays readable forever. Denial, cancelled selection and decoder failure must leave the learner able to choose another input.
Bound decoded pixels before native inference
Read data/ImageStore.kt. A 4000×3000 photo becomes approximately 768×576. This reduces app-side bitmap pressure and creates a JPEG suitable for the scene attachment. It does not guarantee that the vision runtime allocates only a 768-pixel buffer; model signatures and internal tensors are separate.
val ratio = 768f / maxOf(info.size.width, info.size.height)
if (ratio < 1) decoder.setTargetSize(
(info.size.width * ratio).toInt().coerceAtLeast(1),
(info.size.height * ratio).toInt().coerceAtLeast(1),
)
decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
This is the ImageDecoder callback excerpt, not a standalone function. The bitmap is written as JPEG at quality 85 and recycled in finally. Images go under noBackupFilesDir/scenes. A photo can contain private information: the local processing design must be preserved through logging, backup and later export features.
Practice and expected evidence
Use an emulator's virtual camera or a benign object on a phone. Try portrait, landscape and a small image; verify the result is oriented correctly and never enlarged merely to reach 768. Deny permission, reopen capture, then select an image through the picker. Save the captured scene and reopen it without a model installed. Expected evidence is the same image attached to the saved story, not generated prose.
Explain why reducing the JPEG dimensions alone did not fix the observed GPU buffer failure: the runtime compiled a vision signature whose internal allocation exceeded the backend limit. See CameraX capture guidance.