react-native-image-stitcher 0.15.1 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/camera/CameraView.js +38 -0
- package/package.json +1 -1
- package/src/camera/CameraView.tsx +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [0.15.2] — 2026-06-11
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **Sharp non-AR camera preview (WYSIWYG follow-up).** The v0.15.1
|
|
24
|
+
letterbox pinned the vision-camera format by aspect ratio only, so
|
|
25
|
+
`useCameraFormat` could settle on a degenerate 4:3 format — observed as
|
|
26
|
+
a 192×144 video stream on the iPhone 16 Pro — rendering the preview as
|
|
27
|
+
upscaled mush behind a full-resolution capture. The format filter now
|
|
28
|
+
also requests `{ videoResolution: 'max' }`, so among 4:3 formats the
|
|
29
|
+
highest-resolution one is chosen: a sharp preview plus full-res frames
|
|
30
|
+
into the non-AR stitcher, with aspect kept as the top-priority filter so
|
|
31
|
+
4:3 capture parity holds. A bounded target (e.g. 1920×1440) is
|
|
32
|
+
deliberately avoided — the nearest such format on the iPhone 16 Pro is
|
|
33
|
+
10-bit-only (`x420`/`x422`), which the frame processor's 8-bit
|
|
34
|
+
`420v`/`420f` pipeline rejects with `device/pixel-format-not-supported`;
|
|
35
|
+
vision-camera exposes no per-format pixel formats to JS, so `'max'`
|
|
36
|
+
(empirically the device's 8-bit full-res format) is the robust choice.
|
|
37
|
+
Tap-to-photo stills are capped at ~12 MP (`photoResolution: 4032×3024`,
|
|
38
|
+
lowest priority) so the iPhone 16 Pro's max-video format doesn't default
|
|
39
|
+
to a 24 MP still — the panorama path uses the video stream, not
|
|
40
|
+
`takePhoto`, so the cap costs nothing there.
|
|
41
|
+
|
|
19
42
|
## [0.15.1] — 2026-06-08
|
|
20
43
|
|
|
21
44
|
### Fixed
|
|
@@ -102,9 +102,47 @@ exports.CameraView = (0, react_1.forwardRef)(function CameraView({ device, flash
|
|
|
102
102
|
// aspect on essentially every phone camera (incl. ultra-wide), so a
|
|
103
103
|
// matching format is virtually always available; `useCameraFormat`
|
|
104
104
|
// returns the closest match and never throws.
|
|
105
|
+
//
|
|
106
|
+
// Resolution preference matters too: filtering on aspect ALONE lets
|
|
107
|
+
// vision-camera settle on whatever 4:3 format sorts first — observed as
|
|
108
|
+
// a 192×144 VIDEO stream on the iPhone 16 Pro (the photo still uses the
|
|
109
|
+
// format's full-res photo dims, so you'd get a sharp capture behind a
|
|
110
|
+
// mush preview). So we also request the highest video resolution.
|
|
111
|
+
//
|
|
112
|
+
// Why `'max'` and not a bounded target like 1920×1440? We tried the
|
|
113
|
+
// bounded target and it FAILED on the iPhone 16 Pro: the nearest
|
|
114
|
+
// 1920×1440 format is a 10-bit format (pixel formats x420 / x422 only —
|
|
115
|
+
// and it is NOT flagged HDR, so the `videoHdr` filter can't dodge it).
|
|
116
|
+
// The frame processor + the stitcher's CV pipeline need 8-bit
|
|
117
|
+
// `420v`/`420f`, so vision-camera raises
|
|
118
|
+
// `device/pixel-format-not-supported` and silently falls back to a
|
|
119
|
+
// default pixel format — breaking non-AR stitching. vision-camera does
|
|
120
|
+
// NOT expose a format's supported pixel formats to JS (no
|
|
121
|
+
// `pixelFormats` field; `FormatFilter` has no pixel-format key), so we
|
|
122
|
+
// can't select an 8-bit format by inspection. Empirically the device's
|
|
123
|
+
// MAX 4:3 video format is 8-bit (420v/420f) on the iPhone 16 Pro, and
|
|
124
|
+
// Android formats are near-universally 8-bit YUV_420_888, so `'max'` is
|
|
125
|
+
// the robust choice: a sharp preview on a frame-processor-compatible
|
|
126
|
+
// pipeline. Trade-off: the max format tends to run at 30 fps (fine for
|
|
127
|
+
// hold-to-pan) and feeds full-res frames to the non-AR gate — if that
|
|
128
|
+
// ever shows up as dropped frames we can downscale for the gate
|
|
129
|
+
// natively while keeping full-res keyframes. Aspect stays the
|
|
130
|
+
// top-priority filter, so 4:3 WYSIWYG parity holds on every device.
|
|
131
|
+
//
|
|
132
|
+
// Still resolution is capped at ~12 MP. The max-video 4:3 format pairs
|
|
133
|
+
// with a 24 MP photo (5712×4284) on the iPhone 16 Pro by default — 2×
|
|
134
|
+
// the file size + per-capture memory for no benefit on the panorama
|
|
135
|
+
// path (which uses the VIDEO stream, not takePhoto). `photoResolution`
|
|
136
|
+
// is the LOWEST-priority filter, so it only breaks ties between equal
|
|
137
|
+
// max-video formats (e.g. the 12 MP-photo vs 24 MP-photo variants that
|
|
138
|
+
// share the same 4032×3024 video) — it never trades preview/stitch
|
|
139
|
+
// sharpness for a smaller still. 4032×3024 = 12 MP at 4:3; nearest-
|
|
140
|
+
// match keeps stills near there on any device.
|
|
105
141
|
const format = (0, react_native_vision_camera_1.useCameraFormat)(device ?? undefined, [
|
|
106
142
|
{ photoAspectRatio: 4 / 3 },
|
|
107
143
|
{ videoAspectRatio: 4 / 3 },
|
|
144
|
+
{ videoResolution: 'max' },
|
|
145
|
+
{ photoResolution: { width: 4032, height: 3024 } },
|
|
108
146
|
]);
|
|
109
147
|
// Measured size of our container, so we can size the <Camera> view to
|
|
110
148
|
// the largest box of the capture's aspect ratio that fits inside it
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-image-stitcher",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.2",
|
|
4
4
|
"description": "Pose-aware panorama capture + stitching for React Native. One <Camera> component, both tap-to-photo and hold-to-pan modes, both AR-backed and IMU-fallback capture paths.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -163,9 +163,47 @@ export const CameraView = forwardRef<Camera | null, CameraViewProps>(function Ca
|
|
|
163
163
|
// aspect on essentially every phone camera (incl. ultra-wide), so a
|
|
164
164
|
// matching format is virtually always available; `useCameraFormat`
|
|
165
165
|
// returns the closest match and never throws.
|
|
166
|
+
//
|
|
167
|
+
// Resolution preference matters too: filtering on aspect ALONE lets
|
|
168
|
+
// vision-camera settle on whatever 4:3 format sorts first — observed as
|
|
169
|
+
// a 192×144 VIDEO stream on the iPhone 16 Pro (the photo still uses the
|
|
170
|
+
// format's full-res photo dims, so you'd get a sharp capture behind a
|
|
171
|
+
// mush preview). So we also request the highest video resolution.
|
|
172
|
+
//
|
|
173
|
+
// Why `'max'` and not a bounded target like 1920×1440? We tried the
|
|
174
|
+
// bounded target and it FAILED on the iPhone 16 Pro: the nearest
|
|
175
|
+
// 1920×1440 format is a 10-bit format (pixel formats x420 / x422 only —
|
|
176
|
+
// and it is NOT flagged HDR, so the `videoHdr` filter can't dodge it).
|
|
177
|
+
// The frame processor + the stitcher's CV pipeline need 8-bit
|
|
178
|
+
// `420v`/`420f`, so vision-camera raises
|
|
179
|
+
// `device/pixel-format-not-supported` and silently falls back to a
|
|
180
|
+
// default pixel format — breaking non-AR stitching. vision-camera does
|
|
181
|
+
// NOT expose a format's supported pixel formats to JS (no
|
|
182
|
+
// `pixelFormats` field; `FormatFilter` has no pixel-format key), so we
|
|
183
|
+
// can't select an 8-bit format by inspection. Empirically the device's
|
|
184
|
+
// MAX 4:3 video format is 8-bit (420v/420f) on the iPhone 16 Pro, and
|
|
185
|
+
// Android formats are near-universally 8-bit YUV_420_888, so `'max'` is
|
|
186
|
+
// the robust choice: a sharp preview on a frame-processor-compatible
|
|
187
|
+
// pipeline. Trade-off: the max format tends to run at 30 fps (fine for
|
|
188
|
+
// hold-to-pan) and feeds full-res frames to the non-AR gate — if that
|
|
189
|
+
// ever shows up as dropped frames we can downscale for the gate
|
|
190
|
+
// natively while keeping full-res keyframes. Aspect stays the
|
|
191
|
+
// top-priority filter, so 4:3 WYSIWYG parity holds on every device.
|
|
192
|
+
//
|
|
193
|
+
// Still resolution is capped at ~12 MP. The max-video 4:3 format pairs
|
|
194
|
+
// with a 24 MP photo (5712×4284) on the iPhone 16 Pro by default — 2×
|
|
195
|
+
// the file size + per-capture memory for no benefit on the panorama
|
|
196
|
+
// path (which uses the VIDEO stream, not takePhoto). `photoResolution`
|
|
197
|
+
// is the LOWEST-priority filter, so it only breaks ties between equal
|
|
198
|
+
// max-video formats (e.g. the 12 MP-photo vs 24 MP-photo variants that
|
|
199
|
+
// share the same 4032×3024 video) — it never trades preview/stitch
|
|
200
|
+
// sharpness for a smaller still. 4032×3024 = 12 MP at 4:3; nearest-
|
|
201
|
+
// match keeps stills near there on any device.
|
|
166
202
|
const format = useCameraFormat(device ?? undefined, [
|
|
167
203
|
{ photoAspectRatio: 4 / 3 },
|
|
168
204
|
{ videoAspectRatio: 4 / 3 },
|
|
205
|
+
{ videoResolution: 'max' },
|
|
206
|
+
{ photoResolution: { width: 4032, height: 3024 } },
|
|
169
207
|
]);
|
|
170
208
|
|
|
171
209
|
// Measured size of our container, so we can size the <Camera> view to
|