@photivra/engine 2.20.0 → 2.21.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 +178 -1
- package/CITATION.cff +1 -1
- package/README.md +7 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +7 -0
- package/dist/capture/dng-lens-correction-opcodes.d.ts +2 -2
- package/dist/capture/dng-lens-correction-opcodes.js +2 -2
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -1
- package/dist/capture/exposure-build-up-stage.d.ts +16 -0
- package/dist/capture/exposure-build-up-stage.js +4 -0
- package/dist/capture/exposure-build-up-stage.js.map +1 -0
- package/dist/capture/native-environment-lean.d.ts +2 -1
- package/dist/capture/native-environment-lean.js +41 -73
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-tabulated.js +4 -3
- package/dist/capture/native-environment-tabulated.js.map +1 -1
- package/dist/capture/native-raw.d.ts +3 -2
- package/dist/capture/native-raw.js +5 -4
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/sensor-raw-producer.d.ts +4 -1
- package/dist/capture/sensor-raw-producer.js +12 -3
- package/dist/capture/sensor-raw-producer.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-lens-catalogue.d.ts +3 -2
- package/dist/equipment/generic-lens-catalogue.js +18 -5
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +32 -0
- package/dist/equipment/generic-tier-assets.js +16 -11
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/sensor-profile-body.d.ts +78 -0
- package/dist/equipment/sensor-profile-body.js +77 -0
- package/dist/equipment/sensor-profile-body.js.map +1 -0
- package/dist/equipment/sensor-profiles.d.ts +8 -0
- package/dist/equipment/sensor-profiles.js +82 -0
- package/dist/equipment/sensor-profiles.js.map +1 -0
- package/dist/facade/catalogue-lens-signal.d.ts +2 -2
- package/dist/facade/catalogue-lens-signal.js +58 -71
- package/dist/facade/catalogue-lens-signal.js.map +1 -1
- package/dist/facade/chart-radiance-batch.js +2 -1
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/defocus-image-space-provider.d.ts +7 -0
- package/dist/facade/defocus-image-space-provider.js +64 -76
- package/dist/facade/defocus-image-space-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.js +2 -0
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +6 -1
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.js +25 -23
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view.js +5 -23
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.d.ts +3 -1
- package/dist/facade/expected-signal-setup.js +1 -1
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +47 -14
- package/dist/facade/expected-signal.js +117 -112
- package/dist/facade/expected-signal.js.map +1 -1
- package/dist/facade/exposure-build-up.d.ts +70 -0
- package/dist/facade/exposure-build-up.js +164 -0
- package/dist/facade/exposure-build-up.js.map +1 -0
- package/dist/facade/fast-methods.js +9 -1
- package/dist/facade/fast-methods.js.map +1 -1
- package/dist/facade/generic-lens-capture.d.ts +2 -2
- package/dist/facade/generic-lens-capture.js +2 -2
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/image-plane-enable.d.ts +7 -0
- package/dist/facade/image-plane-enable.js +17 -0
- package/dist/facade/image-plane-enable.js.map +1 -0
- package/dist/facade/image-plane-lattice-data.d.ts +6 -0
- package/dist/facade/image-plane-lattice-data.js +10 -0
- package/dist/facade/image-plane-lattice-data.js.map +1 -0
- package/dist/facade/image-plane-support.d.ts +33 -0
- package/dist/facade/image-plane-support.js +11 -0
- package/dist/facade/image-plane-support.js.map +1 -0
- package/dist/facade/image-plane.d.ts +36 -0
- package/dist/facade/image-plane.js +353 -0
- package/dist/facade/image-plane.js.map +1 -0
- package/dist/facade/mixed-illumination.d.ts +108 -0
- package/dist/facade/mixed-illumination.js +174 -0
- package/dist/facade/mixed-illumination.js.map +1 -0
- package/dist/facade/representative-light-sources.d.ts +72 -0
- package/dist/facade/representative-light-sources.js +124 -0
- package/dist/facade/representative-light-sources.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +129 -4
- package/dist/facade/scene-radiance.js +48 -13
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +39 -10
- package/dist/facade/simulate-capture.js +252 -92
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.js +14 -6
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.d.ts +13 -1
- package/dist/gpu/chart-composite-gpu.js +48 -9
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +4 -30
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
- package/dist/gpu/display-view-composite-material-module.js +39 -13
- package/dist/gpu/display-view-composite-material-module.js.map +1 -1
- package/dist/gpu/display-view-image-material-module.d.ts +86 -0
- package/dist/gpu/display-view-image-material-module.js +339 -0
- package/dist/gpu/display-view-image-material-module.js.map +1 -0
- package/dist/gpu/display-view-image-quality.d.ts +45 -0
- package/dist/gpu/display-view-image-quality.js +380 -0
- package/dist/gpu/display-view-image-quality.js.map +1 -0
- package/dist/gpu/display-view-quality-gpu.d.ts +67 -1
- package/dist/gpu/display-view-quality-gpu.js +136 -205
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +51 -3
- package/dist/gpu/display-view-speed-gpu.js +131 -93
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +29 -15
- package/dist/gpu/wgsl-display-view-quality-kernel.js +58 -36
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +21 -6
- package/dist/gpu/wgsl-display-view-speed-kernel.js +46 -11
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
- package/dist/gpu/wgsl-exact-sum.js +42 -0
- package/dist/gpu/wgsl-exact-sum.js.map +1 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/motion/subject-motion.d.ts +66 -0
- package/dist/motion/subject-motion.js +52 -0
- package/dist/motion/subject-motion.js.map +1 -0
- package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
- package/dist/optics/generic-lens-lateral-color.js +77 -0
- package/dist/optics/generic-lens-lateral-color.js.map +1 -0
- package/dist/optics/generic-lens-psf.js +54 -46
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +7 -0
- package/dist/optics/lens-psf-profile.js +2 -1
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/output/developed-lens-corrections.d.ts +19 -5
- package/dist/output/developed-lens-corrections.js +28 -9
- package/dist/output/developed-lens-corrections.js.map +1 -1
- package/dist/output/generic-lens-corrections.d.ts +41 -5
- package/dist/output/generic-lens-corrections.js +52 -8
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/print-plan.d.ts +41 -5
- package/dist/output/print-plan.js +59 -14
- package/dist/output/print-plan.js.map +1 -1
- package/dist/sensor/binomial-sample.d.ts +3 -0
- package/dist/sensor/binomial-sample.js +86 -0
- package/dist/sensor/binomial-sample.js.map +1 -0
- package/dist/sensor/sensor-characteristics.d.ts +10 -0
- package/dist/sensor/sensor-characteristics.js +20 -9
- package/dist/sensor/sensor-characteristics.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +98 -1
- package/docs/QUICK_START.md +125 -0
- package/docs/USAGE.md +92 -1
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +10 -5
- package/docs/api/equipment-sensor-profile-body.md +64 -0
- package/docs/api/equipment-sensor-profiles.md +86 -0
- package/docs/api/exports.json +207 -2
- package/docs/api/facade-exposure-build-up.md +105 -0
- package/docs/api/facade-fast-methods.md +9 -1
- package/docs/api/facade-image-plane-enable.md +16 -0
- package/docs/api/facade-mixed-illumination.md +67 -0
- package/docs/api/facade-representative-light-sources.md +131 -0
- package/docs/api/facade-scene-radiance.md +54 -3
- package/docs/api/facade-simulate-capture.md +26 -6
- package/docs/api/motion-subject-motion.md +23 -0
- package/docs/api/optics-generic-lens-lateral-color.md +79 -0
- package/docs/api/output-developed-lens-corrections.md +10 -1
- package/docs/api/output-generic-lens-corrections.md +40 -4
- package/docs/api/output-print-plan.md +35 -1
- package/llms.txt +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# facade/representative-light-sources.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
|
+
## createRepresentativeLightSourceIlluminant
|
|
6
|
+
|
|
7
|
+
A capture illuminant for a source: `{ kind: "spectrum", spectrum, label }` with the spectrum of
|
|
8
|
+
{@link createRepresentativeLightSourceSpectrum} and the label "<name> (representative, not a named product)".
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
export function createRepresentativeLightSourceIlluminant(input: { sourceId: RepresentativeLightSourceId }): Extract<CaptureIlluminant, { kind: "spectrum" }>;
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
15
|
+
|
|
16
|
+
## createRepresentativeLightSourceSpectrum
|
|
17
|
+
|
|
18
|
+
A source's relative spectral power distribution S(λ) = b + Σ aₖ·exp(−½((λ − μₖ)/σₖ)²) as a function spectrum on
|
|
19
|
+
360–830 nm (relative units; values memoized per wavelength). Pass it to a capture as
|
|
20
|
+
`illuminant: { kind: "spectrum", spectrum }`; for color work use `sensor.spectralStepNanometers: 5` or finer
|
|
21
|
+
(docs/LIGHT_SOURCES.md, "Quadrature"). Throws `InvalidScientificInputError` outside 360–830 nm.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
export function createRepresentativeLightSourceSpectrum(input: { sourceId: RepresentativeLightSourceId }): ColorimetricSpectrum;
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
28
|
+
|
|
29
|
+
## getRepresentativeLightSourceSet
|
|
30
|
+
|
|
31
|
+
The built-in representative light sources: Photivra's own parametric spectra of a tri-phosphor fluorescent tube and
|
|
32
|
+
three white LEDs (low and high color rendering at 4000 K, warm at 2700 K). A static, deeply frozen engine contract.
|
|
33
|
+
Each is "representative, not a named product"; docs/LIGHT_SOURCES.md gives every formula and the reasons for it.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
export function getRepresentativeLightSourceSet(): RepresentativeLightSourceSet;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
40
|
+
|
|
41
|
+
## REPRESENTATIVE_LIGHT_SOURCE_IDS
|
|
42
|
+
|
|
43
|
+
The source ids, in set order.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
REPRESENTATIVE_LIGHT_SOURCE_IDS = Object.freeze([
|
|
47
|
+
"tri-phosphor-fluorescent-4000k", "white-led-low-rendering-4000k", "white-led-high-rendering-4000k", "warm-white-led-2700k"
|
|
48
|
+
] as const)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## REPRESENTATIVE_LIGHT_SOURCE_SET_ID
|
|
52
|
+
|
|
53
|
+
Identity of the built-in light-source set.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
REPRESENTATIVE_LIGHT_SOURCE_SET_ID = "photivra-representative-light-sources"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION
|
|
60
|
+
|
|
61
|
+
Version of the set's spectra; a change to any spectrum changes it.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION = "1.0.0"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS
|
|
68
|
+
|
|
69
|
+
Domain of every spectrum, nm (the CIE 1931 observer's domain; the capture facade uses 380–780 nm of it).
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS = Object.freeze({ minimum: 360, maximum: 830 })
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## RepresentativeLightSource
|
|
76
|
+
|
|
77
|
+
One built-in source: its id, name, design reason and spectrum definition.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
export interface RepresentativeLightSource {
|
|
81
|
+
sourceId: RepresentativeLightSourceId;
|
|
82
|
+
/** Photivra's descriptive name, for example "White LED, high color rendering, 4000 K". */
|
|
83
|
+
name: string;
|
|
84
|
+
family: "fluorescent" | "led";
|
|
85
|
+
/** The CCT the spectrum was designed for, K (its computed CCT is within 1 K of it, Duv within 0.0001; docs/LIGHT_SOURCES.md). */
|
|
86
|
+
nominalCorrelatedColorTemperatureKelvin: number;
|
|
87
|
+
/** Always "representative, not a named product". */
|
|
88
|
+
label: "representative, not a named product";
|
|
89
|
+
/** One sentence: what the source represents and why it is built this way. */
|
|
90
|
+
reason: string;
|
|
91
|
+
/** The constant b (a low continuum), relative units. */
|
|
92
|
+
base: number;
|
|
93
|
+
bands: readonly RepresentativeLightSourceBand[];
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## RepresentativeLightSourceBand
|
|
98
|
+
|
|
99
|
+
One Gaussian band a·exp(−½((λ − μ)/σ)²) of a source spectrum.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
export interface RepresentativeLightSourceBand {
|
|
103
|
+
kind: "gaussian";
|
|
104
|
+
/** What the band represents, for example "blue pump" or "green phosphor line". */
|
|
105
|
+
role: string;
|
|
106
|
+
amplitude: number;
|
|
107
|
+
centerNanometers: number;
|
|
108
|
+
standardDeviationNanometers: number;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## RepresentativeLightSourceId
|
|
113
|
+
|
|
114
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
export type RepresentativeLightSourceId = (typeof REPRESENTATIVE_LIGHT_SOURCE_IDS)[number];
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## RepresentativeLightSourceSet
|
|
121
|
+
|
|
122
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
export interface RepresentativeLightSourceSet {
|
|
126
|
+
setId: typeof REPRESENTATIVE_LIGHT_SOURCE_SET_ID;
|
|
127
|
+
setVersion: typeof REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION;
|
|
128
|
+
wavelengthRangeNanometers: { readonly minimum: number; readonly maximum: number };
|
|
129
|
+
sources: readonly RepresentativeLightSource[];
|
|
130
|
+
}
|
|
131
|
+
```
|
|
@@ -91,7 +91,8 @@ provider `providerProfileId`.
|
|
|
91
91
|
|
|
92
92
|
```ts
|
|
93
93
|
export function createPlanarSceneRadianceProvider(input: {
|
|
94
|
-
scene:
|
|
94
|
+
/** An `image-plane` scene (#581) is refused: it is taken by the facade's capture and display-view functions, which load its module. */
|
|
95
|
+
scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene | ImagePlaneScene;
|
|
95
96
|
illuminant: CaptureIlluminant;
|
|
96
97
|
illuminanceLux: number;
|
|
97
98
|
distanceM: number;
|
|
@@ -110,6 +111,47 @@ export function createPlanarSceneRadianceProvider(input: {
|
|
|
110
111
|
|
|
111
112
|
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
112
113
|
|
|
114
|
+
## ImagePlaneImage
|
|
115
|
+
|
|
116
|
+
2.21 (#581): an image the caller supplies, for an {@link ImagePlaneScene}. `data` holds `width × height` pixels row by row
|
|
117
|
+
from the top, `channels` (3: RGB, 4: RGBA) samples each, in the encoding's type: `srgb-8` Uint8Array or Uint8ClampedArray
|
|
118
|
+
(canvas `ImageData.data`), `srgb-16` Uint16Array, `linear-srgb` Float32Array. sRGB primaries and white (IEC 61966-2-1) in
|
|
119
|
+
every encoding; `srgb-8` and `srgb-16` are decoded with the sRGB transfer function, `linear-srgb` is already linear and is
|
|
120
|
+
clipped to [0, 1] (the clipped samples are counted). Alpha is linear coverage over the paper. The array is read, never
|
|
121
|
+
changed or kept beyond the call.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
export interface ImagePlaneImage {
|
|
125
|
+
width: number;
|
|
126
|
+
height: number;
|
|
127
|
+
channels: 3 | 4;
|
|
128
|
+
encoding: "srgb-8" | "srgb-16" | "linear-srgb";
|
|
129
|
+
data: Uint8Array | Uint8ClampedArray | Uint16Array | Float32Array;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## ImagePlaneScene
|
|
134
|
+
|
|
135
|
+
2.21 (#581): a photo as a flat matte print on the scene plane, lit by the request's illuminant like a chart. Each pixel's
|
|
136
|
+
color becomes a reflectance spectrum through the engine's print reflectance lattice (docs/IMAGE_PLANE.md): an
|
|
137
|
+
approximation, a print of an image that was already processed, clipped and blurred by the camera that took it. The print's
|
|
138
|
+
physical size is `chartSize` (its height defaults to the image's aspect); without it the print is fitted inside the frame,
|
|
139
|
+
centered, on the 18 % surround.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
export interface ImagePlaneScene {
|
|
143
|
+
kind: "image-plane";
|
|
144
|
+
sceneId: string;
|
|
145
|
+
image: ImagePlaneImage;
|
|
146
|
+
/** The paper and the deepest ink: reflectances of sRGB white and black, 0 ≤ black < white ≤ 1. Defaults 0.90 and 0.01. */
|
|
147
|
+
paper?: { whiteReflectance?: number; blackReflectance?: number };
|
|
148
|
+
/** How the print is reconstructed between pixel centers. Default `bilinear` (the pixels' spectra, bilinearly weighted). */
|
|
149
|
+
interpolation?: "bilinear" | "nearest";
|
|
150
|
+
/** Opt-in raised pixel limit: an integer up to the full-resolution ceiling. Default 24 000 000 pixels. */
|
|
151
|
+
maximumPixels?: number;
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
113
155
|
## PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W
|
|
114
156
|
|
|
115
157
|
CIE maximum luminous efficacy for photopic vision, lm/W.
|
|
@@ -128,8 +170,11 @@ export interface PlanarSceneRadianceProvider {
|
|
|
128
170
|
providerProfileId: string;
|
|
129
171
|
evaluateRadiance(request: Readonly<SceneRadianceEvaluationRequest>): SceneRadianceEvaluationResult;
|
|
130
172
|
evaluateApertureRadiance(request: Readonly<SceneRadianceEvaluationRequest>, ray: Readonly<SensorApertureRay>): SceneRadianceEvaluationResult;
|
|
131
|
-
/**
|
|
132
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Spectral radiance at a plane point (frame units), the same value the callbacks return. #551: a moving subject's provider
|
|
175
|
+
* reads it at time `t` (seconds from the first opening, default 0); a still scene ignores it.
|
|
176
|
+
*/
|
|
177
|
+
radianceAt(u: number, v: number, wavelengthNanometers: number, t?: number): number;
|
|
133
178
|
/**
|
|
134
179
|
* 2.3, chart scenes only: the chart material at a plane point (frame units), or `materials.length` for the
|
|
135
180
|
* surround of a fixed-size chart; `materialRadiance` gives that material's spectral radiance, the same value
|
|
@@ -137,6 +182,12 @@ export interface PlanarSceneRadianceProvider {
|
|
|
137
182
|
*/
|
|
138
183
|
chartMaterialAt?(u: number, v: number): number;
|
|
139
184
|
materialRadiance?(material: number, wavelengthNanometers: number): number;
|
|
185
|
+
/**
|
|
186
|
+
* 2.21 (#581), image-plane scenes only: the tabulated expected signal's scene at these spectral nodes and channel responses, its
|
|
187
|
+
* radiance per node and, for the direct path, Σ_n A_c(λ_n)·L(λ_n) integrated from each pixel's reconstructed spectrum
|
|
188
|
+
* (`ResolvedImagePlaneScene.pixelSignals`, the surround's reflectance times the neutral signal outside the print).
|
|
189
|
+
*/
|
|
190
|
+
imageSignalScene?(wavelengths: readonly number[], perNode: readonly Float64Array[]): ImagePlaneSignalScene;
|
|
140
191
|
}
|
|
141
192
|
```
|
|
142
193
|
|
|
@@ -144,7 +144,7 @@ a capture does. `motion.rotation` is a non-zero angular velocity; `sensor.tempor
|
|
|
144
144
|
|
|
145
145
|
```ts
|
|
146
146
|
SIMULATE_CAPTURE_COST_OPTIONS = Object.freeze(["lens.pupilSampling", "lens.projection", "lens.distortion", "lens.vignetting", "lens.psf",
|
|
147
|
-
"lens.diffraction", "lens.defocus", "lens.catalogue", "sensor.antiAliasing", "sensor.pixelAperture.box", "sensor.temporalSampleCount", "motion.rotation", "motion.shutter.rolling", "output.borderHandling.mirror", "output.region",
|
|
147
|
+
"lens.diffraction", "lens.defocus", "lens.catalogue", "sensor.antiAliasing", "sensor.pixelAperture.box", "sensor.temporalSampleCount", "motion.rotation", "motion.subject", "motion.shutter.rolling", "output.borderHandling.mirror", "output.region",
|
|
148
148
|
"output.whiteBalance.auto", "output.demosaic.ahd", "output.highlightMode.reconstruct", "output.colorEncoding.wide-gamut", "output.gamutMapping.perceptual",
|
|
149
149
|
"output.diffractionCorrection", "output.sharpening", "output.lensCorrections", "output.format.jpeg", "output.format.png", "output.format.dng"] as const)
|
|
150
150
|
```
|
|
@@ -175,7 +175,7 @@ the record form with `fast` and is reported in `diagnostics.fast.applied` when i
|
|
|
175
175
|
whether or not it has a fast method yet; one without runs exact and reports `false`.
|
|
176
176
|
|
|
177
177
|
```ts
|
|
178
|
-
SIMULATE_CAPTURE_FAST_OPTIONS = Object.freeze(["lens.diffraction", "lens.catalogue", "sensor.antiAliasing", "sensor.pixelAperture.box", "output.demosaic.ahd"] as const)
|
|
178
|
+
SIMULATE_CAPTURE_FAST_OPTIONS = Object.freeze(["lens.diffraction", "lens.catalogue", "sensor.antiAliasing", "sensor.pixelAperture.box", "output.demosaic.ahd", "motion.subject"] as const)
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
## SIMULATE_CAPTURE_METERING_MODES
|
|
@@ -473,8 +473,9 @@ export interface SimulateCaptureFastReport {
|
|
|
473
473
|
|
|
474
474
|
`lens.catalogue` as a record (#568): the lens id as `kind` and the `fast` override (see {@link SimulateCaptureOptions.fast}).
|
|
475
475
|
Fast: the tabulated fast method (#568), and with `lens.defocus` the lens's bokeh without its cat's eye (#567; fast wides and
|
|
476
|
-
normals only), whose field-varying PSF needs a finer fast grid (measured 2.2–3.4× slower)
|
|
477
|
-
|
|
476
|
+
normals only), whose field-varying PSF needs a finer fast grid (measured 2.2–3.4× slower); with camera rotation under
|
|
477
|
+
`motion.shutter: "rolling"`, the per-tap PSF points instead of the lattice reading (#588). Exact: the per-site PSF with the
|
|
478
|
+
cat's eye, read on the lattice. Blades and spherical aberration always apply (they cost nothing).
|
|
478
479
|
|
|
479
480
|
```ts
|
|
480
481
|
export interface SimulateCaptureLensCatalogueRecord { kind: string; fast?: boolean }
|
|
@@ -529,6 +530,11 @@ export interface SimulateCaptureMotion {
|
|
|
529
530
|
shutter?: "global" | "rolling";
|
|
530
531
|
/** Rolling shutter only: time from the first to the last line over the simulated frame, in s. Default: the body's declared readout skew. */
|
|
531
532
|
rollingShutterSkewSeconds?: number;
|
|
533
|
+
/**
|
|
534
|
+
* #551: a moving subject: the whole scene, or one rectangle of it over a still background, translating on the scene plane
|
|
535
|
+
* (and optionally rotating about the optical axis) during the exposure. Off by default (a still scene).
|
|
536
|
+
*/
|
|
537
|
+
subject?: SimulateCaptureSubjectMotion;
|
|
532
538
|
}
|
|
533
539
|
```
|
|
534
540
|
|
|
@@ -672,9 +678,10 @@ export interface SimulateCaptureOptions {
|
|
|
672
678
|
/**
|
|
673
679
|
* Required: an engine chart (for example `{ preset: "uniform" }`, an 18 % grey card), a declared `material-layers` scene (#491:
|
|
674
680
|
* a chart under shape-mask layers, as `resolveChartMaterialLayers` takes it; the capture is that of its `callerScene`, byte for
|
|
675
|
-
* byte, and the display view can render it on the GPU),
|
|
681
|
+
* byte, and the display view can render it on the GPU), a caller reflectance, radiance or material function, or (2.21, #581) an
|
|
682
|
+
* `image-plane` scene: a photo as a flat print (docs/IMAGE_PLANE.md).
|
|
676
683
|
*/
|
|
677
|
-
scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene;
|
|
684
|
+
scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene | ImagePlaneScene;
|
|
678
685
|
/** Distance from the camera to the scene plane in metres. Default 5. */
|
|
679
686
|
subjectDistanceM?: number;
|
|
680
687
|
/**
|
|
@@ -689,6 +696,12 @@ export interface SimulateCaptureOptions {
|
|
|
689
696
|
illuminant?: CaptureIlluminant;
|
|
690
697
|
/** Illuminance on the scene plane, lux. Default about 21 481 lux (see `SIMULATE_CAPTURE_DEFAULT_ILLUMINANCE_LUX` and the assumptions). */
|
|
691
698
|
illuminanceLux?: number;
|
|
699
|
+
/**
|
|
700
|
+
* 2.22 (#550), opt-in mixed lighting: two or more sources blended across the chart (docs/MIXED_ILLUMINATION.md), instead of
|
|
701
|
+
* `illuminant` and `illuminanceLux`. The frame center's light sets the grey-card meter and the standard-exposure figures, and
|
|
702
|
+
* its strongest source the "scene-illuminant" white balance; both are reported in `assumptions`.
|
|
703
|
+
*/
|
|
704
|
+
illumination?: MixedIllumination;
|
|
692
705
|
output?: {
|
|
693
706
|
/** Output pixels; the native sensor raster adds a one-site demosaic border on each side. Defaults 64 × 64. */
|
|
694
707
|
width?: number;
|
|
@@ -788,6 +801,13 @@ export interface SimulateCaptureOptions {
|
|
|
788
801
|
motion?: SimulateCaptureMotion;
|
|
789
802
|
/** #555: plus the sensor characteristics ({@link SimulateCaptureSensorCharacteristics}), each off by default. */
|
|
790
803
|
sensor?: SimulateCaptureSensorCharacteristics & {
|
|
804
|
+
/**
|
|
805
|
+
* #554: a sensor profile record (`SENSOR_PROFILES`, or `resolveSensorProfile(id)`), checked strictly. It replaces the body's ISO range, readout regimes
|
|
806
|
+
* (full well, read noise of each conversion gain, the dual-gain switch, high-gain storage, ADC bit depth), readout time and
|
|
807
|
+
* fixed-pattern noise, and sets the default pixel pitch and peak QE; explicit fields here still override it one at a time.
|
|
808
|
+
* Default: none (the body's own sensor). See docs/SENSOR_PROFILES.md.
|
|
809
|
+
*/
|
|
810
|
+
profile?: SensorProfile;
|
|
791
811
|
/**
|
|
792
812
|
* Pixel pitch in micrometres, 0.5–1000. Default 6. The simulated sensor is output width × pitch wide. 2.5: above 100 µm the
|
|
793
813
|
* capture is a downsized view of a whole frame (for example 36 mm / 48 pixels = 750 µm), recorded in the assumption
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# motion/subject-motion.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
|
+
## SimulateCaptureSubjectMotion
|
|
6
|
+
|
|
7
|
+
`motion.subject` of `simulateCapture`: a moving subject on the scene plane (#551).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export interface SimulateCaptureSubjectMotion {
|
|
11
|
+
/** Velocity on the scene plane, m/s: +x right, +y up as seen from the camera. Missing components are 0. */
|
|
12
|
+
velocityMPerSec?: { x?: number; y?: number };
|
|
13
|
+
/** Rotation about the optical axis direction, rad/s, counter-clockwise as seen from the camera (+x toward +y). Default 0. */
|
|
14
|
+
angularVelocityRadPerSec?: number;
|
|
15
|
+
/**
|
|
16
|
+
* The moving part: a rectangle on the scene plane at rest (at the first opening reference), its centre and size in metres
|
|
17
|
+
* (+x right, +y up from the optical axis). Omitted: the whole scene moves.
|
|
18
|
+
*/
|
|
19
|
+
region?: { centerXM: number; centerYM: number; widthM: number; heightM: number };
|
|
20
|
+
/** Exact or fast (2.20.0 convention): fast takes fewer temporal midpoints when the subject's streak is short (see the docs). */
|
|
21
|
+
fast?: boolean;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# optics/generic-lens-lateral-color.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
|
+
## calculateLateralColorFringe
|
|
6
|
+
|
|
7
|
+
The red–blue image displacement of a catalogue lens at a field position on a sensor, in micrometres and pixels, from the
|
|
8
|
+
lens's own lateral-colour model Δr(λ) = L·R·H·D(λ) at the lens corrections' channel wavelengths (610 and 465 nm), or at the
|
|
9
|
+
given `channelDispersion`. Exact for the model (no fast mode); an approximation of a generic lens, not a measured product.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
export function calculateLateralColorFringe(input: CalculateLateralColorFringeInput): CalculationResult<LateralColorFringe>;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
16
|
+
|
|
17
|
+
## CalculateLateralColorFringeInput
|
|
18
|
+
|
|
19
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
export interface CalculateLateralColorFringeInput {
|
|
23
|
+
/** A catalogue id (`GENERIC_LENS_IDS`). */
|
|
24
|
+
lensId: string;
|
|
25
|
+
/** The sensor's active capture area, mm (the lens is scaled to it as in `resolveGenericLens`). */
|
|
26
|
+
activeImagingArea: { widthMm: number; heightMm: number };
|
|
27
|
+
/** The sensor's pixel pitch, µm. */
|
|
28
|
+
pixelPitchMicrometers: number;
|
|
29
|
+
/**
|
|
30
|
+
* The field position as fractions of the frame's half-width (x, +right) and half-height (y, +up) from the optical axis, each
|
|
31
|
+
* in [−1, 1]. Default `{ x: 1, y: 1 }`: the top-right corner.
|
|
32
|
+
*/
|
|
33
|
+
fieldPosition?: { x: number; y: number };
|
|
34
|
+
/**
|
|
35
|
+
* 2.21.0: each channel's effective dispersion (`calculateChannelEffectiveDispersion` for the camera's channels and the light;
|
|
36
|
+
* only `red` and `blue` are read). Default: D at the single wavelengths 610 and 465 nm.
|
|
37
|
+
*/
|
|
38
|
+
channelDispersion?: ChannelDispersion;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## LateralColorDisplacement
|
|
43
|
+
|
|
44
|
+
A signed displacement of the blue image from the red one: radial (positive: blue farther from the axis) and its x and y parts.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export interface LateralColorDisplacement {
|
|
48
|
+
radial: number;
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## LateralColorFringe
|
|
55
|
+
|
|
56
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
export interface LateralColorFringe {
|
|
60
|
+
lensId: string;
|
|
61
|
+
/** The image-plane point, mm from the optical axis (+x right, +y up). */
|
|
62
|
+
imagePointMm: { x: number; y: number };
|
|
63
|
+
/** Field height H: the point's distance from the axis as a fraction of the half-diagonal (1 at the corner). */
|
|
64
|
+
fieldHeight: number;
|
|
65
|
+
/** The channel wavelengths the displacement is taken at, nm; null with a given `channelDispersion`. */
|
|
66
|
+
channelWavelengthsNm: { red: number; blue: number } | null;
|
|
67
|
+
/** The red and blue dispersions D used (normalized: 0 at the d line, F minus C = 1). */
|
|
68
|
+
channelDispersion: { red: number; blue: number };
|
|
69
|
+
/** Blue-minus-red image displacement, µm. */
|
|
70
|
+
blueMinusRedMicrometers: LateralColorDisplacement;
|
|
71
|
+
/** The same in pixels of the given pitch. */
|
|
72
|
+
blueMinusRedPixels: LateralColorDisplacement;
|
|
73
|
+
/** The fringe width: |radial| displacement, µm and pixels. */
|
|
74
|
+
fringeWidthMicrometers: number;
|
|
75
|
+
fringeWidthPixels: number;
|
|
76
|
+
/** The lens's own F-to-C (486 to 656 nm) displacement at this point, L·R·H, µm. */
|
|
77
|
+
fToCMicrometers: number;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
@@ -2,10 +2,19 @@
|
|
|
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
|
+
## ChannelDispersion
|
|
6
|
+
|
|
7
|
+
A normalized dispersion per channel (`genericLensDispersion` units: 0 at the d line, F minus C = 1).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export type ChannelDispersion = Readonly<Record<LensCorrectionChannel, number>>;
|
|
11
|
+
```
|
|
12
|
+
|
|
5
13
|
## GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM
|
|
6
14
|
|
|
7
15
|
Effective wavelengths of the red, green and blue channels for the lateral-colour map, nm: a generic approximation of where
|
|
8
|
-
a camera's channel responses peak, not a measured camera.
|
|
16
|
+
a camera's channel responses peak, not a measured camera. The default of `createGenericLensCorrectionProfile` without a
|
|
17
|
+
`channelDispersion`; `simulateCapture`'s `output.lensCorrections` uses the capture's own channels instead (#589).
|
|
9
18
|
|
|
10
19
|
```ts
|
|
11
20
|
GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM: Readonly<Record<LensCorrectionChannel, number>> = Object.freeze({ red: 610, green: 540, blue: 465 })
|
|
@@ -2,13 +2,44 @@
|
|
|
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
|
+
## calculateChannelEffectiveDispersion
|
|
6
|
+
|
|
7
|
+
#589: each channel's effective dispersion for the catalogue lenses' lateral colour, D̄_c = Σ w·D(λ) / Σ w with
|
|
8
|
+
w = response_c(λ)·illuminant(λ) at the nodes and D the normalised Cauchy dispersion (`genericLensDispersion`: 0 at the
|
|
9
|
+
Fraunhofer d line, F minus C = 1). Under lateral colour L·r·D(λ) a neutral surface's image in channel c moves by L·r·D̄_c, so
|
|
10
|
+
blue minus red is L·r·(D̄_blue − D̄_red). Pass the result as `channelDispersion` to `createGenericLensCorrectionProfile`.
|
|
11
|
+
`simulateCapture`'s `output.lensCorrections` computes it from the capture's own channels and reports it in its assumption.
|
|
12
|
+
An approximation: a weighted mean over a neutral surface; a colored surface weights the band differently.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
export function calculateChannelEffectiveDispersion(input: CalculateChannelEffectiveDispersionInput): CalculationResult<ChannelDispersion>;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
19
|
+
|
|
20
|
+
## CalculateChannelEffectiveDispersionInput
|
|
21
|
+
|
|
22
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
export interface CalculateChannelEffectiveDispersionInput {
|
|
26
|
+
/** Spectral nodes, nm, strictly increasing, within 300–1100 nm. */
|
|
27
|
+
wavelengthsNm: readonly number[];
|
|
28
|
+
/** Each channel's response at the nodes (any common linear unit, ≥ 0; for example electrons per unit spectral radiance). */
|
|
29
|
+
channelResponse: { red: readonly number[]; green: readonly number[]; blue: readonly number[] };
|
|
30
|
+
/** The illuminant's relative spectral power at the nodes (≥ 0; the scale cancels). */
|
|
31
|
+
illuminant: readonly number[];
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
5
35
|
## createGenericLensCorrectionProfile
|
|
6
36
|
|
|
7
37
|
Builds the catalogue lens's generic correction profile for one camera state: a radial distortion map (the lens's own
|
|
8
|
-
r_d = r(1 + k1ρ²), read at each ideal destination point), per-channel lateral-colour scales 1 + L·D
|
|
9
|
-
relative-illumination gain at the state's aperture (strength 1). From
|
|
10
|
-
|
|
11
|
-
sensor point, so it flattens a flat-field capture. The
|
|
38
|
+
r_d = r(1 + k1ρ²), read at each ideal destination point), per-channel lateral-colour scales 1 + L·D̄_channel (`channelDispersion`,
|
|
39
|
+
by default D at the generic channel wavelengths), and the relative-illumination gain at the state's aperture (strength 1). From
|
|
40
|
+
profile version 1.1.0 (#584) the vignetting component (version 1.1.0) carries the distortion's area factor
|
|
41
|
+
(`distortionAreaFactor`): its gain is det J(ρ_i)/E(ρ_s) at the capture's sensor point, so it flattens a flat-field capture. The
|
|
42
|
+
result passes `parseGenericLensCorrectionProfile`.
|
|
12
43
|
|
|
13
44
|
```ts
|
|
14
45
|
export function createGenericLensCorrectionProfile(input: CreateGenericLensCorrectionProfileInput): GenericLensCorrectionProfile;
|
|
@@ -28,5 +59,10 @@ export interface CreateGenericLensCorrectionProfileInput {
|
|
|
28
59
|
activeImagingArea: { widthMm: number; heightMm: number };
|
|
29
60
|
/** The exact camera state the profile applies to: its focal length must be the lens's on this sensor, its aperture in range. */
|
|
30
61
|
state: OpticalProfileState;
|
|
62
|
+
/**
|
|
63
|
+
* #589: each channel's effective dispersion (`calculateChannelEffectiveDispersion` for the camera's channels and the light).
|
|
64
|
+
* Default: D at {@link GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM} (610, 540 and 465 nm), a generic approximation.
|
|
65
|
+
*/
|
|
66
|
+
channelDispersion?: ChannelDispersion;
|
|
31
67
|
}
|
|
32
68
|
```
|
|
@@ -42,14 +42,44 @@ export function parsePrintPlanInput(value: unknown): PrintPlanInput;
|
|
|
42
42
|
|
|
43
43
|
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
44
44
|
|
|
45
|
+
## PrintContainLayout
|
|
46
|
+
|
|
47
|
+
The layout of a `contain` fit, in millimetres. The printed image itself is the plan's `printedImageMm`.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
export interface PrintContainLayout {
|
|
51
|
+
/** The paper as placed: after the quarter turn when `paperRotated`. */
|
|
52
|
+
paperMm: { width: number; height: number };
|
|
53
|
+
paperRotated: boolean;
|
|
54
|
+
/** Unprinted border on each side of the centered image; zero when the paper has the image's aspect ratio. */
|
|
55
|
+
bordersMm: { left: number; right: number; top: number; bottom: number };
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
45
59
|
## PrintedImageSize
|
|
46
60
|
|
|
47
61
|
The flat printed image area. It excludes paper margins, borders and canvas wraps.
|
|
62
|
+
With a `contain` fit it is instead the paper, or the printable area of it, that the image is fitted inside.
|
|
48
63
|
|
|
49
64
|
```ts
|
|
50
65
|
export interface PrintedImageSize { width: number; height: number; unit: PrintLength["unit"] }
|
|
51
66
|
```
|
|
52
67
|
|
|
68
|
+
## PrintFit
|
|
69
|
+
|
|
70
|
+
How the printed image relates to `printedImage`.
|
|
71
|
+
- `confirmed-native-aspect`: `printedImage` is the printed image itself and must already have the native aspect ratio,
|
|
72
|
+
within the stated relative error.
|
|
73
|
+
- `contain`: `printedImage` is the paper. The image keeps the native aspect ratio and is scaled to the largest size that
|
|
74
|
+
fits inside it, centered; the rest is unprinted border. `match-image` turns the paper a quarter turn when its
|
|
75
|
+
orientation (portrait or landscape) differs from the image's; `as-given` keeps it. Layout only: nothing is cropped or resampled.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
export type PrintFit =
|
|
79
|
+
| { kind: "confirmed-native-aspect"; maximumRelativeAspectError: number }
|
|
80
|
+
| { kind: "contain"; paperOrientation: "as-given" | "match-image" };
|
|
81
|
+
```
|
|
82
|
+
|
|
53
83
|
## PrintLength
|
|
54
84
|
|
|
55
85
|
A physical length. Not to be confused with image pixels or printer dots.
|
|
@@ -90,6 +120,8 @@ export interface PrintPlan {
|
|
|
90
120
|
alternatives: { maximumImageMmAtCurrentDistance: { width: number; height: number }; minimumViewingDistanceMmAtCurrentSize: number | null } | null;
|
|
91
121
|
capturedDetailAssessment: "unassessed";
|
|
92
122
|
deliveryAssessment: "unassessed";
|
|
123
|
+
/** Present only with a `contain` fit; null when the native raster is unknown. */
|
|
124
|
+
contain?: PrintContainLayout | null;
|
|
93
125
|
}
|
|
94
126
|
```
|
|
95
127
|
|
|
@@ -103,7 +135,7 @@ export interface PrintPlanInput {
|
|
|
103
135
|
printedImage: PrintedImageSize;
|
|
104
136
|
viewingDistance: PrintLength;
|
|
105
137
|
sampling: PrintSamplingCriterion;
|
|
106
|
-
fit:
|
|
138
|
+
fit: PrintFit;
|
|
107
139
|
provider?: PrintProviderConstraints;
|
|
108
140
|
}
|
|
109
141
|
```
|
|
@@ -156,6 +188,8 @@ export interface PrintSizeLimit {
|
|
|
156
188
|
maximumImageMm: { width: number; height: number } | null;
|
|
157
189
|
reasons: string[];
|
|
158
190
|
referencePlan: PrintPlan;
|
|
191
|
+
/** Present only with a `contain` fit: the paper that holds `maximumImageMm` with the same layout (borders scale with it). */
|
|
192
|
+
maximumPaperMm?: { width: number; height: number } | null;
|
|
159
193
|
}
|
|
160
194
|
```
|
|
161
195
|
|
package/llms.txt
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
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
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
|
|
10
|
+
- [Image-plane scene](https://github.com/Photivra/photivra/blob/main/docs/IMAGE_PLANE.md): a photo as a flat print in front of the camera (`{ kind: "image-plane" }`), its input, placement, print reflectance lattice and accuracy
|
|
11
|
+
- [Light sources](https://github.com/Photivra/photivra/blob/main/docs/LIGHT_SOURCES.md): representative fluorescent and LED spectra designed by Photivra (`createRepresentativeLightSourceIlluminant`), their CCT and color rendering
|
|
10
12
|
- [Usage guide](https://github.com/Photivra/photivra/blob/main/docs/USAGE.md): worked examples for every public area
|
|
11
13
|
- [API reference](https://github.com/Photivra/photivra/blob/main/docs/API_REFERENCE.md): every root export, with a task-to-function index
|
|
12
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@photivra/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.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",
|