@photivra/engine 1.5.0 → 2.0.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 +393 -6
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +64 -12
- package/README.md +301 -182
- package/SECURITY.md +37 -28
- package/THIRD_PARTY.md +148 -4
- package/dist/camera/equivalent-focal-length.d.ts +13 -14
- package/dist/camera/equivalent-focal-length.js +15 -13
- package/dist/camera/equivalent-focal-length.js.map +1 -1
- package/dist/camera/field-of-view.d.ts +30 -19
- package/dist/camera/field-of-view.js +67 -18
- package/dist/camera/field-of-view.js.map +1 -1
- package/dist/camera/lens-projection.d.ts +170 -0
- package/dist/camera/lens-projection.js +444 -0
- package/dist/camera/lens-projection.js.map +1 -0
- package/dist/camera/projected-object-size.d.ts +10 -11
- package/dist/camera/projected-object-size.js +12 -10
- package/dist/camera/projected-object-size.js.map +1 -1
- package/dist/capture/capture-export-metadata.d.ts +9 -10
- package/dist/capture/capture-export-metadata.js +8 -5
- package/dist/capture/capture-export-metadata.js.map +1 -1
- package/dist/capture/dng-import.d.ts +91 -0
- package/dist/capture/dng-import.js +343 -0
- package/dist/capture/dng-import.js.map +1 -0
- package/dist/capture/environment-raw-producer.d.ts +37 -17
- package/dist/capture/environment-raw-producer.js +43 -19
- package/dist/capture/environment-raw-producer.js.map +1 -1
- package/dist/capture/export-jpeg.d.ts +35 -4
- package/dist/capture/export-jpeg.js +133 -47
- package/dist/capture/export-jpeg.js.map +1 -1
- package/dist/capture/export-tiff.d.ts +48 -24
- package/dist/capture/export-tiff.js +91 -31
- package/dist/capture/export-tiff.js.map +1 -1
- package/dist/capture/focus-control.d.ts +42 -65
- package/dist/capture/focus-control.js +56 -75
- package/dist/capture/focus-control.js.map +1 -1
- package/dist/capture/host-yield-cadence.d.ts +25 -0
- package/dist/capture/host-yield-cadence.js +25 -0
- package/dist/capture/host-yield-cadence.js.map +1 -0
- package/dist/capture/linear-encoding.d.ts +14 -12
- package/dist/capture/linear-encoding.js +14 -13
- package/dist/capture/linear-encoding.js.map +1 -1
- package/dist/capture/lossless-jpeg.d.ts +27 -0
- package/dist/capture/lossless-jpeg.js +237 -0
- package/dist/capture/lossless-jpeg.js.map +1 -0
- package/dist/capture/native-environment-lean.d.ts +227 -0
- package/dist/capture/native-environment-lean.js +974 -0
- package/dist/capture/native-environment-lean.js.map +1 -0
- package/dist/capture/native-environment-optical-stage.d.ts +97 -0
- package/dist/capture/native-environment-optical-stage.js +340 -0
- package/dist/capture/native-environment-optical-stage.js.map +1 -0
- package/dist/capture/native-environment-raw.d.ts +140 -6
- package/dist/capture/native-environment-raw.js +435 -34
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/native-raw-development.d.ts +116 -9
- package/dist/capture/native-raw-development.js +221 -62
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/capture/native-raw-dng.d.ts +60 -0
- package/dist/capture/native-raw-dng.js +167 -0
- package/dist/capture/native-raw-dng.js.map +1 -0
- package/dist/capture/native-raw.d.ts +65 -12
- package/dist/capture/native-raw.js +81 -19
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/packed-sensor-raw.d.ts +160 -0
- package/dist/capture/packed-sensor-raw.js +221 -0
- package/dist/capture/packed-sensor-raw.js.map +1 -0
- package/dist/capture/photographic-export.d.ts +58 -35
- package/dist/capture/photographic-export.js +177 -70
- package/dist/capture/photographic-export.js.map +1 -1
- package/dist/capture/raw-development-kernel.d.ts +52 -0
- package/dist/capture/raw-development-kernel.js +88 -0
- package/dist/capture/raw-development-kernel.js.map +1 -0
- package/dist/capture/raw-frame-limits.d.ts +7 -7
- package/dist/capture/raw-frame-limits.js +7 -6
- package/dist/capture/raw-frame-limits.js.map +1 -1
- package/dist/capture/raw-frame-reconstruction.d.ts +8 -9
- package/dist/capture/raw-frame-reconstruction.js +9 -8
- package/dist/capture/raw-frame-reconstruction.js.map +1 -1
- package/dist/capture/raw-white-level.d.ts +55 -0
- package/dist/capture/raw-white-level.js +165 -0
- package/dist/capture/raw-white-level.js.map +1 -0
- package/dist/capture/release-sequence.d.ts +5 -7
- package/dist/capture/release-sequence.js +15 -13
- package/dist/capture/release-sequence.js.map +1 -1
- package/dist/capture/sensor-raw-frame.d.ts +5 -6
- package/dist/capture/sensor-raw-frame.js +26 -9
- package/dist/capture/sensor-raw-frame.js.map +1 -1
- package/dist/capture/sensor-raw-producer.d.ts +21 -13
- package/dist/capture/sensor-raw-producer.js +86 -25
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/capture/simulated-capture.d.ts +15 -16
- package/dist/capture/simulated-capture.js +22 -12
- package/dist/capture/simulated-capture.js.map +1 -1
- package/dist/color/camera-color-matrix.d.ts +69 -0
- package/dist/color/camera-color-matrix.js +132 -0
- package/dist/color/camera-color-matrix.js.map +1 -0
- package/dist/color/capture-color.d.ts +17 -10
- package/dist/color/capture-color.js +50 -17
- package/dist/color/capture-color.js.map +1 -1
- package/dist/color/chromatic-adaptation.d.ts +63 -0
- package/dist/color/chromatic-adaptation.js +91 -0
- package/dist/color/chromatic-adaptation.js.map +1 -0
- package/dist/color/color-difference.d.ts +104 -0
- package/dist/color/color-difference.js +205 -0
- package/dist/color/color-difference.js.map +1 -0
- package/dist/color/color-matching-functions.d.ts +168 -0
- package/dist/color/color-matching-functions.js +309 -0
- package/dist/color/color-matching-functions.js.map +1 -0
- package/dist/color/colorimetry-math.d.ts +52 -0
- package/dist/color/colorimetry-math.js +144 -0
- package/dist/color/colorimetry-math.js.map +1 -0
- package/dist/color/gamut-mapping.d.ts +54 -0
- package/dist/color/gamut-mapping.js +107 -0
- package/dist/color/gamut-mapping.js.map +1 -0
- package/dist/color/illuminants.d.ts +182 -0
- package/dist/color/illuminants.js +434 -0
- package/dist/color/illuminants.js.map +1 -0
- package/dist/color/rgb-color-spaces.d.ts +79 -0
- package/dist/color/rgb-color-spaces.js +115 -0
- package/dist/color/rgb-color-spaces.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +33 -11
- package/dist/color/sensor-color-development.js +104 -30
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/color/srgb-icc.d.ts +9 -2
- package/dist/color/srgb-icc.js +16 -5
- package/dist/color/srgb-icc.js.map +1 -1
- package/dist/color/srgb-transfer.d.ts +1 -2
- package/dist/color/srgb-transfer.js +1 -1
- package/dist/color/srgb-transfer.js.map +1 -1
- package/dist/color/white-balance.d.ts +68 -19
- package/dist/color/white-balance.js +168 -35
- package/dist/color/white-balance.js.map +1 -1
- package/dist/composition/image-formation-plan.d.ts +152 -128
- package/dist/composition/image-formation-plan.js +292 -138
- package/dist/composition/image-formation-plan.js.map +1 -1
- package/dist/composition/plan-consumer.d.ts +6 -7
- package/dist/composition/plan-consumer.js +14 -11
- package/dist/composition/plan-consumer.js.map +1 -1
- package/dist/core/calculation-result.d.ts +21 -14
- package/dist/core/calculation-result.js +209 -11
- package/dist/core/calculation-result.js.map +1 -1
- package/dist/core/canonical-json.d.ts +13 -8
- package/dist/core/canonical-json.js +34 -15
- package/dist/core/canonical-json.js.map +1 -1
- package/dist/core/configuration-error.d.ts +5 -4
- package/dist/core/configuration-error.js +5 -3
- package/dist/core/configuration-error.js.map +1 -1
- package/dist/core/evidence-provenance.d.ts +12 -12
- package/dist/core/evidence-provenance.js +10 -9
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/image-formation.d.ts +11 -10
- package/dist/core/image-formation.js +11 -9
- package/dist/core/image-formation.js.map +1 -1
- package/dist/core/owned-data.d.ts +9 -17
- package/dist/core/owned-data.js +9 -16
- package/dist/core/owned-data.js.map +1 -1
- package/dist/core/portable-math.d.ts +15 -0
- package/dist/core/portable-math.js +56 -0
- package/dist/core/portable-math.js.map +1 -0
- package/dist/core/record-validation.d.ts +48 -9
- package/dist/core/record-validation.js +93 -19
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/scientific-assurance.d.ts +16 -14
- package/dist/core/scientific-assurance.js +22 -18
- package/dist/core/scientific-assurance.js.map +1 -1
- package/dist/core/spectral-composition.d.ts +13 -14
- package/dist/core/spectral-composition.js +30 -27
- package/dist/core/spectral-composition.js.map +1 -1
- package/dist/core/spectral.d.ts +5 -6
- package/dist/core/spectral.js +9 -7
- package/dist/core/spectral.js.map +1 -1
- package/dist/core/validation.d.ts +3 -6
- package/dist/core/validation.js +3 -5
- package/dist/core/validation.js.map +1 -1
- package/dist/core/version.d.ts +6 -6
- package/dist/core/version.js +6 -5
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/exposure-capabilities.d.ts +10 -10
- package/dist/equipment/exposure-capabilities.js +40 -30
- package/dist/equipment/exposure-capabilities.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +13 -6
- package/dist/equipment/generic-tier-assets.js +34 -15
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.d.ts +5 -6
- package/dist/equipment/generic-tier-presets.js +15 -13
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/equipment/iso-capabilities.d.ts +21 -22
- package/dist/equipment/iso-capabilities.js +49 -44
- package/dist/equipment/iso-capabilities.js.map +1 -1
- package/dist/equipment/metering-capabilities.d.ts +5 -6
- package/dist/equipment/metering-capabilities.js +22 -19
- package/dist/equipment/metering-capabilities.js.map +1 -1
- package/dist/equipment/release-capabilities.d.ts +3 -4
- package/dist/equipment/release-capabilities.js +18 -14
- package/dist/equipment/release-capabilities.js.map +1 -1
- package/dist/exposure/exposure-duration-control.d.ts +19 -17
- package/dist/exposure/exposure-duration-control.js +27 -23
- package/dist/exposure/exposure-duration-control.js.map +1 -1
- package/dist/exposure/exposure-mode-resolver.d.ts +42 -39
- package/dist/exposure/exposure-mode-resolver.js +127 -82
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/exposure.d.ts +17 -16
- package/dist/exposure/exposure.js +22 -15
- package/dist/exposure/exposure.js.map +1 -1
- package/dist/exposure/flash-ttl.d.ts +135 -0
- package/dist/exposure/flash-ttl.js +193 -0
- package/dist/exposure/flash-ttl.js.map +1 -0
- package/dist/exposure/flash.d.ts +144 -36
- package/dist/exposure/flash.js +259 -59
- package/dist/exposure/flash.js.map +1 -1
- package/dist/exposure/metering-scene-radiance.d.ts +10 -10
- package/dist/exposure/metering-scene-radiance.js +42 -23
- package/dist/exposure/metering-scene-radiance.js.map +1 -1
- package/dist/exposure/metering-target.d.ts +8 -8
- package/dist/exposure/metering-target.js +30 -20
- package/dist/exposure/metering-target.js.map +1 -1
- package/dist/exposure/metering-temporal.d.ts +16 -15
- package/dist/exposure/metering-temporal.js +41 -19
- package/dist/exposure/metering-temporal.js.map +1 -1
- package/dist/exposure/metering.d.ts +64 -17
- package/dist/exposure/metering.js +159 -30
- package/dist/exposure/metering.js.map +1 -1
- package/dist/exposure/program-line.d.ts +5 -5
- package/dist/exposure/program-line.js +20 -13
- package/dist/exposure/program-line.js.map +1 -1
- package/dist/facade/camera-preset.d.ts +8 -0
- package/dist/facade/camera-preset.js +102 -0
- package/dist/facade/camera-preset.js.map +1 -0
- package/dist/facade/chart-radiance-batch.d.ts +57 -0
- package/dist/facade/chart-radiance-batch.js +121 -0
- package/dist/facade/chart-radiance-batch.js.map +1 -0
- package/dist/facade/chart-scenes.d.ts +177 -0
- package/dist/facade/chart-scenes.js +232 -0
- package/dist/facade/chart-scenes.js.map +1 -0
- package/dist/facade/host-yield.d.ts +7 -0
- package/dist/facade/host-yield.js +23 -0
- package/dist/facade/host-yield.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +117 -0
- package/dist/facade/scene-radiance.js +205 -0
- package/dist/facade/scene-radiance.js.map +1 -0
- package/dist/facade/simulate-capture.d.ts +284 -0
- package/dist/facade/simulate-capture.js +1026 -0
- package/dist/facade/simulate-capture.js.map +1 -0
- package/dist/gpu/chart-radiance-gpu.d.ts +17 -0
- package/dist/gpu/chart-radiance-gpu.js +176 -0
- package/dist/gpu/chart-radiance-gpu.js.map +1 -0
- package/dist/gpu/image-kernel-accelerator.d.ts +132 -0
- package/dist/gpu/image-kernel-accelerator.js +720 -0
- package/dist/gpu/image-kernel-accelerator.js.map +1 -0
- package/dist/gpu/image-kernel-execution.d.ts +92 -0
- package/dist/gpu/image-kernel-execution.js +84 -0
- package/dist/gpu/image-kernel-execution.js.map +1 -0
- package/dist/gpu/sensor-stage-gpu.d.ts +44 -0
- package/dist/gpu/sensor-stage-gpu.js +317 -0
- package/dist/gpu/sensor-stage-gpu.js.map +1 -0
- package/dist/gpu/temporal-sum-gpu.d.ts +23 -0
- package/dist/gpu/temporal-sum-gpu.js +150 -0
- package/dist/gpu/temporal-sum-gpu.js.map +1 -0
- package/dist/gpu/webgpu-runtime.d.ts +63 -0
- package/dist/gpu/webgpu-runtime.js +215 -0
- package/dist/gpu/webgpu-runtime.js.map +1 -0
- package/dist/gpu/wgsl-chart-kernel.d.ts +30 -0
- package/dist/gpu/wgsl-chart-kernel.js +165 -0
- package/dist/gpu/wgsl-chart-kernel.js.map +1 -0
- package/dist/gpu/wgsl-kernels.d.ts +53 -0
- package/dist/gpu/wgsl-kernels.js +365 -0
- package/dist/gpu/wgsl-kernels.js.map +1 -0
- package/dist/gpu/wgsl-sensor-kernel.d.ts +64 -0
- package/dist/gpu/wgsl-sensor-kernel.js +409 -0
- package/dist/gpu/wgsl-sensor-kernel.js.map +1 -0
- package/dist/index.d.ts +89 -25
- package/dist/index.js +59 -15
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.d.ts +92 -40
- package/dist/motion/camera-rotation.js +84 -47
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +37 -34
- package/dist/motion/capture-rotation-inverse-mapping.js +32 -24
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +39 -35
- package/dist/motion/capture-rotation-temporal-quadrature.js +37 -28
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.d.ts +32 -28
- package/dist/motion/capture-rotation-trajectory.js +36 -26
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +23 -21
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +33 -14
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
- package/dist/motion/extended-object-projection.d.ts +19 -16
- package/dist/motion/extended-object-projection.js +38 -18
- package/dist/motion/extended-object-projection.js.map +1 -1
- package/dist/motion/projected-motion.d.ts +18 -17
- package/dist/motion/projected-motion.js +25 -17
- package/dist/motion/projected-motion.js.map +1 -1
- package/dist/motion/temporal-exposure-sum.d.ts +55 -0
- package/dist/motion/temporal-exposure-sum.js +141 -0
- package/dist/motion/temporal-exposure-sum.js.map +1 -0
- package/dist/motion/video-sequence.d.ts +111 -0
- package/dist/motion/video-sequence.js +179 -0
- package/dist/motion/video-sequence.js.map +1 -0
- package/dist/optics/aperture.d.ts +14 -15
- package/dist/optics/aperture.js +13 -11
- package/dist/optics/aperture.js.map +1 -1
- package/dist/optics/atmospheric-haze.d.ts +83 -0
- package/dist/optics/atmospheric-haze.js +113 -0
- package/dist/optics/atmospheric-haze.js.map +1 -0
- package/dist/optics/brown-conrady-distortion.d.ts +116 -0
- package/dist/optics/brown-conrady-distortion.js +291 -0
- package/dist/optics/brown-conrady-distortion.js.map +1 -0
- package/dist/optics/circle-of-confusion.d.ts +10 -10
- package/dist/optics/circle-of-confusion.js +15 -11
- package/dist/optics/circle-of-confusion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +64 -33
- package/dist/optics/complex-pupil-psf.js +190 -98
- package/dist/optics/complex-pupil-psf.js.map +1 -1
- package/dist/optics/depth-of-field.d.ts +25 -15
- package/dist/optics/depth-of-field.js +67 -27
- package/dist/optics/depth-of-field.js.map +1 -1
- package/dist/optics/diffraction.d.ts +14 -13
- package/dist/optics/diffraction.js +14 -10
- package/dist/optics/diffraction.js.map +1 -1
- package/dist/optics/focus-breathing.d.ts +88 -27
- package/dist/optics/focus-breathing.js +114 -23
- package/dist/optics/focus-breathing.js.map +1 -1
- package/dist/optics/focus-state.d.ts +18 -18
- package/dist/optics/focus-state.js +21 -15
- package/dist/optics/focus-state.js.map +1 -1
- package/dist/optics/front-of-lens-filter.d.ts +45 -14
- package/dist/optics/front-of-lens-filter.js +259 -88
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/illumination-vignetting.d.ts +16 -17
- package/dist/optics/illumination-vignetting.js +40 -17
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +59 -0
- package/dist/optics/irradiance-convolution.js +138 -0
- package/dist/optics/irradiance-convolution.js.map +1 -0
- package/dist/optics/lateral-chromatic-aberration.d.ts +33 -30
- package/dist/optics/lateral-chromatic-aberration.js +33 -23
- package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
- package/dist/optics/lens-psf-kernels.d.ts +89 -0
- package/dist/optics/lens-psf-kernels.js +175 -0
- package/dist/optics/lens-psf-kernels.js.map +1 -0
- package/dist/optics/lens-psf-profile.d.ts +78 -46
- package/dist/optics/lens-psf-profile.js +335 -124
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/longitudinal-chromatic-aberration.d.ts +102 -0
- package/dist/optics/longitudinal-chromatic-aberration.js +210 -0
- package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -0
- package/dist/optics/polygon-diffraction.d.ts +80 -23
- package/dist/optics/polygon-diffraction.js +130 -25
- package/dist/optics/polygon-diffraction.js.map +1 -1
- package/dist/optics/profile-contract.d.ts +5 -6
- package/dist/optics/profile-contract.js +14 -11
- package/dist/optics/profile-contract.js.map +1 -1
- package/dist/optics/psf-foundation.d.ts +23 -23
- package/dist/optics/psf-foundation.js +24 -21
- package/dist/optics/psf-foundation.js.map +1 -1
- package/dist/optics/pupil-vignetting.d.ts +118 -0
- package/dist/optics/pupil-vignetting.js +264 -0
- package/dist/optics/pupil-vignetting.js.map +1 -0
- package/dist/optics/radial-distortion.d.ts +34 -33
- package/dist/optics/radial-distortion.js +37 -30
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +47 -33
- package/dist/optics/scene-to-sensor-irradiance.js +73 -45
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/scene-to-sensor-quadrature.d.ts +23 -18
- package/dist/optics/scene-to-sensor-quadrature.js +16 -11
- package/dist/optics/scene-to-sensor-quadrature.js.map +1 -1
- package/dist/optics/sensor-aperture-rays.d.ts +20 -4
- package/dist/optics/sensor-aperture-rays.js +32 -14
- package/dist/optics/sensor-aperture-rays.js.map +1 -1
- package/dist/optics/sensor-environment-query.d.ts +81 -16
- package/dist/optics/sensor-environment-query.js +145 -12
- package/dist/optics/sensor-environment-query.js.map +1 -1
- package/dist/optics/sensor-psf-quadrature.d.ts +12 -10
- package/dist/optics/sensor-psf-quadrature.js +18 -11
- package/dist/optics/sensor-psf-quadrature.js.map +1 -1
- package/dist/optics/sensor-psf-support.d.ts +8 -6
- package/dist/optics/sensor-psf-support.js +8 -5
- package/dist/optics/sensor-psf-support.js.map +1 -1
- package/dist/optics/stray-light.d.ts +22 -19
- package/dist/optics/stray-light.js +18 -12
- package/dist/optics/stray-light.js.map +1 -1
- package/dist/optics/thin-lens.d.ts +10 -9
- package/dist/optics/thin-lens.js +12 -8
- package/dist/optics/thin-lens.js.map +1 -1
- package/dist/optics/zernike-wavefront.d.ts +154 -0
- package/dist/optics/zernike-wavefront.js +352 -0
- package/dist/optics/zernike-wavefront.js.map +1 -0
- package/dist/output/capture-corrected-sdr.d.ts +16 -8
- package/dist/output/capture-corrected-sdr.js +16 -8
- package/dist/output/capture-corrected-sdr.js.map +1 -1
- package/dist/output/capture-geometry.d.ts +34 -36
- package/dist/output/capture-geometry.js +52 -32
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/capture-sdr.d.ts +7 -6
- package/dist/output/capture-sdr.js +11 -8
- package/dist/output/capture-sdr.js.map +1 -1
- package/dist/output/crop.d.ts +22 -6
- package/dist/output/crop.js +40 -6
- package/dist/output/crop.js.map +1 -1
- package/dist/output/geometric-transforms.d.ts +60 -23
- package/dist/output/geometric-transforms.js +111 -24
- package/dist/output/geometric-transforms.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +27 -19
- package/dist/output/lens-corrections.js +29 -13
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +71 -16
- package/dist/output/native-capture-sdr.js +190 -33
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/png-encoder.d.ts +65 -0
- package/dist/output/png-encoder.js +461 -0
- package/dist/output/png-encoder.js.map +1 -0
- package/dist/output/print-contrast-reference.d.ts +10 -9
- package/dist/output/print-contrast-reference.js +10 -8
- package/dist/output/print-contrast-reference.js.map +1 -1
- package/dist/output/print-detail.d.ts +18 -17
- package/dist/output/print-detail.js +12 -10
- package/dist/output/print-detail.js.map +1 -1
- package/dist/output/print-jpeg.d.ts +26 -5
- package/dist/output/print-jpeg.js +117 -50
- package/dist/output/print-jpeg.js.map +1 -1
- package/dist/output/print-plan.d.ts +19 -19
- package/dist/output/print-plan.js +11 -10
- package/dist/output/print-plan.js.map +1 -1
- package/dist/output/print-region-statistics.d.ts +14 -15
- package/dist/output/print-region-statistics.js +11 -11
- package/dist/output/print-region-statistics.js.map +1 -1
- package/dist/output/sdr-rendering.d.ts +48 -10
- package/dist/output/sdr-rendering.js +114 -25
- package/dist/output/sdr-rendering.js.map +1 -1
- package/dist/output/subject-framing-crop.d.ts +6 -10
- package/dist/output/subject-framing-crop.js +23 -13
- package/dist/output/subject-framing-crop.js.map +1 -1
- package/dist/processing/demosaic.d.ts +90 -0
- package/dist/processing/demosaic.js +275 -0
- package/dist/processing/demosaic.js.map +1 -0
- package/dist/processing/denoise.d.ts +68 -0
- package/dist/processing/denoise.js +214 -0
- package/dist/processing/denoise.js.map +1 -0
- package/dist/processing/focus-stacking.d.ts +17 -0
- package/dist/processing/focus-stacking.js +80 -0
- package/dist/processing/focus-stacking.js.map +1 -0
- package/dist/processing/hdr.d.ts +54 -0
- package/dist/processing/hdr.js +172 -0
- package/dist/processing/hdr.js.map +1 -0
- package/dist/processing/image-ops.d.ts +66 -0
- package/dist/processing/image-ops.js +192 -0
- package/dist/processing/image-ops.js.map +1 -0
- package/dist/processing/panorama.d.ts +51 -0
- package/dist/processing/panorama.js +305 -0
- package/dist/processing/panorama.js.map +1 -0
- package/dist/processing/processing-task.d.ts +85 -0
- package/dist/processing/processing-task.js +164 -0
- package/dist/processing/processing-task.js.map +1 -0
- package/dist/processing/tone-mapping.d.ts +69 -0
- package/dist/processing/tone-mapping.js +310 -0
- package/dist/processing/tone-mapping.js.map +1 -0
- package/dist/schema/camera.d.ts +5 -4
- package/dist/schema/illumination-spectral.d.ts +13 -19
- package/dist/schema/illumination-spectral.js +23 -19
- package/dist/schema/illumination-spectral.js.map +1 -1
- package/dist/schema/illumination-temporal.d.ts +12 -15
- package/dist/schema/illumination-temporal.js +43 -28
- package/dist/schema/illumination-temporal.js.map +1 -1
- package/dist/schema/illumination.d.ts +5 -4
- package/dist/schema/illumination.js +55 -20
- package/dist/schema/illumination.js.map +1 -1
- package/dist/schema/scene-radiance-temporal.d.ts +9 -11
- package/dist/schema/scene-radiance-temporal.js +26 -23
- package/dist/schema/scene-radiance-temporal.js.map +1 -1
- package/dist/schema/scene-radiance.d.ts +17 -17
- package/dist/schema/scene-radiance.js +56 -34
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/schema/scene.d.ts +14 -13
- package/dist/schema/validation.d.ts +0 -1
- package/dist/schema/validation.js +17 -15
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.d.ts +45 -64
- package/dist/sensor/accumulated-charge.js +41 -47
- package/dist/sensor/accumulated-charge.js.map +1 -1
- package/dist/sensor/architecture.d.ts +22 -25
- package/dist/sensor/architecture.js +17 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +21 -28
- package/dist/sensor/camera-saturation-capacity.js +36 -34
- package/dist/sensor/camera-saturation-capacity.js.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.d.ts +46 -51
- package/dist/sensor/capture-color-sampling-binding.js +39 -41
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.d.ts +8 -9
- package/dist/sensor/capture-mode-timing.js +24 -21
- package/dist/sensor/capture-mode-timing.js.map +1 -1
- package/dist/sensor/capture-mode.d.ts +28 -30
- package/dist/sensor/capture-mode.js +33 -31
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.d.ts +30 -33
- package/dist/sensor/color-sampling.js +32 -37
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.d.ts +19 -23
- package/dist/sensor/constant-rate-temporal-integration.js +28 -26
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
- package/dist/sensor/dark-current.d.ts +53 -49
- package/dist/sensor/dark-current.js +87 -46
- package/dist/sensor/dark-current.js.map +1 -1
- package/dist/sensor/environment-photo-signal.d.ts +71 -30
- package/dist/sensor/environment-photo-signal.js +127 -46
- package/dist/sensor/environment-photo-signal.js.map +1 -1
- package/dist/sensor/eqe-electron-rate.d.ts +14 -13
- package/dist/sensor/eqe-electron-rate.js +34 -14
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/eqe-local-exposure.d.ts +24 -24
- package/dist/sensor/eqe-local-exposure.js +15 -11
- package/dist/sensor/eqe-local-exposure.js.map +1 -1
- package/dist/sensor/eqe-temporal-exposure.d.ts +11 -11
- package/dist/sensor/eqe-temporal-exposure.js +15 -10
- package/dist/sensor/eqe-temporal-exposure.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +48 -34
- package/dist/sensor/exposure-window.js +77 -36
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/fixed-pattern-noise.d.ts +108 -0
- package/dist/sensor/fixed-pattern-noise.js +166 -0
- package/dist/sensor/fixed-pattern-noise.js.map +1 -0
- package/dist/sensor/iso-gain.d.ts +44 -0
- package/dist/sensor/iso-gain.js +119 -0
- package/dist/sensor/iso-gain.js.map +1 -0
- package/dist/sensor/iso-signal-chain.d.ts +25 -48
- package/dist/sensor/iso-signal-chain.js +52 -66
- package/dist/sensor/iso-signal-chain.js.map +1 -1
- package/dist/sensor/local-exposure-binding.d.ts +21 -21
- package/dist/sensor/local-exposure-binding.js +22 -18
- package/dist/sensor/local-exposure-binding.js.map +1 -1
- package/dist/sensor/optical-stack.d.ts +36 -40
- package/dist/sensor/optical-stack.js +34 -37
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.d.ts +22 -28
- package/dist/sensor/photon-energy.js +42 -34
- package/dist/sensor/photon-energy.js.map +1 -1
- package/dist/sensor/physical-charge-capacity.d.ts +20 -30
- package/dist/sensor/physical-charge-capacity.js +35 -36
- package/dist/sensor/physical-charge-capacity.js.map +1 -1
- package/dist/sensor/pixel-pitch.d.ts +2 -3
- package/dist/sensor/pixel-pitch.js +4 -2
- package/dist/sensor/pixel-pitch.js.map +1 -1
- package/dist/sensor/radiometry-readiness.d.ts +13 -15
- package/dist/sensor/radiometry-readiness.js +20 -17
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +173 -83
- package/dist/sensor/raw-readout.js +425 -160
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/raw-reconstruction.d.ts +112 -44
- package/dist/sensor/raw-reconstruction.js +200 -47
- package/dist/sensor/raw-reconstruction.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.d.ts +103 -34
- package/dist/sensor/readout-exposure-linkage.js +125 -27
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.d.ts +43 -44
- package/dist/sensor/readout-timing.js +38 -30
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +21 -28
- package/dist/sensor/response-application-compatibility.js +35 -34
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/response-operating-range.d.ts +26 -35
- package/dist/sensor/response-operating-range.js +40 -39
- package/dist/sensor/response-operating-range.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.d.ts +21 -29
- package/dist/sensor/responsivity-photocurrent.js +57 -40
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sampling-aperture.d.ts +21 -25
- package/dist/sensor/sampling-aperture.js +29 -28
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts +14 -12
- package/dist/sensor/scene-eqe-temporal-exposure.js +13 -8
- package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -1
- package/dist/sensor/sensor-geometry.d.ts +28 -32
- package/dist/sensor/sensor-geometry.js +35 -20
- package/dist/sensor/sensor-geometry.js.map +1 -1
- package/dist/sensor/signal-noise.d.ts +14 -16
- package/dist/sensor/signal-noise.js +15 -13
- package/dist/sensor/signal-noise.js.map +1 -1
- package/dist/sensor/spatial-sample-reduction.d.ts +45 -60
- package/dist/sensor/spatial-sample-reduction.js +39 -48
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.d.ts +46 -54
- package/dist/sensor/spatial-sampling-quadrature.js +31 -36
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.d.ts +32 -42
- package/dist/sensor/spatio-spectral-reduction.js +24 -29
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
- package/dist/sensor/spectral-coverage.d.ts +6 -9
- package/dist/sensor/spectral-coverage.js +9 -6
- package/dist/sensor/spectral-coverage.js.map +1 -1
- package/dist/sensor/spectral-quadrature.d.ts +46 -60
- package/dist/sensor/spectral-quadrature.js +38 -48
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/spectral-response.d.ts +53 -41
- package/dist/sensor/spectral-response.js +80 -47
- package/dist/sensor/spectral-response.js.map +1 -1
- package/dist/sensor/stochastic-seed.d.ts +50 -0
- package/dist/sensor/stochastic-seed.js +123 -0
- package/dist/sensor/stochastic-seed.js.map +1 -0
- package/dist/sensor/temporal-eqe-sum.d.ts +2 -4
- package/dist/sensor/temporal-eqe-sum.js +5 -6
- package/dist/sensor/temporal-eqe-sum.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +5 -6
- package/dist/sensor/temporal-photo-signal.js +11 -10
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/sensor/temporal-sample-binding.d.ts +1 -2
- package/dist/sensor/temporal-sample-binding.js +3 -3
- package/dist/sensor/temporal-sample-binding.js.map +1 -1
- package/dist/simulation/poc-simulation.d.ts +16 -16
- package/dist/simulation/poc-simulation.js +20 -15
- package/dist/simulation/poc-simulation.js.map +1 -1
- package/dist/stabilization/camera-shake.d.ts +42 -18
- package/dist/stabilization/camera-shake.js +43 -20
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +44 -41
- package/dist/stabilization/system.js +196 -108
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +183 -0
- package/docs/API_REFERENCE.md +761 -2
- package/docs/QUICK_START.md +495 -0
- package/docs/USAGE.md +1719 -714
- package/docs/api/camera-equivalent-focal-length.md +6 -7
- package/docs/api/camera-field-of-view.md +16 -8
- package/docs/api/camera-lens-projection.md +246 -0
- package/docs/api/camera-projected-object-size.md +6 -5
- package/docs/api/capture-capture-export-metadata.md +10 -10
- package/docs/api/capture-dng-import.md +134 -0
- package/docs/api/capture-environment-raw-producer.md +17 -11
- package/docs/api/capture-export-jpeg.md +16 -0
- package/docs/api/capture-focus-control.md +25 -47
- package/docs/api/capture-linear-encoding.md +21 -12
- package/docs/api/capture-lossless-jpeg.md +49 -0
- package/docs/api/capture-native-environment-optical-stage.md +75 -0
- package/docs/api/capture-native-environment-raw.md +161 -4
- package/docs/api/capture-native-raw-development.md +69 -8
- package/docs/api/capture-native-raw-dng.md +84 -0
- package/docs/api/capture-native-raw.md +21 -10
- package/docs/api/capture-packed-sensor-raw.md +156 -0
- package/docs/api/capture-photographic-export.md +69 -31
- package/docs/api/capture-raw-frame-reconstruction.md +8 -8
- package/docs/api/capture-raw-white-level.md +37 -0
- package/docs/api/capture-release-sequence.md +6 -7
- package/docs/api/capture-sensor-raw-frame.md +6 -6
- package/docs/api/capture-sensor-raw-producer.md +17 -11
- package/docs/api/capture-simulated-capture.md +15 -15
- package/docs/api/color-camera-color-matrix.md +103 -0
- package/docs/api/color-capture-color.md +22 -11
- package/docs/api/color-chromatic-adaptation.md +82 -0
- package/docs/api/color-color-difference.md +134 -0
- package/docs/api/color-color-matching-functions.md +259 -0
- package/docs/api/color-colorimetry-math.md +54 -0
- package/docs/api/color-gamut-mapping.md +72 -0
- package/docs/api/color-illuminants.md +280 -0
- package/docs/api/color-rgb-color-spaces.md +151 -0
- package/docs/api/color-sensor-color-development.md +27 -0
- package/docs/api/color-srgb-icc.md +2 -4
- package/docs/api/color-white-balance.md +95 -19
- package/docs/api/composition-image-formation-plan.md +124 -95
- package/docs/api/composition-plan-consumer.md +7 -7
- package/docs/api/core-calculation-result.md +18 -14
- package/docs/api/core-configuration-error.md +1 -1
- package/docs/api/core-image-formation.md +7 -7
- package/docs/api/core-scientific-assurance.md +12 -10
- package/docs/api/core-spectral-composition.md +14 -14
- package/docs/api/core-spectral.md +6 -6
- package/docs/api/core-validation.md +3 -3
- package/docs/api/core-version.md +7 -6
- package/docs/api/equipment-exposure-capabilities.md +11 -10
- package/docs/api/equipment-generic-tier-assets.md +7 -2
- package/docs/api/equipment-generic-tier-presets.md +6 -6
- package/docs/api/equipment-iso-capabilities.md +18 -18
- package/docs/api/equipment-metering-capabilities.md +6 -6
- package/docs/api/equipment-release-capabilities.md +4 -4
- package/docs/api/exports.json +2213 -8
- package/docs/api/exposure-exposure-duration-control.md +9 -9
- package/docs/api/exposure-exposure-mode-resolver.md +35 -31
- package/docs/api/exposure-exposure.md +10 -10
- package/docs/api/exposure-flash-ttl.md +182 -0
- package/docs/api/exposure-flash.md +183 -28
- package/docs/api/exposure-metering-scene-radiance.md +11 -10
- package/docs/api/exposure-metering-target.md +9 -8
- package/docs/api/exposure-metering-temporal.md +8 -8
- package/docs/api/exposure-metering.md +69 -9
- package/docs/api/exposure-program-line.md +6 -5
- package/docs/api/facade-chart-radiance-batch.md +96 -0
- package/docs/api/facade-chart-scenes.md +240 -0
- package/docs/api/facade-scene-radiance.md +122 -0
- package/docs/api/facade-simulate-capture.md +324 -0
- package/docs/api/gpu-image-kernel-accelerator.md +157 -0
- package/docs/api/gpu-image-kernel-execution.md +152 -0
- package/docs/api/motion-camera-rotation.md +43 -26
- package/docs/api/motion-capture-rotation-inverse-mapping.md +24 -23
- package/docs/api/motion-capture-rotation-temporal-quadrature.md +22 -22
- package/docs/api/motion-capture-rotation-trajectory.md +15 -15
- package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +15 -14
- package/docs/api/motion-extended-object-projection.md +10 -8
- package/docs/api/motion-projected-motion.md +8 -8
- package/docs/api/motion-temporal-exposure-sum.md +98 -0
- package/docs/api/motion-video-sequence.md +159 -0
- package/docs/api/optics-aperture.md +8 -8
- package/docs/api/optics-atmospheric-haze.md +104 -0
- package/docs/api/optics-brown-conrady-distortion.md +123 -0
- package/docs/api/optics-circle-of-confusion.md +5 -4
- package/docs/api/optics-complex-pupil-psf.md +57 -16
- package/docs/api/optics-depth-of-field.md +12 -6
- package/docs/api/optics-diffraction.md +8 -7
- package/docs/api/optics-focus-breathing.md +104 -16
- package/docs/api/optics-focus-state.md +9 -10
- package/docs/api/optics-front-of-lens-filter.md +72 -14
- package/docs/api/optics-illumination-vignetting.md +10 -10
- package/docs/api/optics-irradiance-convolution.md +95 -0
- package/docs/api/optics-lateral-chromatic-aberration.md +22 -21
- package/docs/api/optics-lens-psf-kernels.md +72 -0
- package/docs/api/optics-lens-psf-profile.md +48 -26
- package/docs/api/optics-longitudinal-chromatic-aberration.md +128 -0
- package/docs/api/optics-polygon-diffraction.md +78 -13
- package/docs/api/optics-profile-contract.md +4 -4
- package/docs/api/optics-psf-foundation.md +12 -12
- package/docs/api/optics-pupil-vignetting.md +132 -0
- package/docs/api/optics-radial-distortion.md +12 -12
- package/docs/api/optics-scene-to-sensor-irradiance.md +25 -14
- package/docs/api/optics-scene-to-sensor-quadrature.md +15 -12
- package/docs/api/optics-sensor-aperture-rays.md +3 -2
- package/docs/api/optics-sensor-environment-query.md +52 -9
- package/docs/api/optics-sensor-psf-quadrature.md +13 -10
- package/docs/api/optics-stray-light.md +12 -11
- package/docs/api/optics-thin-lens.md +4 -3
- package/docs/api/optics-zernike-wavefront.md +229 -0
- package/docs/api/output-capture-corrected-sdr.md +10 -7
- package/docs/api/output-capture-geometry.md +35 -36
- package/docs/api/output-capture-sdr.md +4 -4
- package/docs/api/output-crop.md +7 -4
- package/docs/api/output-geometric-transforms.md +65 -19
- package/docs/api/output-lens-corrections.md +17 -15
- package/docs/api/output-native-capture-sdr.md +26 -13
- package/docs/api/output-png-encoder.md +105 -0
- package/docs/api/output-print-contrast-reference.md +8 -8
- package/docs/api/output-print-detail.md +14 -14
- package/docs/api/output-print-jpeg.md +22 -5
- package/docs/api/output-print-plan.md +18 -18
- package/docs/api/output-print-region-statistics.md +14 -14
- package/docs/api/output-sdr-rendering.md +52 -10
- package/docs/api/output-subject-framing-crop.md +5 -6
- package/docs/api/processing-demosaic.md +120 -0
- package/docs/api/processing-denoise.md +148 -0
- package/docs/api/processing-focus-stacking.md +41 -0
- package/docs/api/processing-hdr.md +113 -0
- package/docs/api/processing-panorama.md +82 -0
- package/docs/api/processing-processing-task.md +107 -0
- package/docs/api/processing-tone-mapping.md +142 -0
- package/docs/api/schema-camera.md +6 -4
- package/docs/api/schema-illumination-spectral.md +10 -11
- package/docs/api/schema-illumination-temporal.md +13 -15
- package/docs/api/schema-illumination.md +4 -4
- package/docs/api/schema-scene-radiance-temporal.md +10 -11
- package/docs/api/schema-scene-radiance.md +18 -17
- package/docs/api/schema-scene.md +9 -9
- package/docs/api/schema-validation.md +1 -1
- package/docs/api/sensor-accumulated-charge.md +12 -20
- package/docs/api/sensor-architecture.md +15 -16
- package/docs/api/sensor-camera-saturation-capacity.md +9 -11
- package/docs/api/sensor-capture-color-sampling-binding.md +47 -51
- package/docs/api/sensor-capture-mode-timing.md +9 -9
- package/docs/api/sensor-capture-mode.md +29 -30
- package/docs/api/sensor-color-sampling.md +31 -33
- package/docs/api/sensor-constant-rate-temporal-integration.md +10 -11
- package/docs/api/sensor-dark-current.md +30 -14
- package/docs/api/sensor-environment-photo-signal.md +13 -6
- package/docs/api/sensor-eqe-electron-rate.md +9 -8
- package/docs/api/sensor-eqe-local-exposure.md +18 -17
- package/docs/api/sensor-eqe-temporal-exposure.md +12 -11
- package/docs/api/sensor-exposure-window.md +24 -24
- package/docs/api/sensor-fixed-pattern-noise.md +104 -0
- package/docs/api/sensor-iso-gain.md +63 -0
- package/docs/api/sensor-iso-signal-chain.md +13 -22
- package/docs/api/sensor-local-exposure-binding.md +12 -13
- package/docs/api/sensor-optical-stack.md +37 -40
- package/docs/api/sensor-photon-energy.md +10 -11
- package/docs/api/sensor-physical-charge-capacity.md +8 -13
- package/docs/api/sensor-pixel-pitch.md +1 -1
- package/docs/api/sensor-radiometry-readiness.md +9 -9
- package/docs/api/sensor-raw-readout.md +118 -52
- package/docs/api/sensor-raw-reconstruction.md +97 -20
- package/docs/api/sensor-readout-exposure-linkage.md +120 -24
- package/docs/api/sensor-readout-timing.md +33 -35
- package/docs/api/sensor-response-application-compatibility.md +9 -11
- package/docs/api/sensor-response-operating-range.md +14 -18
- package/docs/api/sensor-responsivity-photocurrent.md +9 -12
- package/docs/api/sensor-sampling-aperture.md +22 -25
- package/docs/api/sensor-scene-eqe-temporal-exposure.md +9 -8
- package/docs/api/sensor-sensor-geometry.md +23 -24
- package/docs/api/sensor-signal-noise.md +10 -10
- package/docs/api/sensor-spatial-sample-reduction.md +27 -30
- package/docs/api/sensor-spatial-sampling-quadrature.md +37 -39
- package/docs/api/sensor-spatio-spectral-reduction.md +27 -29
- package/docs/api/sensor-spectral-coverage.md +5 -5
- package/docs/api/sensor-spectral-quadrature.md +33 -35
- package/docs/api/sensor-spectral-response.md +28 -16
- package/docs/api/sensor-temporal-photo-signal.md +6 -6
- package/docs/api/simulation-poc-simulation.md +17 -16
- package/docs/api/stabilization-camera-shake.md +29 -10
- package/docs/api/stabilization-system.md +25 -21
- package/docs/examples/production-request.json +3821 -2157
- package/docs/examples/simulate-capture.mjs +14 -0
- package/llms.txt +35 -0
- package/package.json +32 -12
- package/AGENTS.md +0 -674
- package/CONTRIBUTING.md +0 -76
- package/DCO +0 -33
- package/dist/camera/equivalent-focal-length.d.ts.map +0 -1
- package/dist/camera/field-of-view.d.ts.map +0 -1
- package/dist/camera/projected-object-size.d.ts.map +0 -1
- package/dist/capture/capture-export-metadata.d.ts.map +0 -1
- package/dist/capture/environment-raw-producer.d.ts.map +0 -1
- package/dist/capture/export-jpeg.d.ts.map +0 -1
- package/dist/capture/export-tiff.d.ts.map +0 -1
- package/dist/capture/focus-control.d.ts.map +0 -1
- package/dist/capture/linear-encoding.d.ts.map +0 -1
- package/dist/capture/native-environment-raw.d.ts.map +0 -1
- package/dist/capture/native-raw-development.d.ts.map +0 -1
- package/dist/capture/native-raw.d.ts.map +0 -1
- package/dist/capture/photographic-export.d.ts.map +0 -1
- package/dist/capture/raw-frame-limits.d.ts.map +0 -1
- package/dist/capture/raw-frame-reconstruction.d.ts.map +0 -1
- package/dist/capture/release-sequence.d.ts.map +0 -1
- package/dist/capture/sensor-raw-frame.d.ts.map +0 -1
- package/dist/capture/sensor-raw-producer.d.ts.map +0 -1
- package/dist/capture/simulated-capture.d.ts.map +0 -1
- package/dist/color/capture-color.d.ts.map +0 -1
- package/dist/color/sensor-color-development.d.ts.map +0 -1
- package/dist/color/srgb-icc.d.ts.map +0 -1
- package/dist/color/srgb-transfer.d.ts.map +0 -1
- package/dist/color/white-balance.d.ts.map +0 -1
- package/dist/composition/image-formation-plan.d.ts.map +0 -1
- package/dist/composition/plan-consumer.d.ts.map +0 -1
- package/dist/core/calculation-result.d.ts.map +0 -1
- package/dist/core/canonical-json.d.ts.map +0 -1
- package/dist/core/configuration-error.d.ts.map +0 -1
- package/dist/core/evidence-provenance.d.ts.map +0 -1
- package/dist/core/image-formation.d.ts.map +0 -1
- package/dist/core/owned-data.d.ts.map +0 -1
- package/dist/core/record-validation.d.ts.map +0 -1
- package/dist/core/scientific-assurance.d.ts.map +0 -1
- package/dist/core/spectral-composition.d.ts.map +0 -1
- package/dist/core/spectral.d.ts.map +0 -1
- package/dist/core/validation.d.ts.map +0 -1
- package/dist/core/version.d.ts.map +0 -1
- package/dist/equipment/exposure-capabilities.d.ts.map +0 -1
- package/dist/equipment/generic-tier-assets.d.ts.map +0 -1
- package/dist/equipment/generic-tier-presets.d.ts.map +0 -1
- package/dist/equipment/iso-capabilities.d.ts.map +0 -1
- package/dist/equipment/metering-capabilities.d.ts.map +0 -1
- package/dist/equipment/release-capabilities.d.ts.map +0 -1
- package/dist/exposure/exposure-duration-control.d.ts.map +0 -1
- package/dist/exposure/exposure-mode-resolver.d.ts.map +0 -1
- package/dist/exposure/exposure.d.ts.map +0 -1
- package/dist/exposure/flash.d.ts.map +0 -1
- package/dist/exposure/metering-scene-radiance.d.ts.map +0 -1
- package/dist/exposure/metering-target.d.ts.map +0 -1
- package/dist/exposure/metering-temporal.d.ts.map +0 -1
- package/dist/exposure/metering.d.ts.map +0 -1
- package/dist/exposure/program-line.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/motion/camera-rotation.d.ts.map +0 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +0 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +0 -1
- package/dist/motion/capture-rotation-trajectory.d.ts.map +0 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +0 -1
- package/dist/motion/extended-object-projection.d.ts.map +0 -1
- package/dist/motion/projected-motion.d.ts.map +0 -1
- package/dist/optics/aperture.d.ts.map +0 -1
- package/dist/optics/circle-of-confusion.d.ts.map +0 -1
- package/dist/optics/complex-pupil-psf.d.ts.map +0 -1
- package/dist/optics/depth-of-field.d.ts.map +0 -1
- package/dist/optics/diffraction.d.ts.map +0 -1
- package/dist/optics/focus-breathing.d.ts.map +0 -1
- package/dist/optics/focus-state.d.ts.map +0 -1
- package/dist/optics/front-of-lens-filter.d.ts.map +0 -1
- package/dist/optics/illumination-vignetting.d.ts.map +0 -1
- package/dist/optics/lateral-chromatic-aberration.d.ts.map +0 -1
- package/dist/optics/lens-psf-profile.d.ts.map +0 -1
- package/dist/optics/polygon-diffraction.d.ts.map +0 -1
- package/dist/optics/profile-contract.d.ts.map +0 -1
- package/dist/optics/psf-foundation.d.ts.map +0 -1
- package/dist/optics/radial-distortion.d.ts.map +0 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts.map +0 -1
- package/dist/optics/scene-to-sensor-quadrature.d.ts.map +0 -1
- package/dist/optics/sensor-aperture-rays.d.ts.map +0 -1
- package/dist/optics/sensor-environment-query.d.ts.map +0 -1
- package/dist/optics/sensor-psf-quadrature.d.ts.map +0 -1
- package/dist/optics/sensor-psf-support.d.ts.map +0 -1
- package/dist/optics/stray-light.d.ts.map +0 -1
- package/dist/optics/thin-lens.d.ts.map +0 -1
- package/dist/output/capture-corrected-sdr.d.ts.map +0 -1
- package/dist/output/capture-geometry.d.ts.map +0 -1
- package/dist/output/capture-sdr.d.ts.map +0 -1
- package/dist/output/crop.d.ts.map +0 -1
- package/dist/output/geometric-transforms.d.ts.map +0 -1
- package/dist/output/lens-corrections.d.ts.map +0 -1
- package/dist/output/native-capture-sdr.d.ts.map +0 -1
- package/dist/output/print-contrast-reference.d.ts.map +0 -1
- package/dist/output/print-detail.d.ts.map +0 -1
- package/dist/output/print-jpeg.d.ts.map +0 -1
- package/dist/output/print-plan.d.ts.map +0 -1
- package/dist/output/print-region-statistics.d.ts.map +0 -1
- package/dist/output/sdr-rendering.d.ts.map +0 -1
- package/dist/output/subject-framing-crop.d.ts.map +0 -1
- package/dist/schema/camera.d.ts.map +0 -1
- package/dist/schema/camera.js +0 -3
- package/dist/schema/camera.js.map +0 -1
- package/dist/schema/illumination-spectral.d.ts.map +0 -1
- package/dist/schema/illumination-temporal.d.ts.map +0 -1
- package/dist/schema/illumination.d.ts.map +0 -1
- package/dist/schema/scene-radiance-temporal.d.ts.map +0 -1
- package/dist/schema/scene-radiance.d.ts.map +0 -1
- package/dist/schema/scene.d.ts.map +0 -1
- package/dist/schema/scene.js +0 -3
- package/dist/schema/scene.js.map +0 -1
- package/dist/schema/validation.d.ts.map +0 -1
- package/dist/sensor/accumulated-charge.d.ts.map +0 -1
- package/dist/sensor/architecture.d.ts.map +0 -1
- package/dist/sensor/camera-saturation-capacity.d.ts.map +0 -1
- package/dist/sensor/capture-color-sampling-binding.d.ts.map +0 -1
- package/dist/sensor/capture-mode-timing.d.ts.map +0 -1
- package/dist/sensor/capture-mode.d.ts.map +0 -1
- package/dist/sensor/color-sampling.d.ts.map +0 -1
- package/dist/sensor/constant-rate-temporal-integration.d.ts.map +0 -1
- package/dist/sensor/dark-current.d.ts.map +0 -1
- package/dist/sensor/environment-photo-signal.d.ts.map +0 -1
- package/dist/sensor/eqe-electron-rate.d.ts.map +0 -1
- package/dist/sensor/eqe-local-exposure.d.ts.map +0 -1
- package/dist/sensor/eqe-temporal-exposure.d.ts.map +0 -1
- package/dist/sensor/exposure-window.d.ts.map +0 -1
- package/dist/sensor/iso-signal-chain.d.ts.map +0 -1
- package/dist/sensor/local-exposure-binding.d.ts.map +0 -1
- package/dist/sensor/optical-stack.d.ts.map +0 -1
- package/dist/sensor/photon-energy.d.ts.map +0 -1
- package/dist/sensor/physical-charge-capacity.d.ts.map +0 -1
- package/dist/sensor/pixel-pitch.d.ts.map +0 -1
- package/dist/sensor/radiometry-readiness.d.ts.map +0 -1
- package/dist/sensor/raw-readout.d.ts.map +0 -1
- package/dist/sensor/raw-reconstruction.d.ts.map +0 -1
- package/dist/sensor/readout-exposure-linkage.d.ts.map +0 -1
- package/dist/sensor/readout-timing.d.ts.map +0 -1
- package/dist/sensor/response-application-compatibility.d.ts.map +0 -1
- package/dist/sensor/response-operating-range.d.ts.map +0 -1
- package/dist/sensor/responsivity-photocurrent.d.ts.map +0 -1
- package/dist/sensor/sampling-aperture.d.ts.map +0 -1
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +0 -1
- package/dist/sensor/sensor-geometry.d.ts.map +0 -1
- package/dist/sensor/signal-noise.d.ts.map +0 -1
- package/dist/sensor/spatial-sample-reduction.d.ts.map +0 -1
- package/dist/sensor/spatial-sampling-quadrature.d.ts.map +0 -1
- package/dist/sensor/spatio-spectral-reduction.d.ts.map +0 -1
- package/dist/sensor/spectral-coverage.d.ts.map +0 -1
- package/dist/sensor/spectral-quadrature.d.ts.map +0 -1
- package/dist/sensor/spectral-response.d.ts.map +0 -1
- package/dist/sensor/temporal-eqe-sum.d.ts.map +0 -1
- package/dist/sensor/temporal-photo-signal.d.ts.map +0 -1
- package/dist/sensor/temporal-sample-binding.d.ts.map +0 -1
- package/dist/simulation/poc-simulation.d.ts.map +0 -1
- package/dist/stabilization/camera-shake.d.ts.map +0 -1
- package/dist/stabilization/system.d.ts.map +0 -1
- package/docs/API_STYLE.md +0 -235
- package/docs/ARCHITECTURE.md +0 -356
- package/docs/AUTOMATION_COORDINATION.md +0 -190
- package/docs/CAPTURE_COLOR.md +0 -25
- package/docs/CAPTURE_CORRECTED_SDR.md +0 -25
- package/docs/CAPTURE_EXPORT_METADATA.md +0 -27
- package/docs/CAPTURE_SDR.md +0 -22
- package/docs/DENSE_PUPIL_QUALIFICATION.md +0 -121
- package/docs/DEVELOPERS.md +0 -68
- package/docs/DIGITAL_OPTICS_FOUNDATION.md +0 -69
- package/docs/ENVIRONMENT_RAW_CAPTURE.md +0 -208
- package/docs/EXPORT_ACCEPTANCE.md +0 -133
- package/docs/GENERIC_TIER_PRESETS.md +0 -269
- package/docs/GEOMETRIC_PREPARATION_REUSE.md +0 -141
- package/docs/IMAGE_FORMATION.md +0 -247
- package/docs/LINEAR_CAPTURE_ENCODING.md +0 -25
- package/docs/MOTION_AND_SIGNAL.md +0 -250
- package/docs/NATIVE_CAPTURE_SDR.md +0 -70
- package/docs/NATIVE_CAPTURE_SDR_REVIEW.md +0 -37
- package/docs/NATIVE_CAPTURE_SDR_VALIDATION.md +0 -34
- package/docs/NATIVE_RAW_AND_PRINT.md +0 -54
- package/docs/NUMERICAL_CORRECTNESS.md +0 -191
- package/docs/PERFORMANCE_BASELINE.md +0 -56
- package/docs/PHOTOGRAPHIC_EXPORT.md +0 -206
- package/docs/PHYSICS_FOUNDATION.md +0 -426
- package/docs/POC_API.md +0 -278
- package/docs/POC_PROJECTION_PLATFORM_REFERENCE.md +0 -12
- package/docs/POC_PROJECTION_REUSE.md +0 -124
- package/docs/PRINT_195_196_REVIEW.md +0 -93
- package/docs/PRINT_196_ENGINE_ACCEPTANCE.md +0 -45
- package/docs/PRINT_CONTRAST_REFERENCE.md +0 -43
- package/docs/PRINT_DETAIL_ASSESSMENT.md +0 -81
- package/docs/PRINT_DETAIL_JPEG_EVIDENCE.md +0 -36
- package/docs/PRINT_DETAIL_SDR_EVIDENCE.md +0 -29
- package/docs/PRINT_DETAIL_VALIDATION.md +0 -36
- package/docs/PRINT_PLANNING.md +0 -75
- package/docs/PRINT_REGION_STATISTICS.md +0 -38
- package/docs/PROCESSED_OUTPUT.md +0 -157
- package/docs/PRODUCTION_COMPOSITION.md +0 -373
- package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +0 -131
- package/docs/PROVENANCE.md +0 -115
- package/docs/PSF_FOUNDATION.md +0 -165
- package/docs/RAW_FRAME_ENVELOPE.md +0 -56
- package/docs/RAW_FRAME_RECONSTRUCTION.md +0 -30
- package/docs/RELEASE_1_0.md +0 -66
- package/docs/RELEASE_1_0_1.md +0 -61
- package/docs/RELEASE_1_1_0.md +0 -25
- package/docs/RELEASE_1_2_0.md +0 -51
- package/docs/RELEASE_1_3_0.md +0 -15
- package/docs/RELEASE_1_4_0.md +0 -23
- package/docs/RELEASE_1_5_0.md +0 -105
- package/docs/RELEASE_AUDIT.md +0 -39
- package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +0 -298
- package/docs/SCENE_SENSOR_QUADRATURE.md +0 -98
- package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +0 -86
- package/docs/SCIENTIFIC_ASSURANCE.md +0 -280
- package/docs/SCIENTIFIC_CONFORMANCE.md +0 -83
- package/docs/SDR_RENDERING.md +0 -33
- package/docs/SENSOR_APERTURE_RAYS.md +0 -23
- package/docs/SENSOR_ENVIRONMENT_QUERY.md +0 -86
- package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +0 -104
- package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +0 -74
- package/docs/SENSOR_PSF_QUADRATURE.md +0 -90
- package/docs/SENSOR_RAW_FRAME.md +0 -20
- package/docs/SENSOR_RAW_PRODUCER.md +0 -77
- package/docs/SEPARABLE_EMISSION_DRAFT.md +0 -103
- package/docs/SIGNAL_CONFORMANCE.md +0 -23
- package/docs/SIMULATED_CAPTURE.md +0 -65
- package/docs/STABILIZATION.md +0 -234
- package/docs/TEMPORAL_PHOTO_RAW.md +0 -83
- package/docs/TIER_ACCEPTANCE.md +0 -129
- package/docs/TIER_PRESET_ACCEPTANCE.md +0 -59
- package/docs/V1_COMPOSITION_MAP.md +0 -123
- package/docs/V1_HELPER_REUSE_REVIEW.md +0 -60
- package/docs/V1_PERFORMANCE_DISPOSITION.md +0 -88
- package/docs/benchmarks/2026-10-01-main-baseline.json +0 -694
- package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +0 -2190
- package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +0 -2423
- package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +0 -210
- package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +0 -187
- package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +0 -756
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +0 -711
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +0 -711
- package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +0 -885
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +0 -868
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +0 -868
- package/docs/licenses/castleCSF-MIT.txt +0 -21
- package/docs/validation/dense-pupil-2026-10-06/pilot.jsonl +0 -6
- package/docs/validation/documentation-fragments.json +0 -212
- package/docs/validation/native-capture-sdr-darwin-arm64-node26-review.jsonl +0 -4
- package/docs/validation/native-capture-sdr-darwin-arm64.jsonl +0 -3
- package/docs/validation/native-raw-print-2026-10-04/fractional-asymmetric-crop.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/gray-ramp.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/linear-area-checker.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/manifest.json +0 -218
- package/docs/validation/native-raw-print-2026-10-04/megapixel-native.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/native-color.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel-validation.json +0 -9
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json +0 -29
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.codes.u16le.gz +0 -0
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.jpg +0 -0
- package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.rgb.gz +0 -0
- package/docs/validation/native-raw-print-2026-10-04/srgb.icc +0 -0
- package/docs/validation/native-raw-print-2026-10-04/validation.json +0 -41
- package/docs/validation/print-196-candidate-capabilities.json +0 -28
- package/docs/validation/print-196-candidate-evidence.json +0 -356
- package/docs/validation/print-196-engine-acceptance.json +0 -81
- package/docs/validation/print-detail-capabilities.json +0 -103
- package/docs/validation/print-detail-jpeg-evidence.json +0 -116
- package/docs/validation/print-detail-sdr-evidence.json +0 -81
- package/docs/validation/release-audit-inventory.json +0 -1306
- package/docs/validation/tier-acceptance-report-v1.json +0 -2538
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* CIE colour-matching functions (CMFs) and spectrum → CIE XYZ integration.
|
|
4
|
+
*
|
|
5
|
+
* Two CMF sources are supported:
|
|
6
|
+
* 1. The engine's own analytic APPROXIMATION of the CIE 1931 2° observer. Each of x̄, ȳ, z̄ is a sum
|
|
7
|
+
* of split Gaussian lobes (a lobe has an amplitude, a centre, and separate widths below and above
|
|
8
|
+
* the centre): three lobes for x̄, two each for ȳ and z̄. The engine fitted the coefficients itself
|
|
9
|
+
* by non-negative least squares to the CIE 1931 2° table (DOI 10.25039/CIE.DS.xvudnb9b) at 1 nm
|
|
10
|
+
* from 360 to 830 nm, with `scripts/fit-cie-1931-cmf.mjs`. The table is used only when the fit is
|
|
11
|
+
* run and is not stored in the repository. Measured fit error (maximum absolute / RMS): x̄ 0.0122 /
|
|
12
|
+
* 0.00426, ȳ 0.00733 / 0.00265, z̄ 0.0221 / 0.00397; see docs/COLORIMETRY.md.
|
|
13
|
+
* 2. Caller-supplied tabulated CMFs, for example the official CIE datasets. The CIE
|
|
14
|
+
* distributes those under CC BY-SA 4.0, so they are NOT bundled with this Apache-2.0
|
|
15
|
+
* package. Tables are linearly interpolated. Outside their declared range they throw
|
|
16
|
+
* (fail closed); there is no extrapolation.
|
|
17
|
+
*
|
|
18
|
+
* Integration uses explicit wavelength quadrature nodes `{wavelengthNanometers,
|
|
19
|
+
* wavelengthMeasureNanometers}`. Nodes from `calculateSensorSpectralQuadrature()` have the
|
|
20
|
+
* same shape and can be passed directly. X = k Σ S(λᵢ) R(λᵢ) x̄(λᵢ) Δλᵢ: a quadrature of the tristimulus
|
|
21
|
+
* integral X = ∫ L(λ) x̄(λ) dλ with stimulus L = S·R (Wyman, Sloan & Shirley 2013, JCGT 2(2), Eq. 1, free;
|
|
22
|
+
* also CIE 15:2018 §7.1). The normalization k and the quadrature nodes are explicit choices.
|
|
23
|
+
* @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.
|
|
24
|
+
*/
|
|
25
|
+
import { approximationResult, calculatedResult } from "../core/calculation-result.js";
|
|
26
|
+
import { InvalidScientificInputError } from "../core/validation.js";
|
|
27
|
+
import { chromaticityOfXyz, requireFiniteNumber, requireFiniteResult, requirePositiveNumber, requireRecordValue } from "./colorimetry-math.js";
|
|
28
|
+
import { rejectUnknownFields, requireInputKeys } from "../core/record-validation.js";
|
|
29
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
30
|
+
export const COLORIMETRY_MODEL_VERSION = "2.0.0";
|
|
31
|
+
/** Upper bound on quadrature nodes per integration call. */
|
|
32
|
+
export const MAX_COLORIMETRIC_QUADRATURE_NODES = 100_000;
|
|
33
|
+
/** Upper bound on samples in a caller-supplied tabulated spectrum or CMF table. */
|
|
34
|
+
export const MAX_COLORIMETRIC_TABLE_SAMPLES = 100_000;
|
|
35
|
+
/** Wavelength domain over which the analytic CIE 1931 fit is accepted (the domain it was fitted on). */
|
|
36
|
+
export const ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS = Object.freeze({ minimum: 360, maximum: 830 });
|
|
37
|
+
const X_LOBES = [[0.375817, 441.559, 15.3475, 94.5181], [-0.322164, 497.643, 23.3464, 30.5255], [0.968784, 600.86, 33.6528, 29.7704]];
|
|
38
|
+
const Y_LOBES = [[0.285798, 530.874, 16.3146, 31.077], [0.820879, 568.79, 46.8848, 40.4965]];
|
|
39
|
+
const Z_LOBES = [[1.2165, 436.962, 11.8408, 35.9867], [0.681263, 459.034, 25.9609, 13.7926]];
|
|
40
|
+
function lobes(wavelength, set) {
|
|
41
|
+
let sum = 0;
|
|
42
|
+
for (const [amplitude, centre, sigmaBelow, sigmaAbove] of set) {
|
|
43
|
+
const t = (wavelength - centre) / (wavelength < centre ? sigmaBelow : sigmaAbove);
|
|
44
|
+
sum += amplitude * Math.exp(-0.5 * t * t);
|
|
45
|
+
}
|
|
46
|
+
return sum;
|
|
47
|
+
}
|
|
48
|
+
function requireWavelengthIn(wavelength, range, what) {
|
|
49
|
+
if (!Number.isFinite(wavelength) || wavelength < range.minimum || wavelength > range.maximum) {
|
|
50
|
+
throw new InvalidScientificInputError(what + " is outside its declared wavelength range [" + range.minimum + ", " + range.maximum + "] nm.");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Evaluates the engine's multi-lobe analytic approximation of the CIE 1931 2° colour-matching
|
|
55
|
+
* functions at one wavelength (nm, standard-air wavelength as in the CIE tables). Approximation:
|
|
56
|
+
* see the module notes for the measured fit error. The values are non-negative over the domain.
|
|
57
|
+
*/
|
|
58
|
+
export function estimateCie1931ColorMatchingFunctions(wavelengthNanometers) {
|
|
59
|
+
requireWavelengthIn(wavelengthNanometers, ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS, "Analytic CIE 1931 CMF wavelength");
|
|
60
|
+
return { x: lobes(wavelengthNanometers, X_LOBES), y: lobes(wavelengthNanometers, Y_LOBES), z: lobes(wavelengthNanometers, Z_LOBES) };
|
|
61
|
+
}
|
|
62
|
+
function parseIncreasingSamples(samples, path, sampleKeys, parseValue) {
|
|
63
|
+
if (!Array.isArray(samples) || samples.length < 2 || samples.length > MAX_COLORIMETRIC_TABLE_SAMPLES) {
|
|
64
|
+
throw new InvalidScientificInputError(path + " must contain between 2 and " + MAX_COLORIMETRIC_TABLE_SAMPLES + " samples.");
|
|
65
|
+
}
|
|
66
|
+
const parsed = [];
|
|
67
|
+
let previous = -Infinity;
|
|
68
|
+
samples.forEach((raw, i) => {
|
|
69
|
+
const samplePath = path + "[" + i + "]";
|
|
70
|
+
const record = requireRecordValue(raw, samplePath);
|
|
71
|
+
rejectUnknownFields(record, sampleKeys, samplePath);
|
|
72
|
+
const wavelength = requirePositiveNumber(record.wavelengthNanometers, samplePath + ".wavelengthNanometers");
|
|
73
|
+
if (!(wavelength > previous))
|
|
74
|
+
throw new InvalidScientificInputError(path + " wavelengths must be strictly increasing.");
|
|
75
|
+
previous = wavelength;
|
|
76
|
+
parsed.push(parseValue(record, samplePath));
|
|
77
|
+
});
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
/** Finds the bracketing interval for linear interpolation (binary search). */
|
|
81
|
+
function bracket(samples, wavelength) {
|
|
82
|
+
let lo = 0;
|
|
83
|
+
let hi = samples.length - 1;
|
|
84
|
+
while (hi - lo > 1) {
|
|
85
|
+
const mid = (lo + hi) >> 1;
|
|
86
|
+
if (samples[mid].wavelengthNanometers <= wavelength)
|
|
87
|
+
lo = mid;
|
|
88
|
+
else
|
|
89
|
+
hi = mid;
|
|
90
|
+
}
|
|
91
|
+
const a = samples[lo].wavelengthNanometers;
|
|
92
|
+
const b = samples[hi].wavelengthNanometers;
|
|
93
|
+
return [lo, (wavelength - a) / (b - a)];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validates a colour-matching-function source once for repeated evaluation.
|
|
97
|
+
* Tabulated values may be signed only for `caller-defined` observers; CIE observers
|
|
98
|
+
* require non-negative values.
|
|
99
|
+
*/
|
|
100
|
+
export function prepareColorMatchingFunctions(source) {
|
|
101
|
+
const record = requireRecordValue(source, "colorMatchingFunctions");
|
|
102
|
+
rejectUnknownFields(record, ["kind", "observer", "datasetId", "samples"], "colorMatchingFunctions");
|
|
103
|
+
if (record.kind === "analytic-cie-1931-multi-lobe-fit") {
|
|
104
|
+
rejectUnknownFields(record, ["kind"], "colorMatchingFunctions");
|
|
105
|
+
return Object.freeze({
|
|
106
|
+
observer: "cie-1931-2-degree",
|
|
107
|
+
sourceKind: "analytic-cie-1931-multi-lobe-fit",
|
|
108
|
+
datasetId: "photivra-cie-1931-multi-lobe-fit-2026-10-17",
|
|
109
|
+
scientificStatus: "approximation",
|
|
110
|
+
wavelengthRangeNanometers: { ...ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS },
|
|
111
|
+
evaluate: estimateCie1931ColorMatchingFunctions
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (record.kind !== "tabulated")
|
|
115
|
+
throw new InvalidConfigurationError("colorMatchingFunctions.kind is not supported.");
|
|
116
|
+
rejectUnknownFields(record, ["kind", "observer", "datasetId", "samples"], "colorMatchingFunctions");
|
|
117
|
+
const observer = record.observer;
|
|
118
|
+
if (observer !== "cie-1931-2-degree" && observer !== "cie-1964-10-degree" && observer !== "caller-defined") {
|
|
119
|
+
throw new InvalidConfigurationError("colorMatchingFunctions.observer is not supported.");
|
|
120
|
+
}
|
|
121
|
+
if (typeof record.datasetId !== "string" || record.datasetId.trim().length === 0) {
|
|
122
|
+
throw new InvalidConfigurationError("colorMatchingFunctions.datasetId must be a non-empty string.");
|
|
123
|
+
}
|
|
124
|
+
const signed = observer === "caller-defined";
|
|
125
|
+
const samples = parseIncreasingSamples(record.samples, "colorMatchingFunctions.samples", ["wavelengthNanometers", "xBar", "yBar", "zBar"], (s, p) => {
|
|
126
|
+
const v = (key) => {
|
|
127
|
+
const n = requireFiniteNumber(s[key], p + "." + key);
|
|
128
|
+
if (!signed && n < 0)
|
|
129
|
+
throw new InvalidScientificInputError(p + "." + key + " must not be negative for a CIE observer.");
|
|
130
|
+
return n;
|
|
131
|
+
};
|
|
132
|
+
return { wavelengthNanometers: s.wavelengthNanometers, xBar: v("xBar"), yBar: v("yBar"), zBar: v("zBar") };
|
|
133
|
+
});
|
|
134
|
+
const range = { minimum: samples[0].wavelengthNanometers, maximum: samples[samples.length - 1].wavelengthNanometers };
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
observer,
|
|
137
|
+
sourceKind: "tabulated",
|
|
138
|
+
datasetId: record.datasetId.trim(),
|
|
139
|
+
scientificStatus: "caller-tabulated",
|
|
140
|
+
wavelengthRangeNanometers: range,
|
|
141
|
+
evaluate(wavelengthNanometers) {
|
|
142
|
+
requireWavelengthIn(wavelengthNanometers, range, "Tabulated CMF wavelength");
|
|
143
|
+
const [i, t] = bracket(samples, wavelengthNanometers);
|
|
144
|
+
const a = samples[i];
|
|
145
|
+
const b = samples[Math.min(i + 1, samples.length - 1)];
|
|
146
|
+
return { x: a.xBar + (b.xBar - a.xBar) * t, y: a.yBar + (b.yBar - a.yBar) * t, z: a.zBar + (b.zBar - a.zBar) * t };
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Validates a tabulated or functional spectrum (values must be finite; sign is not restricted). */
|
|
151
|
+
export function prepareColorimetricSpectrum(spectrum, path = "spectrum") {
|
|
152
|
+
const record = requireRecordValue(spectrum, path);
|
|
153
|
+
rejectUnknownFields(record, ["kind", "samples", "wavelengthRangeNanometers", "evaluate"], path);
|
|
154
|
+
if (record.kind === "function") {
|
|
155
|
+
rejectUnknownFields(record, ["kind", "wavelengthRangeNanometers", "evaluate"], path);
|
|
156
|
+
const range = requireRecordValue(record.wavelengthRangeNanometers, path + ".wavelengthRangeNanometers");
|
|
157
|
+
rejectUnknownFields(range, ["minimum", "maximum"], path + ".wavelengthRangeNanometers");
|
|
158
|
+
const minimum = requirePositiveNumber(range.minimum, path + ".wavelengthRangeNanometers.minimum");
|
|
159
|
+
const maximum = requirePositiveNumber(range.maximum, path + ".wavelengthRangeNanometers.maximum");
|
|
160
|
+
if (!(minimum < maximum))
|
|
161
|
+
throw new InvalidScientificInputError(path + ".wavelengthRangeNanometers.minimum must be less than maximum.");
|
|
162
|
+
if (typeof record.evaluate !== "function")
|
|
163
|
+
throw new InvalidConfigurationError(path + ".evaluate must be a function.");
|
|
164
|
+
const evaluate = record.evaluate;
|
|
165
|
+
const declared = { minimum, maximum };
|
|
166
|
+
return {
|
|
167
|
+
wavelengthRangeNanometers: declared,
|
|
168
|
+
evaluate(w) {
|
|
169
|
+
requireWavelengthIn(w, declared, path);
|
|
170
|
+
const v = evaluate(w);
|
|
171
|
+
if (typeof v !== "number" || !Number.isFinite(v))
|
|
172
|
+
throw new InvalidScientificInputError(path + " evaluated to a non-finite value.");
|
|
173
|
+
return v;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (record.kind !== "tabulated")
|
|
178
|
+
throw new InvalidConfigurationError(path + ".kind is not supported.");
|
|
179
|
+
rejectUnknownFields(record, ["kind", "samples"], path);
|
|
180
|
+
const samples = parseIncreasingSamples(record.samples, path + ".samples", ["wavelengthNanometers", "value"], (s, p) => ({
|
|
181
|
+
wavelengthNanometers: s.wavelengthNanometers,
|
|
182
|
+
value: requireFiniteNumber(s.value, p + ".value")
|
|
183
|
+
}));
|
|
184
|
+
const range = { minimum: samples[0].wavelengthNanometers, maximum: samples[samples.length - 1].wavelengthNanometers };
|
|
185
|
+
return {
|
|
186
|
+
wavelengthRangeNanometers: range,
|
|
187
|
+
evaluate(w) {
|
|
188
|
+
requireWavelengthIn(w, range, path);
|
|
189
|
+
const [i, t] = bracket(samples, w);
|
|
190
|
+
const a = samples[i].value;
|
|
191
|
+
const b = samples[Math.min(i + 1, samples.length - 1)].value;
|
|
192
|
+
return a + (b - a) * t;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Builds deterministic uniform midpoint wavelength nodes covering the range. Every
|
|
198
|
+
* node carries its d-lambda measure in nm; the measures sum to the range width.
|
|
199
|
+
*/
|
|
200
|
+
export function createColorimetricMidpointQuadrature(input) {
|
|
201
|
+
requireInputKeys(input, "createColorimetricMidpointQuadrature", ["wavelengthRangeNanometers", "maximumSubintervalWidthNanometers"]);
|
|
202
|
+
const range = requireRecordValue(input.wavelengthRangeNanometers, "wavelengthRangeNanometers");
|
|
203
|
+
rejectUnknownFields(range, ["minimum", "maximum"], "wavelengthRangeNanometers");
|
|
204
|
+
const minimum = requirePositiveNumber(range.minimum, "wavelengthRangeNanometers.minimum");
|
|
205
|
+
const maximum = requirePositiveNumber(range.maximum, "wavelengthRangeNanometers.maximum");
|
|
206
|
+
if (!(minimum < maximum))
|
|
207
|
+
throw new InvalidScientificInputError("wavelengthRangeNanometers.minimum must be less than maximum.");
|
|
208
|
+
const width = requirePositiveNumber(input.maximumSubintervalWidthNanometers, "maximumSubintervalWidthNanometers");
|
|
209
|
+
const count = Math.ceil((maximum - minimum) / width - 1e-9);
|
|
210
|
+
if (count > MAX_COLORIMETRIC_QUADRATURE_NODES)
|
|
211
|
+
throw new InvalidScientificInputError("Quadrature would exceed " + MAX_COLORIMETRIC_QUADRATURE_NODES + " nodes.");
|
|
212
|
+
const step = (maximum - minimum) / count;
|
|
213
|
+
const nodes = [];
|
|
214
|
+
for (let i = 0; i < count; i++)
|
|
215
|
+
nodes.push({ wavelengthNanometers: minimum + (i + 0.5) * step, wavelengthMeasureNanometers: step });
|
|
216
|
+
return nodes;
|
|
217
|
+
}
|
|
218
|
+
/** Validates explicit quadrature nodes (positive wavelengths and positive measures). */
|
|
219
|
+
export function parseColorimetricQuadratureNodes(nodes) {
|
|
220
|
+
if (!Array.isArray(nodes) || nodes.length === 0 || nodes.length > MAX_COLORIMETRIC_QUADRATURE_NODES) {
|
|
221
|
+
throw new InvalidScientificInputError("quadratureNodes must contain between 1 and " + MAX_COLORIMETRIC_QUADRATURE_NODES + " nodes.");
|
|
222
|
+
}
|
|
223
|
+
return nodes.map((raw, i) => {
|
|
224
|
+
const r = requireRecordValue(raw, "quadratureNodes[" + i + "]");
|
|
225
|
+
rejectUnknownFields(r, ["wavelengthNanometers", "wavelengthMeasureNanometers"], "quadratureNodes[" + i + "]");
|
|
226
|
+
return {
|
|
227
|
+
wavelengthNanometers: requirePositiveNumber(r.wavelengthNanometers, "quadratureNodes[" + i + "].wavelengthNanometers"),
|
|
228
|
+
wavelengthMeasureNanometers: requirePositiveNumber(r.wavelengthMeasureNanometers, "quadratureNodes[" + i + "].wavelengthMeasureNanometers")
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
export function sampleColorimetricBasis(quadratureNodes, spectralDistribution, cmf) {
|
|
233
|
+
const nodes = parseColorimetricQuadratureNodes(quadratureNodes);
|
|
234
|
+
const n = nodes.length;
|
|
235
|
+
const weights = new Float64Array(n), xBar = new Float64Array(n), yBar = new Float64Array(n), zBar = new Float64Array(n);
|
|
236
|
+
for (let i = 0; i < n; i++) {
|
|
237
|
+
const node = nodes[i];
|
|
238
|
+
const c = cmf.evaluate(node.wavelengthNanometers);
|
|
239
|
+
weights[i] = spectralDistribution.evaluate(node.wavelengthNanometers) * node.wavelengthMeasureNanometers;
|
|
240
|
+
xBar[i] = c.x;
|
|
241
|
+
yBar[i] = c.y;
|
|
242
|
+
zBar[i] = c.z;
|
|
243
|
+
}
|
|
244
|
+
return { nodes, weights, xBar, yBar, zBar, cmf };
|
|
245
|
+
}
|
|
246
|
+
export function sampleFactor(basis, factor) {
|
|
247
|
+
const out = new Float64Array(basis.nodes.length);
|
|
248
|
+
for (let i = 0; i < out.length; i++)
|
|
249
|
+
out[i] = factor === undefined ? 1 : factor.evaluate(basis.nodes[i].wavelengthNanometers);
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
export function integrateSampledXyz(basis, factor) {
|
|
253
|
+
let x = 0, y = 0, z = 0;
|
|
254
|
+
for (let i = 0; i < factor.length; i++) {
|
|
255
|
+
const w = basis.weights[i] * factor[i];
|
|
256
|
+
x += w * basis.xBar[i];
|
|
257
|
+
y += w * basis.yBar[i];
|
|
258
|
+
z += w * basis.zBar[i];
|
|
259
|
+
}
|
|
260
|
+
return { x, y, z };
|
|
261
|
+
}
|
|
262
|
+
export function resolveNormalizationFactor(normalization, unnormalizedWhiteY) {
|
|
263
|
+
const r = requireRecordValue(normalization, "normalization");
|
|
264
|
+
if (r.kind === "white-luminance-one") {
|
|
265
|
+
if (!(unnormalizedWhiteY > 0) || !Number.isFinite(unnormalizedWhiteY)) {
|
|
266
|
+
throw new InvalidScientificInputError("White-luminance normalization requires a positive integrated Y of the spectral distribution.");
|
|
267
|
+
}
|
|
268
|
+
return 1 / unnormalizedWhiteY;
|
|
269
|
+
}
|
|
270
|
+
if (r.kind === "scale")
|
|
271
|
+
return requirePositiveNumber(r.factor, "normalization.factor");
|
|
272
|
+
throw new InvalidConfigurationError("normalization.kind is not supported.");
|
|
273
|
+
}
|
|
274
|
+
function scaleXyz(xyz, k) {
|
|
275
|
+
return { x: xyz.x * k, y: xyz.y * k, z: xyz.z * k };
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Integrates a spectrum (optionally multiplied by a reflectance/transmittance factor)
|
|
279
|
+
* against colour-matching functions with caller-explicit quadrature (the tristimulus integral of
|
|
280
|
+
* Wyman, Sloan & Shirley 2013, Eq. 1; also CIE 15:2018 §7).
|
|
281
|
+
* Provenance is `approximation` for the analytic CMF fit and `calculated` for
|
|
282
|
+
* caller-tabulated CMFs. Either way, the caller chooses the quadrature.
|
|
283
|
+
*/
|
|
284
|
+
export function integrateSpectrumToXyz(input) {
|
|
285
|
+
requireInputKeys(input, "integrateSpectrumToXyz", ["quadratureNodes", "spectralDistribution", "spectralFactor", "colorMatchingFunctions", "normalization"]);
|
|
286
|
+
const cmf = prepareColorMatchingFunctions(input.colorMatchingFunctions);
|
|
287
|
+
const distribution = prepareColorimetricSpectrum(input.spectralDistribution, "spectralDistribution");
|
|
288
|
+
const factor = input.spectralFactor === undefined ? undefined : prepareColorimetricSpectrum(input.spectralFactor, "spectralFactor");
|
|
289
|
+
const basis = sampleColorimetricBasis(input.quadratureNodes, distribution, cmf);
|
|
290
|
+
const rawWhite = integrateSampledXyz(basis, sampleFactor(basis, undefined));
|
|
291
|
+
const rawSample = factor === undefined ? rawWhite : integrateSampledXyz(basis, sampleFactor(basis, factor));
|
|
292
|
+
const k = resolveNormalizationFactor(input.normalization, rawWhite.y);
|
|
293
|
+
const xyz = scaleXyz(rawSample, k);
|
|
294
|
+
const whiteXyz = scaleXyz(rawWhite, k);
|
|
295
|
+
requireFiniteResult([xyz.x, xyz.y, xyz.z, whiteXyz.x, whiteXyz.y, whiteXyz.z], "Spectral integration");
|
|
296
|
+
const sum = xyz.x + xyz.y + xyz.z;
|
|
297
|
+
const value = {
|
|
298
|
+
xyz, whiteXyz, chromaticity: sum > 0 ? chromaticityOfXyz(xyz) : null, normalizationFactor: k,
|
|
299
|
+
observer: cmf.observer, nodeCount: basis.nodes.length
|
|
300
|
+
};
|
|
301
|
+
const assumptions = [
|
|
302
|
+
"Tristimulus integral evaluated as Σ S(λ)·R(λ)·CMF(λ)·Δλ over the caller's quadrature nodes",
|
|
303
|
+
"Caller owns quadrature convergence and wavelength coverage; tabulated inputs are linearly interpolated and fail closed outside their range"
|
|
304
|
+
];
|
|
305
|
+
return cmf.scientificStatus === "approximation"
|
|
306
|
+
? approximationResult(value, "cie-xyz-spectral-integration-analytic-cmf", COLORIMETRY_MODEL_VERSION, [...assumptions, "CIE 1931 2° CMFs from the engine's multi-lobe analytic fit (measured max abs CMF error 0.0122/0.00733/0.0221)"])
|
|
307
|
+
: calculatedResult(value, "cie-xyz-spectral-integration-tabulated-cmf", COLORIMETRY_MODEL_VERSION, [...assumptions, "Caller-supplied tabulated CMFs: " + cmf.datasetId]);
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=color-matching-functions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-matching-functions.js","sourceRoot":"","sources":["../../src/color/color-matching-functions.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * CIE colour-matching functions (CMFs) and spectrum → CIE XYZ integration.\n *\n * Two CMF sources are supported:\n * 1. The engine's own analytic APPROXIMATION of the CIE 1931 2° observer. Each of x̄, ȳ, z̄ is a sum\n * of split Gaussian lobes (a lobe has an amplitude, a centre, and separate widths below and above\n * the centre): three lobes for x̄, two each for ȳ and z̄. The engine fitted the coefficients itself\n * by non-negative least squares to the CIE 1931 2° table (DOI 10.25039/CIE.DS.xvudnb9b) at 1 nm\n * from 360 to 830 nm, with `scripts/fit-cie-1931-cmf.mjs`. The table is used only when the fit is\n * run and is not stored in the repository. Measured fit error (maximum absolute / RMS): x̄ 0.0122 /\n * 0.00426, ȳ 0.00733 / 0.00265, z̄ 0.0221 / 0.00397; see docs/COLORIMETRY.md.\n * 2. Caller-supplied tabulated CMFs, for example the official CIE datasets. The CIE\n * distributes those under CC BY-SA 4.0, so they are NOT bundled with this Apache-2.0\n * package. Tables are linearly interpolated. Outside their declared range they throw\n * (fail closed); there is no extrapolation.\n *\n * Integration uses explicit wavelength quadrature nodes `{wavelengthNanometers,\n * wavelengthMeasureNanometers}`. Nodes from `calculateSensorSpectralQuadrature()` have the\n * same shape and can be passed directly. X = k Σ S(λᵢ) R(λᵢ) x̄(λᵢ) Δλᵢ: a quadrature of the tristimulus\n * integral X = ∫ L(λ) x̄(λ) dλ with stimulus L = S·R (Wyman, Sloan & Shirley 2013, JCGT 2(2), Eq. 1, free;\n * also CIE 15:2018 §7.1). The normalization k and the quadrature nodes are explicit choices.\n * @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.\n */\n\nimport { approximationResult, calculatedResult, type CalculationResult } from \"../core/calculation-result.js\";\nimport type { SpectralWavelengthRangeNanometers, SpectralWavelengthSample } from \"../core/spectral.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n chromaticityOfXyz,\n requireFiniteNumber,\n requireFiniteResult,\n requirePositiveNumber,\n requireRecordValue,\n type CieXyChromaticity,\n type CieXyzTristimulus\n} from \"./colorimetry-math.js\";\nimport { rejectUnknownFields, requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\nexport const COLORIMETRY_MODEL_VERSION = \"2.0.0\" as const;\n/** Upper bound on quadrature nodes per integration call. */\nexport const MAX_COLORIMETRIC_QUADRATURE_NODES = 100_000;\n/** Upper bound on samples in a caller-supplied tabulated spectrum or CMF table. */\nexport const MAX_COLORIMETRIC_TABLE_SAMPLES = 100_000;\n\n/** Wavelength domain over which the analytic CIE 1931 fit is accepted (the domain it was fitted on). */\nexport const ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS: Readonly<SpectralWavelengthRangeNanometers> = Object.freeze({ minimum: 360, maximum: 830 });\n\n/** One wavelength quadrature node; d-lambda is in nanometres. */\nexport interface ColorimetricQuadratureNode {\n wavelengthNanometers: number;\n wavelengthMeasureNanometers: number;\n}\n\n/** One tabulated spectral value at one wavelength. */\nexport interface ColorimetricSpectralSample extends SpectralWavelengthSample {\n value: number;\n}\n\n/**\n * A spectral distribution or spectral factor (reflectance, transmittance, relative SPD,\n * sensitivity).\n * - `tabulated` is the JSON form: strictly increasing wavelengths, linear interpolation, and an\n * error (fail closed) outside the table.\n * - `function` is an in-process evaluator (for example a Planckian SPD). It must be finite over\n * its declared range.\n */\nexport type ColorimetricSpectrum =\n | { kind: \"tabulated\"; samples: readonly ColorimetricSpectralSample[] }\n | { kind: \"function\"; wavelengthRangeNanometers: SpectralWavelengthRangeNanometers; evaluate: (wavelengthNanometers: number) => number };\n\n/** One tabulated colour-matching sample. */\nexport interface TabulatedColorMatchingSample extends SpectralWavelengthSample {\n xBar: number;\n yBar: number;\n zBar: number;\n}\n\nexport type ColorimetricObserver = \"cie-1931-2-degree\" | \"cie-1964-10-degree\" | \"caller-defined\";\n\n/** Selects a colour-matching-function source. */\nexport type ColorMatchingFunctionsSource =\n | { kind: \"analytic-cie-1931-multi-lobe-fit\" }\n | {\n kind: \"tabulated\";\n observer: ColorimetricObserver;\n /** Caller identity for the dataset (for example a DOI); recorded in provenance. */\n datasetId: string;\n samples: readonly TabulatedColorMatchingSample[];\n };\n\n/** Validated, reusable colour-matching functions. */\nexport interface PreparedColorMatchingFunctions {\n observer: ColorimetricObserver;\n sourceKind: ColorMatchingFunctionsSource[\"kind\"];\n datasetId: string;\n scientificStatus: \"approximation\" | \"caller-tabulated\";\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n /** x̄, ȳ, z̄ at one wavelength in nm; throws outside the declared range. */\n evaluate(wavelengthNanometers: number): CieXyzTristimulus;\n}\n\n// The engine's own fit (scripts/fit-cie-1931-cmf.mjs): per lobe the amplitude, the centre (nm),\n// and the standard deviation (nm) used below and above the centre.\ntype Lobe = readonly [amplitude: number, centreNanometers: number, sigmaBelowNanometers: number, sigmaAboveNanometers: number];\nconst X_LOBES: readonly Lobe[] = [[0.375817, 441.559, 15.3475, 94.5181], [-0.322164, 497.643, 23.3464, 30.5255], [0.968784, 600.86, 33.6528, 29.7704]];\nconst Y_LOBES: readonly Lobe[] = [[0.285798, 530.874, 16.3146, 31.077], [0.820879, 568.79, 46.8848, 40.4965]];\nconst Z_LOBES: readonly Lobe[] = [[1.2165, 436.962, 11.8408, 35.9867], [0.681263, 459.034, 25.9609, 13.7926]];\n\nfunction lobes(wavelength: number, set: readonly Lobe[]): number {\n let sum = 0;\n for (const [amplitude, centre, sigmaBelow, sigmaAbove] of set) {\n const t = (wavelength - centre) / (wavelength < centre ? sigmaBelow : sigmaAbove);\n sum += amplitude * Math.exp(-0.5 * t * t);\n }\n return sum;\n}\n\nfunction requireWavelengthIn(wavelength: number, range: SpectralWavelengthRangeNanometers, what: string): void {\n if (!Number.isFinite(wavelength) || wavelength < range.minimum || wavelength > range.maximum) {\n throw new InvalidScientificInputError(what + \" is outside its declared wavelength range [\" + range.minimum + \", \" + range.maximum + \"] nm.\");\n }\n}\n\n/**\n * Evaluates the engine's multi-lobe analytic approximation of the CIE 1931 2° colour-matching\n * functions at one wavelength (nm, standard-air wavelength as in the CIE tables). Approximation:\n * see the module notes for the measured fit error. The values are non-negative over the domain.\n */\nexport function estimateCie1931ColorMatchingFunctions(wavelengthNanometers: number): CieXyzTristimulus {\n requireWavelengthIn(wavelengthNanometers, ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS, \"Analytic CIE 1931 CMF wavelength\");\n return { x: lobes(wavelengthNanometers, X_LOBES), y: lobes(wavelengthNanometers, Y_LOBES), z: lobes(wavelengthNanometers, Z_LOBES) };\n}\n\nfunction parseIncreasingSamples<T extends SpectralWavelengthSample>(\n samples: unknown,\n path: string,\n sampleKeys: readonly string[],\n parseValue: (sample: Record<string, unknown>, samplePath: string) => T\n): T[] {\n if (!Array.isArray(samples) || samples.length < 2 || samples.length > MAX_COLORIMETRIC_TABLE_SAMPLES) {\n throw new InvalidScientificInputError(path + \" must contain between 2 and \" + MAX_COLORIMETRIC_TABLE_SAMPLES + \" samples.\");\n }\n const parsed: T[] = [];\n let previous = -Infinity;\n samples.forEach((raw: unknown, i) => {\n const samplePath = path + \"[\" + i + \"]\";\n const record = requireRecordValue(raw, samplePath);\n rejectUnknownFields(record, sampleKeys, samplePath);\n const wavelength = requirePositiveNumber(record.wavelengthNanometers, samplePath + \".wavelengthNanometers\");\n if (!(wavelength > previous)) throw new InvalidScientificInputError(path + \" wavelengths must be strictly increasing.\");\n previous = wavelength;\n parsed.push(parseValue(record, samplePath));\n });\n return parsed;\n}\n\n/** Finds the bracketing interval for linear interpolation (binary search). */\nfunction bracket(samples: readonly SpectralWavelengthSample[], wavelength: number): [number, number] {\n let lo = 0;\n let hi = samples.length - 1;\n while (hi - lo > 1) {\n const mid = (lo + hi) >> 1;\n if (samples[mid]!.wavelengthNanometers <= wavelength) lo = mid;\n else hi = mid;\n }\n const a = samples[lo]!.wavelengthNanometers;\n const b = samples[hi]!.wavelengthNanometers;\n return [lo, (wavelength - a) / (b - a)];\n}\n\n/**\n * Validates a colour-matching-function source once for repeated evaluation.\n * Tabulated values may be signed only for `caller-defined` observers; CIE observers\n * require non-negative values.\n */\nexport function prepareColorMatchingFunctions(source: ColorMatchingFunctionsSource): PreparedColorMatchingFunctions {\n const record = requireRecordValue(source, \"colorMatchingFunctions\");\n rejectUnknownFields(record, [\"kind\", \"observer\", \"datasetId\", \"samples\"], \"colorMatchingFunctions\");\n if (record.kind === \"analytic-cie-1931-multi-lobe-fit\") {\n rejectUnknownFields(record, [\"kind\"], \"colorMatchingFunctions\");\n return Object.freeze({\n observer: \"cie-1931-2-degree\" as const,\n sourceKind: \"analytic-cie-1931-multi-lobe-fit\" as const,\n datasetId: \"photivra-cie-1931-multi-lobe-fit-2026-10-17\",\n scientificStatus: \"approximation\" as const,\n wavelengthRangeNanometers: { ...ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS },\n evaluate: estimateCie1931ColorMatchingFunctions\n });\n }\n if (record.kind !== \"tabulated\") throw new InvalidConfigurationError(\"colorMatchingFunctions.kind is not supported.\");\n rejectUnknownFields(record, [\"kind\", \"observer\", \"datasetId\", \"samples\"], \"colorMatchingFunctions\");\n const observer = record.observer;\n if (observer !== \"cie-1931-2-degree\" && observer !== \"cie-1964-10-degree\" && observer !== \"caller-defined\") {\n throw new InvalidConfigurationError(\"colorMatchingFunctions.observer is not supported.\");\n }\n if (typeof record.datasetId !== \"string\" || record.datasetId.trim().length === 0) {\n throw new InvalidConfigurationError(\"colorMatchingFunctions.datasetId must be a non-empty string.\");\n }\n const signed = observer === \"caller-defined\";\n const samples = parseIncreasingSamples<TabulatedColorMatchingSample>(record.samples, \"colorMatchingFunctions.samples\",\n [\"wavelengthNanometers\", \"xBar\", \"yBar\", \"zBar\"], (s, p) => {\n const v = (key: \"xBar\" | \"yBar\" | \"zBar\"): number => {\n const n = requireFiniteNumber(s[key], p + \".\" + key);\n if (!signed && n < 0) throw new InvalidScientificInputError(p + \".\" + key + \" must not be negative for a CIE observer.\");\n return n;\n };\n return { wavelengthNanometers: s.wavelengthNanometers as number, xBar: v(\"xBar\"), yBar: v(\"yBar\"), zBar: v(\"zBar\") };\n });\n const range = { minimum: samples[0]!.wavelengthNanometers, maximum: samples[samples.length - 1]!.wavelengthNanometers };\n return Object.freeze({\n observer,\n sourceKind: \"tabulated\" as const,\n datasetId: record.datasetId.trim(),\n scientificStatus: \"caller-tabulated\" as const,\n wavelengthRangeNanometers: range,\n evaluate(wavelengthNanometers: number): CieXyzTristimulus {\n requireWavelengthIn(wavelengthNanometers, range, \"Tabulated CMF wavelength\");\n const [i, t] = bracket(samples, wavelengthNanometers);\n const a = samples[i]!;\n const b = samples[Math.min(i + 1, samples.length - 1)]!;\n return { x: a.xBar + (b.xBar - a.xBar) * t, y: a.yBar + (b.yBar - a.yBar) * t, z: a.zBar + (b.zBar - a.zBar) * t };\n }\n });\n}\n\n/** A validated spectrum ready for evaluation. */\nexport interface PreparedColorimetricSpectrum {\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n evaluate(wavelengthNanometers: number): number;\n}\n\n/** Validates a tabulated or functional spectrum (values must be finite; sign is not restricted). */\nexport function prepareColorimetricSpectrum(spectrum: ColorimetricSpectrum, path = \"spectrum\"): PreparedColorimetricSpectrum {\n const record = requireRecordValue(spectrum, path);\n rejectUnknownFields(record, [\"kind\", \"samples\", \"wavelengthRangeNanometers\", \"evaluate\"], path);\n if (record.kind === \"function\") {\n rejectUnknownFields(record, [\"kind\", \"wavelengthRangeNanometers\", \"evaluate\"], path);\n const range = requireRecordValue(record.wavelengthRangeNanometers, path + \".wavelengthRangeNanometers\");\n rejectUnknownFields(range, [\"minimum\", \"maximum\"], path + \".wavelengthRangeNanometers\");\n const minimum = requirePositiveNumber(range.minimum, path + \".wavelengthRangeNanometers.minimum\");\n const maximum = requirePositiveNumber(range.maximum, path + \".wavelengthRangeNanometers.maximum\");\n if (!(minimum < maximum)) throw new InvalidScientificInputError(path + \".wavelengthRangeNanometers.minimum must be less than maximum.\");\n if (typeof record.evaluate !== \"function\") throw new InvalidConfigurationError(path + \".evaluate must be a function.\");\n const evaluate = record.evaluate as (w: number) => number;\n const declared = { minimum, maximum };\n return {\n wavelengthRangeNanometers: declared,\n evaluate(w: number): number {\n requireWavelengthIn(w, declared, path);\n const v = evaluate(w);\n if (typeof v !== \"number\" || !Number.isFinite(v)) throw new InvalidScientificInputError(path + \" evaluated to a non-finite value.\");\n return v;\n }\n };\n }\n if (record.kind !== \"tabulated\") throw new InvalidConfigurationError(path + \".kind is not supported.\");\n rejectUnknownFields(record, [\"kind\", \"samples\"], path);\n const samples = parseIncreasingSamples<ColorimetricSpectralSample>(record.samples, path + \".samples\", [\"wavelengthNanometers\", \"value\"], (s, p) => ({\n wavelengthNanometers: s.wavelengthNanometers as number,\n value: requireFiniteNumber(s.value, p + \".value\")\n }));\n const range = { minimum: samples[0]!.wavelengthNanometers, maximum: samples[samples.length - 1]!.wavelengthNanometers };\n return {\n wavelengthRangeNanometers: range,\n evaluate(w: number): number {\n requireWavelengthIn(w, range, path);\n const [i, t] = bracket(samples, w);\n const a = samples[i]!.value;\n const b = samples[Math.min(i + 1, samples.length - 1)]!.value;\n return a + (b - a) * t;\n }\n };\n}\n\nexport interface CreateColorimetricMidpointQuadratureInput {\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n /** Hard upper bound on each midpoint subinterval width, nm. */\n maximumSubintervalWidthNanometers: number;\n}\n\n/**\n * Builds deterministic uniform midpoint wavelength nodes covering the range. Every\n * node carries its d-lambda measure in nm; the measures sum to the range width.\n */\nexport function createColorimetricMidpointQuadrature(input: CreateColorimetricMidpointQuadratureInput): ColorimetricQuadratureNode[] {\n requireInputKeys(input, \"createColorimetricMidpointQuadrature\", [\"wavelengthRangeNanometers\", \"maximumSubintervalWidthNanometers\"]);\n const range = requireRecordValue(input.wavelengthRangeNanometers, \"wavelengthRangeNanometers\");\n rejectUnknownFields(range, [\"minimum\", \"maximum\"], \"wavelengthRangeNanometers\");\n const minimum = requirePositiveNumber(range.minimum, \"wavelengthRangeNanometers.minimum\");\n const maximum = requirePositiveNumber(range.maximum, \"wavelengthRangeNanometers.maximum\");\n if (!(minimum < maximum)) throw new InvalidScientificInputError(\"wavelengthRangeNanometers.minimum must be less than maximum.\");\n const width = requirePositiveNumber(input.maximumSubintervalWidthNanometers, \"maximumSubintervalWidthNanometers\");\n const count = Math.ceil((maximum - minimum) / width - 1e-9);\n if (count > MAX_COLORIMETRIC_QUADRATURE_NODES) throw new InvalidScientificInputError(\"Quadrature would exceed \" + MAX_COLORIMETRIC_QUADRATURE_NODES + \" nodes.\");\n const step = (maximum - minimum) / count;\n const nodes: ColorimetricQuadratureNode[] = [];\n for (let i = 0; i < count; i++) nodes.push({ wavelengthNanometers: minimum + (i + 0.5) * step, wavelengthMeasureNanometers: step });\n return nodes;\n}\n\n/** Validates explicit quadrature nodes (positive wavelengths and positive measures). */\nexport function parseColorimetricQuadratureNodes(nodes: unknown): ColorimetricQuadratureNode[] {\n if (!Array.isArray(nodes) || nodes.length === 0 || nodes.length > MAX_COLORIMETRIC_QUADRATURE_NODES) {\n throw new InvalidScientificInputError(\"quadratureNodes must contain between 1 and \" + MAX_COLORIMETRIC_QUADRATURE_NODES + \" nodes.\");\n }\n return nodes.map((raw: unknown, i) => {\n const r = requireRecordValue(raw, \"quadratureNodes[\" + i + \"]\");\n rejectUnknownFields(r, [\"wavelengthNanometers\", \"wavelengthMeasureNanometers\"], \"quadratureNodes[\" + i + \"]\");\n return {\n wavelengthNanometers: requirePositiveNumber(r.wavelengthNanometers, \"quadratureNodes[\" + i + \"].wavelengthNanometers\"),\n wavelengthMeasureNanometers: requirePositiveNumber(r.wavelengthMeasureNanometers, \"quadratureNodes[\" + i + \"].wavelengthMeasureNanometers\")\n };\n });\n}\n\n/**\n * Normalization of integrated tristimulus values.\n * - `white-luminance-one`: k = 1 / Σ S ȳ Δλ, so the perfect reflecting diffuser (or the\n * illuminant itself) has Y = 1 (relative colorimetry with Y scaled to 1; also CIE 15:2018).\n * - `scale`: X = factor · Σ …; for example 683.002 lm/W with spectral radiance in\n * W·m⁻²·sr⁻¹·nm⁻¹ yields luminance in cd/m² (the caller owns the unit semantics).\n */\nexport type TristimulusNormalization = { kind: \"white-luminance-one\" } | { kind: \"scale\"; factor: number };\n\nexport interface IntegrateSpectrumToXyzInput {\n quadratureNodes: readonly ColorimetricQuadratureNode[];\n /** Illuminant SPD or emitted spectral radiance S(λ). */\n spectralDistribution: ColorimetricSpectrum;\n /** Optional spectral reflectance/transmittance factor R(λ); omitted means R = 1. */\n spectralFactor?: ColorimetricSpectrum;\n colorMatchingFunctions: ColorMatchingFunctionsSource;\n normalization: TristimulusNormalization;\n}\n\nexport interface IntegratedSpectrumXyz {\n xyz: CieXyzTristimulus;\n /** Tristimulus values of S(λ) alone under the same normalization (the adopted white). */\n whiteXyz: CieXyzTristimulus;\n chromaticity: CieXyChromaticity | null;\n normalizationFactor: number;\n observer: ColorimetricObserver;\n nodeCount: number;\n}\n\n/** Internal: per-node weights S·Δλ and CMF values; reused by matrix fitting. */\nexport interface SampledColorimetricBasis {\n nodes: readonly ColorimetricQuadratureNode[];\n weights: Float64Array;\n xBar: Float64Array;\n yBar: Float64Array;\n zBar: Float64Array;\n cmf: PreparedColorMatchingFunctions;\n}\n\nexport function sampleColorimetricBasis(\n quadratureNodes: readonly ColorimetricQuadratureNode[],\n spectralDistribution: PreparedColorimetricSpectrum,\n cmf: PreparedColorMatchingFunctions\n): SampledColorimetricBasis {\n const nodes = parseColorimetricQuadratureNodes(quadratureNodes);\n const n = nodes.length;\n const weights = new Float64Array(n), xBar = new Float64Array(n), yBar = new Float64Array(n), zBar = new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const node = nodes[i]!;\n const c = cmf.evaluate(node.wavelengthNanometers);\n weights[i] = spectralDistribution.evaluate(node.wavelengthNanometers) * node.wavelengthMeasureNanometers;\n xBar[i] = c.x; yBar[i] = c.y; zBar[i] = c.z;\n }\n return { nodes, weights, xBar, yBar, zBar, cmf };\n}\n\nexport function sampleFactor(basis: SampledColorimetricBasis, factor: PreparedColorimetricSpectrum | undefined): Float64Array {\n const out = new Float64Array(basis.nodes.length);\n for (let i = 0; i < out.length; i++) out[i] = factor === undefined ? 1 : factor.evaluate(basis.nodes[i]!.wavelengthNanometers);\n return out;\n}\n\nexport function integrateSampledXyz(basis: SampledColorimetricBasis, factor: Float64Array): CieXyzTristimulus {\n let x = 0, y = 0, z = 0;\n for (let i = 0; i < factor.length; i++) {\n const w = basis.weights[i]! * factor[i]!;\n x += w * basis.xBar[i]!; y += w * basis.yBar[i]!; z += w * basis.zBar[i]!;\n }\n return { x, y, z };\n}\n\nexport function resolveNormalizationFactor(normalization: TristimulusNormalization, unnormalizedWhiteY: number): number {\n const r = requireRecordValue(normalization, \"normalization\");\n if (r.kind === \"white-luminance-one\") {\n if (!(unnormalizedWhiteY > 0) || !Number.isFinite(unnormalizedWhiteY)) {\n throw new InvalidScientificInputError(\"White-luminance normalization requires a positive integrated Y of the spectral distribution.\");\n }\n return 1 / unnormalizedWhiteY;\n }\n if (r.kind === \"scale\") return requirePositiveNumber(r.factor, \"normalization.factor\");\n throw new InvalidConfigurationError(\"normalization.kind is not supported.\");\n}\n\nfunction scaleXyz(xyz: CieXyzTristimulus, k: number): CieXyzTristimulus {\n return { x: xyz.x * k, y: xyz.y * k, z: xyz.z * k };\n}\n\n/**\n * Integrates a spectrum (optionally multiplied by a reflectance/transmittance factor)\n * against colour-matching functions with caller-explicit quadrature (the tristimulus integral of\n * Wyman, Sloan & Shirley 2013, Eq. 1; also CIE 15:2018 §7).\n * Provenance is `approximation` for the analytic CMF fit and `calculated` for\n * caller-tabulated CMFs. Either way, the caller chooses the quadrature.\n */\nexport function integrateSpectrumToXyz(input: IntegrateSpectrumToXyzInput): CalculationResult<IntegratedSpectrumXyz> {\n requireInputKeys(input, \"integrateSpectrumToXyz\", [\"quadratureNodes\", \"spectralDistribution\", \"spectralFactor\", \"colorMatchingFunctions\", \"normalization\"]);\n const cmf = prepareColorMatchingFunctions(input.colorMatchingFunctions);\n const distribution = prepareColorimetricSpectrum(input.spectralDistribution, \"spectralDistribution\");\n const factor = input.spectralFactor === undefined ? undefined : prepareColorimetricSpectrum(input.spectralFactor, \"spectralFactor\");\n const basis = sampleColorimetricBasis(input.quadratureNodes, distribution, cmf);\n const rawWhite = integrateSampledXyz(basis, sampleFactor(basis, undefined));\n const rawSample = factor === undefined ? rawWhite : integrateSampledXyz(basis, sampleFactor(basis, factor));\n const k = resolveNormalizationFactor(input.normalization, rawWhite.y);\n const xyz = scaleXyz(rawSample, k);\n const whiteXyz = scaleXyz(rawWhite, k);\n requireFiniteResult([xyz.x, xyz.y, xyz.z, whiteXyz.x, whiteXyz.y, whiteXyz.z], \"Spectral integration\");\n const sum = xyz.x + xyz.y + xyz.z;\n const value: IntegratedSpectrumXyz = {\n xyz, whiteXyz, chromaticity: sum > 0 ? chromaticityOfXyz(xyz) : null, normalizationFactor: k,\n observer: cmf.observer, nodeCount: basis.nodes.length\n };\n const assumptions = [\n \"Tristimulus integral evaluated as Σ S(λ)·R(λ)·CMF(λ)·Δλ over the caller's quadrature nodes\",\n \"Caller owns quadrature convergence and wavelength coverage; tabulated inputs are linearly interpolated and fail closed outside their range\"\n ];\n return cmf.scientificStatus === \"approximation\"\n ? approximationResult(value, \"cie-xyz-spectral-integration-analytic-cmf\", COLORIMETRY_MODEL_VERSION,\n [...assumptions, \"CIE 1931 2° CMFs from the engine's multi-lobe analytic fit (measured max abs CMF error 0.0122/0.00733/0.0221)\"])\n : calculatedResult(value, \"cie-xyz-spectral-integration-tabulated-cmf\", COLORIMETRY_MODEL_VERSION,\n [...assumptions, \"Caller-supplied tabulated CMFs: \" + cmf.datasetId]);\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Three-component vector (dimensionless unless documented otherwise). */
|
|
2
|
+
export type ColorVector3 = readonly [number, number, number];
|
|
3
|
+
/** Row-major 3×3 matrix; `m[row][column]`. Applied as `m · v` to column vectors. */
|
|
4
|
+
export type ColorMatrix3x3 = readonly [ColorVector3, ColorVector3, ColorVector3];
|
|
5
|
+
/**
|
|
6
|
+
* Relative CIE XYZ tristimulus values. Units are relative (dimensionless);
|
|
7
|
+
* a normalized white has `y = 1` unless a function documents another scale.
|
|
8
|
+
*/
|
|
9
|
+
export interface CieXyzTristimulus {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
z: number;
|
|
13
|
+
}
|
|
14
|
+
/** CIE 1931 (x, y) chromaticity coordinates (dimensionless). */
|
|
15
|
+
export interface CieXyChromaticity {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
}
|
|
19
|
+
/** CIE 1960 UCS (u, v) chromaticity coordinates (dimensionless). */
|
|
20
|
+
export interface Cie1960UvChromaticity {
|
|
21
|
+
u: number;
|
|
22
|
+
v: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function requireFiniteNumber(value: unknown, path: string): number;
|
|
25
|
+
export declare function requirePositiveNumber(value: unknown, path: string): number;
|
|
26
|
+
export declare function requireNonNegativeNumber(value: unknown, path: string): number;
|
|
27
|
+
export declare function requireRecordValue(value: unknown, path: string): Record<string, unknown>;
|
|
28
|
+
/** Parses an XYZ tristimulus record with exactly the fields x, y and z; any other field is rejected. */
|
|
29
|
+
export declare function parseXyz(value: unknown, path: string): CieXyzTristimulus;
|
|
30
|
+
/** Parses a white point: finite, non-negative components with Y > 0; fields other than x, y, z are rejected. */
|
|
31
|
+
export declare function parseWhiteXyz(value: unknown, path: string): CieXyzTristimulus;
|
|
32
|
+
/** Parses a CIE 1931 xy chromaticity with exactly the fields x and y, inside the spectrum-locus triangle bound. */
|
|
33
|
+
export declare function parseChromaticity(value: unknown, path: string): CieXyChromaticity;
|
|
34
|
+
export declare function parseMatrix3x3(value: unknown, path: string): ColorMatrix3x3;
|
|
35
|
+
export declare function multiplyMatrixVector(m: ColorMatrix3x3, v: ColorVector3): ColorVector3;
|
|
36
|
+
export declare function multiplyMatrices(a: ColorMatrix3x3, b: ColorMatrix3x3): ColorMatrix3x3;
|
|
37
|
+
export declare function determinant3x3(m: ColorMatrix3x3): number;
|
|
38
|
+
/** Exact cofactor inverse. Throws (fails closed) on a singular or non-finite result. */
|
|
39
|
+
export declare function invertMatrix3x3(m: ColorMatrix3x3, path?: string): ColorMatrix3x3;
|
|
40
|
+
export declare function diagonalMatrix(v: ColorVector3): ColorMatrix3x3;
|
|
41
|
+
export declare function xyzToVector(xyz: CieXyzTristimulus): ColorVector3;
|
|
42
|
+
export declare function vectorToXyz(v: ColorVector3): CieXyzTristimulus;
|
|
43
|
+
export declare function copyMatrix(m: ColorMatrix3x3): ColorMatrix3x3;
|
|
44
|
+
export declare function requireFiniteResult(values: readonly number[], what: string): void;
|
|
45
|
+
/** XYZ → xy; requires X + Y + Z > 0. */
|
|
46
|
+
export declare function chromaticityOfXyz(xyz: CieXyzTristimulus): CieXyChromaticity;
|
|
47
|
+
/** xy with luminance Y → XYZ (CIE 15 Eq. 7.3 inverse). */
|
|
48
|
+
export declare function xyzOfChromaticity(xy: CieXyChromaticity, luminanceY?: number): CieXyzTristimulus;
|
|
49
|
+
/** CIE 1931 xy → CIE 1960 UCS uv: u = 4x/(−2x+12y+3), v = 6y/(−2x+12y+3). */
|
|
50
|
+
export declare function uvOfChromaticity(xy: CieXyChromaticity): Cie1960UvChromaticity;
|
|
51
|
+
/** CIE 1960 UCS uv → CIE 1931 xy: x = 3u/(2u−8v+4), y = 2v/(2u−8v+4). */
|
|
52
|
+
export declare function chromaticityOfUv(uv: Cie1960UvChromaticity): CieXyChromaticity;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Shared colorimetric value types (CIE XYZ tristimulus, xy chromaticity, 3×3
|
|
4
|
+
* row-major matrices) and exact linear-algebra helpers used by the colorimetry
|
|
5
|
+
* modules. Pure mathematics; no colour-science constants live here.
|
|
6
|
+
* @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.
|
|
7
|
+
*/
|
|
8
|
+
import { InvalidScientificInputError, InvalidScientificResultError } from "../core/validation.js";
|
|
9
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
10
|
+
import { rejectUnknownFields } from "../core/record-validation.js";
|
|
11
|
+
export function requireFiniteNumber(value, path) {
|
|
12
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
13
|
+
throw new InvalidScientificInputError(path + " must be a finite number.");
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
export function requirePositiveNumber(value, path) {
|
|
18
|
+
const n = requireFiniteNumber(value, path);
|
|
19
|
+
if (n <= 0)
|
|
20
|
+
throw new InvalidScientificInputError(path + " must be greater than zero.");
|
|
21
|
+
return n;
|
|
22
|
+
}
|
|
23
|
+
export function requireNonNegativeNumber(value, path) {
|
|
24
|
+
const n = requireFiniteNumber(value, path);
|
|
25
|
+
if (n < 0)
|
|
26
|
+
throw new InvalidScientificInputError(path + " must not be negative.");
|
|
27
|
+
return n;
|
|
28
|
+
}
|
|
29
|
+
export function requireRecordValue(value, path) {
|
|
30
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
31
|
+
throw new InvalidConfigurationError(path + " must be an object.");
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
const XYZ_FIELDS = Object.freeze(["x", "y", "z"]);
|
|
36
|
+
const CHROMATICITY_FIELDS = Object.freeze(["x", "y"]);
|
|
37
|
+
/** Parses an XYZ tristimulus record with exactly the fields x, y and z; any other field is rejected. */
|
|
38
|
+
export function parseXyz(value, path) {
|
|
39
|
+
const r = requireRecordValue(value, path);
|
|
40
|
+
rejectUnknownFields(r, XYZ_FIELDS, path);
|
|
41
|
+
return { x: requireFiniteNumber(r.x, path + ".x"), y: requireFiniteNumber(r.y, path + ".y"), z: requireFiniteNumber(r.z, path + ".z") };
|
|
42
|
+
}
|
|
43
|
+
/** Parses a white point: finite, non-negative components with Y > 0; fields other than x, y, z are rejected. */
|
|
44
|
+
export function parseWhiteXyz(value, path) {
|
|
45
|
+
const r = requireRecordValue(value, path);
|
|
46
|
+
rejectUnknownFields(r, XYZ_FIELDS, path);
|
|
47
|
+
return { x: requireNonNegativeNumber(r.x, path + ".x"), y: requirePositiveNumber(r.y, path + ".y"), z: requireNonNegativeNumber(r.z, path + ".z") };
|
|
48
|
+
}
|
|
49
|
+
/** Parses a CIE 1931 xy chromaticity with exactly the fields x and y, inside the spectrum-locus triangle bound. */
|
|
50
|
+
export function parseChromaticity(value, path) {
|
|
51
|
+
const r = requireRecordValue(value, path);
|
|
52
|
+
rejectUnknownFields(r, CHROMATICITY_FIELDS, path);
|
|
53
|
+
const x = requireFiniteNumber(r.x, path + ".x");
|
|
54
|
+
const y = requireFiniteNumber(r.y, path + ".y");
|
|
55
|
+
if (x < 0 || y <= 0 || x + y > 1) {
|
|
56
|
+
throw new InvalidScientificInputError(path + " must satisfy x >= 0, y > 0 and x + y <= 1.");
|
|
57
|
+
}
|
|
58
|
+
return { x, y };
|
|
59
|
+
}
|
|
60
|
+
export function parseMatrix3x3(value, path) {
|
|
61
|
+
if (!Array.isArray(value) || value.length !== 3)
|
|
62
|
+
throw new InvalidScientificInputError(path + " must be a 3×3 row-major matrix.");
|
|
63
|
+
return value.map((row, i) => {
|
|
64
|
+
if (!Array.isArray(row) || row.length !== 3)
|
|
65
|
+
throw new InvalidScientificInputError(path + " must be a 3×3 row-major matrix.");
|
|
66
|
+
return row.map((v, j) => requireFiniteNumber(v, path + "[" + i + "][" + j + "]"));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export function multiplyMatrixVector(m, v) {
|
|
70
|
+
return [
|
|
71
|
+
m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2],
|
|
72
|
+
m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2],
|
|
73
|
+
m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2]
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
export function multiplyMatrices(a, b) {
|
|
77
|
+
const row = (i) => [
|
|
78
|
+
a[i][0] * b[0][0] + a[i][1] * b[1][0] + a[i][2] * b[2][0],
|
|
79
|
+
a[i][0] * b[0][1] + a[i][1] * b[1][1] + a[i][2] * b[2][1],
|
|
80
|
+
a[i][0] * b[0][2] + a[i][1] * b[1][2] + a[i][2] * b[2][2]
|
|
81
|
+
];
|
|
82
|
+
return [row(0), row(1), row(2)];
|
|
83
|
+
}
|
|
84
|
+
export function determinant3x3(m) {
|
|
85
|
+
const [[a, b, c], [d, e, f], [g, h, i]] = m;
|
|
86
|
+
return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);
|
|
87
|
+
}
|
|
88
|
+
/** Exact cofactor inverse. Throws (fails closed) on a singular or non-finite result. */
|
|
89
|
+
export function invertMatrix3x3(m, path = "matrix") {
|
|
90
|
+
const [[a, b, c], [d, e, f], [g, h, i]] = m;
|
|
91
|
+
const det = determinant3x3(m);
|
|
92
|
+
const scale = Math.max(...m.flat().map(Math.abs));
|
|
93
|
+
if (!Number.isFinite(det) || scale === 0 || Math.abs(det) <= 1e-12 * scale ** 3) {
|
|
94
|
+
throw new InvalidScientificInputError(path + " is singular or numerically ill-conditioned.");
|
|
95
|
+
}
|
|
96
|
+
const inv = [
|
|
97
|
+
[(e * i - f * h) / det, (c * h - b * i) / det, (b * f - c * e) / det],
|
|
98
|
+
[(f * g - d * i) / det, (a * i - c * g) / det, (c * d - a * f) / det],
|
|
99
|
+
[(d * h - e * g) / det, (b * g - a * h) / det, (a * e - b * d) / det]
|
|
100
|
+
];
|
|
101
|
+
if (inv.flat().some((v) => !Number.isFinite(v)))
|
|
102
|
+
throw new InvalidScientificResultError(path + " inverse is not finite.");
|
|
103
|
+
return inv;
|
|
104
|
+
}
|
|
105
|
+
export function diagonalMatrix(v) {
|
|
106
|
+
return [[v[0], 0, 0], [0, v[1], 0], [0, 0, v[2]]];
|
|
107
|
+
}
|
|
108
|
+
export function xyzToVector(xyz) {
|
|
109
|
+
return [xyz.x, xyz.y, xyz.z];
|
|
110
|
+
}
|
|
111
|
+
export function vectorToXyz(v) {
|
|
112
|
+
return { x: v[0], y: v[1], z: v[2] };
|
|
113
|
+
}
|
|
114
|
+
export function copyMatrix(m) {
|
|
115
|
+
return [[...m[0]], [...m[1]], [...m[2]]];
|
|
116
|
+
}
|
|
117
|
+
export function requireFiniteResult(values, what) {
|
|
118
|
+
if (values.some((v) => !Number.isFinite(v)))
|
|
119
|
+
throw new InvalidScientificResultError(what + " produced a non-finite value.");
|
|
120
|
+
}
|
|
121
|
+
/** XYZ → xy; requires X + Y + Z > 0. */
|
|
122
|
+
export function chromaticityOfXyz(xyz) {
|
|
123
|
+
const sum = xyz.x + xyz.y + xyz.z;
|
|
124
|
+
if (!(sum > 0) || !Number.isFinite(sum))
|
|
125
|
+
throw new InvalidScientificInputError("Chromaticity requires X + Y + Z > 0.");
|
|
126
|
+
return { x: xyz.x / sum, y: xyz.y / sum };
|
|
127
|
+
}
|
|
128
|
+
/** xy with luminance Y → XYZ (CIE 15 Eq. 7.3 inverse). */
|
|
129
|
+
export function xyzOfChromaticity(xy, luminanceY = 1) {
|
|
130
|
+
if (!(xy.y > 0))
|
|
131
|
+
throw new InvalidScientificInputError("Chromaticity y must be greater than zero.");
|
|
132
|
+
return { x: (xy.x / xy.y) * luminanceY, y: luminanceY, z: ((1 - xy.x - xy.y) / xy.y) * luminanceY };
|
|
133
|
+
}
|
|
134
|
+
/** CIE 1931 xy → CIE 1960 UCS uv: u = 4x/(−2x+12y+3), v = 6y/(−2x+12y+3). */
|
|
135
|
+
export function uvOfChromaticity(xy) {
|
|
136
|
+
const d = -2 * xy.x + 12 * xy.y + 3;
|
|
137
|
+
return { u: (4 * xy.x) / d, v: (6 * xy.y) / d };
|
|
138
|
+
}
|
|
139
|
+
/** CIE 1960 UCS uv → CIE 1931 xy: x = 3u/(2u−8v+4), y = 2v/(2u−8v+4). */
|
|
140
|
+
export function chromaticityOfUv(uv) {
|
|
141
|
+
const d = 2 * uv.u - 8 * uv.v + 4;
|
|
142
|
+
return { x: (3 * uv.u) / d, y: (2 * uv.v) / d };
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=colorimetry-math.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorimetry-math.js","sourceRoot":"","sources":["../../src/color/colorimetry-math.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Shared colorimetric value types (CIE XYZ tristimulus, xy chromaticity, 3×3\n * row-major matrices) and exact linear-algebra helpers used by the colorimetry\n * modules. Pure mathematics; no colour-science constants live here.\n * @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.\n */\n\nimport { InvalidScientificInputError, InvalidScientificResultError } from \"../core/validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { rejectUnknownFields } from \"../core/record-validation.js\";\n\n/** Three-component vector (dimensionless unless documented otherwise). */\nexport type ColorVector3 = readonly [number, number, number];\n/** Row-major 3×3 matrix; `m[row][column]`. Applied as `m · v` to column vectors. */\nexport type ColorMatrix3x3 = readonly [ColorVector3, ColorVector3, ColorVector3];\n\n/**\n * Relative CIE XYZ tristimulus values. Units are relative (dimensionless);\n * a normalized white has `y = 1` unless a function documents another scale.\n */\nexport interface CieXyzTristimulus {\n x: number;\n y: number;\n z: number;\n}\n\n/** CIE 1931 (x, y) chromaticity coordinates (dimensionless). */\nexport interface CieXyChromaticity {\n x: number;\n y: number;\n}\n\n/** CIE 1960 UCS (u, v) chromaticity coordinates (dimensionless). */\nexport interface Cie1960UvChromaticity {\n u: number;\n v: number;\n}\n\nexport function requireFiniteNumber(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new InvalidScientificInputError(path + \" must be a finite number.\");\n }\n return value;\n}\n\nexport function requirePositiveNumber(value: unknown, path: string): number {\n const n = requireFiniteNumber(value, path);\n if (n <= 0) throw new InvalidScientificInputError(path + \" must be greater than zero.\");\n return n;\n}\n\nexport function requireNonNegativeNumber(value: unknown, path: string): number {\n const n = requireFiniteNumber(value, path);\n if (n < 0) throw new InvalidScientificInputError(path + \" must not be negative.\");\n return n;\n}\n\nexport function requireRecordValue(value: unknown, path: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new InvalidConfigurationError(path + \" must be an object.\");\n }\n return value as Record<string, unknown>;\n}\n\nconst XYZ_FIELDS: readonly string[] = Object.freeze([\"x\", \"y\", \"z\"]);\nconst CHROMATICITY_FIELDS: readonly string[] = Object.freeze([\"x\", \"y\"]);\n\n/** Parses an XYZ tristimulus record with exactly the fields x, y and z; any other field is rejected. */\nexport function parseXyz(value: unknown, path: string): CieXyzTristimulus {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, XYZ_FIELDS, path);\n return { x: requireFiniteNumber(r.x, path + \".x\"), y: requireFiniteNumber(r.y, path + \".y\"), z: requireFiniteNumber(r.z, path + \".z\") };\n}\n\n/** Parses a white point: finite, non-negative components with Y > 0; fields other than x, y, z are rejected. */\nexport function parseWhiteXyz(value: unknown, path: string): CieXyzTristimulus {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, XYZ_FIELDS, path);\n return { x: requireNonNegativeNumber(r.x, path + \".x\"), y: requirePositiveNumber(r.y, path + \".y\"), z: requireNonNegativeNumber(r.z, path + \".z\") };\n}\n\n/** Parses a CIE 1931 xy chromaticity with exactly the fields x and y, inside the spectrum-locus triangle bound. */\nexport function parseChromaticity(value: unknown, path: string): CieXyChromaticity {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, CHROMATICITY_FIELDS, path);\n const x = requireFiniteNumber(r.x, path + \".x\");\n const y = requireFiniteNumber(r.y, path + \".y\");\n if (x < 0 || y <= 0 || x + y > 1) {\n throw new InvalidScientificInputError(path + \" must satisfy x >= 0, y > 0 and x + y <= 1.\");\n }\n return { x, y };\n}\n\nexport function parseMatrix3x3(value: unknown, path: string): ColorMatrix3x3 {\n if (!Array.isArray(value) || value.length !== 3) throw new InvalidScientificInputError(path + \" must be a 3×3 row-major matrix.\");\n return value.map((row: unknown, i) => {\n if (!Array.isArray(row) || row.length !== 3) throw new InvalidScientificInputError(path + \" must be a 3×3 row-major matrix.\");\n return row.map((v: unknown, j) => requireFiniteNumber(v, path + \"[\" + i + \"][\" + j + \"]\"));\n }) as unknown as ColorMatrix3x3;\n}\n\nexport function multiplyMatrixVector(m: ColorMatrix3x3, v: ColorVector3): ColorVector3 {\n return [\n m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2],\n m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2],\n m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2]\n ];\n}\n\nexport function multiplyMatrices(a: ColorMatrix3x3, b: ColorMatrix3x3): ColorMatrix3x3 {\n const row = (i: 0 | 1 | 2): ColorVector3 => [\n a[i][0] * b[0][0] + a[i][1] * b[1][0] + a[i][2] * b[2][0],\n a[i][0] * b[0][1] + a[i][1] * b[1][1] + a[i][2] * b[2][1],\n a[i][0] * b[0][2] + a[i][1] * b[1][2] + a[i][2] * b[2][2]\n ];\n return [row(0), row(1), row(2)];\n}\n\nexport function determinant3x3(m: ColorMatrix3x3): number {\n const [[a, b, c], [d, e, f], [g, h, i]] = m;\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n}\n\n/** Exact cofactor inverse. Throws (fails closed) on a singular or non-finite result. */\nexport function invertMatrix3x3(m: ColorMatrix3x3, path = \"matrix\"): ColorMatrix3x3 {\n const [[a, b, c], [d, e, f], [g, h, i]] = m;\n const det = determinant3x3(m);\n const scale = Math.max(...m.flat().map(Math.abs));\n if (!Number.isFinite(det) || scale === 0 || Math.abs(det) <= 1e-12 * scale ** 3) {\n throw new InvalidScientificInputError(path + \" is singular or numerically ill-conditioned.\");\n }\n const inv: ColorMatrix3x3 = [\n [(e * i - f * h) / det, (c * h - b * i) / det, (b * f - c * e) / det],\n [(f * g - d * i) / det, (a * i - c * g) / det, (c * d - a * f) / det],\n [(d * h - e * g) / det, (b * g - a * h) / det, (a * e - b * d) / det]\n ];\n if (inv.flat().some((v) => !Number.isFinite(v))) throw new InvalidScientificResultError(path + \" inverse is not finite.\");\n return inv;\n}\n\nexport function diagonalMatrix(v: ColorVector3): ColorMatrix3x3 {\n return [[v[0], 0, 0], [0, v[1], 0], [0, 0, v[2]]];\n}\n\nexport function xyzToVector(xyz: CieXyzTristimulus): ColorVector3 {\n return [xyz.x, xyz.y, xyz.z];\n}\n\nexport function vectorToXyz(v: ColorVector3): CieXyzTristimulus {\n return { x: v[0], y: v[1], z: v[2] };\n}\n\nexport function copyMatrix(m: ColorMatrix3x3): ColorMatrix3x3 {\n return [[...m[0]], [...m[1]], [...m[2]]] as unknown as ColorMatrix3x3;\n}\n\nexport function requireFiniteResult(values: readonly number[], what: string): void {\n if (values.some((v) => !Number.isFinite(v))) throw new InvalidScientificResultError(what + \" produced a non-finite value.\");\n}\n\n/** XYZ → xy; requires X + Y + Z > 0. */\nexport function chromaticityOfXyz(xyz: CieXyzTristimulus): CieXyChromaticity {\n const sum = xyz.x + xyz.y + xyz.z;\n if (!(sum > 0) || !Number.isFinite(sum)) throw new InvalidScientificInputError(\"Chromaticity requires X + Y + Z > 0.\");\n return { x: xyz.x / sum, y: xyz.y / sum };\n}\n\n/** xy with luminance Y → XYZ (CIE 15 Eq. 7.3 inverse). */\nexport function xyzOfChromaticity(xy: CieXyChromaticity, luminanceY = 1): CieXyzTristimulus {\n if (!(xy.y > 0)) throw new InvalidScientificInputError(\"Chromaticity y must be greater than zero.\");\n return { x: (xy.x / xy.y) * luminanceY, y: luminanceY, z: ((1 - xy.x - xy.y) / xy.y) * luminanceY };\n}\n\n/** CIE 1931 xy → CIE 1960 UCS uv: u = 4x/(−2x+12y+3), v = 6y/(−2x+12y+3). */\nexport function uvOfChromaticity(xy: CieXyChromaticity): Cie1960UvChromaticity {\n const d = -2 * xy.x + 12 * xy.y + 3;\n return { u: (4 * xy.x) / d, v: (6 * xy.y) / d };\n}\n\n/** CIE 1960 UCS uv → CIE 1931 xy: x = 3u/(2u−8v+4), y = 2v/(2u−8v+4). */\nexport function chromaticityOfUv(uv: Cie1960UvChromaticity): CieXyChromaticity {\n const d = 2 * uv.u - 8 * uv.v + 4;\n return { x: (3 * uv.u) / d, y: (2 * uv.v) / d };\n}\n"]}
|