@photivra/engine 2.22.0 → 2.23.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 (39) hide show
  1. package/CHANGELOG.md +33 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/dist/color/neighbor-highlight-reconstruction.d.ts +12 -2
  6. package/dist/color/neighbor-highlight-reconstruction.js +26 -3
  7. package/dist/color/neighbor-highlight-reconstruction.js.map +1 -1
  8. package/dist/core/version.d.ts +1 -1
  9. package/dist/core/version.js +1 -1
  10. package/dist/core/version.js.map +1 -1
  11. package/dist/facade/display-view-rendering.d.ts +5 -0
  12. package/dist/facade/display-view-rendering.js +57 -22
  13. package/dist/facade/display-view-rendering.js.map +1 -1
  14. package/dist/facade/fast-methods.js +2 -2
  15. package/dist/facade/fast-methods.js.map +1 -1
  16. package/dist/gpu/display-view-quality-gpu.js +22 -18
  17. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  18. package/dist/gpu/display-view-speed-gpu.js +15 -10
  19. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  20. package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +6 -1
  21. package/dist/gpu/wgsl-display-view-coupled-stub.js +9 -1
  22. package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -1
  23. package/dist/gpu/wgsl-display-view-coupled.d.ts +3 -0
  24. package/dist/gpu/wgsl-display-view-coupled.js +16 -4
  25. package/dist/gpu/wgsl-display-view-coupled.js.map +1 -1
  26. package/dist/gpu/wgsl-display-view-neighbors.d.ts +46 -0
  27. package/dist/gpu/wgsl-display-view-neighbors.js +114 -0
  28. package/dist/gpu/wgsl-display-view-neighbors.js.map +1 -0
  29. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +2 -0
  30. package/dist/gpu/wgsl-display-view-quality-kernel.js +5 -3
  31. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  32. package/dist/gpu/wgsl-display-view-speed-kernel.js +3 -3
  33. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  34. package/docs/API_REFERENCE.md +1 -1
  35. package/docs/USAGE.md +2 -1
  36. package/docs/api/core-version.md +1 -1
  37. package/docs/api/exports.json +2 -2
  38. package/docs/api/facade-fast-methods.md +2 -2
  39. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,6 +1,38 @@
1
1
  # Changelog
2
2
 
3
- ## 2.22.0 — unreleased (prepared November 11, 2026)
3
+ ## 2.23.0 — unreleased (prepared November 12, 2026)
4
+
5
+ A minor release: neighbor highlight reconstruction on the WebGPU display view (#605), with the CPU region order and the full method's relaxation factor it needed, and the #604 research report. See the [2.23.0 release record](https://github.com/Photivra/photivra/blob/main/docs/RELEASE_2_23_0.md).
6
+
7
+ - **GPU:** `output.highlightMode: "reconstruct-neighbors"` (#602) runs in the WebGPU display view's Speed and Quality kernels, fast
8
+ (ring average) and full (harmonic fill), instead of falling back to the CPU (#605). The host finds each clipped region's ratios with
9
+ the reference's own code and uploads them in the band's flag buffer (no binding is added); the kernels rebuild each clipped
10
+ channel inside the coupled chain in float32, within documented first-order bounds (docs/WEBGPU.md, "Neighbor highlight
11
+ reconstruction (#605)"). Registered in the fast-methods registry (`output.highlightMode.reconstruct-neighbors/region-ratios`).
12
+ - **Display view (CPU):** a clipped region's members are taken in raster order, so its ratios no longer depend on which pixel
13
+ reached the region first; a region render, the GPU host and the whole view agree bit for bit (#605). A region above the search
14
+ cap (65,536 pixels fast, 262,144 full) is solved per tile of 256 × 256 or 512 × 512 pixels (2.22.0 took the part found from the
15
+ first pixel that reached it, which depended on the render's order).
16
+ - **Full method's SOR (captures and the display view):** the relaxation factor is the optimal ω of each region's bounding
17
+ rectangle (`neighborHighlightOmega`) instead of 1.8, at the same 10⁻⁹ tolerance: 3.2–4.9× faster on 68–132 px regions and
18
+ 35–76× closer to the converged fill (`test/neighbor-highlight-sor.test.ts`). Full-method results change below the old
19
+ tolerance's error (at most 2 × 10⁻⁷ in a ratio on the measured regions).
20
+ - **Size measurement:** `test/capture-bundle.test.ts` bundles the shader literals minified, as the published package ships them
21
+ (`npm run build` strips WGSL comments and indentation; owner decision 2026-11-11), for every row. On 2.22.0's tree that reads
22
+ fast worker 333,241 B and on demand 43,456 B (the source text: 337,413 B and 46,977 B); with #605, 333,322 B (+81) and
23
+ 45,110 B (+1,654: the GPU coupled and neighbor chunk +1,288, the CPU Quality kit +314, the GPU Quality chunk +52). No limit changed.
24
+ - **Research (#604, not shipped):** [docs/research/ahd-bias-correction.md](https://github.com/Photivra/photivra/blob/main/docs/research/ahd-bias-correction.md) measures per-site
25
+ estimators of the display view's AHD low-signal bias, computed at use with no table keyed by channel signal levels. None
26
+ is fast enough for the CPU view (10–20 ms per site); #604 is closed and 2.22.0's labeled approximation stays. The prototype is
27
+ in `scripts/research/ahd-bias/`, outside the package.
28
+ - **Root exports:** none added or removed (1,981; runtime exports 672).
29
+ - **CI capacity (owner decision 2026-11-12):** the Node test legs run in three parts (two before) and coverage in ten shards
30
+ (eight before) in `ci.yml` and `publish.yml`, and the SwiftShader WebGPU suite in three jobs (two before; the
31
+ real-GPU Quality full case in four bands of the view); #605's emulation tests are split into ten files by case, the Quality cases and the banding
32
+ check into bands of rows that check the same pixels, with a 900 s per-test deadline for the Quality bands. No test was removed and no job
33
+ time limit was raised (docs/RELEASE_2_23_0.md, "Local gates").
34
+
35
+ ## 2.22.0 — published November 12, 2026
4
36
 
5
37
  A minor release: phone DNG import with JPEG XL and lossy JPEG raw data, the DNG stage image and opcodes (#598, #600) and the channel-response helper (#591); native-photosite sensor figures (#595), read noise per photosite on the tiers (#599), mixed lighting over an image-plane print (#597), sample counts that follow the light and the output (#590) and the catalogue's fast grid (#603); the display view's luminance tone curves, highlight reconstruction and desaturation on the CPU and GPU (#593, #601, #602); the removal of the display view's AHD low-signal correction; Content Credentials writers (#165, engine half); and the full-quality and opt-in code loaded on demand (#594). See the [2.22.0 release record](https://github.com/Photivra/photivra/blob/main/docs/RELEASE_2_22_0.md).
6
38
 
package/CITATION.cff CHANGED
@@ -9,7 +9,7 @@ abstract: "An open TypeScript engine for the science and mathematics of photogra
9
9
  repository-code: "https://github.com/photivra/photivra"
10
10
  url: "https://photivra.com"
11
11
  license: "Apache-2.0"
12
- version: "2.22.0"
12
+ version: "2.23.0"
13
13
  keywords:
14
14
  - photography
15
15
  - camera optics
package/README.md CHANGED
@@ -32,10 +32,10 @@ The source is licensed under Apache-2.0.
32
32
 
33
33
  ## Quick start
34
34
 
35
- Install the published ESM package below. The [2.22.0 release record](https://github.com/Photivra/photivra/blob/main/docs/RELEASE_2_22_0.md) and [changelog](https://github.com/Photivra/photivra/blob/main/CHANGELOG.md) describe the current release:
35
+ Install the published ESM package below. The [2.23.0 release record](https://github.com/Photivra/photivra/blob/main/docs/RELEASE_2_23_0.md) and [changelog](https://github.com/Photivra/photivra/blob/main/CHANGELOG.md) describe the current release:
36
36
 
37
37
  ```sh
38
- npm install @photivra/engine@2.22.0
38
+ npm install @photivra/engine@2.23.0
39
39
  ```
40
40
 
41
41
  Simulate a photograph of a test chart with a generic camera, then read the developed sRGB pixels:
@@ -75,7 +75,7 @@ console.log(horizontal.provenance);
75
75
 
76
76
  Start with the [Developer Guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Then use the [Usage Guide](https://github.com/Photivra/photivra/blob/main/docs/USAGE.md) and the [API reference](https://github.com/Photivra/photivra/blob/main/docs/API_REFERENCE.md), which is generated from the package exports.
77
77
 
78
- Repository `main` may describe newer, unreleased work. For the stable contract, use the docs bundled in the published package, or the exact `v2.22.0` tag.
78
+ Repository `main` may describe newer, unreleased work. For the stable contract, use the docs bundled in the published package, or the exact `v2.23.0` tag.
79
79
 
80
80
  ## Documentation
81
81
 
@@ -363,14 +363,14 @@ The application can then use those results, while the photography calculations t
363
363
 
364
364
  ## Status
365
365
 
366
- - Repository package version: `2.22.0` (release candidate prepared November 11, 2026; publication is separate)
367
- - Engine API contract: `2.22.0`
366
+ - Repository package version: `2.23.0` (release candidate prepared November 12, 2026; publication is separate)
367
+ - Engine API contract: `2.23.0`
368
368
  - Versioned generic tier reference assets: [GENERIC_TIER_PRESETS.md](https://github.com/Photivra/photivra/blob/main/docs/GENERIC_TIER_PRESETS.md).
369
369
  - Sensor profiles from published specifications (#554, unnamed): [SENSOR_PROFILES.md](https://github.com/Photivra/photivra/blob/main/docs/SENSOR_PROFILES.md).
370
370
  - Composed POC simulation API contract: `1.0.0`
371
371
  - Stability: 1.0 root-package compatibility policy; bounded scientific models and independent POC contract
372
372
 
373
- From 1.0.1, the package version and `ENGINE_API_VERSION` are equal. New captures/plans record 2.22.0; existing archives keep their original creator identities. Schema, model and POC contract versions stay independent.
373
+ From 1.0.1, the package version and `ENGINE_API_VERSION` are equal. New captures/plans record 2.23.0; existing archives keep their original creator identities. Schema, model and POC contract versions stay independent.
374
374
 
375
375
  A breaking change to the root contracts now needs a new package major version. Additive and corrective changes follow [compatibility and migration](https://github.com/Photivra/photivra/blob/main/docs/RELEASE_1_3_0.md). A 1.0 package is not a claim of calibrated physical accuracy.
376
376
 
package/SECURITY.md CHANGED
@@ -4,7 +4,7 @@ Please do not open a public issue that contains vulnerability details.
4
4
 
5
5
  ## Supported versions
6
6
 
7
- The published 1.0.0 release started the 1.x root-package compatibility line, and 2.0.0 started the 2.x line. The current release is **2.21.0**, published on November 10, 2026 (see [CHANGELOG.md](CHANGELOG.md)).
7
+ The published 1.0.0 release started the 1.x root-package compatibility line, and 2.0.0 started the 2.x line. The current release is **2.22.0**, published on November 12, 2026 (see [CHANGELOG.md](CHANGELOG.md)).
8
8
 
9
9
  Security fixes target the current maintained development and release line. Do not assume that older 1.x releases, snapshots or pre-1.0 releases will receive fixes.
10
10
 
@@ -27,12 +27,22 @@ export declare const NEIGHBOR_HIGHLIGHT_THRESHOLD = 0.98;
27
27
  export declare const NEIGHBOR_HIGHLIGHT_MARGIN = 2;
28
28
  /** The fast method's ring width in pixels around a (widened) clipped region. */
29
29
  export declare const NEIGHBOR_HIGHLIGHT_RING = 2;
30
- /** The full method's relaxation factor, tolerance and iteration cap. */
30
+ /** The full method's tolerance (the largest change of a sweep) and iteration cap; the relaxation factor is `neighborHighlightOmega`. */
31
31
  export declare const NEIGHBOR_HIGHLIGHT_SOR: Readonly<{
32
- omega: 1.8;
33
32
  tolerance: 1e-9;
34
33
  maximumIterations: 20000;
35
34
  }>;
35
+ /**
36
+ * #605 (2.23.0): the relaxation factor for a region whose members span a × b pixels: the optimal ω = 2/(1 + √(1 − ρ²)) of SOR
37
+ * for the discrete Laplace equation on the a × b rectangle, whose Jacobi iteration has spectral radius
38
+ * ρ = (cos(π/(a + 1)) + cos(π/(b + 1)))/2 (Young's theory of successive over-relaxation; e.g. G. Strang, MIT OpenCourseWare
39
+ * 18.086, and R. J. LeVeque, "Finite Difference Methods for Ordinary and Partial Differential Equations", SIAM 2007, §4.2).
40
+ * A region inside the rectangle has a Jacobi radius at most that of the rectangle, so this ω is at or above its optimum (where
41
+ * SOR converges at the rate ω − 1). The system (each member's neighbor count times its ratio minus its neighbors') is
42
+ * symmetric positive definite, so SOR converges for every ω in (0, 2) (Ostrowski–Reich). 2.22.0 used ω = 1.8 for every region:
43
+ * 5,728 sweeps on a 260 × 260 region against about 400 (docs/DISPLAY_VIEW.md).
44
+ */
45
+ export declare function neighborHighlightOmega(a: number, b: number): number;
36
46
  export interface NeighborHighlightReport {
37
47
  method: "ring-average" | "harmonic-interpolation";
38
48
  /** Clipped pixels rebuilt, and the clipped regions. */
@@ -28,8 +28,22 @@ export const NEIGHBOR_HIGHLIGHT_THRESHOLD = 0.98;
28
28
  export const NEIGHBOR_HIGHLIGHT_MARGIN = 2;
29
29
  /** The fast method's ring width in pixels around a (widened) clipped region. */
30
30
  export const NEIGHBOR_HIGHLIGHT_RING = 2;
31
- /** The full method's relaxation factor, tolerance and iteration cap. */
32
- export const NEIGHBOR_HIGHLIGHT_SOR = /* @__PURE__ */ Object.freeze({ omega: 1.8, tolerance: 1e-9, maximumIterations: 20000 });
31
+ /** The full method's tolerance (the largest change of a sweep) and iteration cap; the relaxation factor is `neighborHighlightOmega`. */
32
+ export const NEIGHBOR_HIGHLIGHT_SOR = /* @__PURE__ */ Object.freeze({ tolerance: 1e-9, maximumIterations: 20000 });
33
+ /**
34
+ * #605 (2.23.0): the relaxation factor for a region whose members span a × b pixels: the optimal ω = 2/(1 + √(1 − ρ²)) of SOR
35
+ * for the discrete Laplace equation on the a × b rectangle, whose Jacobi iteration has spectral radius
36
+ * ρ = (cos(π/(a + 1)) + cos(π/(b + 1)))/2 (Young's theory of successive over-relaxation; e.g. G. Strang, MIT OpenCourseWare
37
+ * 18.086, and R. J. LeVeque, "Finite Difference Methods for Ordinary and Partial Differential Equations", SIAM 2007, §4.2).
38
+ * A region inside the rectangle has a Jacobi radius at most that of the rectangle, so this ω is at or above its optimum (where
39
+ * SOR converges at the rate ω − 1). The system (each member's neighbor count times its ratio minus its neighbors') is
40
+ * symmetric positive definite, so SOR converges for every ω in (0, 2) (Ostrowski–Reich). 2.22.0 used ω = 1.8 for every region:
41
+ * 5,728 sweeps on a 260 × 260 region against about 400 (docs/DISPLAY_VIEW.md).
42
+ */
43
+ export function neighborHighlightOmega(a, b) {
44
+ const rho = (Math.cos(Math.PI / (a + 1)) + Math.cos(Math.PI / (b + 1))) / 2;
45
+ return 2 / (1 + Math.sqrt(Math.max(0, 1 - rho * rho)));
46
+ }
33
47
  /**
34
48
  * The region ratios of an image: per pixel the ratios ρ its rebuild uses (`ratios`, 3 per pixel; for an unclipped pixel its own),
35
49
  * and which pixels are clipped. `clippedAt(i)` tells whether pixel i is clipped; `valueAt(i, out)` writes pixel i's u.
@@ -118,7 +132,16 @@ export function neighborHighlightRatios(width, height, clippedAt, valueAt, fast)
118
132
  if (fast || count === 0)
119
133
  continue;
120
134
  // Full: successive over-relaxation of the discrete Laplace equation over the region, in the region's breadth-first order.
121
- const { omega, tolerance, maximumIterations } = NEIGHBOR_HIGHLIGHT_SOR;
135
+ const { tolerance, maximumIterations } = NEIGHBOR_HIGHLIGHT_SOR;
136
+ let x0 = width, x1 = -1, y0 = height, y1 = -1;
137
+ for (let k = 0; k < tail; k++) {
138
+ const p = queue[k], px = p % width, py = (p - px) / width;
139
+ x0 = Math.min(x0, px);
140
+ x1 = Math.max(x1, px);
141
+ y0 = Math.min(y0, py);
142
+ y1 = Math.max(y1, py);
143
+ }
144
+ const omega = neighborHighlightOmega(x1 - x0 + 1, y1 - y0 + 1);
122
145
  let sweep = 0, change = Infinity;
123
146
  while (sweep < maximumIterations && change > tolerance) {
124
147
  change = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"neighbor-highlight-reconstruction.js","sourceRoot":"","sources":["../../src/color/neighbor-highlight-reconstruction.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * #602 (2.22.0): highlight reconstruction from neighboring pixels, `highlightMode: \"reconstruct-neighbors\"` (opt-in; an estimate,\n * not a recovery of the clipped scene signal). The engine's own method, acting on the developed, white-balanced camera values\n * u = g·c of the whole image at use (no tables):\n *\n * 1. A pixel is clipped when one of its normalized camera channels c_k reaches `NEIGHBOR_HIGHLIGHT_THRESHOLD` of white; clipped\n * pixels form regions (8-connected).\n * 2. Each unclipped pixel has the color ratios ρ = u/(u₀ + u₁ + u₂) (its chromaticity in white-balanced camera space). Pixels\n * within `NEIGHBOR_HIGHLIGHT_MARGIN` pixels of a clipped one give no ratios: their demosaic reads clipped sites, which lowers\n * the clipped channel (and noise selects them by the threshold); the regions below are the clipped pixels widened by it.\n * 3. The clipped region takes its ratios from its unclipped boundary. **Fast:** the mean of ρ over the unclipped pixels within\n * `NEIGHBOR_HIGHLIGHT_RING` pixels (Chebyshev distance) of the region. **Full:** the discrete harmonic (Laplace) interpolation\n * of ρ inward: ρ at each clipped pixel is the mean of its 4-neighbors', with the unclipped neighbors' ratios as Dirichlet\n * boundary values (pixels outside the image are left out), solved by successive over-relaxation from the fast values. A region\n * with no unclipped neighbor keeps the neutral ratios.\n * 4. A clipped pixel keeps its unclipped channels; its scale s = Σ_unclipped u_k / Σ_unclipped ρ_k, and each clipped channel\n * becomes max(u_k, s·ρ_k) (never below what was recorded). Where every channel is clipped, s = max_k u_k/ρ_k.\n * The result is not clipped at the white level: the tone curve and gamut handling then render it.\n *\n * Mathematics only, general and free: the discrete Laplace equation and its Dirichlet problem, and successive over-relaxation\n * (e.g. G. Strang, MIT OpenCourseWare 18.086, \"Mathematical Methods for Engineers II\", finite differences for Laplace's equation\n * and iterative solvers, free at https://ocw.mit.edu/courses/18-086-mathematical-methods-for-engineers-ii-spring-2006/).\n */\n\n/** Normalized channel level at which a channel counts as clipped. */\nexport const NEIGHBOR_HIGHLIGHT_THRESHOLD = 0.98;\n/** Pixels this close (Chebyshev distance) to a clipped pixel give no ratios and are filled with the region. */\nexport const NEIGHBOR_HIGHLIGHT_MARGIN = 2;\n/** The fast method's ring width in pixels around a (widened) clipped region. */\nexport const NEIGHBOR_HIGHLIGHT_RING = 2;\n/** The full method's relaxation factor, tolerance and iteration cap. */\nexport const NEIGHBOR_HIGHLIGHT_SOR = /* @__PURE__ */ Object.freeze({ omega: 1.8, tolerance: 1e-9, maximumIterations: 20000 });\n\nexport interface NeighborHighlightReport {\n method: \"ring-average\" | \"harmonic-interpolation\";\n /** Clipped pixels rebuilt, and the clipped regions. */\n reconstructedPixelCount: number;\n regionCount: number;\n /** Full method: the largest number of relaxation sweeps a region needed, and whether every region met the tolerance. */\n iterations: number;\n converged: boolean;\n}\n\n/**\n * The region ratios of an image: per pixel the ratios ρ its rebuild uses (`ratios`, 3 per pixel; for an unclipped pixel its own),\n * and which pixels are clipped. `clippedAt(i)` tells whether pixel i is clipped; `valueAt(i, out)` writes pixel i's u.\n * Pixels are i = y·width + x.\n */\nexport function neighborHighlightRatios(width: number, height: number, clippedAt: (i: number) => boolean, valueAt: (i: number, out: Float64Array) => void, fast: boolean):\n { clipped: Uint8Array; ratios: Float64Array; regionCount: number; iterations: number; converged: boolean } {\n const n = width * height, clipped = new Uint8Array(n), unknown = new Uint8Array(n), ratios = new Float64Array(3 * n), u = new Float64Array(3), D = NEIGHBOR_HIGHLIGHT_MARGIN;\n for (let i = 0; i < n; i++) if (clippedAt(i)) clipped[i] = 1;\n // The clipped pixels widened by the margin (a separable dilation).\n const rows = new Uint8Array(n);\n for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) if (clipped[y * width + x] === 1) rows.fill(1, y * width + Math.max(0, x - D), y * width + Math.min(width, x + D + 1));\n for (let x = 0; x < width; x++) for (let y = 0; y < height; y++) if (rows[y * width + x] === 1) for (let yy = Math.max(0, y - D); yy <= Math.min(height - 1, y + D); yy++) unknown[yy * width + x] = 1;\n for (let i = 0; i < n; i++) {\n if (unknown[i] === 1) continue;\n valueAt(i, u);\n const sum = u[0]! + u[1]! + u[2]!;\n if (sum > 0) { ratios[3 * i] = u[0]! / sum; ratios[3 * i + 1] = u[1]! / sum; ratios[3 * i + 2] = u[2]! / sum; }\n else { ratios[3 * i] = 1 / 3; ratios[3 * i + 1] = 1 / 3; ratios[3 * i + 2] = 1 / 3; }\n }\n const label = new Int32Array(n).fill(-1), stamp = new Int32Array(n).fill(-1), queue = new Int32Array(n);\n let regionCount = 0, iterations = 0, converged = true;\n for (let start = 0; start < n; start++) {\n if (unknown[start] === 0 || label[start]! >= 0) continue;\n // The region (8-connected), breadth first.\n const region = regionCount++;\n let head = 0, tail = 0;\n queue[tail++] = start; label[start] = region;\n while (head < tail) {\n const p = queue[head++]!, px = p % width, py = (p - px) / width;\n for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {\n const x = px + dx, y = py + dy;\n if (x < 0 || y < 0 || x >= width || y >= height) continue;\n const q = y * width + x;\n if (unknown[q] === 1 && label[q]! < 0) { label[q] = region; queue[tail++] = q; }\n }\n }\n // Fast: the mean ratios over the ring (each unclipped pixel once).\n let r0 = 0, r1 = 0, r2 = 0, count = 0;\n const R = NEIGHBOR_HIGHLIGHT_RING;\n for (let k = 0; k < tail; k++) {\n const p = queue[k]!, px = p % width, py = (p - px) / width;\n for (let y = Math.max(0, py - R); y <= Math.min(height - 1, py + R); y++) for (let x = Math.max(0, px - R); x <= Math.min(width - 1, px + R); x++) {\n const q = y * width + x;\n if (unknown[q] === 1 || stamp[q] === region) continue;\n stamp[q] = region; r0 += ratios[3 * q]!; r1 += ratios[3 * q + 1]!; r2 += ratios[3 * q + 2]!; count++;\n }\n }\n const m0 = count > 0 ? r0 / count : 1 / 3, m1 = count > 0 ? r1 / count : 1 / 3, m2 = count > 0 ? r2 / count : 1 / 3;\n for (let k = 0; k < tail; k++) { const p = queue[k]!; ratios[3 * p] = m0; ratios[3 * p + 1] = m1; ratios[3 * p + 2] = m2; }\n if (fast || count === 0) continue;\n // Full: successive over-relaxation of the discrete Laplace equation over the region, in the region's breadth-first order.\n const { omega, tolerance, maximumIterations } = NEIGHBOR_HIGHLIGHT_SOR;\n let sweep = 0, change = Infinity;\n while (sweep < maximumIterations && change > tolerance) {\n change = 0; sweep++;\n for (let k = 0; k < tail; k++) {\n const p = queue[k]!, px = p % width, py = (p - px) / width;\n let a0 = 0, a1 = 0, a2 = 0, m = 0;\n for (let d = 0; d < 4; d++) {\n const x = px + (d === 0 ? -1 : d === 1 ? 1 : 0), y = py + (d === 2 ? -1 : d === 3 ? 1 : 0);\n if (x < 0 || y < 0 || x >= width || y >= height) continue;\n const q = y * width + x;\n a0 += ratios[3 * q]!; a1 += ratios[3 * q + 1]!; a2 += ratios[3 * q + 2]!; m++;\n }\n if (m === 0) continue;\n for (let c = 0; c < 3; c++) {\n const old = ratios[3 * p + c]!, target = (c === 0 ? a0 : c === 1 ? a1 : a2) / m, next = old + omega * (target - old);\n ratios[3 * p + c] = next;\n const delta = Math.abs(next - old);\n if (delta > change) change = delta;\n }\n }\n }\n iterations = Math.max(iterations, sweep);\n if (change > tolerance) converged = false;\n }\n return { clipped, ratios, regionCount, iterations, converged };\n}\n\n/**\n * The rebuild of one clipped pixel (step 4) into b, with its slopes ∂b/∂c (row-major 3 × 3, a.e.) when `slopes` is given.\n * `c` are the normalized camera channels, `g` the white-balance gains, `rho` the pixel's ratios.\n */\nexport function rebuildClippedPixel(c0: number, c1: number, c2: number, g: ArrayLike<number>, rho: ArrayLike<number>, b: Float64Array | number[], slopes?: Float64Array): void {\n const H = NEIGHBOR_HIGHLIGHT_THRESHOLD, u0 = c0 * g[0]!, u1 = c1 * g[1]!, u2 = c2 * g[2]!;\n const k0 = c0 < H, k1 = c1 < H, k2 = c2 < H;\n if (slopes) slopes.fill(0);\n if (k0 && k1 && k2) {\n b[0] = u0; b[1] = u1; b[2] = u2;\n if (slopes) { slopes[0] = g[0]!; slopes[4] = g[1]!; slopes[8] = g[2]!; }\n return;\n }\n const r0 = rho[0]!, r1 = rho[1]!, r2 = rho[2]!;\n if (!k0 && !k1 && !k2) {\n const q0 = r0 > 0 ? u0 / r0 : 0, q1 = r1 > 0 ? u1 / r1 : 0, q2 = r2 > 0 ? u2 / r2 : 0, m = q0 > q1 ? (q0 > q2 ? 0 : 2) : (q1 > q2 ? 1 : 2), s = m === 0 ? q0 : m === 1 ? q1 : q2;\n b[0] = s * r0; b[1] = s * r1; b[2] = s * r2;\n if (slopes) { const rm = m === 0 ? r0 : m === 1 ? r1 : r2; if (rm > 0) for (let k = 0; k < 3; k++) slopes[k * 3 + m] = (k === 0 ? r0 : k === 1 ? r1 : r2) * g[m]! / rm; }\n return;\n }\n const su = (k0 ? u0 : 0) + (k1 ? u1 : 0) + (k2 ? u2 : 0), sr = (k0 ? r0 : 0) + (k1 ? r1 : 0) + (k2 ? r2 : 0), s = sr > 0 ? su / sr : 0;\n for (let k = 0; k < 3; k++) {\n const kept = k === 0 ? k0 : k === 1 ? k1 : k2, uk = k === 0 ? u0 : k === 1 ? u1 : u2, rk = k === 0 ? r0 : k === 1 ? r1 : r2;\n if (kept) { b[k] = uk; if (slopes) slopes[k * 4] = g[k]!; continue; }\n const estimate = s * rk;\n if (estimate > uk) {\n b[k] = estimate;\n if (slopes && sr > 0) for (let j = 0; j < 3; j++) if (j === 0 ? k0 : j === 1 ? k1 : k2) slopes[k * 3 + j] = rk * g[j]! / sr;\n } else { b[k] = uk; if (slopes) slopes[k * 4] = g[k]!; }\n }\n}\n\n/**\n * Rebuilds the clipped pixels of a white-balanced image u (3 per pixel, in place; becomes b), with the normalized channels\n * c = u/g deciding which channels are clipped.\n */\nexport function reconstructHighlightsFromNeighbors(u: Float64Array, width: number, height: number, gains: ArrayLike<number>, fast: boolean): NeighborHighlightReport {\n const H = NEIGHBOR_HIGHLIGHT_THRESHOLD, g0 = gains[0]!, g1 = gains[1]!, g2 = gains[2]!;\n const field = neighborHighlightRatios(width, height, (i) => u[3 * i]! / g0 >= H || u[3 * i + 1]! / g1 >= H || u[3 * i + 2]! / g2 >= H,\n (i, out) => { out[0] = u[3 * i]!; out[1] = u[3 * i + 1]!; out[2] = u[3 * i + 2]!; }, fast);\n const b = new Float64Array(3);\n let rebuilt = 0;\n for (let i = 0; i < width * height; i++) {\n if (field.clipped[i] === 0) continue;\n rebuildClippedPixel(u[3 * i]! / g0, u[3 * i + 1]! / g1, u[3 * i + 2]! / g2, gains, field.ratios.subarray(3 * i, 3 * i + 3), b);\n u[3 * i] = b[0]!; u[3 * i + 1] = b[1]!; u[3 * i + 2] = b[2]!;\n rebuilt++;\n }\n return { method: fast ? \"ring-average\" : \"harmonic-interpolation\", reconstructedPixelCount: rebuilt, regionCount: field.regionCount, iterations: field.iterations, converged: field.converged };\n}\n"]}
1
+ {"version":3,"file":"neighbor-highlight-reconstruction.js","sourceRoot":"","sources":["../../src/color/neighbor-highlight-reconstruction.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * #602 (2.22.0): highlight reconstruction from neighboring pixels, `highlightMode: \"reconstruct-neighbors\"` (opt-in; an estimate,\n * not a recovery of the clipped scene signal). The engine's own method, acting on the developed, white-balanced camera values\n * u = g·c of the whole image at use (no tables):\n *\n * 1. A pixel is clipped when one of its normalized camera channels c_k reaches `NEIGHBOR_HIGHLIGHT_THRESHOLD` of white; clipped\n * pixels form regions (8-connected).\n * 2. Each unclipped pixel has the color ratios ρ = u/(u₀ + u₁ + u₂) (its chromaticity in white-balanced camera space). Pixels\n * within `NEIGHBOR_HIGHLIGHT_MARGIN` pixels of a clipped one give no ratios: their demosaic reads clipped sites, which lowers\n * the clipped channel (and noise selects them by the threshold); the regions below are the clipped pixels widened by it.\n * 3. The clipped region takes its ratios from its unclipped boundary. **Fast:** the mean of ρ over the unclipped pixels within\n * `NEIGHBOR_HIGHLIGHT_RING` pixels (Chebyshev distance) of the region. **Full:** the discrete harmonic (Laplace) interpolation\n * of ρ inward: ρ at each clipped pixel is the mean of its 4-neighbors', with the unclipped neighbors' ratios as Dirichlet\n * boundary values (pixels outside the image are left out), solved by successive over-relaxation from the fast values. A region\n * with no unclipped neighbor keeps the neutral ratios.\n * 4. A clipped pixel keeps its unclipped channels; its scale s = Σ_unclipped u_k / Σ_unclipped ρ_k, and each clipped channel\n * becomes max(u_k, s·ρ_k) (never below what was recorded). Where every channel is clipped, s = max_k u_k/ρ_k.\n * The result is not clipped at the white level: the tone curve and gamut handling then render it.\n *\n * Mathematics only, general and free: the discrete Laplace equation and its Dirichlet problem, and successive over-relaxation\n * (e.g. G. Strang, MIT OpenCourseWare 18.086, \"Mathematical Methods for Engineers II\", finite differences for Laplace's equation\n * and iterative solvers, free at https://ocw.mit.edu/courses/18-086-mathematical-methods-for-engineers-ii-spring-2006/).\n */\n\n/** Normalized channel level at which a channel counts as clipped. */\nexport const NEIGHBOR_HIGHLIGHT_THRESHOLD = 0.98;\n/** Pixels this close (Chebyshev distance) to a clipped pixel give no ratios and are filled with the region. */\nexport const NEIGHBOR_HIGHLIGHT_MARGIN = 2;\n/** The fast method's ring width in pixels around a (widened) clipped region. */\nexport const NEIGHBOR_HIGHLIGHT_RING = 2;\n/** The full method's tolerance (the largest change of a sweep) and iteration cap; the relaxation factor is `neighborHighlightOmega`. */\nexport const NEIGHBOR_HIGHLIGHT_SOR = /* @__PURE__ */ Object.freeze({ tolerance: 1e-9, maximumIterations: 20000 });\n\n/**\n * #605 (2.23.0): the relaxation factor for a region whose members span a × b pixels: the optimal ω = 2/(1 + √(1 − ρ²)) of SOR\n * for the discrete Laplace equation on the a × b rectangle, whose Jacobi iteration has spectral radius\n * ρ = (cos(π/(a + 1)) + cos(π/(b + 1)))/2 (Young's theory of successive over-relaxation; e.g. G. Strang, MIT OpenCourseWare\n * 18.086, and R. J. LeVeque, \"Finite Difference Methods for Ordinary and Partial Differential Equations\", SIAM 2007, §4.2).\n * A region inside the rectangle has a Jacobi radius at most that of the rectangle, so this ω is at or above its optimum (where\n * SOR converges at the rate ω − 1). The system (each member's neighbor count times its ratio minus its neighbors') is\n * symmetric positive definite, so SOR converges for every ω in (0, 2) (Ostrowski–Reich). 2.22.0 used ω = 1.8 for every region:\n * 5,728 sweeps on a 260 × 260 region against about 400 (docs/DISPLAY_VIEW.md).\n */\nexport function neighborHighlightOmega(a: number, b: number): number {\n const rho = (Math.cos(Math.PI / (a + 1)) + Math.cos(Math.PI / (b + 1))) / 2;\n return 2 / (1 + Math.sqrt(Math.max(0, 1 - rho * rho)));\n}\n\nexport interface NeighborHighlightReport {\n method: \"ring-average\" | \"harmonic-interpolation\";\n /** Clipped pixels rebuilt, and the clipped regions. */\n reconstructedPixelCount: number;\n regionCount: number;\n /** Full method: the largest number of relaxation sweeps a region needed, and whether every region met the tolerance. */\n iterations: number;\n converged: boolean;\n}\n\n/**\n * The region ratios of an image: per pixel the ratios ρ its rebuild uses (`ratios`, 3 per pixel; for an unclipped pixel its own),\n * and which pixels are clipped. `clippedAt(i)` tells whether pixel i is clipped; `valueAt(i, out)` writes pixel i's u.\n * Pixels are i = y·width + x.\n */\nexport function neighborHighlightRatios(width: number, height: number, clippedAt: (i: number) => boolean, valueAt: (i: number, out: Float64Array) => void, fast: boolean):\n { clipped: Uint8Array; ratios: Float64Array; regionCount: number; iterations: number; converged: boolean } {\n const n = width * height, clipped = new Uint8Array(n), unknown = new Uint8Array(n), ratios = new Float64Array(3 * n), u = new Float64Array(3), D = NEIGHBOR_HIGHLIGHT_MARGIN;\n for (let i = 0; i < n; i++) if (clippedAt(i)) clipped[i] = 1;\n // The clipped pixels widened by the margin (a separable dilation).\n const rows = new Uint8Array(n);\n for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) if (clipped[y * width + x] === 1) rows.fill(1, y * width + Math.max(0, x - D), y * width + Math.min(width, x + D + 1));\n for (let x = 0; x < width; x++) for (let y = 0; y < height; y++) if (rows[y * width + x] === 1) for (let yy = Math.max(0, y - D); yy <= Math.min(height - 1, y + D); yy++) unknown[yy * width + x] = 1;\n for (let i = 0; i < n; i++) {\n if (unknown[i] === 1) continue;\n valueAt(i, u);\n const sum = u[0]! + u[1]! + u[2]!;\n if (sum > 0) { ratios[3 * i] = u[0]! / sum; ratios[3 * i + 1] = u[1]! / sum; ratios[3 * i + 2] = u[2]! / sum; }\n else { ratios[3 * i] = 1 / 3; ratios[3 * i + 1] = 1 / 3; ratios[3 * i + 2] = 1 / 3; }\n }\n const label = new Int32Array(n).fill(-1), stamp = new Int32Array(n).fill(-1), queue = new Int32Array(n);\n let regionCount = 0, iterations = 0, converged = true;\n for (let start = 0; start < n; start++) {\n if (unknown[start] === 0 || label[start]! >= 0) continue;\n // The region (8-connected), breadth first.\n const region = regionCount++;\n let head = 0, tail = 0;\n queue[tail++] = start; label[start] = region;\n while (head < tail) {\n const p = queue[head++]!, px = p % width, py = (p - px) / width;\n for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {\n const x = px + dx, y = py + dy;\n if (x < 0 || y < 0 || x >= width || y >= height) continue;\n const q = y * width + x;\n if (unknown[q] === 1 && label[q]! < 0) { label[q] = region; queue[tail++] = q; }\n }\n }\n // Fast: the mean ratios over the ring (each unclipped pixel once).\n let r0 = 0, r1 = 0, r2 = 0, count = 0;\n const R = NEIGHBOR_HIGHLIGHT_RING;\n for (let k = 0; k < tail; k++) {\n const p = queue[k]!, px = p % width, py = (p - px) / width;\n for (let y = Math.max(0, py - R); y <= Math.min(height - 1, py + R); y++) for (let x = Math.max(0, px - R); x <= Math.min(width - 1, px + R); x++) {\n const q = y * width + x;\n if (unknown[q] === 1 || stamp[q] === region) continue;\n stamp[q] = region; r0 += ratios[3 * q]!; r1 += ratios[3 * q + 1]!; r2 += ratios[3 * q + 2]!; count++;\n }\n }\n const m0 = count > 0 ? r0 / count : 1 / 3, m1 = count > 0 ? r1 / count : 1 / 3, m2 = count > 0 ? r2 / count : 1 / 3;\n for (let k = 0; k < tail; k++) { const p = queue[k]!; ratios[3 * p] = m0; ratios[3 * p + 1] = m1; ratios[3 * p + 2] = m2; }\n if (fast || count === 0) continue;\n // Full: successive over-relaxation of the discrete Laplace equation over the region, in the region's breadth-first order.\n const { tolerance, maximumIterations } = NEIGHBOR_HIGHLIGHT_SOR;\n let x0 = width, x1 = -1, y0 = height, y1 = -1;\n for (let k = 0; k < tail; k++) { const p = queue[k]!, px = p % width, py = (p - px) / width; x0 = Math.min(x0, px); x1 = Math.max(x1, px); y0 = Math.min(y0, py); y1 = Math.max(y1, py); }\n const omega = neighborHighlightOmega(x1 - x0 + 1, y1 - y0 + 1);\n let sweep = 0, change = Infinity;\n while (sweep < maximumIterations && change > tolerance) {\n change = 0; sweep++;\n for (let k = 0; k < tail; k++) {\n const p = queue[k]!, px = p % width, py = (p - px) / width;\n let a0 = 0, a1 = 0, a2 = 0, m = 0;\n for (let d = 0; d < 4; d++) {\n const x = px + (d === 0 ? -1 : d === 1 ? 1 : 0), y = py + (d === 2 ? -1 : d === 3 ? 1 : 0);\n if (x < 0 || y < 0 || x >= width || y >= height) continue;\n const q = y * width + x;\n a0 += ratios[3 * q]!; a1 += ratios[3 * q + 1]!; a2 += ratios[3 * q + 2]!; m++;\n }\n if (m === 0) continue;\n for (let c = 0; c < 3; c++) {\n const old = ratios[3 * p + c]!, target = (c === 0 ? a0 : c === 1 ? a1 : a2) / m, next = old + omega * (target - old);\n ratios[3 * p + c] = next;\n const delta = Math.abs(next - old);\n if (delta > change) change = delta;\n }\n }\n }\n iterations = Math.max(iterations, sweep);\n if (change > tolerance) converged = false;\n }\n return { clipped, ratios, regionCount, iterations, converged };\n}\n\n/**\n * The rebuild of one clipped pixel (step 4) into b, with its slopes ∂b/∂c (row-major 3 × 3, a.e.) when `slopes` is given.\n * `c` are the normalized camera channels, `g` the white-balance gains, `rho` the pixel's ratios.\n */\nexport function rebuildClippedPixel(c0: number, c1: number, c2: number, g: ArrayLike<number>, rho: ArrayLike<number>, b: Float64Array | number[], slopes?: Float64Array): void {\n const H = NEIGHBOR_HIGHLIGHT_THRESHOLD, u0 = c0 * g[0]!, u1 = c1 * g[1]!, u2 = c2 * g[2]!;\n const k0 = c0 < H, k1 = c1 < H, k2 = c2 < H;\n if (slopes) slopes.fill(0);\n if (k0 && k1 && k2) {\n b[0] = u0; b[1] = u1; b[2] = u2;\n if (slopes) { slopes[0] = g[0]!; slopes[4] = g[1]!; slopes[8] = g[2]!; }\n return;\n }\n const r0 = rho[0]!, r1 = rho[1]!, r2 = rho[2]!;\n if (!k0 && !k1 && !k2) {\n const q0 = r0 > 0 ? u0 / r0 : 0, q1 = r1 > 0 ? u1 / r1 : 0, q2 = r2 > 0 ? u2 / r2 : 0, m = q0 > q1 ? (q0 > q2 ? 0 : 2) : (q1 > q2 ? 1 : 2), s = m === 0 ? q0 : m === 1 ? q1 : q2;\n b[0] = s * r0; b[1] = s * r1; b[2] = s * r2;\n if (slopes) { const rm = m === 0 ? r0 : m === 1 ? r1 : r2; if (rm > 0) for (let k = 0; k < 3; k++) slopes[k * 3 + m] = (k === 0 ? r0 : k === 1 ? r1 : r2) * g[m]! / rm; }\n return;\n }\n const su = (k0 ? u0 : 0) + (k1 ? u1 : 0) + (k2 ? u2 : 0), sr = (k0 ? r0 : 0) + (k1 ? r1 : 0) + (k2 ? r2 : 0), s = sr > 0 ? su / sr : 0;\n for (let k = 0; k < 3; k++) {\n const kept = k === 0 ? k0 : k === 1 ? k1 : k2, uk = k === 0 ? u0 : k === 1 ? u1 : u2, rk = k === 0 ? r0 : k === 1 ? r1 : r2;\n if (kept) { b[k] = uk; if (slopes) slopes[k * 4] = g[k]!; continue; }\n const estimate = s * rk;\n if (estimate > uk) {\n b[k] = estimate;\n if (slopes && sr > 0) for (let j = 0; j < 3; j++) if (j === 0 ? k0 : j === 1 ? k1 : k2) slopes[k * 3 + j] = rk * g[j]! / sr;\n } else { b[k] = uk; if (slopes) slopes[k * 4] = g[k]!; }\n }\n}\n\n/**\n * Rebuilds the clipped pixels of a white-balanced image u (3 per pixel, in place; becomes b), with the normalized channels\n * c = u/g deciding which channels are clipped.\n */\nexport function reconstructHighlightsFromNeighbors(u: Float64Array, width: number, height: number, gains: ArrayLike<number>, fast: boolean): NeighborHighlightReport {\n const H = NEIGHBOR_HIGHLIGHT_THRESHOLD, g0 = gains[0]!, g1 = gains[1]!, g2 = gains[2]!;\n const field = neighborHighlightRatios(width, height, (i) => u[3 * i]! / g0 >= H || u[3 * i + 1]! / g1 >= H || u[3 * i + 2]! / g2 >= H,\n (i, out) => { out[0] = u[3 * i]!; out[1] = u[3 * i + 1]!; out[2] = u[3 * i + 2]!; }, fast);\n const b = new Float64Array(3);\n let rebuilt = 0;\n for (let i = 0; i < width * height; i++) {\n if (field.clipped[i] === 0) continue;\n rebuildClippedPixel(u[3 * i]! / g0, u[3 * i + 1]! / g1, u[3 * i + 2]! / g2, gains, field.ratios.subarray(3 * i, 3 * i + 3), b);\n u[3 * i] = b[0]!; u[3 * i + 1] = b[1]!; u[3 * i + 2] = b[2]!;\n rebuilt++;\n }\n return { method: fast ? \"ring-average\" : \"harmonic-interpolation\", reconstructedPixelCount: rebuilt, regionCount: field.regionCount, iterations: field.iterations, converged: field.converged };\n}\n"]}
@@ -6,4 +6,4 @@
6
6
  * own versions. Release checks confirm it matches package.json and the packed package.
7
7
  * @see docs/RELEASE_1_0_1.md
8
8
  */
9
- export declare const ENGINE_API_VERSION: "2.22.0";
9
+ export declare const ENGINE_API_VERSION: "2.23.0";
@@ -7,5 +7,5 @@
7
7
  * own versions. Release checks confirm it matches package.json and the packed package.
8
8
  * @see docs/RELEASE_1_0_1.md
9
9
  */
10
- export const ENGINE_API_VERSION = "2.22.0";
10
+ export const ENGINE_API_VERSION = "2.23.0";
11
11
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAiB,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Version of the engine release. Since 1.0.1 it equals the npm package version.\n *\n * New captures and plans record this version as their creator. Archived records keep the\n * version they were made with. Proof-of-concept (POC), schema and model contracts have their\n * own versions. Release checks confirm it matches package.json and the packed package.\n * @see docs/RELEASE_1_0_1.md\n */\nexport const ENGINE_API_VERSION = \"2.22.0\" as const;\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/core/version.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAiB,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Version of the engine release. Since 1.0.1 it equals the npm package version.\n *\n * New captures and plans record this version as their creator. Archived records keep the\n * version they were made with. Proof-of-concept (POC), schema and model contracts have their\n * own versions. Release checks confirm it matches package.json and the packed package.\n * @see docs/RELEASE_1_0_1.md\n */\nexport const ENGINE_API_VERSION = \"2.23.0\" as const;\n"]}
@@ -39,6 +39,11 @@ export interface DisplayViewCoupledRendering {
39
39
  bindView?(setup: DisplayViewSetup): void;
40
40
  /** #602: the real pixel (native site coordinates) whose moments `chain` computes next. */
41
41
  at?(x: number, y: number): void;
42
+ /**
43
+ * #605: the ratios ρ that `chain` uses at real pixel (x, y) (as `at` selects them) into out, or −1 in out[0] where the pixel
44
+ * takes none (the highlight step then keeps u): the GPU kernels read them from the host.
45
+ */
46
+ ratioAt?(x: number, y: number, out: Float64Array): void;
42
47
  /** #602: regions measured, and regions whose search stopped at the size cap (their ratios from the part found). */
43
48
  readonly neighborRegions: {
44
49
  measured: number;
@@ -30,7 +30,7 @@ import { portablePow } from "../core/portable-math.js";
30
30
  import { CLIP_REACH_SIGMA, GL, bigPhi, phi } from "./display-view-normal.js";
31
31
  import { desaturateToLuminance, SDR_LUMINANCE_WEIGHTS } from "../output/sdr-rendering.js";
32
32
  import { RAW_HIGHLIGHT_RECONSTRUCTION_START } from "../color/sensor-color-development.js";
33
- import { NEIGHBOR_HIGHLIGHT_MARGIN, NEIGHBOR_HIGHLIGHT_RING, NEIGHBOR_HIGHLIGHT_SOR, NEIGHBOR_HIGHLIGHT_THRESHOLD, rebuildClippedPixel } from "../color/neighbor-highlight-reconstruction.js";
33
+ import { NEIGHBOR_HIGHLIGHT_MARGIN, NEIGHBOR_HIGHLIGHT_RING, NEIGHBOR_HIGHLIGHT_SOR, NEIGHBOR_HIGHLIGHT_THRESHOLD, neighborHighlightOmega, rebuildClippedPixel } from "../color/neighbor-highlight-reconstruction.js";
34
34
  /**
35
35
  * Internal (exported for tests). The n-point Gauss–Hermite rule of the standard normal: Σ w_i f(x_i) ≈ E[f(Z)], Z ~ N(0, 1).
36
36
  * The nodes are the eigenvalues of the Jacobi matrix of the orthonormal Hermite polynomials (zero diagonal, off-diagonal √k),
@@ -311,7 +311,7 @@ export function createDisplayViewCoupledRendering(choice, gains, clipLevel, matr
311
311
  // #602: the region ratios of the bound view, found on demand (noise-free channels; see the module notes of the capture's method).
312
312
  let rho = null, view = null;
313
313
  const ratioOf = new Map(), channelMemo = new Map(), neighborRegions = { measured: 0, capped: 0 };
314
- const H = NEIGHBOR_HIGHLIGHT_THRESHOLD, limit = choice.fast ? DISPLAY_VIEW_NEIGHBOR_REGION_LIMIT.fast : DISPLAY_VIEW_NEIGHBOR_REGION_LIMIT.full;
314
+ const H = NEIGHBOR_HIGHLIGHT_THRESHOLD, limit = choice.fast ? DISPLAY_VIEW_NEIGHBOR_REGION_LIMIT.fast : DISPLAY_VIEW_NEIGHBOR_REGION_LIMIT.full, tile = Math.round(Math.sqrt(limit));
315
315
  function channelsAt(x, y) {
316
316
  const key = y * 1048576 + x;
317
317
  let v = channelMemo.get(key);
@@ -353,27 +353,40 @@ export function createDisplayViewCoupledRendering(choice, gains, clipLevel, matr
353
353
  const key = y * 1048576 + x, known = ratioOf.get(key);
354
354
  if (known)
355
355
  return known;
356
- // The region (8-connected), breadth first, up to the cap.
357
- const members = [key], index = new Map([[key, 0]]);
358
- let capped = false;
359
- for (let head = 0; head < members.length; head++) {
360
- const p = members[head], px = p % 1048576, py = (p - px) / 1048576;
361
- for (let dy = -1; dy <= 1; dy++)
362
- for (let dx = -1; dx <= 1; dx++) {
363
- const qx = px + dx, qy = py + dy, q = qy * 1048576 + qx;
364
- if (!inside(qx, qy) || index.has(q) || !isUnknown(qx, qy))
365
- continue;
366
- if (members.length >= limit) {
367
- capped = true;
368
- continue;
356
+ // The region (8-connected), breadth first. #605: a region above the cap is solved per tile of `tile` × `tile` pixels (the
357
+ // tile area is the cap): its part in the pixel's tile, which does not depend on where the render reached the region.
358
+ const search = (tiled) => {
359
+ const members = [key], index = new Map([[key, 0]]), tx = Math.floor(x / tile), ty = Math.floor(y / tile);
360
+ let capped = false;
361
+ for (let head = 0; head < members.length && !capped; head++) {
362
+ const p = members[head], px = p % 1048576, py = (p - px) / 1048576;
363
+ for (let dy = -1; dy <= 1; dy++)
364
+ for (let dx = -1; dx <= 1; dx++) {
365
+ const qx = px + dx, qy = py + dy, q = qy * 1048576 + qx;
366
+ if (!inside(qx, qy) || index.has(q) || (tiled && (Math.floor(qx / tile) !== tx || Math.floor(qy / tile) !== ty)) || !isUnknown(qx, qy))
367
+ continue;
368
+ if (members.length >= limit) {
369
+ capped = true;
370
+ break;
371
+ }
372
+ index.set(q, members.length);
373
+ members.push(q);
369
374
  }
370
- index.set(q, members.length);
371
- members.push(q);
372
- }
373
- }
375
+ }
376
+ return { members, index, capped };
377
+ };
378
+ let found = search(false);
374
379
  neighborRegions.measured++;
375
- if (capped)
380
+ if (found.capped) {
376
381
  neighborRegions.capped++;
382
+ found = search(true);
383
+ }
384
+ const { members, index } = found;
385
+ // #605: the members in raster order, so the ratios do not depend on which pixel found the region (a region render, the GPU
386
+ // host's band order and the whole view agree bit for bit).
387
+ members.sort((a, b) => a - b);
388
+ for (let i = 0; i < members.length; i++)
389
+ index.set(members[i], i);
377
390
  // Fast: the ring's mean ratios (unclipped pixels within the ring width, each once).
378
391
  const R = NEIGHBOR_HIGHLIGHT_RING, seen = new Set(), r = new Float64Array(3), mean = new Float64Array(3);
379
392
  let count = 0;
@@ -405,7 +418,16 @@ export function createDisplayViewCoupledRendering(choice, gains, clipLevel, matr
405
418
  values.set(mean, 3 * i);
406
419
  if (!choice.fast && count > 0) {
407
420
  // Full: successive over-relaxation of the discrete Laplace equation, Dirichlet values from the unclipped 4-neighbors.
408
- const { omega, tolerance, maximumIterations } = NEIGHBOR_HIGHLIGHT_SOR, boundary = new Map();
421
+ const { tolerance, maximumIterations } = NEIGHBOR_HIGHLIGHT_SOR, boundary = new Map();
422
+ let bx0 = Infinity, bx1 = -Infinity, by0 = Infinity, by1 = -Infinity;
423
+ for (const p of members) {
424
+ const px = p % 1048576, py = (p - px) / 1048576;
425
+ bx0 = Math.min(bx0, px);
426
+ bx1 = Math.max(bx1, px);
427
+ by0 = Math.min(by0, py);
428
+ by1 = Math.max(by1, py);
429
+ }
430
+ const omega = neighborHighlightOmega(bx1 - bx0 + 1, by1 - by0 + 1);
409
431
  let change = Infinity;
410
432
  for (let sweep = 0; sweep < maximumIterations && change > tolerance; sweep++) {
411
433
  change = 0;
@@ -465,7 +487,20 @@ export function createDisplayViewCoupledRendering(choice, gains, clipLevel, matr
465
487
  rho = own;
466
488
  }
467
489
  }
490
+ function ratioAt(x, y, out) {
491
+ at(x, y);
492
+ if (rho)
493
+ out.set(rho);
494
+ else
495
+ out[0] = -1;
496
+ }
497
+ let boundSignal = null;
468
498
  function bindView(setup) {
499
+ // #605: a render of the same signal keeps the regions found (their ratios depend only on the signal and the frame): the
500
+ // host's recomputation of flagged pixels renders many small regions of one view.
501
+ if (view && setup.signal === boundSignal)
502
+ return;
503
+ boundSignal = setup.signal;
469
504
  // The noise-free mosaic (expected normalized site values clipped at white, read reflect-101 at the raster's edges) through the
470
505
  // bilinear kernels: the expected camera channels of each real pixel (the capture's own demosaic for AHD captures is approximated).
471
506
  const W = setup.nativeWidth, Hh = setup.nativeHeight, k = setup.readout.map((r) => r.perElectron), dark = setup.readout.map((r) => r.darkElectrons);
@@ -593,6 +628,6 @@ export function createDisplayViewCoupledRendering(choice, gains, clipLevel, matr
593
628
  }
594
629
  return !(desaturate && reachesTop);
595
630
  }
596
- return { luminanceTone, reconstruct, neighbors, ...(neighbors ? { bindView, at } : {}), neighborRegions, desaturate, choice, chainPoints: chainRule.x.length, chainRule, luminanceRule: hermite8, ratioAtZero: ratioZero, pixel, chain, reconstructInReach, tone };
631
+ return { luminanceTone, reconstruct, neighbors, ...(neighbors ? { bindView, at, ratioAt } : {}), neighborRegions, desaturate, choice, chainPoints: chainRule.x.length, chainRule, luminanceRule: hermite8, ratioAtZero: ratioZero, pixel, chain, reconstructInReach, tone };
597
632
  }
598
633
  //# sourceMappingURL=display-view-rendering.js.map