@photivra/engine 2.12.0 → 2.13.0
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 +77 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +1 -0
- package/dist/capture/export-jpeg.d.ts +1 -1
- package/dist/capture/export-jpeg.js +6 -4
- package/dist/capture/export-jpeg.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.d.ts +120 -0
- package/dist/exposure/auto-iso-slowest-shutter.js +216 -0
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -0
- package/dist/exposure/exposure-mode-resolver.d.ts +57 -1
- package/dist/exposure/exposure-mode-resolver.js +238 -33
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/facade/diffraction-provider.js +12 -13
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view.d.ts +27 -0
- package/dist/facade/display-view.js +234 -65
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +93 -10
- package/dist/facade/simulate-capture.js +146 -22
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.js +2 -2
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +2 -1
- package/dist/gpu/display-view-quality-gpu.js +24 -14
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +13 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.js +36 -2
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +10 -0
- package/dist/optics/irradiance-convolution.js +48 -13
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/output/print-jpeg.js +12 -9
- package/dist/output/print-jpeg.js.map +1 -1
- package/dist/output/text-metadata.d.ts +22 -2
- package/dist/output/text-metadata.js +58 -9
- package/dist/output/text-metadata.js.map +1 -1
- package/docs/API_REFERENCE.md +21 -1
- package/docs/QUICK_START.md +65 -5
- package/docs/USAGE.md +207 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +67 -2
- package/docs/api/exposure-auto-iso-slowest-shutter.md +139 -0
- package/docs/api/exposure-exposure-mode-resolver.md +68 -0
- package/docs/api/facade-simulate-capture.md +90 -9
- package/docs/api/output-text-metadata.md +34 -0
- package/package.json +1 -1
package/docs/api/exports.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"packageVersion": "2.
|
|
3
|
-
"engineApiVersion": "2.
|
|
2
|
+
"packageVersion": "2.13.0",
|
|
3
|
+
"engineApiVersion": "2.13.0",
|
|
4
4
|
"exports": [
|
|
5
5
|
{
|
|
6
6
|
"name": "AbsoluteUncertaintyEstimate",
|
|
@@ -27,6 +27,16 @@
|
|
|
27
27
|
"source": "src/output/capture-geometry.ts",
|
|
28
28
|
"kind": "type"
|
|
29
29
|
},
|
|
30
|
+
{
|
|
31
|
+
"name": "addJpegTextMetadata",
|
|
32
|
+
"source": "src/output/text-metadata.ts",
|
|
33
|
+
"kind": "runtime"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "addPngTextMetadata",
|
|
37
|
+
"source": "src/output/text-metadata.ts",
|
|
38
|
+
"kind": "runtime"
|
|
39
|
+
},
|
|
30
40
|
{
|
|
31
41
|
"name": "AffineGeometricTransform",
|
|
32
42
|
"source": "src/output/geometric-transforms.ts",
|
|
@@ -192,11 +202,36 @@
|
|
|
192
202
|
"source": "src/optics/atmospheric-haze.ts",
|
|
193
203
|
"kind": "type"
|
|
194
204
|
},
|
|
205
|
+
{
|
|
206
|
+
"name": "AUTO_ISO_SLOWEST_SHUTTER_MAXIMUM_BIAS_STOPS",
|
|
207
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
208
|
+
"kind": "runtime"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "AUTO_ISO_SLOWEST_SHUTTER_MODEL_VERSION",
|
|
212
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
213
|
+
"kind": "runtime"
|
|
214
|
+
},
|
|
195
215
|
{
|
|
196
216
|
"name": "AutoIsoBaselinePolicy",
|
|
197
217
|
"source": "src/exposure/exposure-mode-resolver.ts",
|
|
198
218
|
"kind": "type"
|
|
199
219
|
},
|
|
220
|
+
{
|
|
221
|
+
"name": "AutoIsoLimits",
|
|
222
|
+
"source": "src/exposure/exposure-mode-resolver.ts",
|
|
223
|
+
"kind": "type"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"name": "AutoIsoSlowestShutterBlurBudget",
|
|
227
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
228
|
+
"kind": "type"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "AutoIsoSlowestShutterEstimate",
|
|
232
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
233
|
+
"kind": "type"
|
|
234
|
+
},
|
|
200
235
|
{
|
|
201
236
|
"name": "AxisSamplingPitchMicrometers",
|
|
202
237
|
"source": "src/motion/camera-rotation.ts",
|
|
@@ -2797,6 +2832,16 @@
|
|
|
2797
2832
|
"source": "src/optics/circle-of-confusion.ts",
|
|
2798
2833
|
"kind": "type"
|
|
2799
2834
|
},
|
|
2835
|
+
{
|
|
2836
|
+
"name": "estimateAutoIsoSlowestShutter",
|
|
2837
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
2838
|
+
"kind": "runtime"
|
|
2839
|
+
},
|
|
2840
|
+
{
|
|
2841
|
+
"name": "EstimateAutoIsoSlowestShutterInput",
|
|
2842
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
2843
|
+
"kind": "type"
|
|
2844
|
+
},
|
|
2800
2845
|
{
|
|
2801
2846
|
"name": "estimateAutoWhiteBalance",
|
|
2802
2847
|
"source": "src/color/white-balance.ts",
|
|
@@ -3327,6 +3372,11 @@
|
|
|
3327
3372
|
"source": "src/equipment/generic-tier-presets.ts",
|
|
3328
3373
|
"kind": "runtime"
|
|
3329
3374
|
},
|
|
3375
|
+
{
|
|
3376
|
+
"name": "GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC",
|
|
3377
|
+
"source": "src/exposure/auto-iso-slowest-shutter.ts",
|
|
3378
|
+
"kind": "runtime"
|
|
3379
|
+
},
|
|
3330
3380
|
{
|
|
3331
3381
|
"name": "GENERIC_ISO_SIGNAL_CHAIN_PRESET_CATALOG_SCHEMA_VERSION",
|
|
3332
3382
|
"source": "src/sensor/iso-signal-chain.ts",
|
|
@@ -5917,6 +5967,11 @@
|
|
|
5917
5967
|
"source": "src/exposure/exposure-mode-resolver.ts",
|
|
5918
5968
|
"kind": "type"
|
|
5919
5969
|
},
|
|
5970
|
+
{
|
|
5971
|
+
"name": "ProgramSlowestPreferredShutterPolicy",
|
|
5972
|
+
"source": "src/exposure/exposure-mode-resolver.ts",
|
|
5973
|
+
"kind": "type"
|
|
5974
|
+
},
|
|
5920
5975
|
{
|
|
5921
5976
|
"name": "ProjectedMotionBlur",
|
|
5922
5977
|
"source": "src/motion/projected-motion.ts",
|
|
@@ -8137,6 +8192,16 @@
|
|
|
8137
8192
|
"source": "src/facade/simulate-capture.ts",
|
|
8138
8193
|
"kind": "type"
|
|
8139
8194
|
},
|
|
8195
|
+
{
|
|
8196
|
+
"name": "SimulateCaptureAutomaticSlowestShutterOptions",
|
|
8197
|
+
"source": "src/facade/simulate-capture.ts",
|
|
8198
|
+
"kind": "type"
|
|
8199
|
+
},
|
|
8200
|
+
{
|
|
8201
|
+
"name": "SimulateCaptureAutomaticSlowestShutterReport",
|
|
8202
|
+
"source": "src/facade/simulate-capture.ts",
|
|
8203
|
+
"kind": "type"
|
|
8204
|
+
},
|
|
8140
8205
|
{
|
|
8141
8206
|
"name": "SimulateCaptureBorderHandling",
|
|
8142
8207
|
"source": "src/facade/simulate-capture.ts",
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# exposure/auto-iso-slowest-shutter.ts public contracts
|
|
2
|
+
|
|
3
|
+
The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
|
|
4
|
+
|
|
5
|
+
## AUTO_ISO_SLOWEST_SHUTTER_MAXIMUM_BIAS_STOPS
|
|
6
|
+
|
|
7
|
+
The largest whole-stop bias accepted, either way (makers offer up to 2 stops faster or slower).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
AUTO_ISO_SLOWEST_SHUTTER_MAXIMUM_BIAS_STOPS = 2 as const
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## AUTO_ISO_SLOWEST_SHUTTER_MODEL_VERSION
|
|
14
|
+
|
|
15
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
AUTO_ISO_SLOWEST_SHUTTER_MODEL_VERSION = "1.0.0" as const
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## AutoIsoSlowestShutterBlurBudget
|
|
22
|
+
|
|
23
|
+
The blur allowed during the exposure, on the sensor.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
export type AutoIsoSlowestShutterBlurBudget =
|
|
27
|
+
| {
|
|
28
|
+
/** The blur trace length in pixels of the given pitch. */
|
|
29
|
+
kind: "pixels";
|
|
30
|
+
pixels: number;
|
|
31
|
+
pixelPitchMicrometers: number;
|
|
32
|
+
}
|
|
33
|
+
| {
|
|
34
|
+
/** The blur trace length as a fraction of the image diagonal (width × height in millimetres). */
|
|
35
|
+
kind: "image-diagonal-fraction";
|
|
36
|
+
fraction: number;
|
|
37
|
+
imageWidthMm: number;
|
|
38
|
+
imageHeightMm: number;
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## AutoIsoSlowestShutterEstimate
|
|
43
|
+
|
|
44
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export interface AutoIsoSlowestShutterEstimate {
|
|
48
|
+
/** The exposure time whose shake blur equals the budget, before the bias and the grid. */
|
|
49
|
+
derivedShutterSeconds: number;
|
|
50
|
+
fasterByStops: number;
|
|
51
|
+
/** derivedShutterSeconds · 2^−fasterByStops. */
|
|
52
|
+
biasedShutterSeconds: number;
|
|
53
|
+
/** The slowest preferred shutter: the biased value, snapped to `shutterCapability` when given. */
|
|
54
|
+
shutterSeconds: number;
|
|
55
|
+
shutterResolution: {
|
|
56
|
+
kind: "unconstrained" | "continuous" | "discrete";
|
|
57
|
+
selectionPolicy: "not-longer-than-target";
|
|
58
|
+
quantized: boolean;
|
|
59
|
+
clamped: false | "minimum" | "maximum";
|
|
60
|
+
};
|
|
61
|
+
blurBudgetMm: number;
|
|
62
|
+
/** `estimateCameraShakeBlur()`'s stabilized blur at the derived shutter (equal to the budget within rounding). */
|
|
63
|
+
blurAtDerivedShutterMm: number;
|
|
64
|
+
/** `estimateCameraShakeBlur()`'s stabilized blur at `shutterSeconds`. */
|
|
65
|
+
blurAtShutterMm: number;
|
|
66
|
+
/** The same blur lengths in pixels, for a pixel budget. */
|
|
67
|
+
blurBudgetPixels?: number;
|
|
68
|
+
blurAtShutterPixels?: number;
|
|
69
|
+
projectionDistanceMm: number;
|
|
70
|
+
residualMotionFactor: number;
|
|
71
|
+
angularVelocityRadPerSec: { yaw: number; pitch: number };
|
|
72
|
+
stabilizationStopsEquivalent: number;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## estimateAutoIsoSlowestShutter
|
|
77
|
+
|
|
78
|
+
Estimates the slowest preferred shutter for Auto ISO from the lens, the sensor and the hand's
|
|
79
|
+
shake: the exposure time at which `estimateCameraShakeBlur()`'s stabilized blur equals the blur
|
|
80
|
+
budget, then shifted by a whole-stop bias and optionally snapped to the body's shutter grid (never
|
|
81
|
+
longer than the biased value). Longer focal lengths give faster shutters; each stabilization stop
|
|
82
|
+
doubles the time; each bias stop halves (+1) or doubles (−1) it.
|
|
83
|
+
|
|
84
|
+
An approximation: constant angular velocity (a caller profile, or the labelled generic default
|
|
85
|
+
`GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`), stabilization as 2^−stops, blur on the optical axis
|
|
86
|
+
only. The 1/focal-length "reciprocal rule" is a rule of thumb and is not used.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
export function estimateAutoIsoSlowestShutter(
|
|
90
|
+
input: EstimateAutoIsoSlowestShutterInput
|
|
91
|
+
): CalculationResult<AutoIsoSlowestShutterEstimate>;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
95
|
+
|
|
96
|
+
## EstimateAutoIsoSlowestShutterInput
|
|
97
|
+
|
|
98
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
export interface EstimateAutoIsoSlowestShutterInput {
|
|
102
|
+
focalLengthMm: number;
|
|
103
|
+
/** Optional focus distance in metres: the thin-lens image distance becomes the projection distance, as in `estimateCameraShakeBlur()`. */
|
|
104
|
+
focusDistanceM?: number;
|
|
105
|
+
/**
|
|
106
|
+
* The hand's constant angular velocity in radians per second, the explicit shake profile (signs as in
|
|
107
|
+
* `estimateCameraShakeBlur()`; only the magnitude matters here). At least one axis must be non-zero.
|
|
108
|
+
* `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC` is a cited generic default, not a measurement of you.
|
|
109
|
+
*/
|
|
110
|
+
angularVelocityRadPerSec: { yaw: number; pitch: number };
|
|
111
|
+
/** Stabilization in equivalent stops (≥ 0); the motion is scaled by 2^−stops. Default 0. */
|
|
112
|
+
stabilizationStopsEquivalent?: number;
|
|
113
|
+
blurBudget: AutoIsoSlowestShutterBlurBudget;
|
|
114
|
+
/**
|
|
115
|
+
* The bias in whole stops, applied after the derivation: +1 is one stop faster (half the time), −1 one
|
|
116
|
+
* stop slower (twice the time). An integer from −2 to +2. Default 0.
|
|
117
|
+
*/
|
|
118
|
+
fasterByStops?: number;
|
|
119
|
+
/** Optional: the body's resolved shutter capability. The biased shutter then snaps to it, never longer than the biased value, and is held at its ends. */
|
|
120
|
+
shutterCapability?: ResolvedGenericEquipmentExposureCapabilities["shutter"];
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC
|
|
125
|
+
|
|
126
|
+
A generic handheld angular velocity, labelled as a default and not a measurement of any camera or
|
|
127
|
+
photographer: 4.39 °/s (≈ 0.0766 rad/s), the linear camera-motion rate Xiao, Farrell, Catrysse and
|
|
128
|
+
Wandell use for "an average user" holding "a typical 100g mobile handset with two hands", from their
|
|
129
|
+
earlier gyroscope measurements (F. Xiao, J. Farrell, P. Catrysse, B. Wandell, "Mobile imaging: the
|
|
130
|
+
big challenge of the small pixel", Proc. SPIE 7250, Digital Photography V, 2009, §2; author copy:
|
|
131
|
+
https://web.stanford.edu/~wandell/data/papers/2009-CameraShake-Xiao.pdf; they cite F. Xiao et al.,
|
|
132
|
+
"Camera-motion and mobile imaging", Proc. SPIE 6502, 2007). The value is one rate magnitude; it is
|
|
133
|
+
placed on the yaw axis (for small angles the blur length does not depend on the direction). A
|
|
134
|
+
heavier camera, another grip or another photographer moves differently: pass your own profile.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC: Readonly<{ yaw: number; pitch: number }> =
|
|
138
|
+
Object.freeze({ yaw: (4.39 * Math.PI) / 180, pitch: 0 })
|
|
139
|
+
```
|
|
@@ -198,6 +198,32 @@ export interface AutoIsoBaselinePolicy {
|
|
|
198
198
|
isoBaseline: "minimum-selectable";
|
|
199
199
|
isoQuantizationPolicy:
|
|
200
200
|
"nearest-log2-lower-on-tie";
|
|
201
|
+
/** #505: optional photographer-set Auto ISO limits inside the body's Auto ISO range. */
|
|
202
|
+
autoIsoLimits?: AutoIsoLimits;
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## AutoIsoLimits
|
|
207
|
+
|
|
208
|
+
#505: the photographer's Auto ISO limits, a policy choice kept separate from what the body allows
|
|
209
|
+
(`capabilities.iso.autoIsoMinimum`/`autoIsoMaximum`, else the ISO range). Cameras let the
|
|
210
|
+
photographer cap Auto ISO, and some also raise its floor (for example the Nikon D850's "maximum
|
|
211
|
+
sensitivity", Fujifilm's per-preset default and maximum sensitivity, and Panasonic's separate upper
|
|
212
|
+
and lower Auto ISO limits; makers' manuals, see docs/USAGE.md).
|
|
213
|
+
|
|
214
|
+
Both values are ISO settings: inside the body's Auto ISO range and, on a discrete ISO grid, one of
|
|
215
|
+
its values, with `minimum` at most `maximum`. Anything else fails with
|
|
216
|
+
`InvalidScientificInputError`; the engine never clips a limit silently. When a limit is strictly
|
|
217
|
+
inside the body's range and the ISO is held there, the limiting constraint is `user-iso-maximum` or
|
|
218
|
+
`user-iso-minimum`; a limit equal to the body's bound adds nothing, and the body's `iso-maximum` or
|
|
219
|
+
`iso-minimum` is reported.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
export interface AutoIsoLimits {
|
|
223
|
+
/** The highest ISO Auto ISO may choose. */
|
|
224
|
+
maximum: number;
|
|
225
|
+
/** The lowest ISO Auto ISO may choose, and so its baseline. Default: the body's Auto ISO minimum. */
|
|
226
|
+
minimum?: number;
|
|
201
227
|
}
|
|
202
228
|
```
|
|
203
229
|
|
|
@@ -219,6 +245,8 @@ export type ExposureResolutionConstraint =
|
|
|
219
245
|
| "none"
|
|
220
246
|
| "iso-minimum"
|
|
221
247
|
| "iso-maximum"
|
|
248
|
+
| "user-iso-minimum"
|
|
249
|
+
| "user-iso-maximum"
|
|
222
250
|
| "iso-grid-quantization"
|
|
223
251
|
| "shutter-minimum"
|
|
224
252
|
| "shutter-maximum"
|
|
@@ -366,6 +394,8 @@ export interface FullAutoExposurePolicy {
|
|
|
366
394
|
"minimum-selectable";
|
|
367
395
|
isoQuantizationPolicy:
|
|
368
396
|
"nearest-log2-lower-on-tie";
|
|
397
|
+
/** #505: optional photographer-set Auto ISO limits inside the body's Auto ISO range. */
|
|
398
|
+
autoIsoLimits?: AutoIsoLimits;
|
|
369
399
|
}
|
|
370
400
|
```
|
|
371
401
|
|
|
@@ -467,6 +497,8 @@ export type ManualIsoControl =
|
|
|
467
497
|
kind: "automatic";
|
|
468
498
|
quantizationPolicy:
|
|
469
499
|
"nearest-log2-lower-on-tie";
|
|
500
|
+
/** #505: optional photographer-set Auto ISO limits inside the body's Auto ISO range. */
|
|
501
|
+
autoIsoLimits?: AutoIsoLimits;
|
|
470
502
|
};
|
|
471
503
|
```
|
|
472
504
|
|
|
@@ -521,6 +553,16 @@ export type ProgramAutoExposureModeResolution =
|
|
|
521
553
|
ExposureTargetResidual,
|
|
522
554
|
{ status: "resolved" }
|
|
523
555
|
>;
|
|
556
|
+
/**
|
|
557
|
+
* #504: present only with `isoControl.slowestPreferredShutter`. `applied` is true when the line's
|
|
558
|
+
* shutter was longer than the slowest preferred shutter and was held; `afterMaximumIsoFallbackUsed`
|
|
559
|
+
* when the slower-shutter fallback ran at the Auto ISO maximum. `programLineSelection` stays the
|
|
560
|
+
* line's own selection.
|
|
561
|
+
*/
|
|
562
|
+
slowestPreferredShutter?: ProgramSlowestPreferredShutterPolicy & {
|
|
563
|
+
applied: boolean;
|
|
564
|
+
afterMaximumIsoFallbackUsed: boolean;
|
|
565
|
+
};
|
|
524
566
|
})
|
|
525
567
|
| {
|
|
526
568
|
resolverVersion:
|
|
@@ -573,6 +615,14 @@ export type ProgramAutoIsoControl =
|
|
|
573
615
|
"minimum-selectable";
|
|
574
616
|
isoQuantizationPolicy:
|
|
575
617
|
"nearest-log2-lower-on-tie";
|
|
618
|
+
/** #505: optional photographer-set Auto ISO limits inside the body's Auto ISO range. */
|
|
619
|
+
autoIsoLimits?: AutoIsoLimits;
|
|
620
|
+
/**
|
|
621
|
+
* #504: optionally hold the program line's shutter at or faster than a slowest preferred shutter
|
|
622
|
+
* before the ISO rises (for example from `estimateAutoIsoSlowestShutter()`). Absent, the program line
|
|
623
|
+
* is followed as before.
|
|
624
|
+
*/
|
|
625
|
+
slowestPreferredShutter?: ProgramSlowestPreferredShutterPolicy;
|
|
576
626
|
};
|
|
577
627
|
```
|
|
578
628
|
|
|
@@ -611,6 +661,24 @@ export interface ProgramLineSelectionDiagnostics {
|
|
|
611
661
|
}
|
|
612
662
|
```
|
|
613
663
|
|
|
664
|
+
## ProgramSlowestPreferredShutterPolicy
|
|
665
|
+
|
|
666
|
+
#504: Program + Auto ISO's slowest preferred shutter, the two-axis policy of Aperture Priority + Auto
|
|
667
|
+
ISO applied to the program line. When the line asks for a longer shutter than
|
|
668
|
+
`slowestPreferredShutterSeconds`, the shutter is held there (snapped, never longer) with the line's
|
|
669
|
+
aperture, and Auto ISO makes up the rest. At the Auto ISO maximum, `afterMaximumIso` decides:
|
|
670
|
+
`"allow-slower-shutter"` lengthens the shutter toward the target, but never past the program line's
|
|
671
|
+
own shutter; `"hold-preferred-shutter"` keeps it and leaves the exposure under target.
|
|
672
|
+
|
|
673
|
+
```ts
|
|
674
|
+
export interface ProgramSlowestPreferredShutterPolicy {
|
|
675
|
+
slowestPreferredShutterSeconds: number;
|
|
676
|
+
afterMaximumIso:
|
|
677
|
+
| "allow-slower-shutter"
|
|
678
|
+
| "hold-preferred-shutter";
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
614
682
|
## RelativeExposureControlAnchor
|
|
615
683
|
|
|
616
684
|
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
@@ -21,8 +21,10 @@ export interface DisplayViewResult {
|
|
|
21
21
|
*/
|
|
22
22
|
view: { width: number; height: number; frameWidth: number; frameHeight: number; scaleX: number; scaleY: number; samplesPerAxis: number;
|
|
23
23
|
region?: { x: number; y: number; width: number; height: number } };
|
|
24
|
-
/** The resolved exposure of the capture this view shows; `standardExposureDeviationStops` as in {@link SimulateCaptureResult}. */
|
|
24
|
+
/** The resolved exposure of the capture this view shows; `standardExposureDeviationStops` and `standardExposureIlluminanceLux` as in {@link SimulateCaptureResult}. */
|
|
25
25
|
exposure: { mode: SimulateCaptureExposureMode; settings: { fNumber: number; shutterSeconds: number; iso: number }; ev100: number; standardExposureDeviationStops: number | null;
|
|
26
|
+
/** As in the capture result. */
|
|
27
|
+
standardExposureIlluminanceLux: number | null;
|
|
26
28
|
/** #516: as in the capture result. */
|
|
27
29
|
isoControl: "manual" | "automatic"; autoIso?: SimulateCaptureAutoIsoReport };
|
|
28
30
|
scene: SimulateCaptureResult["scene"];
|
|
@@ -186,23 +188,82 @@ resolver output stays in the capture's `exposure.resolution`.
|
|
|
186
188
|
export interface SimulateCaptureAutoIsoReport {
|
|
187
189
|
/** The ISO the meter target asked for at the resolved aperture and shutter, before the Auto ISO range and the ISO grid. */
|
|
188
190
|
idealIsoBeforeConstraints: number;
|
|
189
|
-
/**
|
|
191
|
+
/**
|
|
192
|
+
* The body's Auto ISO range: its Auto ISO bounds, or its ISO range when it declares none (the tiers: ISO 100 to their
|
|
193
|
+
* maximum). Without `limits` the ISO was chosen in this range.
|
|
194
|
+
*/
|
|
190
195
|
autoIsoMinimum: number;
|
|
191
196
|
autoIsoMaximum: number;
|
|
197
|
+
/**
|
|
198
|
+
* #505: present only with `exposure.autoIso.limits`: the photographer's Auto ISO range the ISO was chosen in, inside the
|
|
199
|
+
* body's (`minimum` is the body's Auto ISO minimum when the option omits it).
|
|
200
|
+
*/
|
|
201
|
+
limits?: { minimum: number; maximum: number };
|
|
192
202
|
/** Whether the ISO was held at an end of the Auto ISO range. */
|
|
193
203
|
clamped: false | "minimum" | "maximum";
|
|
194
204
|
/**
|
|
195
205
|
* The constraint that limited the resolved exposure: the resolver's `targetResidual.limitingConstraint`, for example
|
|
196
|
-
* `"iso-maximum"` (the exposure stays under target at the Auto ISO maximum), `"iso-
|
|
197
|
-
* selectable ISO) or `"none"`
|
|
206
|
+
* `"iso-maximum"` (the exposure stays under target at the body's Auto ISO maximum), `"user-iso-maximum"` (#505: at the
|
|
207
|
+
* photographer's `limits.maximum`, below the body's), `"iso-grid-quantization"` (the nearest selectable ISO) or `"none"`
|
|
208
|
+
* (on target).
|
|
198
209
|
*/
|
|
199
210
|
limitingConstraint: ExposureResolutionConstraint;
|
|
200
211
|
/** The resolver's residual, log2(target / achieved exposure), in stops: positive when the exposure is under the meter target, negative when over it. */
|
|
201
212
|
residualStops: number;
|
|
202
|
-
/**
|
|
213
|
+
/**
|
|
214
|
+
* Aperture priority, and program with a slowest preferred shutter (#504): the policy and slowest preferred shutter used,
|
|
215
|
+
* and whether the slower-shutter fallback ran.
|
|
216
|
+
*/
|
|
203
217
|
afterMaximumIso?: SimulateCaptureAutoIsoAfterMaximum;
|
|
204
218
|
slowestPreferredShutterSeconds?: number;
|
|
205
219
|
afterMaximumIsoFallbackUsed?: boolean;
|
|
220
|
+
/** #504, program only: whether the program line's shutter was longer than the slowest preferred shutter and was held. */
|
|
221
|
+
slowestPreferredShutterApplied?: boolean;
|
|
222
|
+
/** #504: present only with `slowestPreferredShutterSeconds: "auto"`: how the engine derived it (`estimateAutoIsoSlowestShutter`). */
|
|
223
|
+
automaticSlowestShutter?: SimulateCaptureAutomaticSlowestShutterReport;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## SimulateCaptureAutomaticSlowestShutterOptions
|
|
228
|
+
|
|
229
|
+
#504: the settings of `exposure.autoIso.slowestPreferredShutterSeconds: "auto"`. Every field is optional; the defaults are
|
|
230
|
+
labelled generic values, recorded as `default` assumptions.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
export interface SimulateCaptureAutomaticSlowestShutterOptions {
|
|
234
|
+
/** The bias in whole stops, as cameras' Auto minimum-shutter settings offer: +1 one stop faster, −1 one stop slower; −2 to +2. Default 0. */
|
|
235
|
+
fasterByStops?: number;
|
|
236
|
+
/** The shake blur allowed, in sensor pixels of `sensor.pixelPitchMicrometers`. Default 1 (a generic pixel-level budget). */
|
|
237
|
+
blurBudgetPixels?: number;
|
|
238
|
+
/**
|
|
239
|
+
* The hand's constant angular velocity, rad/s (signs as in `motion.angularVelocityRadPerSec`; only the magnitude matters).
|
|
240
|
+
* Default `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`: 4.39 °/s on yaw, a cited generic value for a 100 g phone held in
|
|
241
|
+
* two hands (Xiao et al., Proc. SPIE 7250, 2009), not a measurement of you or of this camera.
|
|
242
|
+
*/
|
|
243
|
+
angularVelocityRadPerSec?: { yaw: number; pitch: number };
|
|
244
|
+
/** Stabilization in equivalent stops (≥ 0, at most 10), scaling the motion by 2^−stops. Default 0: the tiers declare no stabilization. */
|
|
245
|
+
stabilizationStopsEquivalent?: number;
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## SimulateCaptureAutomaticSlowestShutterReport
|
|
250
|
+
|
|
251
|
+
#504: the automatic slowest preferred shutter in the Auto ISO report.
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
export interface SimulateCaptureAutomaticSlowestShutterReport {
|
|
255
|
+
/** The exposure time whose camera-shake blur equals the budget (`estimateCameraShakeBlur`), before the bias and the grid. */
|
|
256
|
+
derivedShutterSeconds: number;
|
|
257
|
+
fasterByStops: number;
|
|
258
|
+
/** derivedShutterSeconds · 2^−fasterByStops. */
|
|
259
|
+
biasedShutterSeconds: number;
|
|
260
|
+
/** The slowest preferred shutter used: the biased time within the body's shutter range. */
|
|
261
|
+
shutterSeconds: number;
|
|
262
|
+
blurBudgetPixels: number;
|
|
263
|
+
/** The shake blur at `shutterSeconds`, in pixels. */
|
|
264
|
+
blurAtShutterPixels: number;
|
|
265
|
+
angularVelocityRadPerSec: { yaw: number; pitch: number };
|
|
266
|
+
stabilizationStopsEquivalent: number;
|
|
206
267
|
}
|
|
207
268
|
```
|
|
208
269
|
|
|
@@ -391,11 +452,24 @@ export interface SimulateCaptureOptions {
|
|
|
391
452
|
*/
|
|
392
453
|
iso?: number | "auto";
|
|
393
454
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
455
|
+
* Auto ISO settings, with `iso: "auto"` only.
|
|
456
|
+
*
|
|
457
|
+
* - `slowestPreferredShutterSeconds` and `afterMaximumIso` (#516): aperture priority, where the slowest shutter is
|
|
458
|
+
* required, and (#504) program, where it is optional. The shutter gets as long as `slowestPreferredShutterSeconds`
|
|
459
|
+
* (seconds, within the body's shutter range) at the lowest Auto ISO; beyond it the ISO rises; at the Auto ISO maximum
|
|
460
|
+
* `afterMaximumIso` decides (default `"allow-slower-shutter"`; in program the shutter then never gets longer than the
|
|
461
|
+
* program line's own). Without it, program follows its line as before.
|
|
462
|
+
* - `slowestPreferredShutterSeconds: "auto"` (#504): the engine derives it from the focal length, the pixel pitch and a
|
|
463
|
+
* hand-shake profile with `estimateAutoIsoSlowestShutter` (the camera-shake model, not the 1/focal-length rule of
|
|
464
|
+
* thumb); `automaticSlowestShutter` sets the bias, the blur budget, the shake and the stabilization.
|
|
465
|
+
* - `limits` (#505): every mode. The photographer's Auto ISO range `{ maximum, minimum? }`, a choice kept apart from
|
|
466
|
+
* the body's Auto ISO capability: both are selectable ISOs inside the body's Auto ISO range, `minimum` at most
|
|
467
|
+
* `maximum` (default: the body's minimum). Outside the body's range or off its ISO grid the request fails; the
|
|
468
|
+
* engine never clips a limit. When the ISO stops at a limit strictly inside the body's range, the report's
|
|
469
|
+
* `limitingConstraint` is `"user-iso-maximum"` or `"user-iso-minimum"`.
|
|
397
470
|
*/
|
|
398
|
-
autoIso?: { slowestPreferredShutterSeconds
|
|
471
|
+
autoIso?: { slowestPreferredShutterSeconds?: number | "auto"; afterMaximumIso?: SimulateCaptureAutoIsoAfterMaximum; limits?: AutoIsoLimits;
|
|
472
|
+
automaticSlowestShutter?: SimulateCaptureAutomaticSlowestShutterOptions };
|
|
399
473
|
/** Shutter for manual and shutter-priority modes. Default 1/125 s. */
|
|
400
474
|
shutterSeconds?: number;
|
|
401
475
|
/** Exposure compensation applied to the meter target, in stops. Default 0. */
|
|
@@ -616,6 +690,13 @@ export interface SimulateCaptureResult {
|
|
|
616
690
|
* the metered luminance is 0 (a black scene has no standard exposure).
|
|
617
691
|
*/
|
|
618
692
|
standardExposureDeviationStops: number | null;
|
|
693
|
+
/**
|
|
694
|
+
* The illuminance, lux, at which the settings used give the standard exposure: E·L_ref(N, t, S)/L = E·2^Δ, with E the
|
|
695
|
+
* request's `illuminanceLux`. Exact for a reflective scene (a chart, a reflectance function or a material scene), whose
|
|
696
|
+
* metered luminance is proportional to E. Null for a black scene (L = 0) and for a radiance-function scene, whose
|
|
697
|
+
* radiance does not depend on the illuminance. It may exceed the 1e7 lux that `illuminanceLux` accepts.
|
|
698
|
+
*/
|
|
699
|
+
standardExposureIlluminanceLux: number | null;
|
|
619
700
|
/** Full output of the existing exposure-mode resolver. */
|
|
620
701
|
resolution: unknown;
|
|
621
702
|
};
|
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
|
|
4
4
|
|
|
5
|
+
## addJpegTextMetadata
|
|
6
|
+
|
|
7
|
+
Returns a copy of a baseline JPEG with the text fields added: merged into its XMP APP1 packet (or a new packet
|
|
8
|
+
after the last leading APPn segment when it has none), plus a COM segment for `comment`. Every other byte,
|
|
9
|
+
including the entropy-coded data, is unchanged. Reads marker segments only up to SOS. The engine's own
|
|
10
|
+
`output.metadata` path calls this function, so for the same JPEG and text the bytes are the same.
|
|
11
|
+
|
|
12
|
+
Root export (#388). `metadata` is checked as `output.metadata` is (see the module notes); a JPEG without SOI,
|
|
13
|
+
a malformed or truncated segment before SOS, an XMP APP1 segment after a non-APPn segment, an XMP packet that is
|
|
14
|
+
not UTF-8 or has no `rdf:RDF`, or text that makes the packet larger than one APP1 segment fails with
|
|
15
|
+
`InvalidConfigurationError`. The input is not changed.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export function addJpegTextMetadata(jpeg: Uint8Array, metadata: Readonly<OutputTextMetadata>): Uint8Array;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
22
|
+
|
|
23
|
+
## addPngTextMetadata
|
|
24
|
+
|
|
25
|
+
Returns a copy of a PNG with one text chunk per field inserted before the first IDAT chunk. Other chunks are
|
|
26
|
+
unchanged. The engine's own `output.metadata` path calls this function, so for the same PNG and text the bytes
|
|
27
|
+
are the same.
|
|
28
|
+
|
|
29
|
+
Root export (#388). `metadata` is checked as `output.metadata` is (see the module notes); a file without the PNG
|
|
30
|
+
signature, or without an IDAT chunk inside its bytes, fails with `InvalidConfigurationError`. Chunk CRCs before
|
|
31
|
+
IDAT are not checked. The input is not changed.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
export function addPngTextMetadata(png: Uint8Array, metadata: Readonly<OutputTextMetadata>): Uint8Array;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
38
|
+
|
|
5
39
|
## OutputTextMetadata
|
|
6
40
|
|
|
7
41
|
Caller-supplied text written into JPEG, PNG and DNG outputs. Every field is optional; at least one must be set.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@photivra/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Scientific TypeScript engine for camera optics, exposure, focus, motion, sensor sampling, diffraction, and digital imaging calculations.",
|
|
6
6
|
"type": "module",
|