feat: Add ambi be ent-luminance stream for measured-dark torch decisions (fixes #693) - #1774
Open
sawan-scapia wants to merge 4 commits into
Open
Conversation
…eenbakker#693) analyzeImage/returnImage only surface a frame once a barcode decodes, so they can't measure a scene that's too dark to decode at all — exactly the case an app needs to detect to offer "turn on the torch?" (juliansteenbakker#693, open since 2023, several users asking if this ever landed). Adds an opt-in ambient-luminance signal instead: - Android: samples the ImageAnalysis Y-plane (Y *is* luminance) on a 16x16 grid, indexed via rowStride/pixelStride so per-row padding is never averaged in (a naive linear scan would bias the sample darker). - iOS/macOS: samples the pixel buffer on a 16x16 grid via captureOutput, handling both planar (YUV) and packed BGRA formats. - Both platforms throttle to ~500ms and run off the main thread; both are gated by `luminanceEnabled`/`setLuminanceEnabled`, off by default, so an app that never calls it pays zero sampling cost. - Dart: `MobileScannerController.luminanceStream` (Stream<double>, 0-255) and `setLuminanceEnabled({required bool enabled})`. Web has no raw-frame access via the BarcodeDetector API, so it exposes a stream that never emits and a no-op setter, rather than throwing, so cross-platform code needs no web-specific branch. This only answers "how dark is it right now" — deciding what to do with that (auto-enable once, debounce, threshold) is left to the app, since that policy varies. README documents the new stream with a torch-auto- enable example; CHANGELOG/version are left for a maintainer release commit, matching this repo's existing convention. Tests: 4 new (method-channel dispatch + argument passthrough, event parsing/filtering, malformed-sample fallback to 255.0/bright). Full suite (389 tests) and `flutter analyze` across lib/ and test/ are green.
…ance-stream # Conflicts: # android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt # darwin/mobile_scanner/Sources/mobile_scanner/MobileScannerPlugin.swift
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #1774 +/- ##
===========================================
+ Coverage 62.85% 62.95% +0.09%
===========================================
Files 48 48
Lines 1233 1247 +14
===========================================
+ Hits 775 785 +10
- Misses 458 462 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #693.
Problem
analyzeImage/returnImageonly surface a frame once a barcode actually decodes. That means a scene too dark to decode at all — the exact scene where an app would want to prompt "turn on the torch?" — never produces a frame the app can inspect. #693 has been open since 2023 asking for auto-torch-in-the-dark, with no signal available that works for a fully dark scene (the ambient-light-sensor route mentioned in the issue isn't available on iOS either).What this adds
An opt-in ambient-luminance signal that's independent of barcode decoding:
ImageAnalysisY-plane (Y is luminance) on a 16x16 grid, indexed viarowStride/pixelStrideso per-row buffer padding is never averaged in (a naive linear scan over the raw buffer would bias the sample darker than the real scene).captureOutput, handling both planar (YUV) and packed BGRA formats, sincevideoSettingscan negotiate either.luminanceEnabled/setLuminanceEnabled, off by default, so an app that never calls it pays zero extra sampling cost — no behavior change for existing users.MobileScannerController.luminanceStream(Stream<double>, 0–255) andsetLuminanceEnabled({required bool enabled}). Web has no raw-frame access via theBarcodeDetectorAPI it's built on, so it exposes a stream that never emits and a no-op setter (rather than throwing), so cross-platform app code doesn't need a web-specific branch.This PR only answers "how dark is it right now." Deciding what to do with that reading — auto-enable once per session, debounce, pick a threshold — is left to the app, since that policy varies (e.g. you generally don't want to keep re-toggling the torch once it's already on and lighting the scene).
Non-goals / left to a maintainer
developwithout a version bump, and CHANGELOG entries get written/bumped separately at release time, sometimes in the project's own house style (e.g. "docs: rewrite 7.4.0 changelog entry in house style"). Happy to add an entry in whatever format you prefer if that's not the right read.Testing
test/method_channel/luminance_test.dart: method-channel dispatch + argument passthrough forsetLuminanceEnabled, event filtering/parsing forluminanceStream, and the malformed-sample fallback to255.0(bright) — a parse failure should never be mistaken for a dark reading.flutter analyzeis clean acrosslib/andtest/.Example usage
README updated with this section and a
Features Supportedtable row.