@photivra/engine 2.19.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 +289 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +7 -5
- package/README.md +7 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +21 -10
- package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
- package/dist/capture/dng-lens-correction-opcodes.js +119 -0
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
- 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 +42 -78
- 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-dng.d.ts +6 -0
- package/dist/capture/native-raw-dng.js +16 -2
- package/dist/capture/native-raw-dng.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 +15 -8
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/core/shared-helpers.d.ts +2 -0
- package/dist/core/shared-helpers.js +4 -0
- package/dist/core/shared-helpers.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 +11 -4
- package/dist/equipment/generic-lens-catalogue.js +49 -7
- 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 +18 -14
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.js +2 -3
- package/dist/equipment/generic-tier-presets.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 +13 -5
- package/dist/facade/display-view-gpu.js +4 -4
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.d.ts +1 -1
- package/dist/facade/display-view-lens-signal.js +30 -26
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view.d.ts +3 -1
- package/dist/facade/display-view.js +6 -24
- 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.d.ts +50 -0
- package/dist/facade/fast-methods.js +58 -0
- package/dist/facade/fast-methods.js.map +1 -0
- package/dist/facade/fast-resolution.d.ts +12 -0
- package/dist/facade/fast-resolution.js +18 -0
- package/dist/facade/fast-resolution.js.map +1 -0
- package/dist/facade/generic-lens-capture.d.ts +5 -4
- package/dist/facade/generic-lens-capture.js +5 -4
- 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 +88 -19
- package/dist/facade/simulate-capture.js +374 -145
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +3 -2
- package/dist/facade/simulate-display-view.js +36 -18
- 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 +18 -3
- package/dist/index.js +12 -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/aperture-diameter.d.ts +47 -0
- package/dist/optics/aperture-diameter.js +50 -0
- package/dist/optics/aperture-diameter.js.map +1 -0
- package/dist/optics/detail-limit.d.ts +182 -0
- package/dist/optics/detail-limit.js +336 -0
- package/dist/optics/detail-limit.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.d.ts +18 -2
- package/dist/optics/generic-lens-psf.js +79 -48
- 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/optics/scene-to-sensor-irradiance.d.ts +13 -0
- package/dist/optics/scene-to-sensor-irradiance.js +7 -0
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/output/crop-to-match-focal-length.d.ts +62 -0
- package/dist/output/crop-to-match-focal-length.js +63 -0
- package/dist/output/crop-to-match-focal-length.js.map +1 -0
- package/dist/output/developed-lens-corrections.d.ts +19 -5
- package/dist/output/developed-lens-corrections.js +30 -11
- package/dist/output/developed-lens-corrections.js.map +1 -1
- package/dist/output/generic-lens-corrections.d.ts +41 -3
- package/dist/output/generic-lens-corrections.js +57 -9
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +12 -2
- package/dist/output/lens-corrections.js +22 -7
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/print-contrast-reference.js +1 -1
- package/dist/output/print-contrast-reference.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/output/print-size-blur-noise.d.ts +110 -0
- package/dist/output/print-size-blur-noise.js +138 -0
- package/dist/output/print-size-blur-noise.js.map +1 -0
- 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/eqe-electron-rate.js +1 -7
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +2 -0
- package/dist/sensor/exposure-window.js +2 -2
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/readout-timing.js +2 -23
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.js +1 -6
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.js +1 -7
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sensor-characteristics.d.ts +147 -0
- package/dist/sensor/sensor-characteristics.js +126 -0
- package/dist/sensor/sensor-characteristics.js.map +1 -0
- package/dist/sensor/spatial-sample-reduction.js +1 -5
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spectral-quadrature.js +1 -6
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +3 -0
- package/dist/sensor/temporal-photo-signal.js +5 -2
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/stabilization/system.d.ts +9 -0
- package/dist/stabilization/system.js +5 -6
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +5 -0
- package/docs/API_REFERENCE.md +173 -2
- package/docs/QUICK_START.md +213 -6
- package/docs/USAGE.md +157 -3
- package/docs/api/capture-native-raw-dng.md +6 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +17 -7
- package/docs/api/equipment-sensor-profile-body.md +64 -0
- package/docs/api/equipment-sensor-profiles.md +86 -0
- package/docs/api/exports.json +357 -2
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-exposure-build-up.md +105 -0
- package/docs/api/facade-fast-methods.md +99 -0
- 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 +60 -15
- package/docs/api/facade-simulate-display-view.md +3 -2
- package/docs/api/motion-subject-motion.md +23 -0
- package/docs/api/optics-aperture-diameter.md +51 -0
- package/docs/api/optics-detail-limit.md +203 -0
- package/docs/api/optics-generic-lens-lateral-color.md +79 -0
- package/docs/api/output-crop-to-match-focal-length.md +67 -0
- package/docs/api/output-developed-lens-corrections.md +10 -1
- package/docs/api/output-generic-lens-corrections.md +40 -2
- package/docs/api/output-lens-corrections.md +11 -1
- package/docs/api/output-print-plan.md +35 -1
- package/docs/api/output-print-size-blur-noise.md +115 -0
- package/docs/api/sensor-sensor-characteristics.md +105 -0
- package/llms.txt +6 -0
- package/package.json +1 -1
|
@@ -2,11 +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).
|
|
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`.
|
|
10
43
|
|
|
11
44
|
```ts
|
|
12
45
|
export function createGenericLensCorrectionProfile(input: CreateGenericLensCorrectionProfileInput): GenericLensCorrectionProfile;
|
|
@@ -26,5 +59,10 @@ export interface CreateGenericLensCorrectionProfileInput {
|
|
|
26
59
|
activeImagingArea: { widthMm: number; heightMm: number };
|
|
27
60
|
/** The exact camera state the profile applies to: its focal length must be the lens's on this sensor, its aperture in range. */
|
|
28
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;
|
|
29
67
|
}
|
|
30
68
|
```
|
|
@@ -31,7 +31,9 @@ This call is synchronous; any supplied provider must follow its explicit synchro
|
|
|
31
31
|
## calculatePeripheralIlluminationCorrection
|
|
32
32
|
|
|
33
33
|
Applies a gain after capture and reports the variance before clipping. It does not rewrite
|
|
34
|
-
the photon or SNR (signal-to-noise ratio) history of the capture.
|
|
34
|
+
the photon or SNR (signal-to-noise ratio) history of the capture. The gain is T^(−strength), T the relative illumination at
|
|
35
|
+
`imagePointMm`: E(ρ) of the component's profile, divided by det J(ρ_i) when the component has a `distortionAreaFactor` (#584;
|
|
36
|
+
then `imagePointMm` is the capture's sensor point, where the capture applied both).
|
|
35
37
|
|
|
36
38
|
```ts
|
|
37
39
|
export function calculatePeripheralIlluminationCorrection(input: {
|
|
@@ -77,6 +79,14 @@ export interface IlluminationLensCorrection extends CorrectionComponentIdentity
|
|
|
77
79
|
kind: "peripheral-illumination";
|
|
78
80
|
profile: IlluminationVignettingProfile;
|
|
79
81
|
strength: number;
|
|
82
|
+
/**
|
|
83
|
+
* Optional (#584): the capture's radial distortion r_d = r(1 + k1ρ² + k2ρ⁴ + k3ρ⁶), whose area factor 1/det J the capture also
|
|
84
|
+
* multiplied into the irradiance (det J = (1 + k1ρ_i² + k2ρ_i⁴ + k3ρ_i⁶)(1 + 3k1ρ_i² + 5k2ρ_i⁴ + 7k3ρ_i⁶) at the ideal point ρ_i that
|
|
85
|
+
* the lens images to the sensor point). With it, the relative illumination corrected is E(ρ_s)/det J(ρ_i), evaluated at the
|
|
86
|
+
* capture's sensor (source) point, so strength 1 flattens a flat field. It holds whether or not the distortion itself is corrected.
|
|
87
|
+
* Without it the gain is 1/E alone, as before.
|
|
88
|
+
*/
|
|
89
|
+
distortionAreaFactor?: RadialDistortionProfile;
|
|
80
90
|
}
|
|
81
91
|
```
|
|
82
92
|
|
|
@@ -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
|
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# output/print-size-blur-noise.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
|
+
## calculatePrintSizeLimitWithBlurAndNoise
|
|
6
|
+
|
|
7
|
+
Calculates the largest print, at a fixed viewing distance, at which the capture still looks sharp and clean, and names
|
|
8
|
+
the factor that limits it: pixels, blur or noise. An approximation throughout; the equations are exact under its model.
|
|
9
|
+
|
|
10
|
+
With θ the criterion angle, d the viewing distance, s = 2 d tan(θ/2) the length θ covers on the print, N_w the raster
|
|
11
|
+
width in pixels, b the blur diameter in pixels and SNR_px the per-pixel SNR (print width W, height in proportion):
|
|
12
|
+
- pixels: a print pixel (W / N_w) may cover at most s, so W ≤ N_w·s (as `calculatePrintPlan` with
|
|
13
|
+
`angular-pixel-pitch`, before its whole-pixel rounding);
|
|
14
|
+
- blur: the blur on the print (b·W / N_w) may cover at most s, so W ≤ N_w·s / b: the criterion of an acceptable circle
|
|
15
|
+
of confusion with the eye's resolution as the limit;
|
|
16
|
+
- noise: the eye averages the (W / N_w) wide pixels inside s, so the visible SNR is SNR_px·(N_w·s / W) while a pixel is
|
|
17
|
+
smaller than s (the mean of n independent values has 1/√n of their standard deviation); W ≤ N_w·s·SNR_px / SNR_min,
|
|
18
|
+
and noise never limits when SNR_px ≥ SNR_min.
|
|
19
|
+
One arcminute is normal (20/20) acuity under optimal conditions (Z. Alomar, K. D. Bojikian, "Visual Acuity Testing in
|
|
20
|
+
Adults", EyeWiki, American Academy of Ophthalmology, https://eyewiki.aao.org/Visual_Acuity_Testing_in_Adults, last edited
|
|
21
|
+
June 16, 2026); the SNR threshold has no default and is the caller's. Blur parts add in root-sum-square, which is exact
|
|
22
|
+
for Gaussian spots (variances of independent displacements add: C. M. Grinstead, J. L. Snell, "Introduction to
|
|
23
|
+
Probability", 2nd rev. ed., AMS 1997, sec. 6.2, free under the GNU FDL) and an approximation for discs and Airy patterns.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
export function calculatePrintSizeLimitWithBlurAndNoise(value: PrintSizeLimitWithBlurAndNoiseInput): CalculationResult<PrintSizeLimitWithBlurAndNoise>;
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
30
|
+
|
|
31
|
+
## PrintBlurInput
|
|
32
|
+
|
|
33
|
+
The capture's blur at the sensor plane, as blur-spot diameters in millimetres.
|
|
34
|
+
`components` combines the parts by root-sum-square (an approximation, see the docs); `measured-total` is one measured diameter.
|
|
35
|
+
A zero component is allowed and means that part is left out. Engine helpers give the parts: `calculateDefocusCircle` (defocus),
|
|
36
|
+
`calculateAiryDisk` (diffraction, micrometres), `calculateProjectedMotionBlur` (motion length).
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
export type PrintBlurInput =
|
|
40
|
+
| { kind: "components"; lensMm?: number; defocusMm?: number; diffractionMm?: number; motionMm?: number }
|
|
41
|
+
| { kind: "measured-total"; diameterMm: number };
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## PrintImageMm
|
|
45
|
+
|
|
46
|
+
A print size in millimetres at the raster's aspect ratio.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
export interface PrintImageMm { width: number; height: number }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## PrintNoiseInput
|
|
53
|
+
|
|
54
|
+
The noise of one pixel of the printed raster, for the tone the caller cares about (for example mid-gray).
|
|
55
|
+
`shot-and-read-noise` uses the engine's noise model (`calculateSignalToNoise`: Poisson shot noise plus RMS read noise);
|
|
56
|
+
`pixel-snr` is a per-pixel signal-to-noise ratio the caller already has. `capture-noise-figure` (2.20.0) takes a capture's own
|
|
57
|
+
mid-gray noise figure (#535: `result.sensor.midGrey` of a `simulateCapture` with `fast: false`), whose SNR S/σ_total counts photon
|
|
58
|
+
shot, read, dark-current, quantization and any fixed-pattern noise; it is one sensor site's, so it applies as the pixel SNR when one
|
|
59
|
+
printed pixel is one capture pixel. A clipped figure (the patch at white) is refused.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
export type PrintNoiseInput =
|
|
63
|
+
| { kind: "shot-and-read-noise"; signalElectrons: number; readNoiseElectrons: number }
|
|
64
|
+
| { kind: "pixel-snr"; snrLinear: number }
|
|
65
|
+
| { kind: "capture-noise-figure"; midGrey: NonNullable<SimulateCaptureSensorReport["midGrey"]> };
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## PrintSharpCleanCriterion
|
|
69
|
+
|
|
70
|
+
What "looks sharp and clean" means: the smallest angle the viewer resolves, and the lowest signal-to-noise ratio the viewer
|
|
71
|
+
accepts after the eye averages over that angle. Both are the caller's choice; one arcminute is normal (20/20) acuity.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
export interface PrintSharpCleanCriterion {
|
|
75
|
+
kind: "visual-resolution";
|
|
76
|
+
arcminutes: number;
|
|
77
|
+
minimumVisibleSnr: number;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## PrintSizeLimitWithBlurAndNoise
|
|
82
|
+
|
|
83
|
+
Result. Each factor's own limit is the largest print it allows on its own; null means that factor never limits.
|
|
84
|
+
`limitingFactor` names the smallest; on a tie the order is pixels, blur, noise.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
export interface PrintSizeLimitWithBlurAndNoise {
|
|
88
|
+
engineApiVersion: string;
|
|
89
|
+
status: "finite" | "no-positive-size";
|
|
90
|
+
limitingFactor: "pixels" | "blur" | "noise";
|
|
91
|
+
maximumImageMm: PrintImageMm;
|
|
92
|
+
limits: { pixels: PrintImageMm; blur: PrintImageMm | null; noise: PrintImageMm | null };
|
|
93
|
+
viewingDistanceMm: number;
|
|
94
|
+
/** The criterion angle as a length on the print at the viewing distance: 2 d tan(θ/2). */
|
|
95
|
+
resolvedSpotMm: number;
|
|
96
|
+
blur: { diameterMm: number; diameterPixels: number; largestComponent: "lens" | "defocus" | "diffraction" | "motion" | "measured-total" | null };
|
|
97
|
+
noise: { pixelSnr: number; visibleSnrAtMaximum: number };
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## PrintSizeLimitWithBlurAndNoiseInput
|
|
102
|
+
|
|
103
|
+
Input. The raster is the retained image that is printed (after any crop), with square pixels; `pixelPitchMm` is the
|
|
104
|
+
sensor length one of those pixels covers. The print keeps the raster's aspect ratio. The viewing distance is fixed.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
export interface PrintSizeLimitWithBlurAndNoiseInput {
|
|
108
|
+
raster: RasterDimensions;
|
|
109
|
+
pixelPitchMm: number;
|
|
110
|
+
viewingDistance: PrintLength;
|
|
111
|
+
criterion: PrintSharpCleanCriterion;
|
|
112
|
+
blur: PrintBlurInput;
|
|
113
|
+
noise: PrintNoiseInput;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# sensor/sensor-characteristics.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
|
+
## SimulateCaptureNoiseComponents
|
|
6
|
+
|
|
7
|
+
One RMS noise component of the mid-grey figure, e⁻ (input-referred).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export interface SimulateCaptureNoiseComponents {
|
|
11
|
+
/** Photon shot noise √S (Poisson). */
|
|
12
|
+
photonShot: number;
|
|
13
|
+
/** Read noise of the capture's readout regime. */
|
|
14
|
+
read: number;
|
|
15
|
+
/** Dark-current shot noise √(D·t), D = 1 e⁻/s at 20 °C. */
|
|
16
|
+
darkCurrent: number;
|
|
17
|
+
/** ADC quantization, one code (and one more after a digital gain) as a uniform 1/12 code² variance, in e⁻. */
|
|
18
|
+
quantization: number;
|
|
19
|
+
/** With `sensor.fixedPatternNoise`: √((PRNU·S)² + (DSNU·D·t)² + row² + column²), hot pixels excluded; a spatial, not temporal, noise. */
|
|
20
|
+
fixedPattern?: number;
|
|
21
|
+
/** √ of the sum of the squares. */
|
|
22
|
+
total: number;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## SimulateCaptureSensorCharacteristics
|
|
27
|
+
|
|
28
|
+
#555: sensor characteristics a capture can set one at a time (`simulateCapture({ sensor })`). Each is off by default: an
|
|
29
|
+
omitted field keeps the camera body's value, and a request with none of them is byte-identical to one before 2.20.0.
|
|
30
|
+
Every value set is listed in the result's `assumptions`.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
export interface SimulateCaptureSensorCharacteristics {
|
|
34
|
+
/**
|
|
35
|
+
* Peak external quantum efficiency of the green channel (its value at 555 nm), 0.05–0.9. Default 0.5, the facade's
|
|
36
|
+
* idealized sensor. Every channel's EQE curve is multiplied by `peakQuantumEfficiency / 0.5`, so the curves keep their
|
|
37
|
+
* shape (and the colour matrix is unchanged) and the collected charge scales in proportion.
|
|
38
|
+
*/
|
|
39
|
+
peakQuantumEfficiency?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Full-well capacity: the charge, e⁻, that reaches the RAW white level at base ISO. Default: the body's base-ISO saturation
|
|
42
|
+
* at 6 µm, scaled by the pixel area (the `sensor.isoAreaNormalization` approximation). `link` `"pixel-area"` (default)
|
|
43
|
+
* scales `electrons`, the full well at `referencePixelPitchMicrometers` (default 6), by (pitch / reference)²; `"none"`
|
|
44
|
+
* uses `electrons` at any pitch. The result is 100 e⁻ to 1e10 e⁻.
|
|
45
|
+
*/
|
|
46
|
+
fullWell?: { electrons: number; link?: "pixel-area" | "none"; referencePixelPitchMicrometers?: number };
|
|
47
|
+
/**
|
|
48
|
+
* Read noise, RMS e⁻ (0–100), of the low and the high conversion gain, and the dual-gain switch: the ISO setting from
|
|
49
|
+
* which the high conversion gain is used (any ISO from 100; above the body's highest ISO, the low gain is used throughout).
|
|
50
|
+
* An omitted field keeps the body's value. Needs readout regimes that declare their exposure index (the tiers do).
|
|
51
|
+
*/
|
|
52
|
+
readNoise?: { lowGainElectrons?: number; highGainElectrons?: number; highGainFromIso?: number };
|
|
53
|
+
/** Readout time, s (1e-6 to 1): the rolling shutter's top-to-bottom skew. Default: the body's (tiers 8, 15 and 30 ms). */
|
|
54
|
+
readoutSeconds?: number;
|
|
55
|
+
/**
|
|
56
|
+
* ADC bit depth: 12, 14 or 16. Default: the body's (consumer 12, the others 14). The black level scales with the code range
|
|
57
|
+
* (×2^Δbits), and the conversion gain follows so the same charge reaches the same fraction of the range.
|
|
58
|
+
*/
|
|
59
|
+
adcBitDepth?: 12 | 14 | 16;
|
|
60
|
+
/**
|
|
61
|
+
* Opt-in (advanced): the body's synthetic fixed-pattern noise profile (PRNU, DSNU, hot pixels, row and column offsets; EMVA
|
|
62
|
+
* 1288 Release 4.0 non-uniformities), the same pattern in every capture. Default false. Not in `simulateDisplayView`.
|
|
63
|
+
*/
|
|
64
|
+
fixedPatternNoise?: boolean;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## SimulateCaptureSensorReport
|
|
69
|
+
|
|
70
|
+
#555, #535: the capture's sensor characteristics as used, and the figures calculated from them (reported, not settable).
|
|
71
|
+
Model figures from the engine's own noise model, not measurements.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
export interface SimulateCaptureSensorReport {
|
|
75
|
+
pixelPitchMicrometers: number;
|
|
76
|
+
/** The green channel's peak EQE (at 555 nm). */
|
|
77
|
+
peakQuantumEfficiency: number;
|
|
78
|
+
/** Full-well capacity, e⁻: the base-ISO saturation charge (`sensor.capacityElectrons`). */
|
|
79
|
+
fullWellElectrons: number;
|
|
80
|
+
/** Read noise, RMS e⁻, of each conversion gain, and the ISO from which the high gain is used (null: one gain throughout). */
|
|
81
|
+
readNoise: { lowGainElectrons: number; highGainElectrons: number; highGainFromIso: number | null };
|
|
82
|
+
/** The body's rolling readout skew, s (null when it declares no rolling readout). */
|
|
83
|
+
readoutSeconds: number | null;
|
|
84
|
+
/** ADC bit depth of the capture's readout regime. */
|
|
85
|
+
adcBitDepth: number;
|
|
86
|
+
fixedPatternNoise: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Engineering dynamic range at the capture's ISO, stops: log₂(S_sat / σ_floor), with S_sat the charge at the RAW white
|
|
89
|
+
* level (full well over the analog gain, limited by the charge capacity and the ADC range) and σ_floor the read noise and
|
|
90
|
+
* ADC quantization added in quadrature (the temporal dark noise of EMVA 1288 Release 4.0 without dark current). An ideal
|
|
91
|
+
* noiseless readout is limited by the ADC alone: log₂((white − black)·√12) for unit digital gain.
|
|
92
|
+
*/
|
|
93
|
+
dynamicRangeStops: number;
|
|
94
|
+
/** The same per ISO setting of the body, in its order. */
|
|
95
|
+
dynamicRangeByIso: readonly { iso: number; stops: number }[];
|
|
96
|
+
/**
|
|
97
|
+
* #535: the expected signal-to-noise ratio of an 18 % Lambertian grey patch under the request's illuminant and illuminance
|
|
98
|
+
* at the capture's exposure, ISO and sensor, on the green channel next to the optical axis (no vignetting, PSF or motion).
|
|
99
|
+
* `snr` = S/σ_total and `snrDecibels` = 20·log₁₀(snr). `clipped`: S is at or above the white level, where the RAW clips and
|
|
100
|
+
* the figure no longer describes the image. Computed only when the request resolves to exact (`fast: false`, the default for
|
|
101
|
+
* DNG, JPEG and PNG exports; omitted for a fast request).
|
|
102
|
+
*/
|
|
103
|
+
midGrey?: { reflectance: 0.18; channel: "green"; signalElectrons: number; noiseElectrons: SimulateCaptureNoiseComponents; snr: number; snrDecibels: number; clipped: boolean };
|
|
104
|
+
}
|
|
105
|
+
```
|
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
|
|
|
@@ -26,9 +28,13 @@
|
|
|
26
28
|
- [calculateEquivalentFocalLength35Mm()](https://github.com/Photivra/photivra/blob/main/docs/api/camera-equivalent-focal-length.md#calculateequivalentfocallength35mm): crop factor and 35 mm-equivalent focal length
|
|
27
29
|
- [calculateSensorEquivalence()](https://github.com/Photivra/photivra/blob/main/docs/api/camera-sensor-equivalence.md#calculatesensorequivalence): equivalent focal length and f-number, sensor area ratio and angles of view of a lens on one sensor, each marked exact or approximated
|
|
28
30
|
- [calculateBlurShareOfFrame()](https://github.com/Photivra/photivra/blob/main/docs/api/camera-sensor-equivalence.md#calculateblurshareofframe): a blur circle as a share of the frame diagonal, or its size on a print
|
|
31
|
+
- [calculatePrintSizeLimitWithBlurAndNoise()](https://github.com/Photivra/photivra/blob/main/docs/api/output-print-size-blur-noise.md#calculateprintsizelimitwithblurandnoise): the largest print at a viewing distance that still looks sharp and clean, counting blur and noise as well as pixels (an approximation)
|
|
29
32
|
- [calculateCenteredCrop()](https://github.com/Photivra/photivra/blob/main/docs/api/output-crop.md#calculatecenteredcrop): pixels left after a centred crop
|
|
33
|
+
- [calculateCropToMatchFocalLength()](https://github.com/Photivra/photivra/blob/main/docs/api/output-crop-to-match-focal-length.md#calculatecroptomatchfocallength): crop factor and pixels left when cropping a shorter lens's image to match a longer focal length
|
|
34
|
+
- [calculateApertureDiameter()](https://github.com/Photivra/photivra/blob/main/docs/api/optics-aperture-diameter.md#calculateaperturediameter): entrance-pupil (aperture) diameter in mm, focal length ÷ f-number
|
|
30
35
|
- [calculateProjectedMotionBlur()](https://github.com/Photivra/photivra/blob/main/docs/api/motion-projected-motion.md#calculateprojectedmotionblur): how far a moving subject smears on the sensor during the shutter time
|
|
31
36
|
- [calculateFilteredExposureTime()](https://github.com/Photivra/photivra/blob/main/docs/api/exposure-filtered-exposure-time.md#calculatefilteredexposuretime): shutter time that keeps the same exposure with an ND (or any front-of-lens) filter, and the nearest shutter-dial value; `GENERIC_ND_FILTER_PROFILES` gives idealized 3-, 6- and 10-stop filters (exactly 2^-N)
|
|
37
|
+
- [calculateDetailLimit()](https://github.com/Photivra/photivra/blob/main/docs/api/optics-detail-limit.md#calculatedetaillimit): which limits detail for given settings, the lens (diffraction, aberrations, defocus) or the sensor's pixel pitch, with the optics MTF50, the Nyquist frequency and the system MTF50
|
|
32
38
|
- [calculateAiryDisk()](https://github.com/Photivra/photivra/blob/main/docs/api/optics-diffraction.md#calculateairydisk): diffraction spot size from f-number and wavelength
|
|
33
39
|
- [calculateSignalToNoise()](https://github.com/Photivra/photivra/blob/main/docs/api/sensor-signal-noise.md#calculatesignaltonoise): expected SNR from signal and read noise in electrons
|
|
34
40
|
- [calculateChromaticityFromCorrelatedColorTemperature()](https://github.com/Photivra/photivra/blob/main/docs/api/color-illuminants.md#calculatechromaticityfromcorrelatedcolortemperature): white point for a colour temperature in kelvin
|
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",
|