@photivra/engine 2.20.0 → 2.22.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.
Files changed (275) hide show
  1. package/CHANGELOG.md +295 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +7 -6
  4. package/SECURITY.md +1 -1
  5. package/THIRD_PARTY.md +18 -0
  6. package/dist/capture/c2pa-embed.d.ts +116 -0
  7. package/dist/capture/c2pa-embed.js +493 -0
  8. package/dist/capture/c2pa-embed.js.map +1 -0
  9. package/dist/capture/dng-import.d.ts +73 -8
  10. package/dist/capture/dng-import.js +315 -80
  11. package/dist/capture/dng-import.js.map +1 -1
  12. package/dist/capture/dng-lens-correction-opcodes.d.ts +2 -2
  13. package/dist/capture/dng-lens-correction-opcodes.js +2 -2
  14. package/dist/capture/dng-lens-correction-opcodes.js.map +1 -1
  15. package/dist/capture/dng-opcodes.d.ts +96 -0
  16. package/dist/capture/dng-opcodes.js +391 -0
  17. package/dist/capture/dng-opcodes.js.map +1 -0
  18. package/dist/capture/dng-profile-maps.d.ts +99 -0
  19. package/dist/capture/dng-profile-maps.js +381 -0
  20. package/dist/capture/dng-profile-maps.js.map +1 -0
  21. package/dist/capture/dng-stage-image.d.ts +23 -0
  22. package/dist/capture/dng-stage-image.js +65 -0
  23. package/dist/capture/dng-stage-image.js.map +1 -0
  24. package/dist/capture/exposure-build-up-stage.d.ts +16 -0
  25. package/dist/capture/exposure-build-up-stage.js +4 -0
  26. package/dist/capture/exposure-build-up-stage.js.map +1 -0
  27. package/dist/capture/jpeg-xl-tiles.d.ts +22 -0
  28. package/dist/capture/jpeg-xl-tiles.js +151 -0
  29. package/dist/capture/jpeg-xl-tiles.js.map +1 -0
  30. package/dist/capture/lossy-jpeg.d.ts +17 -0
  31. package/dist/capture/lossy-jpeg.js +369 -0
  32. package/dist/capture/lossy-jpeg.js.map +1 -0
  33. package/dist/capture/native-environment-lean.d.ts +2 -1
  34. package/dist/capture/native-environment-lean.js +41 -73
  35. package/dist/capture/native-environment-lean.js.map +1 -1
  36. package/dist/capture/native-environment-tabulated.js +4 -3
  37. package/dist/capture/native-environment-tabulated.js.map +1 -1
  38. package/dist/capture/native-raw-development.d.ts +2 -1
  39. package/dist/capture/native-raw-development.js.map +1 -1
  40. package/dist/capture/native-raw.d.ts +3 -2
  41. package/dist/capture/native-raw.js +5 -4
  42. package/dist/capture/native-raw.js.map +1 -1
  43. package/dist/capture/sensor-raw-producer.d.ts +4 -1
  44. package/dist/capture/sensor-raw-producer.js +12 -3
  45. package/dist/capture/sensor-raw-producer.js.map +1 -1
  46. package/dist/color/neighbor-highlight-reconstruction.d.ts +66 -0
  47. package/dist/color/neighbor-highlight-reconstruction.js +234 -0
  48. package/dist/color/neighbor-highlight-reconstruction.js.map +1 -0
  49. package/dist/color/sensor-color-development.d.ts +5 -0
  50. package/dist/color/sensor-color-development.js +7 -1
  51. package/dist/color/sensor-color-development.js.map +1 -1
  52. package/dist/color/spectral-spikiness.d.ts +11 -0
  53. package/dist/color/spectral-spikiness.js +23 -0
  54. package/dist/color/spectral-spikiness.js.map +1 -0
  55. package/dist/core/execution-error.d.ts +21 -0
  56. package/dist/core/execution-error.js +12 -0
  57. package/dist/core/execution-error.js.map +1 -0
  58. package/dist/core/version.d.ts +1 -1
  59. package/dist/core/version.js +1 -1
  60. package/dist/core/version.js.map +1 -1
  61. package/dist/equipment/generic-lens-catalogue.d.ts +3 -2
  62. package/dist/equipment/generic-lens-catalogue.js +18 -5
  63. package/dist/equipment/generic-lens-catalogue.js.map +1 -1
  64. package/dist/equipment/generic-tier-assets.d.ts +32 -0
  65. package/dist/equipment/generic-tier-assets.js +16 -11
  66. package/dist/equipment/generic-tier-assets.js.map +1 -1
  67. package/dist/equipment/sensor-profile-body.d.ts +78 -0
  68. package/dist/equipment/sensor-profile-body.js +77 -0
  69. package/dist/equipment/sensor-profile-body.js.map +1 -0
  70. package/dist/equipment/sensor-profiles.d.ts +8 -0
  71. package/dist/equipment/sensor-profiles.js +82 -0
  72. package/dist/equipment/sensor-profiles.js.map +1 -0
  73. package/dist/facade/catalogue-lens-signal.d.ts +28 -3
  74. package/dist/facade/catalogue-lens-signal.js +83 -78
  75. package/dist/facade/catalogue-lens-signal.js.map +1 -1
  76. package/dist/facade/chart-radiance-batch.js +2 -1
  77. package/dist/facade/chart-radiance-batch.js.map +1 -1
  78. package/dist/facade/defocus-image-space-provider.d.ts +7 -0
  79. package/dist/facade/defocus-image-space-provider.js +64 -76
  80. package/dist/facade/defocus-image-space-provider.js.map +1 -1
  81. package/dist/facade/diffraction-provider.d.ts +1 -1
  82. package/dist/facade/diffraction-provider.js +4 -4
  83. package/dist/facade/diffraction-provider.js.map +1 -1
  84. package/dist/facade/display-view-gpu-session.js +39 -5
  85. package/dist/facade/display-view-gpu-session.js.map +1 -1
  86. package/dist/facade/display-view-gpu.d.ts +19 -6
  87. package/dist/facade/display-view-gpu.js.map +1 -1
  88. package/dist/facade/display-view-lens-signal.js +25 -23
  89. package/dist/facade/display-view-lens-signal.js.map +1 -1
  90. package/dist/facade/display-view-normal.d.ts +15 -0
  91. package/dist/facade/display-view-normal.js +44 -0
  92. package/dist/facade/display-view-normal.js.map +1 -0
  93. package/dist/facade/display-view-rendering.d.ts +97 -0
  94. package/dist/facade/display-view-rendering.js +598 -0
  95. package/dist/facade/display-view-rendering.js.map +1 -0
  96. package/dist/facade/display-view.d.ts +37 -65
  97. package/dist/facade/display-view.js +152 -499
  98. package/dist/facade/display-view.js.map +1 -1
  99. package/dist/facade/expected-signal-setup.d.ts +3 -1
  100. package/dist/facade/expected-signal-setup.js +3 -3
  101. package/dist/facade/expected-signal-setup.js.map +1 -1
  102. package/dist/facade/expected-signal.d.ts +47 -14
  103. package/dist/facade/expected-signal.js +117 -112
  104. package/dist/facade/expected-signal.js.map +1 -1
  105. package/dist/facade/exposure-build-up.d.ts +70 -0
  106. package/dist/facade/exposure-build-up.js +164 -0
  107. package/dist/facade/exposure-build-up.js.map +1 -0
  108. package/dist/facade/fast-methods.d.ts +1 -1
  109. package/dist/facade/fast-methods.js +46 -9
  110. package/dist/facade/fast-methods.js.map +1 -1
  111. package/dist/facade/generic-lens-capture.d.ts +3 -3
  112. package/dist/facade/generic-lens-capture.js +3 -3
  113. package/dist/facade/generic-lens-capture.js.map +1 -1
  114. package/dist/facade/image-plane-enable.d.ts +7 -0
  115. package/dist/facade/image-plane-enable.js +17 -0
  116. package/dist/facade/image-plane-enable.js.map +1 -0
  117. package/dist/facade/image-plane-lattice-data.d.ts +6 -0
  118. package/dist/facade/image-plane-lattice-data.js +10 -0
  119. package/dist/facade/image-plane-lattice-data.js.map +1 -0
  120. package/dist/facade/image-plane-support.d.ts +33 -0
  121. package/dist/facade/image-plane-support.js +11 -0
  122. package/dist/facade/image-plane-support.js.map +1 -0
  123. package/dist/facade/image-plane.d.ts +36 -0
  124. package/dist/facade/image-plane.js +384 -0
  125. package/dist/facade/image-plane.js.map +1 -0
  126. package/dist/facade/mixed-illumination.d.ts +108 -0
  127. package/dist/facade/mixed-illumination.js +174 -0
  128. package/dist/facade/mixed-illumination.js.map +1 -0
  129. package/dist/facade/on-demand-kits.d.ts +14 -0
  130. package/dist/facade/on-demand-kits.js +36 -0
  131. package/dist/facade/on-demand-kits.js.map +1 -0
  132. package/dist/facade/opt-in-kit.d.ts +9 -0
  133. package/dist/facade/opt-in-kit.js +11 -0
  134. package/dist/facade/opt-in-kit.js.map +1 -0
  135. package/dist/facade/quality-kit.d.ts +21 -0
  136. package/dist/facade/quality-kit.js +23 -0
  137. package/dist/facade/quality-kit.js.map +1 -0
  138. package/dist/facade/quality-paths.d.ts +22 -0
  139. package/dist/facade/quality-paths.js +44 -0
  140. package/dist/facade/quality-paths.js.map +1 -0
  141. package/dist/facade/representative-light-sources.d.ts +72 -0
  142. package/dist/facade/representative-light-sources.js +124 -0
  143. package/dist/facade/representative-light-sources.js.map +1 -0
  144. package/dist/facade/scene-radiance.d.ts +145 -4
  145. package/dist/facade/scene-radiance.js +50 -13
  146. package/dist/facade/scene-radiance.js.map +1 -1
  147. package/dist/facade/simulate-capture.d.ts +68 -20
  148. package/dist/facade/simulate-capture.js +399 -146
  149. package/dist/facade/simulate-capture.js.map +1 -1
  150. package/dist/facade/simulate-display-view.d.ts +10 -12
  151. package/dist/facade/simulate-display-view.js +70 -53
  152. package/dist/facade/simulate-display-view.js.map +1 -1
  153. package/dist/gpu/chart-composite-gpu.d.ts +13 -1
  154. package/dist/gpu/chart-composite-gpu.js +48 -9
  155. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  156. package/dist/gpu/chart-radiance-gpu.js +4 -30
  157. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  158. package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
  159. package/dist/gpu/display-view-composite-material-module.js +39 -13
  160. package/dist/gpu/display-view-composite-material-module.js.map +1 -1
  161. package/dist/gpu/display-view-gpu-renderer.d.ts +43 -0
  162. package/dist/gpu/display-view-gpu-renderer.js +134 -0
  163. package/dist/gpu/display-view-gpu-renderer.js.map +1 -0
  164. package/dist/gpu/display-view-image-material-module.d.ts +87 -0
  165. package/dist/gpu/display-view-image-material-module.js +361 -0
  166. package/dist/gpu/display-view-image-material-module.js.map +1 -0
  167. package/dist/gpu/display-view-image-quality.d.ts +87 -0
  168. package/dist/gpu/display-view-image-quality.js +625 -0
  169. package/dist/gpu/display-view-image-quality.js.map +1 -0
  170. package/dist/gpu/display-view-quality-gpu.d.ts +80 -65
  171. package/dist/gpu/display-view-quality-gpu.js +187 -445
  172. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  173. package/dist/gpu/display-view-speed-gpu.d.ts +67 -19
  174. package/dist/gpu/display-view-speed-gpu.js +181 -105
  175. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  176. package/dist/gpu/image-kernel-accelerator.js +3 -0
  177. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  178. package/dist/gpu/image-kernel-execution.d.ts +2 -13
  179. package/dist/gpu/image-kernel-execution.js +2 -10
  180. package/dist/gpu/image-kernel-execution.js.map +1 -1
  181. package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +8 -0
  182. package/dist/gpu/wgsl-display-view-coupled-stub.js +21 -0
  183. package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
  184. package/dist/gpu/wgsl-display-view-coupled.d.ts +88 -0
  185. package/dist/gpu/wgsl-display-view-coupled.js +353 -0
  186. package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
  187. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +33 -24
  188. package/dist/gpu/wgsl-display-view-quality-kernel.js +166 -146
  189. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  190. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +19 -44
  191. package/dist/gpu/wgsl-display-view-speed-kernel.js +116 -18
  192. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  193. package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
  194. package/dist/gpu/wgsl-exact-sum.js +42 -0
  195. package/dist/gpu/wgsl-exact-sum.js.map +1 -0
  196. package/dist/index.d.ts +22 -6
  197. package/dist/index.js +16 -2
  198. package/dist/index.js.map +1 -1
  199. package/dist/motion/subject-motion.d.ts +66 -0
  200. package/dist/motion/subject-motion.js +52 -0
  201. package/dist/motion/subject-motion.js.map +1 -0
  202. package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
  203. package/dist/optics/generic-lens-lateral-color.js +77 -0
  204. package/dist/optics/generic-lens-lateral-color.js.map +1 -0
  205. package/dist/optics/generic-lens-psf.js +54 -46
  206. package/dist/optics/generic-lens-psf.js.map +1 -1
  207. package/dist/optics/lens-psf-profile.d.ts +7 -0
  208. package/dist/optics/lens-psf-profile.js +2 -1
  209. package/dist/optics/lens-psf-profile.js.map +1 -1
  210. package/dist/output/camera-channel-response.d.ts +50 -0
  211. package/dist/output/camera-channel-response.js +69 -0
  212. package/dist/output/camera-channel-response.js.map +1 -0
  213. package/dist/output/developed-lens-corrections.d.ts +19 -5
  214. package/dist/output/developed-lens-corrections.js +28 -9
  215. package/dist/output/developed-lens-corrections.js.map +1 -1
  216. package/dist/output/generic-lens-corrections.d.ts +41 -5
  217. package/dist/output/generic-lens-corrections.js +52 -8
  218. package/dist/output/generic-lens-corrections.js.map +1 -1
  219. package/dist/output/native-capture-sdr.js +5 -2
  220. package/dist/output/native-capture-sdr.js.map +1 -1
  221. package/dist/output/print-plan.d.ts +41 -5
  222. package/dist/output/print-plan.js +59 -14
  223. package/dist/output/print-plan.js.map +1 -1
  224. package/dist/output/sdr-rendering.d.ts +18 -1
  225. package/dist/output/sdr-rendering.js +39 -2
  226. package/dist/output/sdr-rendering.js.map +1 -1
  227. package/dist/sensor/binomial-sample.d.ts +3 -0
  228. package/dist/sensor/binomial-sample.js +86 -0
  229. package/dist/sensor/binomial-sample.js.map +1 -0
  230. package/dist/sensor/native-sensor-report.d.ts +10 -0
  231. package/dist/sensor/native-sensor-report.js +16 -0
  232. package/dist/sensor/native-sensor-report.js.map +1 -0
  233. package/dist/sensor/sensor-characteristics.d.ts +91 -13
  234. package/dist/sensor/sensor-characteristics.js +30 -15
  235. package/dist/sensor/sensor-characteristics.js.map +1 -1
  236. package/docs/AGENT_GUIDE.md +1 -0
  237. package/docs/API_REFERENCE.md +214 -4
  238. package/docs/QUICK_START.md +162 -8
  239. package/docs/USAGE.md +195 -22
  240. package/docs/api/capture-c2pa-embed.md +177 -0
  241. package/docs/api/capture-dng-import.md +86 -10
  242. package/docs/api/capture-dng-opcodes.md +93 -0
  243. package/docs/api/capture-dng-profile-maps.md +141 -0
  244. package/docs/api/capture-dng-stage-image.md +43 -0
  245. package/docs/api/capture-jpeg-xl-tiles.md +33 -0
  246. package/docs/api/capture-lossy-jpeg.md +41 -0
  247. package/docs/api/capture-native-raw-development.md +2 -1
  248. package/docs/api/core-execution-error.md +43 -0
  249. package/docs/api/core-version.md +1 -1
  250. package/docs/api/equipment-generic-lens-catalogue.md +10 -5
  251. package/docs/api/equipment-sensor-profile-body.md +64 -0
  252. package/docs/api/equipment-sensor-profiles.md +86 -0
  253. package/docs/api/exports.json +460 -5
  254. package/docs/api/facade-display-view-gpu.md +5 -2
  255. package/docs/api/facade-display-view.md +11 -15
  256. package/docs/api/facade-exposure-build-up.md +105 -0
  257. package/docs/api/facade-fast-methods.md +47 -10
  258. package/docs/api/facade-image-plane-enable.md +16 -0
  259. package/docs/api/facade-mixed-illumination.md +67 -0
  260. package/docs/api/facade-quality-paths.md +24 -0
  261. package/docs/api/facade-representative-light-sources.md +131 -0
  262. package/docs/api/facade-scene-radiance.md +54 -3
  263. package/docs/api/facade-simulate-capture.md +48 -11
  264. package/docs/api/facade-simulate-display-view.md +10 -12
  265. package/docs/api/gpu-image-kernel-execution.md +0 -36
  266. package/docs/api/motion-subject-motion.md +23 -0
  267. package/docs/api/optics-generic-lens-lateral-color.md +79 -0
  268. package/docs/api/output-camera-channel-response.md +55 -0
  269. package/docs/api/output-developed-lens-corrections.md +10 -1
  270. package/docs/api/output-generic-lens-corrections.md +40 -4
  271. package/docs/api/output-print-plan.md +35 -1
  272. package/docs/api/output-sdr-rendering.md +6 -1
  273. package/docs/api/sensor-sensor-characteristics.md +54 -2
  274. package/llms.txt +3 -0
  275. package/package.json +6 -5
@@ -58,10 +58,13 @@ export interface DisplayViewGpuConformance {
58
58
  2.11 (#481): why a display view that asked for the GPU (`gpu: "auto"`) ran the CPU reference. The accelerator's acquisition
59
59
  reasons, plus: `unsupported-on-backend` (no GPU display-view renderer exists in this version, or it does not support the
60
60
  request), `conformance-failed` (the device failed the run-time self-check before the view's first GPU render), `device-lost`
61
- (the device was lost; the rest of the view runs on the CPU) and `disposed` (the prepared view was disposed).
61
+ (the device was lost; the rest of the view runs on the CPU) and `disposed` (the prepared view was disposed). 2.22.0 (#594):
62
+ `quality-code-unavailable` (the on-demand GPU full-quality code could not be loaded; that render runs the CPU reference, and
63
+ the next render that needs the code tries to load it again).
62
64
 
63
65
  ```ts
64
- export type DisplayViewGpuFallbackReason = ImageKernelFallbackReason | "unsupported-on-backend" | "conformance-failed" | "device-lost" | "disposed";
66
+ export type DisplayViewGpuFallbackReason = ImageKernelFallbackReason | "unsupported-on-backend" | "conformance-failed" | "device-lost" | "disposed" |
67
+ "quality-code-unavailable";
65
68
  ```
66
69
 
67
70
  ## DisplayViewGpuMode
@@ -4,14 +4,10 @@ The package and root API versions are recorded once in [Navigation](../API_REFER
4
4
 
5
5
  ## bindDisplayViewCorrectionStates
6
6
 
7
- 2.10 (#447): adds states another realm computed (an export, or `computeCorrectionStates` results) to this realm's cache and
8
- returns the number of states added. For each entry, the grid keys its setup does not hold yet are appended; known ones are
9
- left as they are (a state's values follow from its key, so they are equal). Every entry is checked before the cache is
10
- touched: `key` a non-empty string, `gridKeys` an Int32Array of grid keys, `values` a Float64Array of 3 × `gridKeys.length`
11
- finite numbers; otherwise it fails with an InvalidConfigurationError and the cache is unchanged. The cache's bounds apply as
12
- in a render: an unknown key creates a setup and can evict the least recently used of the four kept, and a setup that
13
- reaches 65 536 states is cleared before the next one is added. Import only keys a prepared view reported
14
- (`correctionKey()`), so states a render here will read.
7
+ 2.10 (#447), deprecated in 2.22.0: added states another realm computed to this realm's cache. The display view keeps no
8
+ correction states since 2.22.0, so this checks `entries` as before (an array of `{ key, gridKeys, values }` with a non-empty
9
+ string key, an Int32Array of grid keys and a Float64Array of 3 finite values per key; otherwise an
10
+ InvalidConfigurationError) and returns 0: nothing is stored and no render reads them. Kept until 3.0.0.
15
11
 
16
12
  ```ts
17
13
  export function bindDisplayViewCorrectionStates(entries: readonly DisplayViewCorrectionStateSet[]): number;
@@ -21,7 +17,7 @@ This call is synchronous; any supplied provider must follow its explicit synchro
21
17
 
22
18
  ## DisplayViewCorrectionStateKeys
23
19
 
24
- 2.10 (#447): the grid keys of the states a region needs (`PreparedDisplayView.collectCorrectionStates`), ascending.
20
+ 2.10 (#447), deprecated in 2.22.0: the grid keys of the states a region needs (`PreparedDisplayView.collectCorrectionStates`).
25
21
 
26
22
  ```ts
27
23
  export interface DisplayViewCorrectionStateKeys { key: string; gridKeys: Int32Array }
@@ -29,9 +25,9 @@ export interface DisplayViewCorrectionStateKeys { key: string; gridKeys: Int32Ar
29
25
 
30
26
  ## DisplayViewCorrectionStateSet
31
27
 
32
- 2.10 (#447): the AHD low-signal correction states of one setup, as a realm sends them to another. `key` is the setup's
33
- correction key (`PreparedDisplayView.correctionKey()`), `gridKeys[i]` a state's grid key and `values[3·i …]` its three
34
- values (28 bytes per state). Both arrays are transferable.
28
+ 2.10 (#447), deprecated in 2.22.0: the AHD low-signal correction states of one setup, as a realm sent them to another. The
29
+ display view keeps no correction states since 2.22.0, so {@link serializeDisplayViewCorrectionStates} returns none.
30
+ Kept until 3.0.0.
35
31
 
36
32
  ```ts
37
33
  export interface DisplayViewCorrectionStateSet { key: string; gridKeys: Int32Array; values: Float64Array }
@@ -39,9 +35,9 @@ export interface DisplayViewCorrectionStateSet { key: string; gridKeys: Int32Arr
39
35
 
40
36
  ## serializeDisplayViewCorrectionStates
41
37
 
42
- 2.10 (#447): the AHD low-signal correction states this JavaScript realm holds (a Web Worker, a page), one entry per cached
43
- setup, least recently used first, each state's grid key and three values copied out. Another realm adds them with
44
- {@link bindDisplayViewCorrectionStates}; a render there then reads them instead of computing them, with the same bytes.
38
+ 2.10 (#447), deprecated in 2.22.0: returned the AHD low-signal correction states this realm held. The display view keeps no
39
+ correction states since 2.22.0 (the correction was removed; docs/DISPLAY_VIEW.md, "AHD at low signal"), so this returns an
40
+ empty array. Kept until 3.0.0.
45
41
 
46
42
  ```ts
47
43
  export function serializeDisplayViewCorrectionStates(): DisplayViewCorrectionStateSet[];
@@ -0,0 +1,105 @@
1
+ # facade/exposure-build-up.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS
6
+
7
+ The most fractions one build-up takes.
8
+
9
+ ```ts
10
+ EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS = 64
11
+ ```
12
+
13
+ ## EXPOSURE_BUILD_UP_STREAM_BASE
14
+
15
+ The first stream ID of the build-up's per-site random streams (`deriveNativeSiteStreamSeedUint32`): fraction j's photo split,
16
+ dark split and readout use streams base + 3j, + 3j + 1 and + 3j + 2 (j = 0 … 63). The whole exposure keeps the ordinary
17
+ streams 0 (charge) and 1 (read noise).
18
+
19
+ ```ts
20
+ EXPOSURE_BUILD_UP_STREAM_BASE = 0x42550000
21
+ ```
22
+
23
+ ## simulateExposureBuildUp
24
+
25
+ Renders fractions of one exposure as one accumulating process (#534), the way a camera's live readout of a long exposure
26
+ would show the light building up. Each fraction is read out and developed as its own photo.
27
+
28
+ The model: photon and dark-charge arrivals at a site are Poisson processes (photon shot noise: EMVA 1288 Release 4.0,
29
+ section 2, free), with any rate over time. Given the count n over [0, t] of a Poisson process with mean Λ(t), its arrival
30
+ times are n independent times with distribution Λ(s)/Λ(t) on [0, t], so its count over [0, s] is Binomial(n, Λ(s)/Λ(t))
31
+ (R. G. Gallager, Discrete Stochastic Processes, chapter 2, sections 2.4 and 2.5, MIT OpenCourseWare 6.262, free).
32
+
33
+ The method: the whole exposure is `simulateCapture(options)` itself, with its ordinary draws and seeds. Each earlier fraction
34
+ fⱼ is a capture of the same request in manual mode at the whole exposure's resolved f-number and ISO and the shutter fⱼ·t,
35
+ so its expected signal at every site is integrated from the spectrum over the window [0, fⱼ·t] by the capture itself (the
36
+ camera rotation, `motion.subject` and mixed lighting included, and each row's own window with a rolling shutter). Its
37
+ counts are not drawn anew: going down the fractions, each site's photo and dark counts are N(fⱼ) ~ Binomial(N(fⱼ₊₁), λ(fⱼ) /
38
+ λ(fⱼ₊₁)), with λ the site's expected mean in each render (after PRNU and DSNU). So every fraction's counts are Poisson with
39
+ that fraction's own mean (the mean and variance of `simulateCapture` at fⱼ·t), they never decrease from one fraction to the
40
+ next, and two fractions' counts covary by the earlier one's mean. Fixed-pattern noise is the sensor's own and the same in
41
+ every fraction. Each fraction's charge is clipped at the full well, then read once: its own read noise (dual gain as the ISO
42
+ selects), pre-ADC and ADC saturation and quantization at the ADC bit depth.
43
+
44
+ The windows are nested, so the true means never decrease; the capture's temporal midpoint quadrature can still put an
45
+ earlier fraction's estimate above a later one's at a site (motion blur). There the split takes probability 1 (the count is
46
+ kept), and the `exposure.buildUp` assumption counts those sites (`nonMonotoneSites`): an approximation of the quadrature,
47
+ not of the binomial law. Raise `sensor.temporalSampleCount` to remove them.
48
+
49
+ Cost: one capture per fraction, plus about 64 bytes per native site for the chain. Exact or fast: the request's own `fast`
50
+ (and the format default) applies to every fraction; the build-up adds no fast method, so with `fast: false` (the calculator's
51
+ setting) every fraction is an exact capture. On screen only: formats "srgb-8" and "srgb-16" (a fraction's JPEG, PNG or DNG
52
+ is refused). A fraction's realization depends on the whole `fractions` list (each step of the chain has its own streams);
53
+ the same request and list always give the same frames.
54
+
55
+ ```ts
56
+ export async function simulateExposureBuildUp(options: SimulateCaptureOptions, buildUp: SimulateExposureBuildUpOptions): Promise<SimulateExposureBuildUpResult>;
57
+ ```
58
+
59
+ This call is asynchronous; byte hashing uses the caller runtime's Web Crypto.
60
+
61
+ ## SimulateExposureBuildUpFrame
62
+
63
+ One readout of a build-up.
64
+
65
+ ```ts
66
+ export interface SimulateExposureBuildUpFrame {
67
+ /** The fraction of the exposure collected. */
68
+ fraction: number;
69
+ /** fraction × the request's shutter time, in s. */
70
+ elapsedSeconds: number;
71
+ /**
72
+ * The fraction developed as its own photo. At fraction 1 it is `simulateCapture(options)` itself, byte for byte. Below 1 it is
73
+ * the result of the fraction's capture (manual, the whole exposure's f-number and ISO, shutter fraction·t: its `image`, `raw`,
74
+ * `plan` and `request`), with the build-up's counts, the `exposure.buildUp` assumption, and the whole exposure's `exposure` and
75
+ * `sensor` reports (the camera's settings and noise figure, not the elapsed part's).
76
+ */
77
+ result: SimulateCaptureResult;
78
+ }
79
+ ```
80
+
81
+ ## SimulateExposureBuildUpOptions
82
+
83
+ The build-up to render with {@link simulateExposureBuildUp}.
84
+
85
+ ```ts
86
+ export interface SimulateExposureBuildUpOptions {
87
+ /**
88
+ * Fractions of `exposure.shutterSeconds` to read out, strictly increasing, each above 0 and at most 1 (1 to 64 of them), for
89
+ * example `[0.2, 0.4, 0.6, 0.8, 1]`. A fraction of 1 is the whole exposure: `simulateCapture` of the request.
90
+ */
91
+ fractions: readonly number[];
92
+ }
93
+ ```
94
+
95
+ ## SimulateExposureBuildUpResult
96
+
97
+ The readouts of {@link simulateExposureBuildUp}, in the order of `fractions`.
98
+
99
+ ```ts
100
+ export interface SimulateExposureBuildUpResult {
101
+ /** The whole exposure's shutter time, in s. */
102
+ shutterSeconds: number;
103
+ frames: readonly SimulateExposureBuildUpFrame[];
104
+ }
105
+ ```
@@ -9,9 +9,13 @@ The package and root API versions are recorded once in [Navigation](../API_REFER
9
9
  ```ts
10
10
  SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = Object.freeze([
11
11
  { id: "lens.catalogue/field-grid", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture"],
12
- fast: "#568: the PSF blended over a field grid and tabulated expected electrons, verified per CFA phase against the exact chain",
12
+ fast: "#568: the PSF blended over a field grid, with each site's expected electrons integrated from its taps' material spectra at use, verified per CFA phase against the exact chain",
13
13
  exact: "the environment PSF quadrature with the PSF resolved at each query point", followsFormatDefault: true,
14
14
  resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "fast.lens.catalogue" } },
15
+ { id: "lens.catalogue/field-grid-cells", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture"],
16
+ fast: "#603: when the field-grid method runs on a fast request, at least 4 grid cells per field interval (2.20.0's grid), except for the measured lenses of CATALOGUE_FAST_GRID_FULL_ON_SCREEN, whose fallbacks made 4 cells slower",
17
+ exact: "at least 10 cells per field interval when the field-grid method runs on an exact request (lens.catalogue fast: true with an export or fast: false)", followsFormatDefault: true,
18
+ resolver: { file: CAPTURE, call: "catalogueFastGridSubdivisions(catalogue!.lensId, fastTop)" }, report: { assumption: "fast.lens.catalogue" } },
15
19
  { id: "lens.catalogue/cats-eye", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
16
20
  fast: "#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)",
17
21
  exact: "the cat's eye shaped at each field point (fast wides and normals)", followsFormatDefault: true,
@@ -21,13 +25,13 @@ SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = Object.fre
21
25
  exact: "one zone per site: the PSF at each site centre", followsFormatDefault: true,
22
26
  resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "view.lensPsf" } },
23
27
  { id: "lens.diffraction/rolling-shutter-taps", override: "lens.diffraction", methods: "fast-and-exact", runs: ["simulateCapture"],
24
- fast: "#565: under rolling-shutter rotation, each PSF tap reads the scene at its own source point",
28
+ fast: "#565: under rolling-shutter rotation (#551: or subject motion), each PSF tap reads the scene at its own source point",
25
29
  exact: "each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)", followsFormatDefault: true,
26
30
  resolver: { file: CAPTURE, call: "resolveFast(diffractionFast, fastTop)" }, report: { applied: "lens.diffraction", assumption: "fast.lens.diffraction" } },
27
- { id: "output.demosaic.ahd/view-low-signal-correction", override: "output.demosaic", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
28
- fast: "(H3) 2048 draws per correction state, applied where a pixel's linear noise exceeds 0.01",
29
- exact: "8192 draws per state, at the same 0.01 threshold", followsFormatDefault: true,
30
- resolver: { file: CAPTURE, call: "resolveFast(demosaicFast, fastTop)" }, report: { applied: "output.demosaic.ahd", assumption: "view.demosaic" } },
31
+ { id: "lens.catalogue/rolling-shutter-taps", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture"],
32
+ fast: "#588: under rolling-shutter rotation, each catalogue PSF tap reads the scene at its own source point",
33
+ exact: "each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)", followsFormatDefault: true,
34
+ resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "fast.lens.catalogue" } },
31
35
  { id: "view.uniform-pixel-sampling", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
32
36
  fast: "(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail",
33
37
  exact: "the full samples per axis in every display pixel", followsFormatDefault: true,
@@ -37,9 +41,42 @@ SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = Object.fre
37
41
  exact: "gpu \"off\": the CPU reference; an explicit gpu wins", followsFormatDefault: true,
38
42
  resolver: { file: VIEW, call: "parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)" },
39
43
  report: { field: "diagnostics.fast.execution" } },
44
+ { id: "illumination/image-plane-gpu", override: "fast", methods: "fast-and-exact", runs: ["prepareDisplayView"],
45
+ fast: "#597: gpu \"auto\": an image-plane print under mixed lighting on WebGPU (float32, a bounded approximation): the print's Quality passes light each lattice " +
46
+ "point per spectral node from the light's spectra and parts (Speed requests too, without site kernels); flagged points resolved on the host",
47
+ exact: "gpu \"off\": the CPU reference integrates each site from the lit radiance per spectral node in float64; an explicit gpu wins", followsFormatDefault: true,
48
+ resolver: { file: VIEW, call: "parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)" },
49
+ report: { field: "diagnostics.fast.execution" } },
50
+ { id: "sensor.spectralStepNanometers", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
51
+ fast: "#590: the default spectral step is 20 nm under any light; under a spiky one (R(20) > 0.01) sensor.spectralSpikiness notes the possible cast",
52
+ exact: "5 nm under a spiky light, else 20 nm (an explicit sensor.spectralStepNanometers always wins)", followsFormatDefault: true,
53
+ resolver: { file: CAPTURE, call: "fastTop || !spiky" }, report: { applied: "sensor.spectralStepNanometers", assumption: "sensor.spectralSpikiness" } },
40
54
  { id: "sensor.midGrey", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
41
55
  fast: "#535: the mid-gray noise figure is not computed (about 0.3 ms)", exact: "result.sensor.midGrey is computed", followsFormatDefault: true,
42
56
  resolver: { file: CAPTURE, call: "fastTop ? undefined : 0" }, report: { field: "sensor.midGrey" } },
57
+ { id: "motion.subject/temporal-midpoints", override: "motion.subject", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
58
+ fast: "#551: with the default count and a still camera, one temporal midpoint per site of the subject's streak plus one, when that is fewer than 8",
59
+ exact: "the default 8 temporal midpoints (an explicit sensor.temporalSampleCount always wins)", followsFormatDefault: true,
60
+ resolver: { file: CAPTURE, call: "resolveFast(subjectFast, fastTop)" }, report: { applied: "motion.subject", assumption: "fast.motion.subject" } },
61
+ { id: "dngImport.warpRectilinear", override: "fast", methods: "fast-and-exact", runs: ["developDngStageImage"],
62
+ fast: "#600: an imported DNG's WarpRectilinear opcode resampled bilinearly", exact: "cubic convolution (Keys, a = −0.75, the DNG SDK's kernel); default fast unless format names an export", followsFormatDefault: true,
63
+ resolver: { file: "src/capture/dng-stage-image.ts", call: "resolveFast(options.fast, fastFormatDefault(format, \"capture\"))" }, report: { field: "fast" } },
64
+ { id: "output.toneCurve/view-luminance-moments", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
65
+ fast: "#593: a luminance tone curve's moments by an 8-point Gauss–Hermite rule in luminance where its range stays clear of L = 0 (else the full rule)",
66
+ exact: "a composite 4 × 16-point Gauss–Legendre rule over the luminance's ±8.5σ, split at L = 0", followsFormatDefault: true,
67
+ resolver: { file: CAPTURE, call: "rendering: fastTop" }, report: { assumption: "view.rendering" } },
68
+ { id: "output.highlightMode.reconstruct/view-moments", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
69
+ fast: "#593, #601: where the reconstruct blend or the desaturation is within reach, the development chain integrated with 6 Gauss–Hermite points per axis (216 nodes)",
70
+ exact: "16 points per axis (4,096 nodes)", followsFormatDefault: true,
71
+ resolver: { file: CAPTURE, call: "rendering: fastTop" }, report: { assumption: "view.rendering" } },
72
+ { id: "prepareDisplayView.gpu/view-coupled-moments", override: "fast", methods: "fast-and-exact", runs: ["prepareDisplayView"],
73
+ fast: "#593, #601: the WebGPU Speed and Quality kernels' coupled steps with the fast rules (8-point Gauss–Hermite in luminance; 6 points per axis for the chain), float32 within the a-priori bound",
74
+ exact: "the same kernels with the full rules (4 × 16 Gauss–Legendre; 16 points per axis), fast: false with an explicit gpu", followsFormatDefault: true,
75
+ resolver: { file: "src/gpu/wgsl-display-view-coupled.ts", call: "out[C.fast] = r.fast ? 1 : 0" }, report: { assumption: "view.rendering" } },
76
+ { id: "output.highlightMode.reconstruct-neighbors/region-ratios", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
77
+ fast: "#602: each clipped region takes the mean color ratios of the unclipped pixels within 2 pixels of it",
78
+ exact: "the ratios' harmonic (Laplace) interpolation inward from the region's unclipped neighbors (successive over-relaxation)", followsFormatDefault: true,
79
+ resolver: { file: CAPTURE, call: "const neighborFast = fastTop" }, report: { assumption: "output.highlightMode.reconstructNeighbors" } },
43
80
  { id: "lens.diffraction", override: "lens.diffraction", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
44
81
  fast: "", exact: "the diffraction kernels (a fast method only under rolling-shutter rotation, above)", followsFormatDefault: true,
45
82
  resolver: { file: CAPTURE, call: "resolveFast(diffractionFast, fastTop)" }, report: { applied: "lens.diffraction" } },
@@ -49,9 +86,9 @@ SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = Object.fre
49
86
  { id: "sensor.pixelAperture.box", override: "sensor.pixelAperture", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
50
87
  fast: "", exact: "the N × N midpoint rule", followsFormatDefault: true,
51
88
  resolver: { file: CAPTURE, call: "fastInUse" }, report: { applied: "sensor.pixelAperture.box" } },
52
- { id: "output.demosaic.ahd", override: "output.demosaic", methods: "exact-only", runs: ["simulateCapture"],
53
- fast: "", exact: "the AHD demosaic of the capture (a fast method only in the display view's correction, above)", followsFormatDefault: true,
54
- resolver: { file: CAPTURE, call: "resolveFast(demosaicFast, fastTop)" }, report: { applied: "output.demosaic.ahd" } }
89
+ { id: "output.demosaic.ahd", override: "output.demosaic", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
90
+ fast: "", exact: "the AHD demosaic of the capture; in the display view, AHD's two linear candidates and its choice on the noise-free mosaic (2.22.0: no low-signal correction, so no fast method)", followsFormatDefault: true,
91
+ resolver: { file: CAPTURE, call: "[\"output.demosaic.ahd\", ahd, demosaicFast]" }, report: { applied: "output.demosaic.ahd" } }
55
92
  ] as const satisfies readonly SimulateCaptureFastMethod[])
56
93
  ```
57
94
 
@@ -71,7 +108,7 @@ export interface SimulateCaptureFastMethod {
71
108
  /** "fast-and-exact": both methods exist; "exact-only": the record takes `fast`, but there is no fast method yet (reports false). */
72
109
  methods: "fast-and-exact" | "exact-only";
73
110
  /** Where it applies. */
74
- runs: readonly ("simulateCapture" | "simulateDisplayView" | "prepareDisplayView")[];
111
+ runs: readonly ("simulateCapture" | "simulateDisplayView" | "prepareDisplayView" | "developDngStageImage")[];
75
112
  /** The fast method and the exact one, in words (empty for exact-only). */
76
113
  fast: string;
77
114
  exact: string;
@@ -0,0 +1,16 @@
1
+ # facade/image-plane-enable.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## prepareImagePlaneScenes
6
+
7
+ 2.21 (#581): enables `{ kind: "image-plane" }` scenes (a photo as a flat print, docs/IMAGE_PLANE.md) in this JavaScript realm by
8
+ loading their module (a lazy chunk of about 14 KB gzip with its lattice data). Call it once, in the worker that captures, before
9
+ the first request with such a scene; later calls resolve at once. A request with an image-plane scene before it fails with a
10
+ message saying so.
11
+
12
+ ```ts
13
+ export async function prepareImagePlaneScenes(): Promise<void>;
14
+ ```
15
+
16
+ This call is asynchronous; byte hashing uses the caller runtime's Web Crypto.
@@ -0,0 +1,67 @@
1
+ # facade/mixed-illumination.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## MixedIllumination
6
+
7
+ 2.22 (#550), `simulateCapture` `illumination`: sources blended across the chart and point sources with inverse-square falloff
8
+ (docs/MIXED_ILLUMINATION.md). It replaces `illuminant` and `illuminanceLux`. `sources` lists 1 to 8 sources (with two or more, a
9
+ `blend` is required; one lights the whole plane); `points` lists 1 to 8 point sources; a request needs two or more sources or at least one point. Blend
10
+ coordinates are chart-local with `chartSize` and frame units without it; (0, 0) is the frame center.
11
+
12
+ ```ts
13
+ export interface MixedIllumination {
14
+ sources?: readonly MixedIlluminationSource[];
15
+ blend?: MixedIlluminationBlend;
16
+ points?: readonly MixedIlluminationPointSource[];
17
+ }
18
+ ```
19
+
20
+ ## MixedIlluminationBlend
21
+
22
+ How the sources blend across the chart. `linear-gradient` and `radial` map a point to a position t in [0, 1] (its projection
23
+ onto `from` → `to`, clamped; or its distance from `center` over `radius`, clamped) and crossfade linearly between consecutive
24
+ sources at their `stops` (one per source, non-decreasing in [0, 1]; default evenly spaced from 0 to 1): source 0 alone up to
25
+ stops[0], the last source alone from its stop on, and two equal stops a hard edge (the later source from the stop on).
26
+ `regions` gives each point the source of the first rectangle that contains it (bounds inclusive) and `outsideSource` elsewhere.
27
+
28
+ ```ts
29
+ export type MixedIlluminationBlend =
30
+ | { kind: "linear-gradient"; from: MixedIlluminationPoint; to: MixedIlluminationPoint; stops?: readonly number[] }
31
+ | { kind: "radial"; center?: MixedIlluminationPoint; radius: number; stops?: readonly number[] }
32
+ | { kind: "regions"; regions: readonly { source: number; uMin: number; uMax: number; vMin: number; vMax: number }[]; outsideSource: number };
33
+ ```
34
+
35
+ ## MixedIlluminationPoint
36
+
37
+ A point in chart coordinates (see {@link MixedIllumination}).
38
+
39
+ ```ts
40
+ export interface MixedIlluminationPoint { u: number; v: number }
41
+ ```
42
+
43
+ ## MixedIlluminationPointSource
44
+
45
+ 2.22 (#550): a point light on the scene plane's front side: an illuminant spectrum, a position in metres (`xM`, `yM` on the plane
46
+ from the optical axis, +x right and +y up as seen from the camera; `heightM` > 0 in front of the plane, toward the camera) and an
47
+ intensity, either in candela or as the illuminance it gives at normal incidence at a reference distance (I = E·r²).
48
+
49
+ ```ts
50
+ export interface MixedIlluminationPointSource {
51
+ illuminant: CaptureIlluminant;
52
+ position: { xM: number; yM: number; heightM: number };
53
+ intensity: { candela: number } | { illuminanceLux: number; distanceM: number };
54
+ }
55
+ ```
56
+
57
+ ## MixedIlluminationSource
58
+
59
+ One light source of a mixed illumination: an illuminant (as `simulateCapture` `illuminant` takes it) at an illuminance.
60
+
61
+ ```ts
62
+ export interface MixedIlluminationSource {
63
+ illuminant: CaptureIlluminant;
64
+ /** Illuminance this source alone gives where its weight is 1, lux, (0, 1e7]. */
65
+ illuminanceLux: number;
66
+ }
67
+ ```
@@ -0,0 +1,24 @@
1
+ # facade/quality-paths.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## prepareQualityPaths
6
+
7
+ Loads the engine's on-demand full-quality code now instead of at the first request that needs it (#594): the CPU Quality kit
8
+ (diffraction, the capture's AHD demosaic, `lens.defocus` beyond the geometric disc, the image-space provider of lens projection,
9
+ distortion and vignetting, the display view's coupled tone, reconstruct and desaturation steps, the neighbor highlight
10
+ reconstruction), the opt-in kit (`sensor.profile`, `illumination`, `motion.subject`) and the display view's GPU full-quality code
11
+ (the Quality passes behind `prepareDisplayView(…, { gpu: "auto" | "require" })`), together with the GPU session it builds on.
12
+
13
+ Optional: without it, the first request that needs the code loads it. Safe to call at any time and from any number of places:
14
+ concurrent calls share one load, and a call after it loaded resolves at once and loads nothing. It changes no result. If the
15
+ load fails (for example a chunk download error) the promise rejects with `ImageKernelExecutionError` reason
16
+ `quality-code-unavailable`; nothing is remembered, so a later call or request tries again, and a render in the meantime runs
17
+ the CPU reference, labelled with that reason. A bundler that splits dynamic imports keeps this code out of the first load
18
+ whether or not this function is imported.
19
+
20
+ ```ts
21
+ export function prepareQualityPaths(): Promise<void>;
22
+ ```
23
+
24
+ This call is asynchronous; byte hashing uses the caller runtime's Web Crypto.
@@ -0,0 +1,131 @@
1
+ # facade/representative-light-sources.ts public contracts
2
+
3
+ The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
4
+
5
+ ## createRepresentativeLightSourceIlluminant
6
+
7
+ A capture illuminant for a source: `{ kind: "spectrum", spectrum, label }` with the spectrum of
8
+ {@link createRepresentativeLightSourceSpectrum} and the label "<name> (representative, not a named product)".
9
+
10
+ ```ts
11
+ export function createRepresentativeLightSourceIlluminant(input: { sourceId: RepresentativeLightSourceId }): Extract<CaptureIlluminant, { kind: "spectrum" }>;
12
+ ```
13
+
14
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
15
+
16
+ ## createRepresentativeLightSourceSpectrum
17
+
18
+ A source's relative spectral power distribution S(λ) = b + Σ aₖ·exp(−½((λ − μₖ)/σₖ)²) as a function spectrum on
19
+ 360–830 nm (relative units; values memoized per wavelength). Pass it to a capture as
20
+ `illuminant: { kind: "spectrum", spectrum }`; for color work use `sensor.spectralStepNanometers: 5` or finer
21
+ (docs/LIGHT_SOURCES.md, "Quadrature"). Throws `InvalidScientificInputError` outside 360–830 nm.
22
+
23
+ ```ts
24
+ export function createRepresentativeLightSourceSpectrum(input: { sourceId: RepresentativeLightSourceId }): ColorimetricSpectrum;
25
+ ```
26
+
27
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
28
+
29
+ ## getRepresentativeLightSourceSet
30
+
31
+ The built-in representative light sources: Photivra's own parametric spectra of a tri-phosphor fluorescent tube and
32
+ three white LEDs (low and high color rendering at 4000 K, warm at 2700 K). A static, deeply frozen engine contract.
33
+ Each is "representative, not a named product"; docs/LIGHT_SOURCES.md gives every formula and the reasons for it.
34
+
35
+ ```ts
36
+ export function getRepresentativeLightSourceSet(): RepresentativeLightSourceSet;
37
+ ```
38
+
39
+ This call is synchronous; any supplied provider must follow its explicit synchronous contract.
40
+
41
+ ## REPRESENTATIVE_LIGHT_SOURCE_IDS
42
+
43
+ The source ids, in set order.
44
+
45
+ ```ts
46
+ REPRESENTATIVE_LIGHT_SOURCE_IDS = Object.freeze([
47
+ "tri-phosphor-fluorescent-4000k", "white-led-low-rendering-4000k", "white-led-high-rendering-4000k", "warm-white-led-2700k"
48
+ ] as const)
49
+ ```
50
+
51
+ ## REPRESENTATIVE_LIGHT_SOURCE_SET_ID
52
+
53
+ Identity of the built-in light-source set.
54
+
55
+ ```ts
56
+ REPRESENTATIVE_LIGHT_SOURCE_SET_ID = "photivra-representative-light-sources"
57
+ ```
58
+
59
+ ## REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION
60
+
61
+ Version of the set's spectra; a change to any spectrum changes it.
62
+
63
+ ```ts
64
+ REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION = "1.0.0"
65
+ ```
66
+
67
+ ## REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS
68
+
69
+ Domain of every spectrum, nm (the CIE 1931 observer's domain; the capture facade uses 380–780 nm of it).
70
+
71
+ ```ts
72
+ REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS = Object.freeze({ minimum: 360, maximum: 830 })
73
+ ```
74
+
75
+ ## RepresentativeLightSource
76
+
77
+ One built-in source: its id, name, design reason and spectrum definition.
78
+
79
+ ```ts
80
+ export interface RepresentativeLightSource {
81
+ sourceId: RepresentativeLightSourceId;
82
+ /** Photivra's descriptive name, for example "White LED, high color rendering, 4000 K". */
83
+ name: string;
84
+ family: "fluorescent" | "led";
85
+ /** The CCT the spectrum was designed for, K (its computed CCT is within 1 K of it, Duv within 0.0001; docs/LIGHT_SOURCES.md). */
86
+ nominalCorrelatedColorTemperatureKelvin: number;
87
+ /** Always "representative, not a named product". */
88
+ label: "representative, not a named product";
89
+ /** One sentence: what the source represents and why it is built this way. */
90
+ reason: string;
91
+ /** The constant b (a low continuum), relative units. */
92
+ base: number;
93
+ bands: readonly RepresentativeLightSourceBand[];
94
+ }
95
+ ```
96
+
97
+ ## RepresentativeLightSourceBand
98
+
99
+ One Gaussian band a·exp(−½((λ − μ)/σ)²) of a source spectrum.
100
+
101
+ ```ts
102
+ export interface RepresentativeLightSourceBand {
103
+ kind: "gaussian";
104
+ /** What the band represents, for example "blue pump" or "green phosphor line". */
105
+ role: string;
106
+ amplitude: number;
107
+ centerNanometers: number;
108
+ standardDeviationNanometers: number;
109
+ }
110
+ ```
111
+
112
+ ## RepresentativeLightSourceId
113
+
114
+ The exact contract is declared below; use the domain guide for assumptions and staged integration.
115
+
116
+ ```ts
117
+ export type RepresentativeLightSourceId = (typeof REPRESENTATIVE_LIGHT_SOURCE_IDS)[number];
118
+ ```
119
+
120
+ ## RepresentativeLightSourceSet
121
+
122
+ The exact contract is declared below; use the domain guide for assumptions and staged integration.
123
+
124
+ ```ts
125
+ export interface RepresentativeLightSourceSet {
126
+ setId: typeof REPRESENTATIVE_LIGHT_SOURCE_SET_ID;
127
+ setVersion: typeof REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION;
128
+ wavelengthRangeNanometers: { readonly minimum: number; readonly maximum: number };
129
+ sources: readonly RepresentativeLightSource[];
130
+ }
131
+ ```
@@ -91,7 +91,8 @@ provider `providerProfileId`.
91
91
 
92
92
  ```ts
93
93
  export function createPlanarSceneRadianceProvider(input: {
94
- scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene;
94
+ /** An `image-plane` scene (#581) is refused: it is taken by the facade's capture and display-view functions, which load its module. */
95
+ scene: ChartScene | ChartMaterialLayerScene | CallerReflectanceScene | CallerRadianceScene | CallerMaterialScene | ImagePlaneScene;
95
96
  illuminant: CaptureIlluminant;
96
97
  illuminanceLux: number;
97
98
  distanceM: number;
@@ -110,6 +111,47 @@ export function createPlanarSceneRadianceProvider(input: {
110
111
 
111
112
  This call is synchronous; any supplied provider must follow its explicit synchronous contract.
112
113
 
114
+ ## ImagePlaneImage
115
+
116
+ 2.21 (#581): an image the caller supplies, for an {@link ImagePlaneScene}. `data` holds `width × height` pixels row by row
117
+ from the top, `channels` (3: RGB, 4: RGBA) samples each, in the encoding's type: `srgb-8` Uint8Array or Uint8ClampedArray
118
+ (canvas `ImageData.data`), `srgb-16` Uint16Array, `linear-srgb` Float32Array. sRGB primaries and white (IEC 61966-2-1) in
119
+ every encoding; `srgb-8` and `srgb-16` are decoded with the sRGB transfer function, `linear-srgb` is already linear and is
120
+ clipped to [0, 1] (the clipped samples are counted). Alpha is linear coverage over the paper. The array is read, never
121
+ changed or kept beyond the call.
122
+
123
+ ```ts
124
+ export interface ImagePlaneImage {
125
+ width: number;
126
+ height: number;
127
+ channels: 3 | 4;
128
+ encoding: "srgb-8" | "srgb-16" | "linear-srgb";
129
+ data: Uint8Array | Uint8ClampedArray | Uint16Array | Float32Array;
130
+ }
131
+ ```
132
+
133
+ ## ImagePlaneScene
134
+
135
+ 2.21 (#581): a photo as a flat matte print on the scene plane, lit by the request's illuminant like a chart. Each pixel's
136
+ color becomes a reflectance spectrum through the engine's print reflectance lattice (docs/IMAGE_PLANE.md): an
137
+ approximation, a print of an image that was already processed, clipped and blurred by the camera that took it. The print's
138
+ physical size is `chartSize` (its height defaults to the image's aspect); without it the print is fitted inside the frame,
139
+ centered, on the 18 % surround.
140
+
141
+ ```ts
142
+ export interface ImagePlaneScene {
143
+ kind: "image-plane";
144
+ sceneId: string;
145
+ image: ImagePlaneImage;
146
+ /** The paper and the deepest ink: reflectances of sRGB white and black, 0 ≤ black < white ≤ 1. Defaults 0.90 and 0.01. */
147
+ paper?: { whiteReflectance?: number; blackReflectance?: number };
148
+ /** How the print is reconstructed between pixel centers. Default `bilinear` (the pixels' spectra, bilinearly weighted). */
149
+ interpolation?: "bilinear" | "nearest";
150
+ /** Opt-in raised pixel limit: an integer up to the full-resolution ceiling. Default 24 000 000 pixels. */
151
+ maximumPixels?: number;
152
+ }
153
+ ```
154
+
113
155
  ## PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W
114
156
 
115
157
  CIE maximum luminous efficacy for photopic vision, lm/W.
@@ -128,8 +170,11 @@ export interface PlanarSceneRadianceProvider {
128
170
  providerProfileId: string;
129
171
  evaluateRadiance(request: Readonly<SceneRadianceEvaluationRequest>): SceneRadianceEvaluationResult;
130
172
  evaluateApertureRadiance(request: Readonly<SceneRadianceEvaluationRequest>, ray: Readonly<SensorApertureRay>): SceneRadianceEvaluationResult;
131
- /** Spectral radiance at a plane point (frame units), the same value the callbacks return. */
132
- radianceAt(u: number, v: number, wavelengthNanometers: number): number;
173
+ /**
174
+ * Spectral radiance at a plane point (frame units), the same value the callbacks return. #551: a moving subject's provider
175
+ * reads it at time `t` (seconds from the first opening, default 0); a still scene ignores it.
176
+ */
177
+ radianceAt(u: number, v: number, wavelengthNanometers: number, t?: number): number;
133
178
  /**
134
179
  * 2.3, chart scenes only: the chart material at a plane point (frame units), or `materials.length` for the
135
180
  * surround of a fixed-size chart; `materialRadiance` gives that material's spectral radiance, the same value
@@ -137,6 +182,12 @@ export interface PlanarSceneRadianceProvider {
137
182
  */
138
183
  chartMaterialAt?(u: number, v: number): number;
139
184
  materialRadiance?(material: number, wavelengthNanometers: number): number;
185
+ /**
186
+ * 2.21 (#581), image-plane scenes only: the tabulated expected signal's scene at these spectral nodes and channel responses, its
187
+ * radiance per node and, for the direct path, Σ_n A_c(λ_n)·L(λ_n) integrated from each pixel's reconstructed spectrum
188
+ * (`ResolvedImagePlaneScene.pixelSignals`, the surround's reflectance times the neutral signal outside the print).
189
+ */
190
+ imageSignalScene?(wavelengths: readonly number[], perNode: readonly Float64Array[]): ImagePlaneSignalScene | ImagePlaneLitScene;
140
191
  }
141
192
  ```
142
193