@photivra/engine 2.12.0 → 2.14.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 +144 -1
- package/CITATION.cff +1 -1
- package/README.md +7 -7
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +3 -0
- package/dist/camera/lens-projection.js +2 -1
- package/dist/camera/lens-projection.js.map +1 -1
- package/dist/capture/dng-import.js +1 -1
- package/dist/capture/dng-import.js.map +1 -1
- 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/capture/host-yield-cadence.js +1 -1
- package/dist/capture/host-yield-cadence.js.map +1 -1
- package/dist/capture/native-environment-optical-stage.js +1 -1
- package/dist/capture/native-environment-optical-stage.js.map +1 -1
- package/dist/capture/native-raw.js +1 -1
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/packed-sensor-raw.js +3 -3
- package/dist/capture/packed-sensor-raw.js.map +1 -1
- package/dist/capture/sensor-raw-producer.js +1 -1
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/capture-color.js +3 -3
- package/dist/color/capture-color.js.map +1 -1
- package/dist/color/chromatic-adaptation.js +2 -2
- package/dist/color/chromatic-adaptation.js.map +1 -1
- package/dist/color/color-matching-functions.js +1 -1
- package/dist/color/color-matching-functions.js.map +1 -1
- package/dist/color/colorimetry-math.js +2 -2
- package/dist/color/colorimetry-math.js.map +1 -1
- package/dist/color/illuminants.js +3 -3
- package/dist/color/illuminants.js.map +1 -1
- package/dist/color/rgb-color-spaces.js +1 -1
- package/dist/color/rgb-color-spaces.js.map +1 -1
- package/dist/color/sensor-color-development.js +1 -1
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/core/record-validation.js +3 -3
- package/dist/core/record-validation.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/equipment/generic-prime-lenses.js +3 -3
- package/dist/equipment/generic-prime-lenses.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +23 -1
- package/dist/equipment/generic-tier-assets.js +58 -30
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.d.ts +6 -3
- package/dist/equipment/generic-tier-presets.js +26 -13
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.d.ts +120 -0
- package/dist/exposure/auto-iso-slowest-shutter.js +217 -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/exposure/flash-ttl.js +1 -1
- package/dist/exposure/flash-ttl.js.map +1 -1
- package/dist/exposure/flash.js +1 -1
- package/dist/exposure/flash.js.map +1 -1
- package/dist/facade/chart-material-layers.js +2 -2
- package/dist/facade/chart-material-layers.js.map +1 -1
- package/dist/facade/chart-radiance-batch.js +1 -1
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/chart-scenes.d.ts +45 -8
- package/dist/facade/chart-scenes.js +101 -44
- package/dist/facade/chart-scenes.js.map +1 -1
- package/dist/facade/color-patches.d.ts +129 -0
- package/dist/facade/color-patches.js +209 -0
- package/dist/facade/color-patches.js.map +1 -0
- package/dist/facade/diffraction-provider.js +12 -13
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu.js +1 -1
- package/dist/facade/display-view-gpu.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/scene-radiance.js +2 -2
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +139 -12
- package/dist/facade/simulate-capture.js +209 -36
- 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/chart-composite-gpu.js +2 -2
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/display-view-composite-material-module.js +1 -1
- package/dist/gpu/display-view-composite-material-module.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/image-kernel-execution.js +2 -2
- package/dist/gpu/image-kernel-execution.js.map +1 -1
- package/dist/gpu/temporal-sum-gpu.js +23 -23
- package/dist/gpu/webgpu-runtime.js +1 -1
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/gpu/wgsl-chart-composite-kernel.js +318 -318
- package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -1
- package/dist/gpu/wgsl-chart-kernel.js +117 -117
- package/dist/gpu/wgsl-chart-kernel.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 +522 -488
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.js +248 -248
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/gpu/wgsl-kernels.js +203 -203
- package/dist/gpu/wgsl-kernels.js.map +1 -1
- package/dist/gpu/wgsl-sensor-kernel.js +302 -302
- package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/motion/temporal-exposure-sum.js +1 -1
- package/dist/motion/temporal-exposure-sum.js.map +1 -1
- package/dist/optics/diffraction-psf-profile.js +4 -4
- package/dist/optics/diffraction-psf-profile.js.map +1 -1
- package/dist/optics/front-of-lens-filter.js +1 -1
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +10 -0
- package/dist/optics/irradiance-convolution.js +49 -14
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/output/native-capture-sdr.js +1 -1
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/png-encoder.js +2 -2
- package/dist/output/png-encoder.js.map +1 -1
- package/dist/output/print-jpeg.js +13 -10
- 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/dist/sensor/fixed-pattern-noise.js +1 -1
- package/dist/sensor/fixed-pattern-noise.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +1 -1
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/docs/API_REFERENCE.md +49 -1
- package/docs/QUICK_START.md +104 -9
- package/docs/USAGE.md +241 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-tier-assets.md +41 -1
- package/docs/api/equipment-generic-tier-presets.md +11 -3
- package/docs/api/exports.json +172 -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-chart-scenes.md +36 -5
- package/docs/api/facade-color-patches.md +150 -0
- package/docs/api/facade-simulate-capture.md +140 -9
- package/docs/api/output-text-metadata.md +34 -0
- package/llms.txt +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# facade/color-patches.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
|
+
## COLOR_PATCH_IDS
|
|
6
|
+
|
|
7
|
+
The ids of the built-in patches, in the order of the `color-patches` chart (row-major, six per row).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
COLOR_PATCH_IDS = Object.freeze([
|
|
11
|
+
"neutral-1", "neutral-2", "neutral-3", "neutral-4", "neutral-5", "neutral-6",
|
|
12
|
+
"red", "yellow", "green", "cyan", "blue", "magenta",
|
|
13
|
+
"red-soft", "yellow-soft", "green-soft", "cyan-soft", "blue-soft", "magenta-soft",
|
|
14
|
+
"skin-pale", "skin-medium", "skin-tan", "skin-deep", "sky-blue", "foliage-green",
|
|
15
|
+
"brick-red", "sand", "teal", "lavender", "deep-orange", "deep-violet"
|
|
16
|
+
] as const)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## COLOR_PATCH_SET_ID
|
|
20
|
+
|
|
21
|
+
Identity of the built-in patch set.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
COLOR_PATCH_SET_ID = "photivra-color-patches"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## COLOR_PATCH_SET_VERSION
|
|
28
|
+
|
|
29
|
+
Version of the patch set's spectra and reference values; a change to any spectrum changes it.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
COLOR_PATCH_SET_VERSION = "1.0.0"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## COLOR_PATCH_WAVELENGTH_RANGE_NANOMETERS
|
|
36
|
+
|
|
37
|
+
Wavelengths on which every patch spectrum is defined, nanometers, inclusive.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
COLOR_PATCH_WAVELENGTH_RANGE_NANOMETERS = Object.freeze({ minimum: 360, maximum: 830 })
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## ColorPatch
|
|
44
|
+
|
|
45
|
+
One built-in patch: its id, short code, name, reason for being on the chart, spectrum definition and reference
|
|
46
|
+
colorimetry.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
export interface ColorPatch {
|
|
50
|
+
/** Stable API id, e.g. `"skin-medium"`. */
|
|
51
|
+
patchId: ColorPatchId;
|
|
52
|
+
/**
|
|
53
|
+
* Stable short code for labels and printed charts: `PV-` and a group letter and number, e.g. `"PV-N4"`. The letters are
|
|
54
|
+
* N neutral, S strong, T soft (tint), P skin (portrait), M memory and G gamut-edge, numbered in chart order.
|
|
55
|
+
*/
|
|
56
|
+
code: string;
|
|
57
|
+
/** Photivra's own descriptive name, in US English, e.g. `"Studio Gray 4"`; not a third-party color name. */
|
|
58
|
+
name: string;
|
|
59
|
+
group: ColorPatchGroup;
|
|
60
|
+
/** One sentence: why the patch is on the chart. */
|
|
61
|
+
reason: string;
|
|
62
|
+
/** The constant b of the formula. */
|
|
63
|
+
base: number;
|
|
64
|
+
terms: readonly ColorPatchSpectralTerm[];
|
|
65
|
+
/**
|
|
66
|
+
* Reference colorimetry of the reflectance (not of a rendered capture): CIELAB under CIE illuminant D65 with the CIE
|
|
67
|
+
* 1931 2° observer, the CIE tables at 1 nm over 360–830 nm, white = the perfect diffuser under D65 (Y = 100); and the
|
|
68
|
+
* sRGB color of that XYZ (CSS Color 4 matrix, after XYZ scaling of the D65 table white to the sRGB white),
|
|
69
|
+
* 8-bit hex. Rounded for publication: L*, a*, b* to 0.01.
|
|
70
|
+
*/
|
|
71
|
+
reference: { cielabD65: readonly [number, number, number]; srgbHex: string; inSrgbGamut: boolean };
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## ColorPatchGroup
|
|
76
|
+
|
|
77
|
+
Groups of the patch set, in chart order.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
export type ColorPatchGroup = "neutral" | "strong" | "soft" | "skin" | "memory" | "gamut-edge";
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## ColorPatchId
|
|
84
|
+
|
|
85
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
export type ColorPatchId = (typeof COLOR_PATCH_IDS)[number];
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## ColorPatchSet
|
|
92
|
+
|
|
93
|
+
The built-in patch set (see {@link getColorPatchSet}).
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
export interface ColorPatchSet {
|
|
97
|
+
setId: typeof COLOR_PATCH_SET_ID;
|
|
98
|
+
version: typeof COLOR_PATCH_SET_VERSION;
|
|
99
|
+
wavelengthRangeNanometers: { minimum: number; maximum: number };
|
|
100
|
+
/** Patches per row of the `color-patches` chart's default layout. */
|
|
101
|
+
columns: number;
|
|
102
|
+
patches: readonly ColorPatch[];
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## ColorPatchSpectralTerm
|
|
107
|
+
|
|
108
|
+
One term of a patch spectrum (see the module formula).
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
export type ColorPatchSpectralTerm =
|
|
112
|
+
| { kind: "gaussian"; amplitude: number; centerNanometers: number; standardDeviationNanometers: number }
|
|
113
|
+
| { kind: "logistic-rise" | "logistic-fall"; amplitude: number; midpointNanometers: number; scaleNanometers: number };
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## evaluateColorPatchReflectance
|
|
117
|
+
|
|
118
|
+
The reflectance (dimensionless, in [0, 1]) of a built-in color patch at one wavelength, from its analytic formula.
|
|
119
|
+
Labeled `approximation`: the spectra are Photivra's own smooth designs, not measurements of a physical sample.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
export function evaluateColorPatchReflectance(input: EvaluateColorPatchReflectanceInput): CalculationResult<{ reflectance: number }>;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
126
|
+
|
|
127
|
+
## EvaluateColorPatchReflectanceInput
|
|
128
|
+
|
|
129
|
+
Input of {@link evaluateColorPatchReflectance}.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
export interface EvaluateColorPatchReflectanceInput {
|
|
133
|
+
patchId: ColorPatchId;
|
|
134
|
+
/** Vacuum wavelength, nanometers, in 360–830. */
|
|
135
|
+
wavelengthNanometers: number;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## getColorPatchSet
|
|
140
|
+
|
|
141
|
+
The built-in Photivra color-patch set: every patch's id, code, name, group, reason, spectrum parameters and reference CIELAB (D65,
|
|
142
|
+
CIE 1931 2°) and sRGB values. A static, deeply frozen engine contract. Pass a patch to a chart as
|
|
143
|
+
`{ kind: "color-patch", patchId }` wherever a chart reflectance is accepted, or draw the whole set with the
|
|
144
|
+
`color-patches` chart preset.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
export function getColorPatchSet(): ColorPatchSet;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
@@ -21,8 +21,17 @@ 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
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The resolved exposure of the capture this view shows; `standardExposureDeviationStops`, `standardExposureIlluminanceLux`
|
|
26
|
+
* and `greyCardDeviationStops` as in {@link SimulateCaptureResult}.
|
|
27
|
+
*/
|
|
25
28
|
exposure: { mode: SimulateCaptureExposureMode; settings: { fNumber: number; shutterSeconds: number; iso: number }; ev100: number; standardExposureDeviationStops: number | null;
|
|
29
|
+
/** As in the capture result. */
|
|
30
|
+
standardExposureIlluminanceLux: number | null;
|
|
31
|
+
/** 2.14: as in the capture result. */
|
|
32
|
+
greyCardDeviationStops: number | null;
|
|
33
|
+
/** 2.14: as in the capture result. */
|
|
34
|
+
metering: SimulateCaptureMetering;
|
|
26
35
|
/** #516: as in the capture result. */
|
|
27
36
|
isoControl: "manual" | "automatic"; autoIso?: SimulateCaptureAutoIsoReport };
|
|
28
37
|
scene: SimulateCaptureResult["scene"];
|
|
@@ -134,6 +143,14 @@ whether or not it has a fast method yet; one without runs exact and reports `fal
|
|
|
134
143
|
SIMULATE_CAPTURE_FAST_OPTIONS = Object.freeze(["lens.diffraction", "sensor.antiAliasing", "sensor.pixelAperture.box", "output.demosaic.ahd"] as const)
|
|
135
144
|
```
|
|
136
145
|
|
|
146
|
+
## SIMULATE_CAPTURE_METERING_MODES
|
|
147
|
+
|
|
148
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
SIMULATE_CAPTURE_METERING_MODES: readonly SimulateCaptureMetering[] = Object.freeze(["scene-average", "grey-card"] as const)
|
|
152
|
+
```
|
|
153
|
+
|
|
137
154
|
## SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS
|
|
138
155
|
|
|
139
156
|
Default stratified samples per axis of a display view (`view.samplesPerAxis`): 16 × 16 sampled real pixels per display pixel with detail, 4 × 4 where it is uniform.
|
|
@@ -186,23 +203,84 @@ resolver output stays in the capture's `exposure.resolution`.
|
|
|
186
203
|
export interface SimulateCaptureAutoIsoReport {
|
|
187
204
|
/** The ISO the meter target asked for at the resolved aperture and shutter, before the Auto ISO range and the ISO grid. */
|
|
188
205
|
idealIsoBeforeConstraints: number;
|
|
189
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* The body's Auto ISO range: its Auto ISO bounds, or its ISO range when it declares none (the tiers: ISO 100 to their
|
|
208
|
+
* maximum). Without `limits` the ISO was chosen in this range.
|
|
209
|
+
*/
|
|
190
210
|
autoIsoMinimum: number;
|
|
191
211
|
autoIsoMaximum: number;
|
|
212
|
+
/**
|
|
213
|
+
* #505: present only with `exposure.autoIso.limits`: the photographer's Auto ISO range the ISO was chosen in, inside the
|
|
214
|
+
* body's (`minimum` is the body's Auto ISO minimum when the option omits it).
|
|
215
|
+
*/
|
|
216
|
+
limits?: { minimum: number; maximum: number };
|
|
192
217
|
/** Whether the ISO was held at an end of the Auto ISO range. */
|
|
193
218
|
clamped: false | "minimum" | "maximum";
|
|
194
219
|
/**
|
|
195
220
|
* 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"`
|
|
221
|
+
* `"iso-maximum"` (the exposure stays under target at the body's Auto ISO maximum), `"user-iso-maximum"` (#505: at the
|
|
222
|
+
* photographer's `limits.maximum`, below the body's), `"iso-grid-quantization"` (the nearest selectable ISO) or `"none"`
|
|
223
|
+
* (on target).
|
|
198
224
|
*/
|
|
199
225
|
limitingConstraint: ExposureResolutionConstraint;
|
|
200
226
|
/** The resolver's residual, log2(target / achieved exposure), in stops: positive when the exposure is under the meter target, negative when over it. */
|
|
201
227
|
residualStops: number;
|
|
202
|
-
/**
|
|
228
|
+
/**
|
|
229
|
+
* Aperture priority, and program with a slowest preferred shutter (#504): the policy and slowest preferred shutter used,
|
|
230
|
+
* and whether the slower-shutter fallback ran.
|
|
231
|
+
*/
|
|
203
232
|
afterMaximumIso?: SimulateCaptureAutoIsoAfterMaximum;
|
|
204
233
|
slowestPreferredShutterSeconds?: number;
|
|
205
234
|
afterMaximumIsoFallbackUsed?: boolean;
|
|
235
|
+
/** #504, program only: whether the program line's shutter was longer than the slowest preferred shutter and was held. */
|
|
236
|
+
slowestPreferredShutterApplied?: boolean;
|
|
237
|
+
/** #504: present only with `slowestPreferredShutterSeconds: "auto"`: how the engine derived it (`estimateAutoIsoSlowestShutter`). */
|
|
238
|
+
automaticSlowestShutter?: SimulateCaptureAutomaticSlowestShutterReport;
|
|
239
|
+
/** 2.14: present when `exposure.autoIso.isoSteps` is given: the ISO steps Auto ISO chose from. */
|
|
240
|
+
isoSteps?: "whole-stop" | "third-stop";
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## SimulateCaptureAutomaticSlowestShutterOptions
|
|
245
|
+
|
|
246
|
+
#504: the settings of `exposure.autoIso.slowestPreferredShutterSeconds: "auto"`. Every field is optional; the defaults are
|
|
247
|
+
labelled generic values, recorded as `default` assumptions.
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
export interface SimulateCaptureAutomaticSlowestShutterOptions {
|
|
251
|
+
/** 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. */
|
|
252
|
+
fasterByStops?: number;
|
|
253
|
+
/** The shake blur allowed, in sensor pixels of `sensor.pixelPitchMicrometers`. Default 1 (a generic pixel-level budget). */
|
|
254
|
+
blurBudgetPixels?: number;
|
|
255
|
+
/**
|
|
256
|
+
* The hand's constant angular velocity, rad/s (signs as in `motion.angularVelocityRadPerSec`; only the magnitude matters).
|
|
257
|
+
* Default `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`: 4.39 °/s on yaw, a cited generic value for a 100 g phone held in
|
|
258
|
+
* two hands (Xiao et al., Proc. SPIE 7250, 2009), not a measurement of you or of this camera.
|
|
259
|
+
*/
|
|
260
|
+
angularVelocityRadPerSec?: { yaw: number; pitch: number };
|
|
261
|
+
/** Stabilization in equivalent stops (≥ 0, at most 10), scaling the motion by 2^−stops. Default 0: the tiers declare no stabilization. */
|
|
262
|
+
stabilizationStopsEquivalent?: number;
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## SimulateCaptureAutomaticSlowestShutterReport
|
|
267
|
+
|
|
268
|
+
#504: the automatic slowest preferred shutter in the Auto ISO report.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
export interface SimulateCaptureAutomaticSlowestShutterReport {
|
|
272
|
+
/** The exposure time whose camera-shake blur equals the budget (`estimateCameraShakeBlur`), before the bias and the grid. */
|
|
273
|
+
derivedShutterSeconds: number;
|
|
274
|
+
fasterByStops: number;
|
|
275
|
+
/** derivedShutterSeconds · 2^−fasterByStops. */
|
|
276
|
+
biasedShutterSeconds: number;
|
|
277
|
+
/** The slowest preferred shutter used: the biased time within the body's shutter range. */
|
|
278
|
+
shutterSeconds: number;
|
|
279
|
+
blurBudgetPixels: number;
|
|
280
|
+
/** The shake blur at `shutterSeconds`, in pixels. */
|
|
281
|
+
blurAtShutterPixels: number;
|
|
282
|
+
angularVelocityRadPerSec: { yaw: number; pitch: number };
|
|
283
|
+
stabilizationStopsEquivalent: number;
|
|
206
284
|
}
|
|
207
285
|
```
|
|
208
286
|
|
|
@@ -308,6 +386,17 @@ export type SimulateCaptureLensDistortion =
|
|
|
308
386
|
| { kind: "brown-conrady"; profile: BrownConradyDistortionProfile };
|
|
309
387
|
```
|
|
310
388
|
|
|
389
|
+
## SimulateCaptureMetering
|
|
390
|
+
|
|
391
|
+
2.14: what the meter reads. `scene-average` (the default): the body's 16 × 16-zone meter reads the scene's luminance.
|
|
392
|
+
`grey-card`: incident metering; every zone reads the luminance 0.18·E/π of an 18 % Lambertian grey card under the
|
|
393
|
+
request's illuminance E, so the automatic modes choose settings whose `greyCardDeviationStops` is 0 (up to their steps
|
|
394
|
+
and limits), whatever the scene's reflectances.
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
export type SimulateCaptureMetering = "scene-average" | "grey-card";
|
|
398
|
+
```
|
|
399
|
+
|
|
311
400
|
## SimulateCaptureMotion
|
|
312
401
|
|
|
313
402
|
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
@@ -391,15 +480,37 @@ export interface SimulateCaptureOptions {
|
|
|
391
480
|
*/
|
|
392
481
|
iso?: number | "auto";
|
|
393
482
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
483
|
+
* Auto ISO settings, with `iso: "auto"` only.
|
|
484
|
+
*
|
|
485
|
+
* - `slowestPreferredShutterSeconds` and `afterMaximumIso` (#516): aperture priority, where the slowest shutter is
|
|
486
|
+
* required, and (#504) program, where it is optional. The shutter gets as long as `slowestPreferredShutterSeconds`
|
|
487
|
+
* (seconds, within the body's shutter range) at the lowest Auto ISO; beyond it the ISO rises; at the Auto ISO maximum
|
|
488
|
+
* `afterMaximumIso` decides (default `"allow-slower-shutter"`; in program the shutter then never gets longer than the
|
|
489
|
+
* program line's own). Without it, program follows its line as before.
|
|
490
|
+
* - `slowestPreferredShutterSeconds: "auto"` (#504): the engine derives it from the focal length, the pixel pitch and a
|
|
491
|
+
* hand-shake profile with `estimateAutoIsoSlowestShutter` (the camera-shake model, not the 1/focal-length rule of
|
|
492
|
+
* thumb); `automaticSlowestShutter` sets the bias, the blur budget, the shake and the stabilization.
|
|
493
|
+
* - `limits` (#505): every mode. The photographer's Auto ISO range `{ maximum, minimum? }`, a choice kept apart from
|
|
494
|
+
* the body's Auto ISO capability: both are selectable ISOs inside the body's Auto ISO range, `minimum` at most
|
|
495
|
+
* `maximum` (default: the body's minimum). Outside the body's range or off its ISO grid the request fails; the
|
|
496
|
+
* engine never clips a limit. When the ISO stops at a limit strictly inside the body's range, the report's
|
|
497
|
+
* `limitingConstraint` is `"user-iso-maximum"` or `"user-iso-minimum"`.
|
|
498
|
+
* - `isoSteps` (2.14): `"whole-stop"` (default) lets Auto ISO choose only the whole-stop ISOs of the body's grid
|
|
499
|
+
* (100, 200, 400 …), as before the generic bodies gained third-stop settings (preset 2.1.0); `"third-stop"` lets it
|
|
500
|
+
* choose every setting (100, 125, 160 …). Manual ISO always takes any setting of the grid. Limits must lie on the
|
|
501
|
+
* grid Auto ISO uses.
|
|
397
502
|
*/
|
|
398
|
-
autoIso?: { slowestPreferredShutterSeconds
|
|
503
|
+
autoIso?: { slowestPreferredShutterSeconds?: number | "auto"; afterMaximumIso?: SimulateCaptureAutoIsoAfterMaximum; limits?: AutoIsoLimits;
|
|
504
|
+
automaticSlowestShutter?: SimulateCaptureAutomaticSlowestShutterOptions; isoSteps?: "whole-stop" | "third-stop" };
|
|
399
505
|
/** Shutter for manual and shutter-priority modes. Default 1/125 s. */
|
|
400
506
|
shutterSeconds?: number;
|
|
401
507
|
/** Exposure compensation applied to the meter target, in stops. Default 0. */
|
|
402
508
|
compensationStops?: number;
|
|
509
|
+
/**
|
|
510
|
+
* 2.14: `"scene-average"` (default) or `"grey-card"` (incident metering, see {@link SimulateCaptureMetering}). Manual
|
|
511
|
+
* exposure does not use the meter's reading, so the setting changes only the automatic modes and Auto ISO.
|
|
512
|
+
*/
|
|
513
|
+
metering?: SimulateCaptureMetering;
|
|
403
514
|
};
|
|
404
515
|
/**
|
|
405
516
|
* Required: an engine chart (for example `{ preset: "uniform" }`, an 18 % grey card), a declared `material-layers` scene (#491:
|
|
@@ -608,6 +719,9 @@ export interface SimulateCaptureResult {
|
|
|
608
719
|
isoControl: "manual" | "automatic";
|
|
609
720
|
/** #516: present with `iso: "auto"`: how Auto ISO chose `settings.iso` and what limited it. */
|
|
610
721
|
autoIso?: SimulateCaptureAutoIsoReport;
|
|
722
|
+
/** 2.14: the metering the exposure used (`exposure.metering`; `"scene-average"` when omitted). */
|
|
723
|
+
metering: SimulateCaptureMetering;
|
|
724
|
+
/** The scene's average luminance on the meter's zones, cd/m², with either metering. */
|
|
611
725
|
meteredSceneLuminanceCdPerSquareMeter: number;
|
|
612
726
|
/**
|
|
613
727
|
* #515: deviation, in stops, of the exposure used from the CIPA DC-004-2020 standard exposure for the metered luminance L:
|
|
@@ -616,6 +730,23 @@ export interface SimulateCaptureResult {
|
|
|
616
730
|
* the metered luminance is 0 (a black scene has no standard exposure).
|
|
617
731
|
*/
|
|
618
732
|
standardExposureDeviationStops: number | null;
|
|
733
|
+
/**
|
|
734
|
+
* The illuminance, lux, at which the settings used give the standard exposure: E·L_ref(N, t, S)/L = E·2^Δ, with E the
|
|
735
|
+
* request's `illuminanceLux`. Exact for a reflective scene (a chart, a reflectance function or a material scene), whose
|
|
736
|
+
* metered luminance is proportional to E. Null for a black scene (L = 0) and for a radiance-function scene, whose
|
|
737
|
+
* radiance does not depend on the illuminance. It may exceed the 1e7 lux that `illuminanceLux` accepts.
|
|
738
|
+
*/
|
|
739
|
+
standardExposureIlluminanceLux: number | null;
|
|
740
|
+
/**
|
|
741
|
+
* 2.14: deviation, in stops, of the exposure used from the CIPA DC-004-2020 standard exposure of an 18 % Lambertian grey
|
|
742
|
+
* card under the request's illuminance E (incident metering: the light falling on the scene, as a grey card or a
|
|
743
|
+
* hand-held incident meter reads it): log2(L_ref(N, t, S) / (0.18·E/π)), with L_ref = 10·N²/(0.65·t·S). Same sign as
|
|
744
|
+
* `standardExposureDeviationStops` (positive is darker, under). It does not depend on the scene's reflectances; with the
|
|
745
|
+
* default settings and illuminance it is exactly 0. The exposure modes still meter the scene (`meteredSceneLuminanceCdPerSquareMeter`);
|
|
746
|
+
* this only reports where the settings used sit against the grey card. Null for a radiance-function scene, whose radiance
|
|
747
|
+
* does not depend on the illuminance.
|
|
748
|
+
*/
|
|
749
|
+
greyCardDeviationStops: number | null;
|
|
619
750
|
/** Full output of the existing exposure-mode resolver. */
|
|
620
751
|
resolution: unknown;
|
|
621
752
|
};
|
|
@@ -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/llms.txt
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- [Agent guide](https://github.com/Photivra/photivra/blob/main/docs/AGENT_GUIDE.md): which function to call, units, reading results, errors and limits
|
|
8
8
|
- [Quick start](https://github.com/Photivra/photivra/blob/main/docs/QUICK_START.md): `simulateCapture()` inputs, defaults, chart presets and output formats
|
|
9
|
+
- [Color patches](https://github.com/Photivra/photivra/blob/main/docs/COLOR_PATCHES.md): the built-in color chart patches (`color-patches` preset, `{ kind: "color-patch", patchId }`), their spectra and CIELAB
|
|
9
10
|
- [Usage guide](https://github.com/Photivra/photivra/blob/main/docs/USAGE.md): worked examples for every public area
|
|
10
11
|
- [API reference](https://github.com/Photivra/photivra/blob/main/docs/API_REFERENCE.md): every root export, with a task-to-function index
|
|
11
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@photivra/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.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",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"node": ">=22.13.0"
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|
|
76
|
-
"build": "tsc -p tsconfig.build.json",
|
|
76
|
+
"build": "tsc -p tsconfig.build.json && node scripts/minify-wgsl-dist.mjs",
|
|
77
77
|
"hooks:install": "node scripts/install-git-hooks.mjs",
|
|
78
78
|
"prepush": "node scripts/prepush.mjs",
|
|
79
79
|
"check:static": "eslint . && tsc --noEmit && npm run check:licenses && npm run check:license-headers && npm run check:identity && npm run check:browser-surface",
|