@photivra/engine 2.21.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.
- package/CHANGELOG.md +118 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +11 -0
- package/dist/capture/c2pa-embed.d.ts +116 -0
- package/dist/capture/c2pa-embed.js +493 -0
- package/dist/capture/c2pa-embed.js.map +1 -0
- package/dist/capture/dng-import.d.ts +73 -8
- package/dist/capture/dng-import.js +315 -80
- package/dist/capture/dng-import.js.map +1 -1
- package/dist/capture/dng-opcodes.d.ts +96 -0
- package/dist/capture/dng-opcodes.js +391 -0
- package/dist/capture/dng-opcodes.js.map +1 -0
- package/dist/capture/dng-profile-maps.d.ts +99 -0
- package/dist/capture/dng-profile-maps.js +381 -0
- package/dist/capture/dng-profile-maps.js.map +1 -0
- package/dist/capture/dng-stage-image.d.ts +23 -0
- package/dist/capture/dng-stage-image.js +65 -0
- package/dist/capture/dng-stage-image.js.map +1 -0
- package/dist/capture/jpeg-xl-tiles.d.ts +22 -0
- package/dist/capture/jpeg-xl-tiles.js +151 -0
- package/dist/capture/jpeg-xl-tiles.js.map +1 -0
- package/dist/capture/lossy-jpeg.d.ts +17 -0
- package/dist/capture/lossy-jpeg.js +369 -0
- package/dist/capture/lossy-jpeg.js.map +1 -0
- package/dist/capture/native-raw-development.d.ts +2 -1
- package/dist/capture/native-raw-development.js.map +1 -1
- package/dist/color/neighbor-highlight-reconstruction.d.ts +66 -0
- package/dist/color/neighbor-highlight-reconstruction.js +234 -0
- package/dist/color/neighbor-highlight-reconstruction.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +5 -0
- package/dist/color/sensor-color-development.js +7 -1
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/color/spectral-spikiness.d.ts +11 -0
- package/dist/color/spectral-spikiness.js +23 -0
- package/dist/color/spectral-spikiness.js.map +1 -0
- package/dist/core/execution-error.d.ts +21 -0
- package/dist/core/execution-error.js +12 -0
- package/dist/core/execution-error.js.map +1 -0
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/facade/catalogue-lens-signal.d.ts +26 -1
- package/dist/facade/catalogue-lens-signal.js +25 -7
- package/dist/facade/catalogue-lens-signal.js.map +1 -1
- package/dist/facade/diffraction-provider.d.ts +1 -1
- package/dist/facade/diffraction-provider.js +4 -4
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.js +38 -6
- package/dist/facade/display-view-gpu-session.js.map +1 -1
- package/dist/facade/display-view-gpu.d.ts +13 -5
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-normal.d.ts +15 -0
- package/dist/facade/display-view-normal.js +44 -0
- package/dist/facade/display-view-normal.js.map +1 -0
- package/dist/facade/display-view-rendering.d.ts +97 -0
- package/dist/facade/display-view-rendering.js +598 -0
- package/dist/facade/display-view-rendering.js.map +1 -0
- package/dist/facade/display-view.d.ts +37 -65
- package/dist/facade/display-view.js +147 -476
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.js +2 -2
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/fast-methods.d.ts +1 -1
- package/dist/facade/fast-methods.js +37 -8
- package/dist/facade/fast-methods.js.map +1 -1
- package/dist/facade/generic-lens-capture.d.ts +1 -1
- package/dist/facade/generic-lens-capture.js +1 -1
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/image-plane.js +41 -10
- package/dist/facade/image-plane.js.map +1 -1
- package/dist/facade/on-demand-kits.d.ts +14 -0
- package/dist/facade/on-demand-kits.js +36 -0
- package/dist/facade/on-demand-kits.js.map +1 -0
- package/dist/facade/opt-in-kit.d.ts +9 -0
- package/dist/facade/opt-in-kit.js +11 -0
- package/dist/facade/opt-in-kit.js.map +1 -0
- package/dist/facade/quality-kit.d.ts +21 -0
- package/dist/facade/quality-kit.js +23 -0
- package/dist/facade/quality-kit.js.map +1 -0
- package/dist/facade/quality-paths.d.ts +22 -0
- package/dist/facade/quality-paths.js +44 -0
- package/dist/facade/quality-paths.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +18 -2
- package/dist/facade/scene-radiance.js +6 -4
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +32 -13
- package/dist/facade/simulate-capture.js +162 -69
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +10 -12
- package/dist/facade/simulate-display-view.js +57 -48
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/display-view-gpu-renderer.d.ts +43 -0
- package/dist/gpu/display-view-gpu-renderer.js +134 -0
- package/dist/gpu/display-view-gpu-renderer.js.map +1 -0
- package/dist/gpu/display-view-image-material-module.d.ts +3 -2
- package/dist/gpu/display-view-image-material-module.js +25 -3
- package/dist/gpu/display-view-image-material-module.js.map +1 -1
- package/dist/gpu/display-view-image-quality.d.ts +43 -1
- package/dist/gpu/display-view-image-quality.js +256 -11
- package/dist/gpu/display-view-image-quality.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +13 -64
- package/dist/gpu/display-view-quality-gpu.js +60 -249
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.d.ts +16 -16
- package/dist/gpu/display-view-speed-gpu.js +50 -12
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/image-kernel-accelerator.js +3 -0
- package/dist/gpu/image-kernel-accelerator.js.map +1 -1
- package/dist/gpu/image-kernel-execution.d.ts +2 -13
- package/dist/gpu/image-kernel-execution.js +2 -10
- package/dist/gpu/image-kernel-execution.js.map +1 -1
- package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +8 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js +21 -0
- package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
- package/dist/gpu/wgsl-display-view-coupled.d.ts +88 -0
- package/dist/gpu/wgsl-display-view-coupled.js +353 -0
- package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +4 -9
- package/dist/gpu/wgsl-display-view-quality-kernel.js +109 -111
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +1 -41
- package/dist/gpu/wgsl-display-view-speed-kernel.js +71 -8
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/output/camera-channel-response.d.ts +50 -0
- package/dist/output/camera-channel-response.js +69 -0
- package/dist/output/camera-channel-response.js.map +1 -0
- package/dist/output/native-capture-sdr.js +5 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/sdr-rendering.d.ts +18 -1
- package/dist/output/sdr-rendering.js +39 -2
- package/dist/output/sdr-rendering.js.map +1 -1
- package/dist/sensor/native-sensor-report.d.ts +10 -0
- package/dist/sensor/native-sensor-report.js +16 -0
- package/dist/sensor/native-sensor-report.js.map +1 -0
- package/dist/sensor/sensor-characteristics.d.ts +81 -13
- package/dist/sensor/sensor-characteristics.js +10 -6
- package/dist/sensor/sensor-characteristics.js.map +1 -1
- package/docs/API_REFERENCE.md +117 -4
- package/docs/QUICK_START.md +37 -8
- package/docs/USAGE.md +104 -22
- package/docs/api/capture-c2pa-embed.md +177 -0
- package/docs/api/capture-dng-import.md +86 -10
- package/docs/api/capture-dng-opcodes.md +93 -0
- package/docs/api/capture-dng-profile-maps.md +141 -0
- package/docs/api/capture-dng-stage-image.md +43 -0
- package/docs/api/capture-jpeg-xl-tiles.md +33 -0
- package/docs/api/capture-lossy-jpeg.md +41 -0
- package/docs/api/capture-native-raw-development.md +2 -1
- package/docs/api/core-execution-error.md +43 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +255 -5
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-display-view.md +11 -15
- package/docs/api/facade-fast-methods.md +38 -9
- package/docs/api/facade-quality-paths.md +24 -0
- package/docs/api/facade-scene-radiance.md +1 -1
- package/docs/api/facade-simulate-capture.md +24 -7
- package/docs/api/facade-simulate-display-view.md +10 -12
- package/docs/api/gpu-image-kernel-execution.md +0 -36
- package/docs/api/output-camera-channel-response.md +55 -0
- package/docs/api/output-sdr-rendering.md +6 -1
- package/docs/api/sensor-sensor-characteristics.md +54 -2
- package/llms.txt +1 -0
- package/package.json +6 -5
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* (`siteDiffractionKernel`, then `convolveSiteKernels`), so the two have the same bits.
|
|
14
14
|
*/
|
|
15
15
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
16
|
-
import {
|
|
16
|
+
import { loadedKit, qualityKit } from "./on-demand-kits.js";
|
|
17
17
|
import { convolveSiteKernels } from "../optics/defocus-disc-kernel.js";
|
|
18
18
|
import { DEFOCUS_DIRECT_KERNEL_MAXIMUM_RADIUS_SITES, siteKernelRuns } from "../optics/site-kernel-runs.js";
|
|
19
19
|
import { resolveProjectionDistanceMm } from "../motion/camera-rotation.js";
|
|
@@ -35,7 +35,7 @@ export function buildExpectedSignalInput(input) {
|
|
|
35
35
|
kernels = { radius, perNode: wavelengths.map((wavelengthNm) => {
|
|
36
36
|
if (!diffraction.profileWavelengths.includes(wavelengthNm))
|
|
37
37
|
throw new InvalidConfigurationError(input.caller + ": a spectral node has no diffraction kernel.");
|
|
38
|
-
return siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + ": diffraction kernels must sample the site pitch exactly.");
|
|
38
|
+
return loadedKit(qualityKit).siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + ": diffraction kernels must sample the site pitch exactly.");
|
|
39
39
|
}) };
|
|
40
40
|
}
|
|
41
41
|
if (input.lensKernels) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expected-signal-setup.js","sourceRoot":"","sources":["../../src/facade/expected-signal-setup.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Internal (#394, not exported from the package): the input of the tabulated expected signal (`createDisplayViewExpectedSignal`)\n * for a resolved `simulateCapture` request, shared by the display view and the capture's tabulated RAW path so both build it\n * the same way: query offsets of each site, the environment's query points, the diffraction kernels and the scene tables.\n *\n * Defocus (#492, `lens.defocus`): the geometric disc D on the site lattice (`createDefocusDiscSiteKernel`) enters as a site\n * kernel, so every query stays on the lattice. Without diffraction every spectral node takes D itself (a wavelength-independent\n * kernel). With diffraction node λ takes K_λ ∗ D, the full 2-D convolution of the diffraction kernel with the disc (radius\n * R_diff + R_defocus): a labelled approximation, since the defocused wave's PSF is not the in-focus Airy pattern convolved\n * with a geometric disc. The convolution is linear, so Σ_t (K_λ ∗ D)(t)·L(p − t) is the diffracted radiance blurred by D, the\n * order the capture's object-space convolutions apply them in. The kernels are built as the capture builds them\n * (`siteDiffractionKernel`, then `convolveSiteKernels`), so the two have the same bits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport type { resolveLensPsfConvolutionKernels } from \"../optics/lens-psf-kernels.js\";\nimport { siteDiffractionKernel } from \"../optics/site-diffraction-kernel.js\";\nimport { convolveSiteKernels } from \"../optics/defocus-disc-kernel.js\";\nimport { DEFOCUS_DIRECT_KERNEL_MAXIMUM_RADIUS_SITES, siteKernelRuns, type SiteKernelRuns } from \"../optics/site-kernel-runs.js\";\nimport { resolveProjectionDistanceMm } from \"../motion/camera-rotation.js\";\nimport { hypot3 } from \"../core/portable-math.js\";\nimport type { DisplayViewExpectedSignalInput, DisplayViewScene } from \"./display-view.js\";\n\n/** A unit site kernel of radius 0 (shared: the tables only read it). */\nconst UNIT_TAP = Float64Array.of(1);\n\ntype Psf = Parameters<typeof resolveLensPsfConvolutionKernels>[0][\"psf\"];\n\nexport interface ExpectedSignalSetupInput {\n nativeWidth: number;\n nativeHeight: number;\n /** Frame output width (plane coordinates are 2 / width frame units per site). */\n width: number;\n wavelengths: readonly number[];\n /** Per CFA channel (red, green, blue): expected electrons per unit spectral radiance at each node. */\n perNode: readonly [Float64Array, Float64Array, Float64Array];\n /** Pixel-aperture nodes in sites from the site centre (`apertureNodeOffsets(boxSamples)`) and the box sample count. */\n apertureNodes: readonly { x: number; y: number }[];\n boxSamples: number;\n antiAliasing?: { components: readonly { offsetMicrometers: { x: number; y: number }; normalizedWeight: number }[] } | undefined;\n pitch: number;\n /** Object-space diffraction: the kernel radius, the PSF and its profile wavelengths. */\n diffraction?: { radius: number; psf: Psf; profileWavelengths: readonly number[] } | undefined;\n /**\n * #569: a lens PSF's kernels per spectral node on the site lattice (the catalogue lens's at the frame centre; the display view's\n * lens signal reads each field zone's own), used when there is no diffraction and no defocus disc (the lens's PSF includes both).\n */\n lensKernels?: { radius: number; perNode: Float64Array[] } | undefined;\n /** Defocus (#492): the geometric disc on the site lattice, (2R + 1)² row-major weights; absent or null in focus. */\n defocus?: { radius: number; weights: Float64Array } | null | undefined;\n /**\n * #564: a defocus kernel above the direct radius, as runs, used instead of `defocus`: the tables keep the in-focus kernels\n * (diffraction, or a unit tap per node for the lattice formula) and the expected signal convolves the result with it. A\n * `defocus` disc of radius above 64 sites takes this path too.\n */\n largeDefocus?: SiteKernelRuns | undefined;\n /** Material scenes: the materials (neutral reflectances, or radiance per wavelength), the material lookup and the white radiance. */\n materials?: { list: readonly ({ neutral: number } | { radiance: (nm: number) => number })[]; materialAt(u: number, v: number): number; whiteRadiance(nm: number): number } | undefined;\n radianceAt(u: number, v: number, nm: number): number;\n /** #581, image-plane scenes: the provider's `imageSignalScene` (the radiance, and the direct path's signals integrated from each pixel's reconstructed spectrum). */\n imageSignalScene?: ((wavelengths: readonly number[], perNode: readonly Float64Array[]) => DisplayViewScene) | undefined;\n imagingArea: { widthMm: number; heightMm: number };\n focalLengthMm: number;\n focusDistanceM: number;\n subjectDistanceM: number;\n metresPerFrameUnit: number;\n /** Prefix of the error messages (\"simulateDisplayView\", \"simulateCapture\"). */\n caller: string;\n}\n\n/** The query offsets of each site and the expected-signal input (see the module comment). */\nexport function buildExpectedSignalInput(input: ExpectedSignalSetupInput): { offsets: { x: number; y: number; weight: number }[]; signalInput: DisplayViewExpectedSignalInput } {\n const { boxSamples, pitch, wavelengths, imagingArea, subjectDistanceM, metresPerFrameUnit } = input;\n // Query offsets of each site: pixel-aperture nodes minus anti-aliasing split offsets (sites, +x right, +y down), as the environment forms them.\n const spots = input.antiAliasing ? input.antiAliasing.components : [{ offsetMicrometers: { x: 0, y: 0 }, normalizedWeight: 1 }];\n const offsets = input.apertureNodes.flatMap((node) => spots.map((c) => ({ x: node.x - c.offsetMicrometers.x / pitch, y: node.y - c.offsetMicrometers.y / pitch,\n weight: c.normalizedWeight / (boxSamples * boxSamples) })));\n // Diffraction: the same per-node site kernels as the object-space convolution (createDiffractedPlanarProvider).\n let kernels: { radius: number; perNode: Float64Array[] } | undefined;\n const diffraction = input.diffraction;\n if (diffraction) {\n const radius = diffraction.radius;\n kernels = { radius, perNode: wavelengths.map((wavelengthNm) => {\n if (!diffraction.profileWavelengths.includes(wavelengthNm)) throw new InvalidConfigurationError(input.caller + \": a spectral node has no diffraction kernel.\");\n return siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + \": diffraction kernels must sample the site pitch exactly.\");\n }) };\n }\n if (input.lensKernels) {\n if (diffraction || input.defocus || input.largeDefocus) throw new InvalidConfigurationError(input.caller + \": a lens PSF includes its own diffraction and defocus.\");\n if (input.lensKernels.perNode.length !== wavelengths.length) throw new InvalidConfigurationError(input.caller + \": the lens PSF needs one kernel per spectral node.\");\n kernels = input.lensKernels;\n }\n // #564: a disc above the direct radius (64 sites) is convolved by runs after the in-focus signal instead (below).\n const largeDefocus = input.largeDefocus ?? (input.defocus && input.defocus.radius > DEFOCUS_DIRECT_KERNEL_MAXIMUM_RADIUS_SITES ?\n siteKernelRuns(input.defocus.weights, input.defocus.radius) : undefined);\n // Defocus (#492): the disc alone at every node (one shared array), or each node's diffraction kernel convolved with it.\n const defocus = largeDefocus ? undefined : input.defocus;\n if (defocus) {\n const diffracted = kernels;\n kernels = diffracted ? { radius: diffracted.radius + defocus.radius, perNode: diffracted.perNode.map((k) => convolveSiteKernels(k, diffracted.radius, defocus.weights, defocus.radius)) } :\n { radius: defocus.radius, perNode: wavelengths.map(() => defocus.weights) };\n }\n // #564: a large defocus kernel is applied after the in-focus signal (expected-signal.ts); without diffraction the in-focus\n // kernels are a unit tap per node, so the tables read the scene on the lattice formula as the defocus path does.\n if (largeDefocus && !kernels) kernels = { radius: 0, perNode: wavelengths.map(() => UNIT_TAP) };\n // Chart presets and (2.7) caller material scenes take the material path: each material tabulated once per node.\n const materials = input.materials;\n const scene: DisplayViewScene = materials ? { kind: \"materials\", materialAt: materials.materialAt,\n materials: materials.list.map((m) => (\"neutral\" in m ? { neutral: m.neutral } : { radiance: Float64Array.from(wavelengths, (nm) => m.radiance(nm)) })),\n whiteRadiance: Float64Array.from(wavelengths, (nm) => materials.whiteRadiance(nm)) } :\n input.imageSignalScene ? input.imageSignalScene(wavelengths, input.perNode) : { kind: \"radiance\", radianceAt: input.radianceAt };\n const channelIndex = (x: number, y: number): number => ((y & 1) === 0 ? ((x & 1) === 0 ? 0 : 1) : ((x & 1) === 0 ? 1 : 2));\n // Without diffraction the environment's own query arithmetic (native-environment-lean.ts `geometry`, then the rectilinear\n // still-camera ray and the planar provider's plane point), so boundary points resolve as in the capture.\n const projectionDistance = resolveProjectionDistanceMm(input.focalLengthMm, input.focusDistanceM).projectionDistanceMm, siteWidthMm = pitch / 1000;\n const nodePhases = input.apertureNodes.flatMap((_, index) => spots.map((c) => ({ xPhase: (index % boxSamples + 0.5) / boxSamples, yPhase: (Math.floor(index / boxSamples) + 0.5) / boxSamples,\n aaX: c.offsetMicrometers.x / 1000, aaY: c.offsetMicrometers.y / 1000 })));\n const queryPoint = (x: number, y: number, o: number, out: Float64Array): void => {\n const node = nodePhases[o]!;\n const centerX = -imagingArea.widthMm / 2 + (pitch / 2 + x * pitch + 0) / 1000, centerY = -imagingArea.heightMm / 2 + (pitch / 2 + y * pitch + 0) / 1000;\n const sourceX = (centerX - siteWidthMm / 2 + node.xPhase * siteWidthMm) - node.aaX, sourceY = (centerY - siteWidthMm / 2 + node.yPhase * siteWidthMm) - node.aaY;\n const rx = projectionDistance * (sourceX / projectionDistance), ry = projectionDistance * (-sourceY / projectionDistance);\n const length = hypot3(rx, ry, projectionDistance), t = subjectDistanceM / (projectionDistance / length);\n out[0] = rx / length * t / metresPerFrameUnit; out[1] = ry / length * t / metresPerFrameUnit;\n };\n return { offsets, signalInput: { nativeWidth: input.nativeWidth, nativeHeight: input.nativeHeight, outputWidth: input.width, wavelengthsNm: wavelengths,\n electronsPerRadiance: input.perNode, offsets, ...(kernels ? { kernels } : { queryPoint }), ...(largeDefocus ? { largeKernel: largeDefocus } : {}), scene, channelAt: channelIndex } };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"expected-signal-setup.js","sourceRoot":"","sources":["../../src/facade/expected-signal-setup.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Internal (#394, not exported from the package): the input of the tabulated expected signal (`createDisplayViewExpectedSignal`)\n * for a resolved `simulateCapture` request, shared by the display view and the capture's tabulated RAW path so both build it\n * the same way: query offsets of each site, the environment's query points, the diffraction kernels and the scene tables.\n *\n * Defocus (#492, `lens.defocus`): the geometric disc D on the site lattice (`createDefocusDiscSiteKernel`) enters as a site\n * kernel, so every query stays on the lattice. Without diffraction every spectral node takes D itself (a wavelength-independent\n * kernel). With diffraction node λ takes K_λ ∗ D, the full 2-D convolution of the diffraction kernel with the disc (radius\n * R_diff + R_defocus): a labelled approximation, since the defocused wave's PSF is not the in-focus Airy pattern convolved\n * with a geometric disc. The convolution is linear, so Σ_t (K_λ ∗ D)(t)·L(p − t) is the diffracted radiance blurred by D, the\n * order the capture's object-space convolutions apply them in. The kernels are built as the capture builds them\n * (`siteDiffractionKernel`, then `convolveSiteKernels`), so the two have the same bits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport type { resolveLensPsfConvolutionKernels } from \"../optics/lens-psf-kernels.js\";\nimport { loadedKit, qualityKit } from \"./on-demand-kits.js\";\nimport { convolveSiteKernels } from \"../optics/defocus-disc-kernel.js\";\nimport { DEFOCUS_DIRECT_KERNEL_MAXIMUM_RADIUS_SITES, siteKernelRuns, type SiteKernelRuns } from \"../optics/site-kernel-runs.js\";\nimport { resolveProjectionDistanceMm } from \"../motion/camera-rotation.js\";\nimport { hypot3 } from \"../core/portable-math.js\";\nimport type { DisplayViewExpectedSignalInput, DisplayViewScene } from \"./display-view.js\";\n\n/** A unit site kernel of radius 0 (shared: the tables only read it). */\nconst UNIT_TAP = Float64Array.of(1);\n\ntype Psf = Parameters<typeof resolveLensPsfConvolutionKernels>[0][\"psf\"];\n\nexport interface ExpectedSignalSetupInput {\n nativeWidth: number;\n nativeHeight: number;\n /** Frame output width (plane coordinates are 2 / width frame units per site). */\n width: number;\n wavelengths: readonly number[];\n /** Per CFA channel (red, green, blue): expected electrons per unit spectral radiance at each node. */\n perNode: readonly [Float64Array, Float64Array, Float64Array];\n /** Pixel-aperture nodes in sites from the site centre (`apertureNodeOffsets(boxSamples)`) and the box sample count. */\n apertureNodes: readonly { x: number; y: number }[];\n boxSamples: number;\n antiAliasing?: { components: readonly { offsetMicrometers: { x: number; y: number }; normalizedWeight: number }[] } | undefined;\n pitch: number;\n /** Object-space diffraction: the kernel radius, the PSF and its profile wavelengths. */\n diffraction?: { radius: number; psf: Psf; profileWavelengths: readonly number[] } | undefined;\n /**\n * #569: a lens PSF's kernels per spectral node on the site lattice (the catalogue lens's at the frame centre; the display view's\n * lens signal reads each field zone's own), used when there is no diffraction and no defocus disc (the lens's PSF includes both).\n */\n lensKernels?: { radius: number; perNode: Float64Array[] } | undefined;\n /** Defocus (#492): the geometric disc on the site lattice, (2R + 1)² row-major weights; absent or null in focus. */\n defocus?: { radius: number; weights: Float64Array } | null | undefined;\n /**\n * #564: a defocus kernel above the direct radius, as runs, used instead of `defocus`: the tables keep the in-focus kernels\n * (diffraction, or a unit tap per node for the lattice formula) and the expected signal convolves the result with it. A\n * `defocus` disc of radius above 64 sites takes this path too.\n */\n largeDefocus?: SiteKernelRuns | undefined;\n /** Material scenes: the materials (neutral reflectances, or radiance per wavelength), the material lookup and the white radiance. */\n materials?: { list: readonly ({ neutral: number } | { radiance: (nm: number) => number })[]; materialAt(u: number, v: number): number; whiteRadiance(nm: number): number } | undefined;\n radianceAt(u: number, v: number, nm: number): number;\n /** #581, image-plane scenes: the provider's `imageSignalScene` (the radiance, and the direct path's signals integrated from each pixel's reconstructed spectrum). */\n imageSignalScene?: ((wavelengths: readonly number[], perNode: readonly Float64Array[]) => DisplayViewScene) | undefined;\n imagingArea: { widthMm: number; heightMm: number };\n focalLengthMm: number;\n focusDistanceM: number;\n subjectDistanceM: number;\n metresPerFrameUnit: number;\n /** Prefix of the error messages (\"simulateDisplayView\", \"simulateCapture\"). */\n caller: string;\n}\n\n/** The query offsets of each site and the expected-signal input (see the module comment). */\nexport function buildExpectedSignalInput(input: ExpectedSignalSetupInput): { offsets: { x: number; y: number; weight: number }[]; signalInput: DisplayViewExpectedSignalInput } {\n const { boxSamples, pitch, wavelengths, imagingArea, subjectDistanceM, metresPerFrameUnit } = input;\n // Query offsets of each site: pixel-aperture nodes minus anti-aliasing split offsets (sites, +x right, +y down), as the environment forms them.\n const spots = input.antiAliasing ? input.antiAliasing.components : [{ offsetMicrometers: { x: 0, y: 0 }, normalizedWeight: 1 }];\n const offsets = input.apertureNodes.flatMap((node) => spots.map((c) => ({ x: node.x - c.offsetMicrometers.x / pitch, y: node.y - c.offsetMicrometers.y / pitch,\n weight: c.normalizedWeight / (boxSamples * boxSamples) })));\n // Diffraction: the same per-node site kernels as the object-space convolution (createDiffractedPlanarProvider).\n let kernels: { radius: number; perNode: Float64Array[] } | undefined;\n const diffraction = input.diffraction;\n if (diffraction) {\n const radius = diffraction.radius;\n kernels = { radius, perNode: wavelengths.map((wavelengthNm) => {\n if (!diffraction.profileWavelengths.includes(wavelengthNm)) throw new InvalidConfigurationError(input.caller + \": a spectral node has no diffraction kernel.\");\n return loadedKit(qualityKit).siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + \": diffraction kernels must sample the site pitch exactly.\");\n }) };\n }\n if (input.lensKernels) {\n if (diffraction || input.defocus || input.largeDefocus) throw new InvalidConfigurationError(input.caller + \": a lens PSF includes its own diffraction and defocus.\");\n if (input.lensKernels.perNode.length !== wavelengths.length) throw new InvalidConfigurationError(input.caller + \": the lens PSF needs one kernel per spectral node.\");\n kernels = input.lensKernels;\n }\n // #564: a disc above the direct radius (64 sites) is convolved by runs after the in-focus signal instead (below).\n const largeDefocus = input.largeDefocus ?? (input.defocus && input.defocus.radius > DEFOCUS_DIRECT_KERNEL_MAXIMUM_RADIUS_SITES ?\n siteKernelRuns(input.defocus.weights, input.defocus.radius) : undefined);\n // Defocus (#492): the disc alone at every node (one shared array), or each node's diffraction kernel convolved with it.\n const defocus = largeDefocus ? undefined : input.defocus;\n if (defocus) {\n const diffracted = kernels;\n kernels = diffracted ? { radius: diffracted.radius + defocus.radius, perNode: diffracted.perNode.map((k) => convolveSiteKernels(k, diffracted.radius, defocus.weights, defocus.radius)) } :\n { radius: defocus.radius, perNode: wavelengths.map(() => defocus.weights) };\n }\n // #564: a large defocus kernel is applied after the in-focus signal (expected-signal.ts); without diffraction the in-focus\n // kernels are a unit tap per node, so the tables read the scene on the lattice formula as the defocus path does.\n if (largeDefocus && !kernels) kernels = { radius: 0, perNode: wavelengths.map(() => UNIT_TAP) };\n // Chart presets and (2.7) caller material scenes take the material path: each material tabulated once per node.\n const materials = input.materials;\n const scene: DisplayViewScene = materials ? { kind: \"materials\", materialAt: materials.materialAt,\n materials: materials.list.map((m) => (\"neutral\" in m ? { neutral: m.neutral } : { radiance: Float64Array.from(wavelengths, (nm) => m.radiance(nm)) })),\n whiteRadiance: Float64Array.from(wavelengths, (nm) => materials.whiteRadiance(nm)) } :\n input.imageSignalScene ? input.imageSignalScene(wavelengths, input.perNode) : { kind: \"radiance\", radianceAt: input.radianceAt };\n const channelIndex = (x: number, y: number): number => ((y & 1) === 0 ? ((x & 1) === 0 ? 0 : 1) : ((x & 1) === 0 ? 1 : 2));\n // Without diffraction the environment's own query arithmetic (native-environment-lean.ts `geometry`, then the rectilinear\n // still-camera ray and the planar provider's plane point), so boundary points resolve as in the capture.\n const projectionDistance = resolveProjectionDistanceMm(input.focalLengthMm, input.focusDistanceM).projectionDistanceMm, siteWidthMm = pitch / 1000;\n const nodePhases = input.apertureNodes.flatMap((_, index) => spots.map((c) => ({ xPhase: (index % boxSamples + 0.5) / boxSamples, yPhase: (Math.floor(index / boxSamples) + 0.5) / boxSamples,\n aaX: c.offsetMicrometers.x / 1000, aaY: c.offsetMicrometers.y / 1000 })));\n const queryPoint = (x: number, y: number, o: number, out: Float64Array): void => {\n const node = nodePhases[o]!;\n const centerX = -imagingArea.widthMm / 2 + (pitch / 2 + x * pitch + 0) / 1000, centerY = -imagingArea.heightMm / 2 + (pitch / 2 + y * pitch + 0) / 1000;\n const sourceX = (centerX - siteWidthMm / 2 + node.xPhase * siteWidthMm) - node.aaX, sourceY = (centerY - siteWidthMm / 2 + node.yPhase * siteWidthMm) - node.aaY;\n const rx = projectionDistance * (sourceX / projectionDistance), ry = projectionDistance * (-sourceY / projectionDistance);\n const length = hypot3(rx, ry, projectionDistance), t = subjectDistanceM / (projectionDistance / length);\n out[0] = rx / length * t / metresPerFrameUnit; out[1] = ry / length * t / metresPerFrameUnit;\n };\n return { offsets, signalInput: { nativeWidth: input.nativeWidth, nativeHeight: input.nativeHeight, outputWidth: input.width, wavelengthsNm: wavelengths,\n electronsPerRadiance: input.perNode, offsets, ...(kernels ? { kernels } : { queryPoint }), ...(largeDefocus ? { largeKernel: largeDefocus } : {}), scene, channelAt: channelIndex } };\n}\n"]}
|
|
@@ -22,7 +22,7 @@ export interface SimulateCaptureFastMethod {
|
|
|
22
22
|
/** "fast-and-exact": both methods exist; "exact-only": the record takes `fast`, but there is no fast method yet (reports false). */
|
|
23
23
|
methods: "fast-and-exact" | "exact-only";
|
|
24
24
|
/** Where it applies. */
|
|
25
|
-
runs: readonly ("simulateCapture" | "simulateDisplayView" | "prepareDisplayView")[];
|
|
25
|
+
runs: readonly ("simulateCapture" | "simulateDisplayView" | "prepareDisplayView" | "developDngStageImage")[];
|
|
26
26
|
/** The fast method and the exact one, in words (empty for exact-only). */
|
|
27
27
|
fast: string;
|
|
28
28
|
exact: string;
|
|
@@ -3,9 +3,13 @@ const CAPTURE = "src/facade/simulate-capture.ts", VIEW = "src/facade/simulate-di
|
|
|
3
3
|
/** 2.20.0: every speed-versus-accuracy choice of the capture facade and the display view (see the module comment). */
|
|
4
4
|
export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
5
5
|
{ id: "lens.catalogue/field-grid", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture"],
|
|
6
|
-
fast: "#568: the PSF blended over a field grid
|
|
6
|
+
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",
|
|
7
7
|
exact: "the environment PSF quadrature with the PSF resolved at each query point", followsFormatDefault: true,
|
|
8
8
|
resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "fast.lens.catalogue" } },
|
|
9
|
+
{ id: "lens.catalogue/field-grid-cells", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture"],
|
|
10
|
+
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",
|
|
11
|
+
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,
|
|
12
|
+
resolver: { file: CAPTURE, call: "catalogueFastGridSubdivisions(catalogue!.lensId, fastTop)" }, report: { assumption: "fast.lens.catalogue" } },
|
|
9
13
|
{ id: "lens.catalogue/cats-eye", override: "lens.catalogue", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
10
14
|
fast: "#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)",
|
|
11
15
|
exact: "the cat's eye shaped at each field point (fast wides and normals)", followsFormatDefault: true,
|
|
@@ -22,10 +26,6 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
22
26
|
fast: "#588: under rolling-shutter rotation, each catalogue PSF tap reads the scene at its own source point",
|
|
23
27
|
exact: "each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)", followsFormatDefault: true,
|
|
24
28
|
resolver: { file: CAPTURE, call: "resolveFast(catalogueFast, fastTop)" }, report: { applied: "lens.catalogue", assumption: "fast.lens.catalogue" } },
|
|
25
|
-
{ id: "output.demosaic.ahd/view-low-signal-correction", override: "output.demosaic", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
26
|
-
fast: "(H3) 2048 draws per correction state, applied where a pixel's linear noise exceeds 0.01",
|
|
27
|
-
exact: "8192 draws per state, at the same 0.01 threshold", followsFormatDefault: true,
|
|
28
|
-
resolver: { file: CAPTURE, call: "resolveFast(demosaicFast, fastTop)" }, report: { applied: "output.demosaic.ahd", assumption: "view.demosaic" } },
|
|
29
29
|
{ id: "view.uniform-pixel-sampling", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
30
30
|
fast: "(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail",
|
|
31
31
|
exact: "the full samples per axis in every display pixel", followsFormatDefault: true,
|
|
@@ -35,6 +35,16 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
35
35
|
exact: "gpu \"off\": the CPU reference; an explicit gpu wins", followsFormatDefault: true,
|
|
36
36
|
resolver: { file: VIEW, call: "parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)" },
|
|
37
37
|
report: { field: "diagnostics.fast.execution" } },
|
|
38
|
+
{ id: "illumination/image-plane-gpu", override: "fast", methods: "fast-and-exact", runs: ["prepareDisplayView"],
|
|
39
|
+
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 " +
|
|
40
|
+
"point per spectral node from the light's spectra and parts (Speed requests too, without site kernels); flagged points resolved on the host",
|
|
41
|
+
exact: "gpu \"off\": the CPU reference integrates each site from the lit radiance per spectral node in float64; an explicit gpu wins", followsFormatDefault: true,
|
|
42
|
+
resolver: { file: VIEW, call: "parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)" },
|
|
43
|
+
report: { field: "diagnostics.fast.execution" } },
|
|
44
|
+
{ id: "sensor.spectralStepNanometers", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
45
|
+
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",
|
|
46
|
+
exact: "5 nm under a spiky light, else 20 nm (an explicit sensor.spectralStepNanometers always wins)", followsFormatDefault: true,
|
|
47
|
+
resolver: { file: CAPTURE, call: "fastTop || !spiky" }, report: { applied: "sensor.spectralStepNanometers", assumption: "sensor.spectralSpikiness" } },
|
|
38
48
|
{ id: "sensor.midGrey", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
39
49
|
fast: "#535: the mid-gray noise figure is not computed (about 0.3 ms)", exact: "result.sensor.midGrey is computed", followsFormatDefault: true,
|
|
40
50
|
resolver: { file: CAPTURE, call: "fastTop ? undefined : 0" }, report: { field: "sensor.midGrey" } },
|
|
@@ -42,6 +52,25 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
42
52
|
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",
|
|
43
53
|
exact: "the default 8 temporal midpoints (an explicit sensor.temporalSampleCount always wins)", followsFormatDefault: true,
|
|
44
54
|
resolver: { file: CAPTURE, call: "resolveFast(subjectFast, fastTop)" }, report: { applied: "motion.subject", assumption: "fast.motion.subject" } },
|
|
55
|
+
{ id: "dngImport.warpRectilinear", override: "fast", methods: "fast-and-exact", runs: ["developDngStageImage"],
|
|
56
|
+
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,
|
|
57
|
+
resolver: { file: "src/capture/dng-stage-image.ts", call: "resolveFast(options.fast, fastFormatDefault(format, \"capture\"))" }, report: { field: "fast" } },
|
|
58
|
+
{ id: "output.toneCurve/view-luminance-moments", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
59
|
+
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)",
|
|
60
|
+
exact: "a composite 4 × 16-point Gauss–Legendre rule over the luminance's ±8.5σ, split at L = 0", followsFormatDefault: true,
|
|
61
|
+
resolver: { file: CAPTURE, call: "rendering: fastTop" }, report: { assumption: "view.rendering" } },
|
|
62
|
+
{ id: "output.highlightMode.reconstruct/view-moments", override: "fast", methods: "fast-and-exact", runs: ["simulateDisplayView", "prepareDisplayView"],
|
|
63
|
+
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)",
|
|
64
|
+
exact: "16 points per axis (4,096 nodes)", followsFormatDefault: true,
|
|
65
|
+
resolver: { file: CAPTURE, call: "rendering: fastTop" }, report: { assumption: "view.rendering" } },
|
|
66
|
+
{ id: "prepareDisplayView.gpu/view-coupled-moments", override: "fast", methods: "fast-and-exact", runs: ["prepareDisplayView"],
|
|
67
|
+
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",
|
|
68
|
+
exact: "the same kernels with the full rules (4 × 16 Gauss–Legendre; 16 points per axis), fast: false with an explicit gpu", followsFormatDefault: true,
|
|
69
|
+
resolver: { file: "src/gpu/wgsl-display-view-coupled.ts", call: "out[C.fast] = r.fast ? 1 : 0" }, report: { assumption: "view.rendering" } },
|
|
70
|
+
{ id: "output.highlightMode.reconstruct-neighbors/region-ratios", override: "fast", methods: "fast-and-exact", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
71
|
+
fast: "#602: each clipped region takes the mean color ratios of the unclipped pixels within 2 pixels of it",
|
|
72
|
+
exact: "the ratios' harmonic (Laplace) interpolation inward from the region's unclipped neighbors (successive over-relaxation)", followsFormatDefault: true,
|
|
73
|
+
resolver: { file: CAPTURE, call: "const neighborFast = fastTop" }, report: { assumption: "output.highlightMode.reconstructNeighbors" } },
|
|
45
74
|
{ id: "lens.diffraction", override: "lens.diffraction", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
46
75
|
fast: "", exact: "the diffraction kernels (a fast method only under rolling-shutter rotation, above)", followsFormatDefault: true,
|
|
47
76
|
resolver: { file: CAPTURE, call: "resolveFast(diffractionFast, fastTop)" }, report: { applied: "lens.diffraction" } },
|
|
@@ -51,8 +80,8 @@ export const SIMULATE_CAPTURE_FAST_METHODS = /* @__PURE__ */ Object.freeze([
|
|
|
51
80
|
{ id: "sensor.pixelAperture.box", override: "sensor.pixelAperture", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
52
81
|
fast: "", exact: "the N × N midpoint rule", followsFormatDefault: true,
|
|
53
82
|
resolver: { file: CAPTURE, call: "fastInUse" }, report: { applied: "sensor.pixelAperture.box" } },
|
|
54
|
-
{ id: "output.demosaic.ahd", override: "output.demosaic", methods: "exact-only", runs: ["simulateCapture"],
|
|
55
|
-
fast: "", exact: "the AHD demosaic of the capture
|
|
56
|
-
resolver: { file: CAPTURE, call: "
|
|
83
|
+
{ id: "output.demosaic.ahd", override: "output.demosaic", methods: "exact-only", runs: ["simulateCapture", "simulateDisplayView", "prepareDisplayView"],
|
|
84
|
+
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,
|
|
85
|
+
resolver: { file: CAPTURE, call: "[\"output.demosaic.ahd\", ahd, demosaicFast]" }, report: { applied: "output.demosaic.ahd" } }
|
|
57
86
|
]);
|
|
58
87
|
//# sourceMappingURL=fast-methods.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fast-methods.js","sourceRoot":"","sources":["../../src/facade/fast-methods.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The registry of every speed-versus-accuracy choice (#395, owner rule of 2.20.0): one entry per choice that has a fast and an\n * exact (full) method, and per option record that accepts `fast` without a fast method yet. Every entry resolves through\n * `resolveFast` and `fastFormatDefault` (fast-resolution.ts): an option record's `fast`, else the top-level `fast`, else the\n * format default (fast for \"srgb-8\", \"srgb-16\" and the display view; exact for \"dng\", \"jpeg\", \"png\" and `simulateIdealReference`).\n *\n * Data only (a root export, so developers can read which choices exist), read by `test/fast-methods-registry.test.ts`, which\n * fails when an option accepts `fast` without an entry here, an entry lacks its resolver or its report, or a format's default\n * leaves the rule. Captures and display views do not import this module (tree-shaking leaves it out of their bundles). A new\n * fast method adds its entry here and to docs/API_STYLE.md, \"Exact and fast modes\".\n * @see docs/API_STYLE.md, \"Exact and fast modes\".\n */\n\n/** One speed-versus-accuracy choice of {@link SIMULATE_CAPTURE_FAST_METHODS} (2.20.0). */\nexport interface SimulateCaptureFastMethod {\n /** A short id: the option path and, where one option has several fast methods, the method. */\n id: string;\n /**\n * The request path whose record takes the `fast` override (`allowKeys` path in simulate-capture.ts), or \"fast\" when only the\n * top-level flag sets it (a choice with no option record of its own).\n */\n override: string;\n /** \"fast-and-exact\": both methods exist; \"exact-only\": the record takes `fast`, but there is no fast method yet (reports false). */\n methods: \"fast-and-exact\" | \"exact-only\";\n /** Where it applies. */\n runs: readonly (\"simulateCapture\" | \"simulateDisplayView\" | \"prepareDisplayView\")[];\n /** The fast method and the exact one, in words (empty for exact-only). */\n fast: string;\n exact: string;\n /** Always true: no choice keeps its own default (the test checks it). */\n followsFormatDefault: true;\n /**\n * The resolver call in the source (`resolveFast(<record flag>, fastTop)`, or `fastTop` itself for a top-level choice), which the\n * test finds in the named file.\n */\n resolver: { file: string; call: string };\n /**\n * How the result reports it: the `diagnostics.fast.applied` key (true where the fast method ran), an assumption id the fast\n * method adds, or another result field. At least one; the test finds each assumption id in the source.\n */\n report: { applied?: string; assumption?: string; field?: string };\n}\n\nconst CAPTURE = \"src/facade/simulate-capture.ts\", VIEW = \"src/facade/simulate-display-view.ts\";\n\n/** 2.20.0: every speed-versus-accuracy choice of the capture facade and the display view (see the module comment). */\nexport const SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = /* @__PURE__ */ Object.freeze([\n { id: \"lens.catalogue/field-grid\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#568: the PSF blended over a field grid and tabulated expected electrons, verified per CFA phase against the exact chain\",\n exact: \"the environment PSF quadrature with the PSF resolved at each query point\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"lens.catalogue/cats-eye\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)\",\n exact: \"the cat's eye shaped at each field point (fast wides and normals)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue.catsEye\" } },\n { id: \"lens.catalogue/view-psf-zones\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#569 (H1): 64 field zones along the longer side, each with the PSF at its centre\",\n exact: \"one zone per site: the PSF at each site centre\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"view.lensPsf\" } },\n { id: \"lens.diffraction/rolling-shutter-taps\", override: \"lens.diffraction\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#565: under rolling-shutter rotation (#551: or subject motion), each PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\", assumption: \"fast.lens.diffraction\" } },\n { id: \"lens.catalogue/rolling-shutter-taps\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#588: under rolling-shutter rotation, each catalogue PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"output.demosaic.ahd/view-low-signal-correction\", override: \"output.demosaic\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"(H3) 2048 draws per correction state, applied where a pixel's linear noise exceeds 0.01\",\n exact: \"8192 draws per state, at the same 0.01 threshold\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(demosaicFast, fastTop)\" }, report: { applied: \"output.demosaic.ahd\", assumption: \"view.demosaic\" } },\n { id: \"view.uniform-pixel-sampling\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail\",\n exact: \"the full samples per axis in every display pixel\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"uniformSampling: fastTop\" }, report: { assumption: \"view.estimation\" } },\n { id: \"prepareDisplayView.gpu\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n fast: \"gpu \\\"auto\\\": WebGPU float32 where a conforming device supports the request (a bounded approximation), else the CPU reference\",\n exact: \"gpu \\\"off\\\": the CPU reference; an explicit gpu wins\", followsFormatDefault: true,\n resolver: { file: VIEW, call: \"parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)\" },\n report: { field: \"diagnostics.fast.execution\" } },\n { id: \"sensor.midGrey\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#535: the mid-gray noise figure is not computed (about 0.3 ms)\", exact: \"result.sensor.midGrey is computed\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastTop ? undefined : 0\" }, report: { field: \"sensor.midGrey\" } },\n { id: \"motion.subject/temporal-midpoints\", override: \"motion.subject\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n 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\",\n exact: \"the default 8 temporal midpoints (an explicit sensor.temporalSampleCount always wins)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(subjectFast, fastTop)\" }, report: { applied: \"motion.subject\", assumption: \"fast.motion.subject\" } },\n { id: \"lens.diffraction\", override: \"lens.diffraction\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the diffraction kernels (a fast method only under rolling-shutter rotation, above)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\" } },\n { id: \"sensor.antiAliasing\", override: \"sensor.antiAliasing\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the point-splitting filter\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.antiAliasing\" } },\n { id: \"sensor.pixelAperture.box\", override: \"sensor.pixelAperture\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the N × N midpoint rule\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.pixelAperture.box\" } },\n { id: \"output.demosaic.ahd\", override: \"output.demosaic\", methods: \"exact-only\", runs: [\"simulateCapture\"],\n fast: \"\", exact: \"the AHD demosaic of the capture (a fast method only in the display view's correction, above)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(demosaicFast, fastTop)\" }, report: { applied: \"output.demosaic.ahd\" } }\n] as const satisfies readonly SimulateCaptureFastMethod[]);\n"]}
|
|
1
|
+
{"version":3,"file":"fast-methods.js","sourceRoot":"","sources":["../../src/facade/fast-methods.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The registry of every speed-versus-accuracy choice (#395, owner rule of 2.20.0): one entry per choice that has a fast and an\n * exact (full) method, and per option record that accepts `fast` without a fast method yet. Every entry resolves through\n * `resolveFast` and `fastFormatDefault` (fast-resolution.ts): an option record's `fast`, else the top-level `fast`, else the\n * format default (fast for \"srgb-8\", \"srgb-16\" and the display view; exact for \"dng\", \"jpeg\", \"png\" and `simulateIdealReference`).\n *\n * Data only (a root export, so developers can read which choices exist), read by `test/fast-methods-registry.test.ts`, which\n * fails when an option accepts `fast` without an entry here, an entry lacks its resolver or its report, or a format's default\n * leaves the rule. Captures and display views do not import this module (tree-shaking leaves it out of their bundles). A new\n * fast method adds its entry here and to docs/API_STYLE.md, \"Exact and fast modes\".\n * @see docs/API_STYLE.md, \"Exact and fast modes\".\n */\n\n/** One speed-versus-accuracy choice of {@link SIMULATE_CAPTURE_FAST_METHODS} (2.20.0). */\nexport interface SimulateCaptureFastMethod {\n /** A short id: the option path and, where one option has several fast methods, the method. */\n id: string;\n /**\n * The request path whose record takes the `fast` override (`allowKeys` path in simulate-capture.ts), or \"fast\" when only the\n * top-level flag sets it (a choice with no option record of its own).\n */\n override: string;\n /** \"fast-and-exact\": both methods exist; \"exact-only\": the record takes `fast`, but there is no fast method yet (reports false). */\n methods: \"fast-and-exact\" | \"exact-only\";\n /** Where it applies. */\n runs: readonly (\"simulateCapture\" | \"simulateDisplayView\" | \"prepareDisplayView\" | \"developDngStageImage\")[];\n /** The fast method and the exact one, in words (empty for exact-only). */\n fast: string;\n exact: string;\n /** Always true: no choice keeps its own default (the test checks it). */\n followsFormatDefault: true;\n /**\n * The resolver call in the source (`resolveFast(<record flag>, fastTop)`, or `fastTop` itself for a top-level choice), which the\n * test finds in the named file.\n */\n resolver: { file: string; call: string };\n /**\n * How the result reports it: the `diagnostics.fast.applied` key (true where the fast method ran), an assumption id the fast\n * method adds, or another result field. At least one; the test finds each assumption id in the source.\n */\n report: { applied?: string; assumption?: string; field?: string };\n}\n\nconst CAPTURE = \"src/facade/simulate-capture.ts\", VIEW = \"src/facade/simulate-display-view.ts\";\n\n/** 2.20.0: every speed-versus-accuracy choice of the capture facade and the display view (see the module comment). */\nexport const SIMULATE_CAPTURE_FAST_METHODS: readonly SimulateCaptureFastMethod[] = /* @__PURE__ */ Object.freeze([\n { id: \"lens.catalogue/field-grid\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n 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\",\n exact: \"the environment PSF quadrature with the PSF resolved at each query point\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"lens.catalogue/field-grid-cells\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n 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\",\n 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,\n resolver: { file: CAPTURE, call: \"catalogueFastGridSubdivisions(catalogue!.lensId, fastTop)\" }, report: { assumption: \"fast.lens.catalogue\" } },\n { id: \"lens.catalogue/cats-eye\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#567: with lens.defocus, the lens's bokeh without its cat's eye (the axis kernel everywhere)\",\n exact: \"the cat's eye shaped at each field point (fast wides and normals)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue.catsEye\" } },\n { id: \"lens.catalogue/view-psf-zones\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#569 (H1): 64 field zones along the longer side, each with the PSF at its centre\",\n exact: \"one zone per site: the PSF at each site centre\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"view.lensPsf\" } },\n { id: \"lens.diffraction/rolling-shutter-taps\", override: \"lens.diffraction\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#565: under rolling-shutter rotation (#551: or subject motion), each PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\", assumption: \"fast.lens.diffraction\" } },\n { id: \"lens.catalogue/rolling-shutter-taps\", override: \"lens.catalogue\", methods: \"fast-and-exact\", runs: [\"simulateCapture\"],\n fast: \"#588: under rolling-shutter rotation, each catalogue PSF tap reads the scene at its own source point\",\n exact: \"each tap reads the scene at its site-lattice point (ties on chart boundaries resolve as on the lattice)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(catalogueFast, fastTop)\" }, report: { applied: \"lens.catalogue\", assumption: \"fast.lens.catalogue\" } },\n { id: \"view.uniform-pixel-sampling\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"(H2) a quarter of the samples per axis in display pixels whose pilot finds no detail\",\n exact: \"the full samples per axis in every display pixel\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"uniformSampling: fastTop\" }, report: { assumption: \"view.estimation\" } },\n { id: \"prepareDisplayView.gpu\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n fast: \"gpu \\\"auto\\\": WebGPU float32 where a conforming device supports the request (a bounded approximation), else the CPU reference\",\n exact: \"gpu \\\"off\\\": the CPU reference; an explicit gpu wins\", followsFormatDefault: true,\n resolver: { file: VIEW, call: \"parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)\" },\n report: { field: \"diagnostics.fast.execution\" } },\n { id: \"illumination/image-plane-gpu\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n 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 \" +\n \"point per spectral node from the light's spectra and parts (Speed requests too, without site kernels); flagged points resolved on the host\",\n exact: \"gpu \\\"off\\\": the CPU reference integrates each site from the lit radiance per spectral node in float64; an explicit gpu wins\", followsFormatDefault: true,\n resolver: { file: VIEW, call: \"parsePrepareDisplayViewOptions(prepareOptions, (options as { fast?: unknown } | null | undefined)?.fast !== false)\" },\n report: { field: \"diagnostics.fast.execution\" } },\n { id: \"sensor.spectralStepNanometers\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n 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\",\n exact: \"5 nm under a spiky light, else 20 nm (an explicit sensor.spectralStepNanometers always wins)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastTop || !spiky\" }, report: { applied: \"sensor.spectralStepNanometers\", assumption: \"sensor.spectralSpikiness\" } },\n { id: \"sensor.midGrey\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#535: the mid-gray noise figure is not computed (about 0.3 ms)\", exact: \"result.sensor.midGrey is computed\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastTop ? undefined : 0\" }, report: { field: \"sensor.midGrey\" } },\n { id: \"motion.subject/temporal-midpoints\", override: \"motion.subject\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n 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\",\n exact: \"the default 8 temporal midpoints (an explicit sensor.temporalSampleCount always wins)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(subjectFast, fastTop)\" }, report: { applied: \"motion.subject\", assumption: \"fast.motion.subject\" } },\n { id: \"dngImport.warpRectilinear\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"developDngStageImage\"],\n 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,\n resolver: { file: \"src/capture/dng-stage-image.ts\", call: \"resolveFast(options.fast, fastFormatDefault(format, \\\"capture\\\"))\" }, report: { field: \"fast\" } },\n { id: \"output.toneCurve/view-luminance-moments\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n 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)\",\n exact: \"a composite 4 × 16-point Gauss–Legendre rule over the luminance's ±8.5σ, split at L = 0\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"rendering: fastTop\" }, report: { assumption: \"view.rendering\" } },\n { id: \"output.highlightMode.reconstruct/view-moments\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateDisplayView\", \"prepareDisplayView\"],\n 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)\",\n exact: \"16 points per axis (4,096 nodes)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"rendering: fastTop\" }, report: { assumption: \"view.rendering\" } },\n { id: \"prepareDisplayView.gpu/view-coupled-moments\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"prepareDisplayView\"],\n 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\",\n exact: \"the same kernels with the full rules (4 × 16 Gauss–Legendre; 16 points per axis), fast: false with an explicit gpu\", followsFormatDefault: true,\n resolver: { file: \"src/gpu/wgsl-display-view-coupled.ts\", call: \"out[C.fast] = r.fast ? 1 : 0\" }, report: { assumption: \"view.rendering\" } },\n { id: \"output.highlightMode.reconstruct-neighbors/region-ratios\", override: \"fast\", methods: \"fast-and-exact\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"#602: each clipped region takes the mean color ratios of the unclipped pixels within 2 pixels of it\",\n exact: \"the ratios' harmonic (Laplace) interpolation inward from the region's unclipped neighbors (successive over-relaxation)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"const neighborFast = fastTop\" }, report: { assumption: \"output.highlightMode.reconstructNeighbors\" } },\n { id: \"lens.diffraction\", override: \"lens.diffraction\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the diffraction kernels (a fast method only under rolling-shutter rotation, above)\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"resolveFast(diffractionFast, fastTop)\" }, report: { applied: \"lens.diffraction\" } },\n { id: \"sensor.antiAliasing\", override: \"sensor.antiAliasing\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the point-splitting filter\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.antiAliasing\" } },\n { id: \"sensor.pixelAperture.box\", override: \"sensor.pixelAperture\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n fast: \"\", exact: \"the N × N midpoint rule\", followsFormatDefault: true,\n resolver: { file: CAPTURE, call: \"fastInUse\" }, report: { applied: \"sensor.pixelAperture.box\" } },\n { id: \"output.demosaic.ahd\", override: \"output.demosaic\", methods: \"exact-only\", runs: [\"simulateCapture\", \"simulateDisplayView\", \"prepareDisplayView\"],\n 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,\n resolver: { file: CAPTURE, call: \"[\\\"output.demosaic.ahd\\\", ahd, demosaicFast]\" }, report: { applied: \"output.demosaic.ahd\" } }\n] as const satisfies readonly SimulateCaptureFastMethod[]);\n"]}
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { GENERIC_LENS_EVIDENCE, genericLensDistortionProfile, genericLensVignettingProfile, resolveGenericLens, simulateGenericLensFocusError } from "../equipment/generic-lens-catalogue.js";
|
|
7
7
|
export { createGenericLensPsfProfile, genericLensBokehKernel, genericLensPsfKernelRadius, GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES } from "../optics/generic-lens-psf.js";
|
|
8
|
-
export { CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
8
|
+
export { catalogueFastGridSubdivisions, CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
9
9
|
export { applyDevelopedLensCorrection, channelEffectiveDispersion, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
10
10
|
export { createDngLensCorrectionOpcodes } from "../capture/dng-lens-correction-opcodes.js";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { GENERIC_LENS_EVIDENCE, genericLensDistortionProfile, genericLensVignettingProfile, resolveGenericLens, simulateGenericLensFocusError } from "../equipment/generic-lens-catalogue.js";
|
|
8
8
|
export { createGenericLensPsfProfile, genericLensBokehKernel, genericLensPsfKernelRadius, GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES } from "../optics/generic-lens-psf.js";
|
|
9
|
-
export { CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
9
|
+
export { catalogueFastGridSubdivisions, CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from "./catalogue-lens-signal.js";
|
|
10
10
|
export { applyDevelopedLensCorrection, channelEffectiveDispersion, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
11
11
|
export { createDngLensCorrectionOpcodes } from "../capture/dng-lens-correction-opcodes.js";
|
|
12
12
|
//# sourceMappingURL=generic-lens-capture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-lens-capture.js","sourceRoot":"","sources":["../../src/facade/generic-lens-capture.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAC9L,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,8CAA8C,EAAE,MAAM,+BAA+B,CAAC;AAChL,OAAO,EAAE,qCAAqC,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"generic-lens-capture.js","sourceRoot":"","sources":["../../src/facade/generic-lens-capture.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAC9L,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,8CAA8C,EAAE,MAAM,+BAA+B,CAAC;AAChL,OAAO,EAAE,6BAA6B,EAAE,qCAAqC,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvK,OAAO,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,iCAAiC,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AACtL,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * What `simulateCapture` needs for `lens.catalogue` (#549), loaded on demand: a capture without a catalogue lens (and a bundle\n * that never asks for one) does not load the catalogue's data or its PSF builder. It also holds the developed-image lens\n * corrections (`output.lensCorrections`, #570) and their DNG opcodes (`output.dng.lensCorrectionOpcodes`, #587), which need a catalogue lens.\n */\nexport { GENERIC_LENS_EVIDENCE, genericLensDistortionProfile, genericLensVignettingProfile, resolveGenericLens, simulateGenericLensFocusError } from \"../equipment/generic-lens-catalogue.js\";\nexport { createGenericLensPsfProfile, genericLensBokehKernel, genericLensPsfKernelRadius, GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES } from \"../optics/generic-lens-psf.js\";\nexport { catalogueFastGridSubdivisions, CATALOGUE_FAST_VERIFICATION_TOLERANCE, catalogueFastAssumptions, createCatalogueLensSignal } from \"./catalogue-lens-signal.js\";\nexport { applyDevelopedLensCorrection, channelEffectiveDispersion, developedLensCorrectionSourceRect, prepareDevelopedLensCorrection } from \"../output/developed-lens-corrections.js\";\nexport { createDngLensCorrectionOpcodes } from \"../capture/dng-lens-correction-opcodes.js\";\n"]}
|
|
@@ -207,16 +207,44 @@ export async function resolveImagePlaneScene(value, aspect, assume) {
|
|
|
207
207
|
return (1 - fy) * ((1 - fx) * at(ja + ia) + fx * at(ja + ib)) + fy * ((1 - fx) * at(jb + ia) + fx * at(jb + ib));
|
|
208
208
|
}
|
|
209
209
|
const sampleAt = (cu, cv, nodeValues, neutral) => interpolate(cu, cv, (index) => pixelValue(index, nodeValues, neutral));
|
|
210
|
-
// Per wavelength the node reflectances (the facade asks for a few spectral nodes many times)
|
|
211
|
-
|
|
210
|
+
// Per wavelength the node reflectances (the facade asks for a few spectral nodes many times), and (#597) each pixel's reflectance
|
|
211
|
+
// there, kept by pixel row as the queries reach it: a spectrum cache (no channel value), the same value `pixelValue` gives.
|
|
212
|
+
const atWavelength = new Map(), spectrumRows = new Map();
|
|
213
|
+
const keptSpectrumRows = Math.max(8, Math.floor(SIGNAL_ROW_CACHE_BYTES / (width * 8)));
|
|
212
214
|
function reflectanceAt(cu, cv, nm) {
|
|
213
|
-
let
|
|
214
|
-
if (!
|
|
215
|
-
nodes = nodeReflectancesAt(nm);
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
let reader = atWavelength.get(nm);
|
|
216
|
+
if (!reader) {
|
|
217
|
+
const nodes = nodeReflectancesAt(nm), slot = atWavelength.size * height;
|
|
218
|
+
const kept = atWavelength.size < 4096;
|
|
219
|
+
// The two latest rows of this wavelength are held apart (a bilinear point reads two rows).
|
|
220
|
+
let keyA = -1, rowA = new Float64Array(0), keyB = -1, rowB = rowA;
|
|
221
|
+
reader = !kept ? (index) => pixelValue(index, nodes, 1) : (index) => {
|
|
222
|
+
const j = Math.floor(index / width), key = slot + j, i = index - j * width;
|
|
223
|
+
let row;
|
|
224
|
+
if (key === keyA)
|
|
225
|
+
row = rowA;
|
|
226
|
+
else if (key === keyB)
|
|
227
|
+
row = rowB;
|
|
228
|
+
else {
|
|
229
|
+
let found = spectrumRows.get(key);
|
|
230
|
+
if (!found) {
|
|
231
|
+
found = new Float64Array(width).fill(NaN);
|
|
232
|
+
spectrumRows.set(key, found);
|
|
233
|
+
if (spectrumRows.size > keptSpectrumRows)
|
|
234
|
+
spectrumRows.delete(spectrumRows.keys().next().value);
|
|
235
|
+
}
|
|
236
|
+
keyB = keyA;
|
|
237
|
+
rowB = rowA;
|
|
238
|
+
keyA = key;
|
|
239
|
+
rowA = row = found;
|
|
240
|
+
}
|
|
241
|
+
const value = row[i];
|
|
242
|
+
return value === value ? value : (row[i] = pixelValue(index, nodes, 1));
|
|
243
|
+
};
|
|
244
|
+
if (kept)
|
|
245
|
+
atWavelength.set(nm, reader);
|
|
218
246
|
}
|
|
219
|
-
return
|
|
247
|
+
return interpolate(cu, cv, reader);
|
|
220
248
|
}
|
|
221
249
|
/**
|
|
222
250
|
* One pixel's channel signals, integrated from its reconstructed spectrum (owner decision 2026-11-09): per spectral node n its
|
|
@@ -241,7 +269,7 @@ export async function resolveImagePlaneScene(value, aspect, assume) {
|
|
|
241
269
|
out[at + 1] = s1;
|
|
242
270
|
out[at + 2] = s2;
|
|
243
271
|
}
|
|
244
|
-
function signalScene(wavelengths, perNode, whiteRadiance, radianceAt, scale, half, surroundReflectance) {
|
|
272
|
+
function signalScene(wavelengths, perNode, whiteRadiance, radianceAt, scale, half, surroundReflectance, light) {
|
|
245
273
|
// The lattice's spectra at the nodes (node k's reflectance at λ_n at k·N + n); no channel response is folded in.
|
|
246
274
|
const N = wavelengths.length, spectraAt = wavelengths.map((nm) => nodeReflectancesAt(nm)), nodeSpectra = new Float64Array(NODES * N);
|
|
247
275
|
for (let k = 0; k < NODES; k++)
|
|
@@ -251,6 +279,9 @@ export async function resolveImagePlaneScene(value, aspect, assume) {
|
|
|
251
279
|
// The surround's channel signals, integrated from its spectrum ρ·W_n like a pixel's (no white-integral shortcut, 2.21.0).
|
|
252
280
|
const surround = [0, 1, 2].map((c) => { let s = 0; for (let n = 0; n < N; n++)
|
|
253
281
|
s += perNode[c][n] * (surroundReflectance * whiteRadiance[n]); return s; });
|
|
282
|
+
// #597: under mixed light, the lit radiance alone (each site integrates it at use) and the print with the light's parts for the GPU pass.
|
|
283
|
+
if (light !== undefined)
|
|
284
|
+
return { kind: "radiance", radianceAt, image: { scene: resolved, nodes, surround, whiteRadiance, surroundReflectance, light: { layout: light, halfWidthM: half } } };
|
|
254
285
|
// The pixels' signals as the query points reach them: rows of three values per pixel (NaN until computed), the latest rows kept.
|
|
255
286
|
const rows = new Map(), keptRows = Math.max(8, Math.floor(SIGNAL_ROW_CACHE_BYTES / (width * 24)));
|
|
256
287
|
let lastJ = -1, lastRow = new Float64Array(0);
|
|
@@ -291,7 +322,7 @@ export async function resolveImagePlaneScene(value, aspect, assume) {
|
|
|
291
322
|
}
|
|
292
323
|
const resolved = Object.freeze({ kind: "image-plane", sceneId: record.sceneId, width, height, aspect, channels, encoding: encoding,
|
|
293
324
|
interpolation, paperWhiteReflectance: white, paperBlackReflectance: black, maximumPixels, clippedSampleCount: clipped, dataSha256,
|
|
294
|
-
reflectanceAt, sampleAt, pixelValue, pixelSignals, pixelLattice, nodeReflectances: nodeReflectancesAt, signalScene, get digestForm() { return imagePlaneDigestForm(resolved); }, parameters: Object.freeze({ width, height, channels, encoding, interpolation, paperWhiteReflectance: white, paperBlackReflectance: black,
|
|
325
|
+
reflectanceAt, sampleAt, pixelValue, pixelSignals, pixelLattice, nodeReflectances: nodeReflectancesAt, signalScene: signalScene, get digestForm() { return imagePlaneDigestForm(resolved); }, parameters: Object.freeze({ width, height, channels, encoding, interpolation, paperWhiteReflectance: white, paperBlackReflectance: black,
|
|
295
326
|
clippedSampleCount: clipped, imageSha256: dataSha256 }) });
|
|
296
327
|
if (assume)
|
|
297
328
|
for (const [id, kind, v, explanation] of imagePlaneAssumptions(resolved, record))
|