@photivra/engine 2.11.1 → 2.13.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 +94 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +2 -4
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +1 -0
- package/dist/capture/export-jpeg.d.ts +1 -1
- package/dist/capture/export-jpeg.js +6 -4
- package/dist/capture/export-jpeg.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.d.ts +120 -0
- package/dist/exposure/auto-iso-slowest-shutter.js +216 -0
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -0
- package/dist/exposure/exposure-mode-resolver.d.ts +57 -1
- package/dist/exposure/exposure-mode-resolver.js +238 -33
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/facade/diffraction-provider.js +12 -13
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view.d.ts +27 -0
- package/dist/facade/display-view.js +234 -65
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +159 -3
- package/dist/facade/simulate-capture.js +203 -10
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.js +2 -2
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +2 -1
- package/dist/gpu/display-view-quality-gpu.js +24 -14
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +13 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.js +36 -2
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +10 -0
- package/dist/optics/irradiance-convolution.js +48 -13
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/output/print-jpeg.js +12 -9
- package/dist/output/print-jpeg.js.map +1 -1
- package/dist/output/text-metadata.d.ts +22 -2
- package/dist/output/text-metadata.js +58 -9
- package/dist/output/text-metadata.js.map +1 -1
- package/docs/API_REFERENCE.md +23 -1
- package/docs/QUICK_START.md +109 -3
- package/docs/USAGE.md +234 -1
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +77 -2
- package/docs/api/exposure-auto-iso-slowest-shutter.md +139 -0
- package/docs/api/exposure-exposure-mode-resolver.md +68 -0
- package/docs/api/facade-simulate-capture.md +153 -5
- package/docs/api/output-text-metadata.md +34 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,99 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 2.
|
|
3
|
+
## 2.13.0 — unreleased (prepared October 31, 2026)
|
|
4
|
+
|
|
5
|
+
A minor release for the app's Beta camera: Auto ISO with photographer-set limits and an automatic slowest shutter, the illuminance that gives the standard exposure, and root exports for adding text metadata to a file the caller encoded. Captures, RAW codes and files are the same as 2.12.0 for the same request; Quality (AHD) display views change where the scene decides AHD's choice, closer to the capture (#457).
|
|
6
|
+
- **New:** `estimateAutoIsoSlowestShutter()` and `exposure.autoIso.slowestPreferredShutterSeconds: "auto"` (#504); `autoIsoLimits` on every Auto ISO resolver and `exposure.autoIso.limits` (#505); `exposure.standardExposureIlluminanceLux`; `addJpegTextMetadata` and `addPngTextMetadata` (#388).
|
|
7
|
+
- **Fixed:** the Quality (AHD) display view follows AHD's direction choice (#457).
|
|
8
|
+
- **Faster, same output:** diffraction captures (#419); the print JPEG task (#417).
|
|
9
|
+
- **Compatibility:** 13 new root exports (1,780), none removed or changed; new optional options and result fields only; no default changed. `ExposureResolutionConstraint` gains two members, `"user-iso-maximum"` and `"user-iso-minimum"`, reported only when the new limits are given.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Auto ISO: an automatic slowest shutter from the lens and the hand's shake, with a faster/slower bias (#504).** New `estimateAutoIsoSlowestShutter()` (approximation, model `camera-shake-blur-budget-slowest-shutter` 1.0.0). It gives the exposure time at which `estimateCameraShakeBlur()`'s stabilized on-axis blur, v·hypot(tan(r·ω_yaw·t), tan(r·ω_pitch·t)) with r = 2^−stops, equals a blur budget (in pixels of a pitch, or a fraction of the image diagonal). Then it applies a whole-stop bias `fasterByStops` (−2 to +2: derived · 2^−bias) and, when `shutterCapability` is given, snaps to the body's shutter grid without ever lengthening the time. One axis uses the closed form t = atan(budget/v)/(r·|ω|); two axes use deterministic bisection. The 1/focal-length reciprocal rule is a rule of thumb and is not used. Makers' manuals for the feature: Sony ISO AUTO Min. SS, Fujifilm ISO Auto setting, Nikon D850 Auto ISO control.
|
|
14
|
+
- **Hand shake, a labelled generic default:** `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC` = 4.39 °/s (0.0766 rad/s) on yaw. It is the linear camera-motion rate for an average user holding a 100 g handset with two hands, in F. Xiao, J. Farrell, P. Catrysse, B. Wandell, "Mobile imaging: the big challenge of the small pixel", Proc. SPIE 7250 (2009), §2 (free author copy at web.stanford.edu/~wandell). It comes from the gyroscope measurements of Xiao et al., Proc. SPIE 6502 (2007). It describes a phone, not any camera or photographer, so the estimator takes the profile as an explicit input; the default is only the facade's.
|
|
15
|
+
- **Program + Auto ISO:** `resolveProgramAutoExposureMode` takes an optional `isoControl.slowestPreferredShutter: { slowestPreferredShutterSeconds, afterMaximumIso }` (`ProgramSlowestPreferredShutterPolicy`). The line's shutter is held at or faster than the threshold, with the line's aperture, before the ISO rises. At the Auto ISO maximum (the body's or #505's `autoIsoLimits`), `allow-slower-shutter` lengthens the shutter toward the target but never past the line's own shutter, and `hold-preferred-shutter` keeps it. The result adds `slowestPreferredShutter: { …, applied, afterMaximumIsoFallbackUsed }` only when the option is given. Full Auto does not take it.
|
|
16
|
+
- **`simulateCapture` and the display view:** `exposure.autoIso.slowestPreferredShutterSeconds` accepts `"auto"` in aperture priority and is now optional in program (a number or `"auto"`, with `afterMaximumIso`). `exposure.autoIso.automaticSlowestShutter` sets `fasterByStops` (default 0), `blurBudgetPixels` (default 1), `angularVelocityRadPerSec` (default the generic hand) and `stabilizationStopsEquivalent` (default 0); each default is a `default` assumption, and the derivation is a `model` assumption. The Auto ISO report gains `automaticSlowestShutter` (derived, biased and used times, budget, blur at the used time in pixels) and, in program, `slowestPreferredShutterApplied`.
|
|
17
|
+
- **Unchanged without the options:** every hash lock holds. A numeric slowest shutter in aperture priority and program without the option give the same results and reports as before.
|
|
18
|
+
- **Tests:** `test/auto-iso-slowest-shutter.test.ts`:
|
|
19
|
+
- the closed form, and the shake model's blur at the derived time equals the budget (one and two axes);
|
|
20
|
+
- nine focal lengths give strictly faster thresholds, with 400 mm 8× faster than 50 mm;
|
|
21
|
+
- the thin-lens projection at a focus distance;
|
|
22
|
+
- stabilization lengthens by exactly 2^stops;
|
|
23
|
+
- the bias moves by exact whole stops;
|
|
24
|
+
- the diagonal-fraction budget;
|
|
25
|
+
- the discrete-grid snap and its clamps;
|
|
26
|
+
- no NaN or Infinity across a sweep;
|
|
27
|
+
- 15 invalid inputs fail with domain errors.
|
|
28
|
+
|
|
29
|
+
`test/auto-iso-limits.test.ts` adds the program hold: applied and not applied, both after-maximum policies, the fallback stopping at the line's shutter, and invalid holds. `test/simulate-capture-auto-iso.test.ts` adds the facade:
|
|
30
|
+
- aperture priority with `"auto"`;
|
|
31
|
+
- equality with a direct estimator call;
|
|
32
|
+
- focal length and bias;
|
|
33
|
+
- program with a number and with `"auto"`;
|
|
34
|
+
- the display view report;
|
|
35
|
+
- 11 invalid options fail.
|
|
36
|
+
- New root exports (1,780): `estimateAutoIsoSlowestShutter`, `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`, `AUTO_ISO_SLOWEST_SHUTTER_MODEL_VERSION`, `AUTO_ISO_SLOWEST_SHUTTER_MAXIMUM_BIAS_STOPS`, and the types `EstimateAutoIsoSlowestShutterInput`, `AutoIsoSlowestShutterBlurBudget`, `AutoIsoSlowestShutterEstimate`, `ProgramSlowestPreferredShutterPolicy`, `SimulateCaptureAutomaticSlowestShutterOptions` and `SimulateCaptureAutomaticSlowestShutterReport`. Docs: `docs/USAGE.md` ("Automatic slowest shutter (#504)", "Program Auto with Auto ISO: a slowest preferred shutter (#504)"), `docs/QUICK_START.md` ("Auto ISO") and `docs/STABILIZATION.md`.
|
|
37
|
+
- **Auto ISO: photographer-set limits, separate from the body's capability (#505).** A new optional policy input `autoIsoLimits: { maximum, minimum? }` (type `AutoIsoLimits`) on every Auto ISO entry point: `resolveManualExposureMode` (`isoControl.autoIsoLimits`), `resolveAperturePriorityAutoIsoExposureMode` (`policy.autoIsoLimits`), `resolveShutterPriorityExposureMode` (`isoControl.policy.autoIsoLimits`), `resolveProgramAutoExposureMode` (`isoControl.autoIsoLimits`) and `resolveFullAutoExposureMode` (`policy.autoIsoLimits`); and `exposure.autoIso.limits` in `simulateCapture`, the display view and the ideal reference, in every mode. Sources, makers' manuals: Nikon D850 Auto ISO control (maximum sensitivity), Fujifilm X-Pro2 ISO Auto setting (default and maximum sensitivity), Panasonic GH5 II (upper and lower Auto ISO limits).
|
|
38
|
+
- **Policy, not capability:** the body's `capabilities.iso.autoIsoMinimum`/`autoIsoMaximum` (else its ISO range) still say what the body allows; the limits narrow that range. Both must be selectable ISOs inside it, `minimum` at most `maximum` (default the body's minimum); otherwise the resolvers fail with `InvalidScientificInputError` (a malformed record with `InvalidConfigurationError`) and `simulateCapture` with `InvalidConfigurationError`. Nothing is clipped. The policies' lowest-selectable-ISO baseline starts at the user's minimum.
|
|
39
|
+
- **Reporting:** `ExposureResolutionConstraint` gains `"user-iso-maximum"` and `"user-iso-minimum"`, reported when the ISO is held at a limit strictly inside the body's range (a limit equal to the body's bound reports the body's `"iso-maximum"`/`"iso-minimum"`). `SimulateCaptureAutoIsoReport` gains the optional `limits: { minimum, maximum }`, the range used; `autoIsoMinimum`/`autoIsoMaximum` stay the body's range. The `exposure.autoIso` assumption records the limits when given.
|
|
40
|
+
- **Unchanged without the input:** no result, sample or hash changes when `autoIsoLimits` / `exposure.autoIso.limits` is absent; every hash lock holds. `exposure.autoIso` is now accepted with `iso: "auto"` in every mode, but `slowestPreferredShutterSeconds` and `afterMaximumIso` stay aperture priority only. A separate flash cap is not included (it belongs with flash-aware exposure).
|
|
41
|
+
- **Tests:** `test/auto-iso-limits.test.ts` (each of the five resolvers stops at the user maximum with `user-iso-maximum` and the exact residual; a maximum equal to the body's reports `iso-maximum` and changes nothing; the user minimum raises the baseline and reports `user-iso-minimum`; aperture priority's `allow-slower-shutter` and `hold-preferred-shutter` give the same settings and residual against a user cap of 800 as against a body capped at 800; limits equal to the body's range give results equal to no limits; out-of-range, off-grid, unordered, non-finite, missing and malformed limits fail in every resolver) and `test/simulate-capture-auto-iso.test.ts` (the facade in manual, aperture priority, shutter priority and program; a capped capture byte-identical to that manual ISO; the display view and ideal reference report the same limits; ten invalid options fail).
|
|
42
|
+
- New root export: the type `AutoIsoLimits` (1,770 root symbols). Docs: `docs/USAGE.md` ("Photographer-set Auto ISO limits (#505)", "Priority modes with Auto ISO") and `docs/QUICK_START.md` ("Auto ISO").
|
|
43
|
+
- **The illuminance at which the settings give the standard exposure.** `simulateCapture`'s and the display view's `exposure` gain `standardExposureIlluminanceLux`, next to `standardExposureDeviationStops`: E·L_ref(N, t, S)/L = E·2^Δ, with E the request's `illuminanceLux`, L the metered scene luminance and L_ref = 10·N²/(0.65·t·S) (CIPA DC-004-2020, as for Δ). A chart, reflectance-function or material scene's radiance is reflectance × k(E)·S(λ)/π with k proportional to E, so its metered luminance is proportional to E and the same request at this illuminance meters at Δ = 0. It is `null` for a black scene (L = 0) and for a `radiance-function` scene, whose radiance does not follow the illuminance; it may exceed the 1e7 lux that `illuminanceLux` accepts. No sample, RAW code or other result changes; every hash lock holds.
|
|
44
|
+
- Tests (`test/exposure-standard-illuminance.test.ts`): re-running at the reported illuminance gives |Δ| < 1e-9 stops (≈ 2e-15 measured; the 16 × 16-zone, 5 nm metering quadrature is the same at both illuminances and cancels) for the default request at f/11 (40 612 lux) and a 3200 K Siemens star at 5000 lux (10 557 lux); with the defaults it is the default illuminance to 1e-4 (the quadrature's ≈ 1.2 × 10⁻⁵ stop); aperture priority equals manual at the settings it resolved, shutter priority and program are E·2^Δ, the display view equals the capture; `null` for a black and a radiance scene. `test/simulate-capture-auto-iso.test.ts` expects the new field in the display view's exposure.
|
|
45
|
+
- **Display-view bundle size, measured and guarded (#383).** Tests and documentation only; no `src/` change, so no result, sample or RAW code changes and every hash lock holds. Sizes with rolldown 1.2.9 (Vite 8's bundler), minified, gzip level 9, from 2.11.1's `dist`, in docs/DISPLAY_VIEW.md, "Bundle size":
|
|
46
|
+
- **The display view adds 42,228 B minified and 16,888 B gzip** to a `simulateCapture` + `simulateIdealReference` bundle (846,928 B / 229,007 B gzip). #383's target of 40 % less is not met: the addition is mostly the renderer itself (55 % of the rendered size), the result's assumption texts and the portable functions, and no smaller form was found that keeps every result's bytes and the measured render times. `test/capture-bundle.test.ts` keeps the addition within a budget about 2 % above the measured size: 43,100 B minified and 17,250 B gzip on 2.11.1's display view, raised to 46,500 B and 18,550 B for #457's AHD choice (#527), which added 3,307 B minified and 1,294 B gzip (the test's build from `src/` measures 45,546 B / 18,186 B gzip; all of the growth is `facade/display-view.ts`, rendered 55,908 → 64,855 B, with no new import and no `src/gpu` module in the entry).
|
|
47
|
+
- **The GPU display view stays out of a split bundle's first load:** a bundle of `simulateCapture`, `simulateDisplayView` and `prepareDisplayView` has no `src/gpu` module in its entry chunk (892,566 B / 247,193 B gzip); the GPU session, the renderers and their WGSL (15 `src/gpu` modules, 52,446 B gzip) are a chunk `prepareDisplayView` imports only for `gpu: "auto"` or `"require"`. The new test fails if they reach the entry. A build that cannot split inlines them (302,217 B gzip as one `iife` file): Vite's default `iife` worker format is how the GPU code reached the Photivra app's capture worker in 2.11; with `worker: { format: "es" }` its worker measured 258,618 B gzip instead of 317,120 B. docs/USAGE.md notes this under "Rendering a prepared view on the GPU".
|
|
48
|
+
- **`addJpegTextMetadata` and `addPngTextMetadata` are root exports (#388).** A caller that encodes a JPEG or PNG itself (for example a full-size file joined from `output.region` parts with `composePrintJpegStrips` or `serializePngImage`) adds the caller's text with the functions `output.metadata` already calls, so the bytes are the same as a whole-frame `simulateCapture` with `output.metadata`. This lets Photivra/apps delete its adapted copy (`src/export/textMetadata.ts`). No file, sample or RAW code changes; every hash lock holds.
|
|
49
|
+
- **Validation:** the bytes must be a `Uint8Array`; the text is checked by `output.metadata`'s rules (messages name `addJpegTextMetadata metadata` or `addPngTextMetadata metadata`). The JPEG writer now also rejects, with `InvalidConfigurationError`, a marker without a length before SOS (SOI, EOI, RSTm, TEM, fill bytes), a segment length below 2, an XMP APP1 segment after a non-APPn segment (before, it would have duplicated the bytes in between), and an XMP packet that is not UTF-8 (before, a raw `TypeError`). The engine's own JPEGs have none of these.
|
|
50
|
+
- **Tests** (`test/output-text-metadata.test.ts`): for three files (8-bit JPEG, 8-bit PNG, 16-bit Display P3 PNG) and four texts (the app's export text, the app encoder test's `{ description: "x" }`, and this file's Latin-1 and non-Latin vectors), the exported functions give the bytes of `simulateCapture` with `output.metadata`, locked by SHA-256 digests that were recorded three ways and agreed: the app's copy run unmodified on the same inputs, `output.metadata` at origin/main `50dfe3e`, and the exports; the same for a JPEG without an XMP packet (against the app's copy) and the ideal-reference PNG; plus sixteen invalid inputs.
|
|
51
|
+
- **Naming:** `add*` is a new verb family in `docs/API_STYLE.md` (a copy of an encoded file with caller data inserted, every other byte kept), with `test/api-style-compatibility.test.ts` updated; the two functions are classified in `test/root-export-input-errors.test.ts` (raw bytes and the text).
|
|
52
|
+
- New root exports: `addJpegTextMetadata` and `addPngTextMetadata` (1,769). Docs: `docs/USAGE.md` ("Text metadata on a file you encoded"), `docs/QUICK_START.md` ("Text metadata (2.4)"); API reference regenerated.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- **Tests and CI: three hash locks are x64 locks, with recorded arm64 hashes (#508).** No engine output, package content or x64 hash lock changes. The display view's "keeps its bytes" locks, the pixel-memo locks and the Airy cell construction locks were recorded on x64; on arm64 (Apple silicon and Linux arm64, Node 24.19.0 and 24.22.1) 13 of their 17 digests differ, because V8's `Math` `sin`, `cos`, `asin`, `atan2` and `log` return results one ulp apart on the two architectures for some arguments (first a `Math.cos` in the β = 12.5 Airy cells and `Math.log(14)` in the display view; neither architecture is the more accurate). On x64 the tests assert the locks exactly as before; on arm64 (`process.arch === "arm64"`) each differing lock is asserted against its own recorded arm64 hash (`test/helpers/architecture-hash-locks.ts`), so arm64 is locked too, and the whole suite passes on Apple silicon. The display-view test no longer claims "the same on every JavaScript engine". The `hash locks (macos-latest)` job's step for these three files no longer has `continue-on-error`, so a failure there fails the step instead of showing as passed. Docs: `docs/NUMERICAL_CORRECTNESS.md` ("Test hash locks and platforms", which also corrects the macOS job to eight test files) and `docs/DISPLAY_VIEW.md` ("Same bytes in every engine").
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- **Display view, AHD (Quality): the expected value follows AHD's choice where the scene decides it (#457).** The view averaged AHD's two directional candidates at every real pixel. Where structure finer than a few sites decides AHD's homogeneity choice (a Siemens star's centre, a sharp edge), the capture takes one candidate, so at device-pixel widths the view's colour at the star's centre was 5.1 codes RMS and up to 34 codes from the capture (24 MP at 2028 wide; limit 2). The view now runs AHD's own steps on the noise-free mosaic (the expected sites, clipped at white, reflect-101 at the raster edges, as `createAhdDemosaicTask`) and takes the chosen candidate's expected value; a tie, which is every flat neighbourhood, keeps the average, and the noise terms are unchanged. docs/DISPLAY_VIEW.md, "AHD's choice where the scene decides it".
|
|
61
|
+
- **Measured** (seven reference seeds, limits unchanged): set F star centre 5.13 → 0.78 codes RMS (24 MP, 2028 wide) and 3.60 → 1.02 (100 MP, 4000 wide); AHD alone 19.3 → 2.84 against the seven-reference mean, where one reference is 3.08 from it. On the default matrix 50 of 75 Quality cases change and none leaves a limit; star-centre RMS falls (for example 1.64 → 0.82 codes, 24 MP at 800 wide), case 17's false-colour difference +0.41 → +0.01 and case 92's +0.48 → +0.41. No Speed case and no uniform patch changes, so the Quality noise limit (#379) is unchanged.
|
|
62
|
+
- **The view's direction is the task's:** equal to `createAhdDemosaicTask`'s direction map at every pixel of a random and a star mosaic, borders included (`test/display-view-ahd-choice.test.ts`, with the set F star case against seven captures as a regression test).
|
|
63
|
+
- **Bytes:** Quality (AHD) display views change wherever the two candidates differ; Speed views and the views of uniform scenes keep their bytes. Three hash locks were re-recorded on Linux x64, each closer to the capture against 16 reference captures: `test/display-view.test.ts` (AHD dead leaves, Reinhard: 0.37 → 0.16 codes RMS), `test/display-view-pixel-memo.test.ts` (AHD star: 1.51 → 0.61) and `test/display-view-speed-material.test.ts` (AHD patch edge at ISO 3200: 7.56 → 3.88; its `sceneLookups` diagnostic rises 26 400 → 28 252 because the choice reads 5 sites around each pixel). The other locks hold. Captures are unchanged.
|
|
64
|
+
- **Cost:** +12–15 % on the app's Quality request at 2028 × 1352 (whole view extrapolated 23.4–24.4 s → 26.9–28.0 s, Node 24.19.0, Apple M5 Pro), +12–21 % for whole Quality views on the stratified estimator.
|
|
65
|
+
- **Bundle:** the display view's addition to a capture bundle grows by 3,307 B minified and 1,294 B gzip (42,239 → 45,546 B, 16,888 → 18,186 B gzip; rolldown 1.2.9, `test/capture-bundle.test.ts`'s build), all in `facade/display-view.ts`; #383's budget is raised for it.
|
|
66
|
+
- **GPU (Quality):** the kernel still renders the candidates' average; it now flags (`ahdChoice`) and the host recomputes with the CPU reference every display pixel where the choice could move it by more than 2⁻¹⁰ of its noise σ, recomputing runs of flagged pixels as one region. GPU renders keep agreeing with the CPU reference within their bounds, but busy scenes recompute a large share on the CPU (3–75 % of the emulation fixtures' pixels; 21.6 % of a 24 MP checkerboard band at 2028 × 1352). Computing the choice in the pixel pass is the follow-up. docs/WEBGPU.md, "Display view (Quality) on the GPU".
|
|
67
|
+
|
|
68
|
+
### Faster, same output
|
|
69
|
+
|
|
70
|
+
- **`simulateCapture` with `lens.diffraction`: the object-space convolution computes only each band's own values (#419).**
|
|
71
|
+
- **What changed:** each 32-row band convolved its whole padded grid, (rows + 2R) × (columns + 2R), and kept the centre (about 3× the rows at R = 32, and more on narrow rasters). It now gathers only the interior (internal `createIrradianceConvolutionInteriorRunner`), with the same validation and messages as before. The scene samples per band are unchanged. Defocus (#492) already did this.
|
|
72
|
+
- **Same bytes:** each interior value is the same products added in the same order (v outer, u inner, every tap), so it is `calculateIrradianceConvolution`'s value bit for bit. Checked with `Object.is` on 2,354,304 provider values against main's provider (R 1–32, material and radiance-function scenes, three offset sets, four windows, three bands), on new unit tests of the interior runner, and on twelve captures whose samples, RAW codes and `providerEvaluationCount` are identical (SHA-256) to main's. Every hash lock holds.
|
|
73
|
+
- **Measured** (Node 24.19.0, one thread, an 18-core Mac shared with other jobs, load 6–43, five rounds alternating fresh processes of the two builds; medians): `diagnostics.timingsMs.diffraction` on a function scene with the Quality options (diffraction, four-spot, AHD) at 96 × 72 went 0.86 → 0.16 s at 1.4 µm f/8 (R 15), 4.9 → 0.54 s at f/16 (R 29) and 6.3 → 0.62 s at 1 µm f/16 (R 32), total 7.2 → 1.8 s; at 192 × 144 and R 32, 17.0 → 2.1 s (total 19.6 → 5.2 s). The tabulated capture's four verification sites (a 2 × 2 window) went 0.41 → 0.004 s at 1.4 µm f/16 (total 0.85 → 0.50 s at 96 × 72 and 1.05 → 0.76 s at 384 × 288). At small R nothing slows down: 6 µm f/8 and the 24 MP whole-frame view are within ±5 % over eight rounds.
|
|
74
|
+
- **Not done:** a row ring sharing the 2R overlap samples between bands. Sampling is about 6 % of the band time at R 29–32 after this change (measured), so the ring would save at most about 4 % of it, for up to 2R rows × columns × nodes × lattices of doubles (about 42 MB per lattice on a 4000-site row).
|
|
75
|
+
- **Print JPEG task: each block's samples in one reused `Uint8Array`, without the per-sample check (#417).** `createPrintJpegTask` built every 8 × 8 block's 192 samples as a new `number[]` by `push`, and the encoder then checked each entry with `Number.isInteger` and the 0–255 bounds. Both paths (1:1 and area average) now write the samples into one reused `Uint8Array(192)`, and the internal encoder's `writeRgbBlock` skips the entry scan for a `Uint8Array`, whose entries are integers 0–255 by type; it still checks the length. The strip path (`createPrintJpegStrip`, the app's workers) already coded from a `Uint8Array` and is unchanged. #416 (2.8.1) had already replaced the 1:1 accumulation with a 256-entry table; the DCT and entropy coding are untouched.
|
|
76
|
+
- **Same bytes:** the files' SHA-256 equals main's (50dfe3e) for nine plans: 6000 × 4000 noise and smooth, 3000 × 2000 noise, 1001 × 757 noise, 9 × 7, 256 × 32, 1543 × 1 at 1:1, and 3000 × 2000 → 1500 × 1000 and 1001 × 757 → 270 × 205 area averages. Every JPEG hash lock holds. New test: a reused `Uint8Array` block codes to the same bytes as arrays, and a 191- or 193-sample one is refused.
|
|
77
|
+
- **Measured** (Node 24.19.0, one thread, Apple M5 Pro, with six other agents running on the machine, so absolute times are noisy; builds alternated, 3 rounds × 3 runs, median of 9): 24 MP noise at 1:1, q = 2: 3.06 → 2.90 s (×0.95); 24 MP smooth at 1:1, q = 1: 1.46 → 1.32 s (×0.91); 6 MP → 1.5 MP area average: 0.363 → 0.349 s (×0.96). The saving is below #417's profiled ceiling of about 27 %.
|
|
78
|
+
|
|
79
|
+
## 2.12.0 — published October 31, 2026
|
|
80
|
+
|
|
81
|
+
A minor release for the app's Beta camera: Auto ISO through the one-call API, and the deviation from the standard exposure for an exposure meter. With `iso` absent or a number, samples, RAW codes and files are the same as 2.11.1; the exposure result gains `isoControl` and `standardExposureDeviationStops`.
|
|
82
|
+
- **New:** `exposure.iso: "auto"` in every exposure mode, with `exposure.autoIso` in aperture priority and an Auto ISO report in the result (#516, #518); `exposure.standardExposureDeviationStops` (#515, #517).
|
|
83
|
+
- **Compatibility:** two new root type exports (1,767), none removed; `exposure.iso` widens to `number | "auto"`; new result fields only.
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
|
|
87
|
+
- **`simulateCapture` and the display view: Auto ISO in every exposure mode (#516).** `exposure.iso: "auto"` hands the ISO to the existing exposure-mode resolvers' Auto ISO branches, within the body's Auto ISO range, in `manual`, `aperture-priority`, `shutter-priority` and `program`; the default stays ISO 100. With `iso` absent or a number nothing changes: every hash lock holds, and the only result change is the new `exposure.isoControl: "manual"`.
|
|
88
|
+
- **Per mode:** manual keeps the aperture and shutter (`resolveManualExposureMode`, automatic ISO); aperture priority uses `resolveAperturePriorityAutoIsoExposureMode` with the new `exposure.autoIso: { slowestPreferredShutterSeconds, afterMaximumIso? }` (the slowest preferred shutter is required, within the body's shutter range; `afterMaximumIso` is `"allow-slower-shutter"`, the default, or `"hold-preferred-shutter"`); shutter priority uses the `minimum-iso-aperture-first` policy; program uses the program line at the lowest ISO and raises the ISO beyond the line's end. Every policy starts at the lowest selectable Auto ISO and snaps to the nearest selectable ISO in stops (the lower on a tie). The automatic slowest shutter (#504) and photographer-set limits (#505) are not part of this change.
|
|
89
|
+
- **Result:** `exposure.settings.iso` is the ISO used; `exposure.isoControl` is `"automatic"`; `exposure.autoIso` (`SimulateCaptureAutoIsoReport`) gives `idealIsoBeforeConstraints`, `autoIsoMinimum`, `autoIsoMaximum`, `clamped`, the resolver's `limitingConstraint` (for example `"iso-maximum"`) and `residualStops`, and in aperture priority the policy, the slowest preferred shutter and `afterMaximumIsoFallbackUsed`. The display view (`simulateDisplayView`, `prepareDisplayView`) and the ideal reference report the same fields; a new `exposure.autoIso` assumption records the policy.
|
|
90
|
+
- **Validation:** a string other than `"auto"`, `exposure.autoIso` outside aperture priority with Auto ISO, a missing, non-finite or out-of-range slowest preferred shutter, an unknown `afterMaximumIso` or key, and a body without Auto ISO fail with `InvalidConfigurationError`.
|
|
91
|
+
- **Tests** (`test/simulate-capture-auto-iso.test.ts`): each mode with `"auto"` (the default scene at f/8, 1/125 s gives ISO 100; three stops darker gives ISO 800, byte-identical to a manual ISO 800 capture in manual and aperture priority; compensation; the minimum and maximum with their limiting constraints; both `afterMaximumIso` policies; shutter priority past the widest aperture; program past the line's end); a capture, its display view (direct and prepared), its ideal reference and its region parts give the same exposure and report, and the parts stitch to the capture's bytes; fourteen invalid options fail with a domain error in the capture and the prepared view.
|
|
92
|
+
- New root exports: the types `SimulateCaptureAutoIsoAfterMaximum` and `SimulateCaptureAutoIsoReport` (1,767). `SimulateCaptureOptions.exposure.iso` widens to `number | "auto"` and gains `autoIso`; the capture, display-view and ideal-reference `exposure` gain `isoControl` and the optional `autoIso`. Docs: `docs/QUICK_START.md` ("Inputs and defaults", "Auto ISO") and `docs/USAGE.md`.
|
|
93
|
+
- **The deviation from the standard exposure, in stops (#515, for Photivra/apps#124).** `simulateCapture`'s and the display view's `exposure` gain `standardExposureDeviationStops`: Δ = log₂(N²/t) − log₂(0.65·L·S/10), from the CIPA DC-004-2020 relations the facade already meters with (S = 10/H, §3.2; H = 0.65·L·t/N², §5.5 (4)), with the settings used and `meteredSceneLuminanceCdPerSquareMeter`; no new metering. Positive is darker than the standard exposure (under), negative brighter (over); in an automatic mode it is minus the compensation plus any step or limit the resolver hit. It is `null` when the metered luminance is 0 (a black scene, which manual mode captures), never infinite. No other result, sample or RAW code changes; every hash lock holds.
|
|
94
|
+
- Tests: `test/exposure-deviation.test.ts`: 0 with the defaults (|Δ| ≈ 1.2 × 10⁻⁵ from the metering quadrature), +0.919 at f/11, +1.000 at f/8√2, −1.059 at 1/60 s, −1.000 at ISO 200, −⅔ in aperture priority with +⅔ stop, the 30 s limit at 0.01 lux (+9.16), the display view's value equal to the capture's, and `null` for a black scene.
|
|
95
|
+
|
|
96
|
+
## 2.11.1 — published October 31, 2026
|
|
4
97
|
|
|
5
98
|
A patch release that publishes 2.11.0's engine to npm. The owner tagged `v2.11.0` on `6bef763` and published its GitHub release on October 28, 2026, but its npm publish run (40636849817) was cancelled at the verify job's 25-minute limit while the single-job coverage gate was still running, so `@photivra/engine@2.11.0` was never published; npm `latest` is 2.10.0. A published tag runs the publish workflow of its own commit, so 2.11.0 cannot be published again; 2.11.1 carries the fixed workflow.
|
|
6
99
|
- **No API, behaviour or value change from 2.11.0:** `src/` differs only in `ENGINE_API_VERSION`; the packed files differ only in the version fields and the release documentation (docs/RELEASE_2_11_1.md, "Same package").
|
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.
|
|
12
|
+
version: "2.13.0"
|
|
13
13
|
keywords:
|
|
14
14
|
- photography
|
|
15
15
|
- camera optics
|
package/NODE_SUPPORT.md
CHANGED
|
@@ -90,11 +90,9 @@ For **7 days** from a line's LTS start, the guard therefore accepts a build of t
|
|
|
90
90
|
- Other majors, prereleases and end-of-life dates are checked as before.
|
|
91
91
|
- A build that carries the LTS marker passes as before.
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### Checking ahead
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
The warning is expected once a year: from 7 days before a line's LTS start until Node publishes its first LTS build, it reports the end of the grace period. It clears by itself when the LTS build appears. If it stays red near the end of the grace period, review the snapshot against the official schedule. Do not widen a window just to clear it. An end of life inside the next 14 days fails it the same way.
|
|
95
|
+
No scheduled job checks the policy ahead of time; the guard in every CI job is the check, so a date boundary first shows as a failing required check on the first run after it. To see a boundary coming, for example before a release, run `node .github/node-lts-lookahead.mjs`. It fetches `https://nodejs.org/dist/index.json`, takes the newest stable release of each supported major, and runs the policy guard against it at 00:00 UTC on today and each of the next 14 days. A failing date names the major, the first failing date, the build and the reason. Do not widen a window just to clear it.
|
|
98
96
|
|
|
99
97
|
Routine minor and patch updates within an approved major may follow normal green-PR rules. Do not auto-merge a major upgrade of the Node runtime, a Node image, or `@types/node` on its own. Where Dependabot is configured, keep Node typings major upgrades out of its routine queue, while still allowing updates within supported majors.
|
|
100
98
|
|
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.
|
|
35
|
+
Install the published ESM package below. The [2.13.0 release record](https://github.com/Photivra/photivra/blob/main/docs/RELEASE_2_13_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.
|
|
38
|
+
npm install @photivra/engine@2.13.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.
|
|
78
|
+
Repository `main` may describe newer, unreleased work. For the stable contract, use the docs bundled in the published package, or the exact `v2.13.0` tag.
|
|
79
79
|
|
|
80
80
|
## Documentation
|
|
81
81
|
|
|
@@ -363,13 +363,13 @@ The application can then use those results, while the photography calculations t
|
|
|
363
363
|
|
|
364
364
|
## Status
|
|
365
365
|
|
|
366
|
-
- Repository package version: `2.
|
|
367
|
-
- Engine API contract: `2.
|
|
366
|
+
- Repository package version: `2.13.0` (release candidate prepared October 31, 2026; publication is separate)
|
|
367
|
+
- Engine API contract: `2.13.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
|
- Composed POC simulation API contract: `1.0.0`
|
|
370
370
|
- Stability: 1.0 root-package compatibility policy; bounded scientific models and independent POC contract
|
|
371
371
|
|
|
372
|
-
From 1.0.1, the package version and `ENGINE_API_VERSION` are equal. New captures/plans record 2.
|
|
372
|
+
From 1.0.1, the package version and `ENGINE_API_VERSION` are equal. New captures/plans record 2.13.0; existing archives keep their original creator identities. Schema, model and POC contract versions stay independent.
|
|
373
373
|
|
|
374
374
|
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.
|
|
375
375
|
|
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.
|
|
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.12.0**, published on October 31, 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
|
|
package/THIRD_PARTY.md
CHANGED
|
@@ -97,6 +97,7 @@ The colorimetry modules in `src/color/` (see [docs/COLORIMETRY.md](https://githu
|
|
|
97
97
|
| Bradford and CAT16 matrices (`chromatic-adaptation.ts`) | Lam (1985) / ICC.1:2010 Annex E; CAT16: Li et al. (2016), IS&T CIC24, Eq. (15), doi:10.2352/ISSN.2169-2629.2017.32.208 (free; checked 2026-10-17 to match the engine; journal version Li et al. 2017) | Published 3×3 model constants. CAT02, the Hunt–Pointer–Estévez matrix and the CIECAM02 degree-of-adaptation formula were removed from 2.0 (owner decisions, 2026-10-17) because no confirmed free source prints them. |
|
|
98
98
|
| Primaries and white points; BT.709 and BT.1886 constants (`rgb-color-spaces.ts`) | ITU-R BT.709-6, BT.1886, BT.2020-2; W3C CSS Color 4 (`srgb`, `display-p3`); also IEC 61966-2-1, SMPTE EG 432-1 | Standardized numeric constants; every value is available from the freely published ITU-R and W3C documents. |
|
|
99
99
|
| h, c, k | BIPM SI Brochure (2019) | Exact SI defining constants (facts). |
|
|
100
|
+
| Generic handheld angular velocity 4.39 °/s (`GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`, `src/exposure/auto-iso-slowest-shutter.ts`, #504) | F. Xiao, J. Farrell, P. Catrysse, B. Wandell, "Mobile imaging: the big challenge of the small pixel", Proc. SPIE 7250 (2009), §2 (free author copy: https://web.stanford.edu/~wandell/data/papers/2009-CameraShake-Xiao.pdf, read 2026-10-31); from the gyroscope measurements of F. Xiao et al., Proc. SPIE 6502 (2007) | One published measured value used as a fact, labelled as a generic default for a 100 g handset held in two hands, not a measurement of any camera or photographer. No text, figure, table or dataset is copied. |
|
|
100
101
|
| Standard output sensitivity S = 10/H, camera-equation constant 0.65 and the 18 % grey reference, K_m = 683 lm/W (`src/facade/`) | CIPA DC-004-2020 (free); BIPM SI Brochure, definition of the candela | Standardized scalar constants used as facts. The capture facade's charts (slanted edge, Siemens star, step wedge, grey ramp, checkerboard, point grid) are engine-authored analytic patterns; the slanted edge only follows the ISO 12233 geometry (a few degrees of slant, 4:1 contrast) and reproduces no chart artwork or data. |
|
|
101
102
|
|
|
102
103
|
The following datasets are deliberately **excluded**:
|
|
@@ -64,7 +64,7 @@ export declare function createExportJpegEncoder(input: Omit<ExportJpegInput, "sa
|
|
|
64
64
|
icc?: Uint8Array;
|
|
65
65
|
densityDotsPerInch?: number;
|
|
66
66
|
}): {
|
|
67
|
-
writeRgbBlock(samples: readonly number[]): void;
|
|
67
|
+
writeRgbBlock(samples: readonly number[] | Uint8Array): void;
|
|
68
68
|
appendStrip(strip: JpegStripBits): void;
|
|
69
69
|
finish(): Uint8Array;
|
|
70
70
|
dispose(): void;
|
|
@@ -307,10 +307,12 @@ export function createExportJpegEncoder(input) {
|
|
|
307
307
|
return {
|
|
308
308
|
writeRgbBlock(samples) {
|
|
309
309
|
let valid = !disposed && blocks < totalBlocks && samples.length === 192;
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
310
|
+
// A Uint8Array holds only integers 0–255, so only an array's entries need the scan.
|
|
311
|
+
if (!(samples instanceof Uint8Array))
|
|
312
|
+
for (let i = 0; valid && i < 192; i++) {
|
|
313
|
+
const v = samples[i];
|
|
314
|
+
valid = Number.isInteger(v) && v >= 0 && v <= 255;
|
|
315
|
+
}
|
|
314
316
|
if (!valid)
|
|
315
317
|
throw new InvalidConfigurationError("JPEG requires complete bounded RGB coding blocks.");
|
|
316
318
|
coder.transform(samples, coefficients);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-jpeg.js","sourceRoot":"","sources":["../../src/capture/export-jpeg.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Baseline JPEG encoder written for this project. It computes the DCT (discrete cosine transform)\n * directly and uses no third-party encoder source, default quantization tables or Huffman tables.\n * @see docs/SIMULATED_CAPTURE.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, scaleBudgetCeiling } from \"../core/pixel-limits.js\";\n\n/**\n * Identifies the exact byte output of the baseline encoder.\n *\n * Version 2 (engine 2.0.0) uses the fixed cosine table below instead of runtime `Math.cos`, and rounds\n * quantized coefficients half away from zero. Compared with version 1, bytes can differ only where a\n * coefficient before rounding was within about one ULP (unit in the last place) of a half-integer, or\n * was exactly a negative half-integer. The repository's test images are unchanged.\n */\nexport const EXPORT_JPEG_ENCODER_ID = \"photivra-baseline-jpeg-444-v2\" as const;\n/**\n * C(u,x) = cos((2x+1)·u·π/16) for u,x in 0..7, row-major by u.\n *\n * Each entry is the correctly rounded IEEE-754 double of the exact cosine. They were computed offline with\n * 130-digit decimal arithmetic and checked so that no neighbouring double is closer (see\n * docs/PHOTOGRAPHIC_EXPORT.md). Hard-coding them makes the DCT independent of each JavaScript engine's\n * `Math.cos`, which differs in the last bit between engines. These are mathematical facts, not third-party data.\n */\nexport const JPEG_DCT_COSINES: Readonly<Float64Array> = Float64Array.of(\n 1,1,1,1,1,1,1,1,\n 0.9807852804032304,0.8314696123025452,0.5555702330196022,0.19509032201612828,-0.19509032201612828,-0.5555702330196022,-0.8314696123025452,-0.9807852804032304,\n 0.9238795325112867,0.3826834323650898,-0.3826834323650898,-0.9238795325112867,-0.9238795325112867,-0.3826834323650898,0.3826834323650898,0.9238795325112867,\n 0.8314696123025452,-0.19509032201612828,-0.9807852804032304,-0.5555702330196022,0.5555702330196022,0.9807852804032304,0.19509032201612828,-0.8314696123025452,\n 0.7071067811865476,-0.7071067811865476,-0.7071067811865476,0.7071067811865476,0.7071067811865476,-0.7071067811865476,-0.7071067811865476,0.7071067811865476,\n 0.5555702330196022,-0.9807852804032304,0.19509032201612828,0.8314696123025452,-0.8314696123025452,-0.19509032201612828,0.9807852804032304,-0.5555702330196022,\n 0.3826834323650898,-0.9238795325112867,0.9238795325112867,-0.3826834323650898,-0.3826834323650898,0.9238795325112867,-0.9238795325112867,0.3826834323650898,\n 0.19509032201612828,-0.5555702330196022,0.8314696123025452,-0.9807852804032304,0.9807852804032304,-0.8314696123025452,0.5555702330196022,-0.19509032201612828\n);\n/**\n * Rounds a quantized coefficient to the nearest integer, with ties going away from zero (−2.5 → −3,\n * 2.5 → 3), so positive and negative values round the same way. `Math.round` alone sends −2.5 to −2.\n */\nexport function roundJpegCoefficient(value: number): number {\n return value<0 ? -Math.round(-value) : Math.round(value);\n}\n\n/** Internal baseline JPEG settings: 8-bit YCbCr 4:4:4, one explicit constant quantization step, and uniform Huffman tables written for this project. */\nexport interface ExportJpegInput { width: number; height: number; samples: readonly number[]; quantizationStep: number; exif: Uint8Array; xmp: Uint8Array }\n/** Encodes a baseline JPEG with a directly computed DCT. Uses no third-party encoder source, default quantization tables or Huffman tables. */\nexport function encodeExportJpeg(input: ExportJpegInput): Uint8Array {\n const { width, height, samples, quantizationStep: q } = input;\n if (![width,height,q].every(Number.isSafeInteger) || width < 1 || height < 1 || width*height > 4096 ||\n q < 1 || q > 255 || samples.length !== width*height*3 || Array.from(samples).some((v) => !Number.isInteger(v) || v < 0 || v > 255)) {\n throw new InvalidConfigurationError(\"Unsupported baseline JPEG input.\");\n }\n const encoder=createExportJpegEncoder({...input,maximumOutputBytes:1_000_000});\n for(let by=0;by<height;by+=8)for(let bx=0;bx<width;bx+=8){\n const block:number[]=[];\n for(let y=0;y<8;y++)for(let x=0;x<8;x++){\n const p=(Math.min(by+y,height-1)*width+Math.min(bx+x,width-1))*3;\n block.push(samples[p]!,samples[p+1]!,samples[p+2]!);\n }\n encoder.writeRgbBlock(block);\n }\n return encoder.finish();\n}\n/**\n * The entropy-coded bits of consecutive blocks of one image, coded apart from the blocks before them (`encodeJpegStrip`):\n * the first block's quantized coefficients (3 × 64, natural order), whose DC differences need the block before; the other\n * blocks' bits, unstuffed, most-significant first; and the last block's DC values, which the next strip's first block needs.\n */\nexport interface JpegStripBits { first: Float64Array; bits: Uint8Array; bitLength: number; blockCount: number; lastDc: Float64Array }\n/**\n * The DCT, quantization and entropy coding of one 8 × 8 RGB block, shared by the whole-image writer and strips so both\n * make the same bits.\n *\n * The 8×8 DCT, computed directly, with orthonormal DC factors and one chosen quantization step.\n *\n * This is a deliberately simple 4:4:4 reference encoder. Lossy quantization means exact RGB pixels are\n * not preserved. Decoding the JPEG and comparing is an interoperability check, not an exact scientific\n * check of pixel values.\n *\n * Each coefficient is the direct 64-term sum Σ_y Σ_x (f(x,y)·C(u,x))·C(v,y), summed over y, then x.\n * The row products f(x,y)·C(u,x) are computed once per u and reused for all eight v. This reuses the\n * identical IEEE-754 products and keeps the exact order of multiplication and summation. A factored\n * row/column DCT would reorder the sum, so it is deliberately not used.\n *\n * C(u,x) comes from the fixed table `JPEG_DCT_COSINES` (correctly rounded constants), not `Math.cos`,\n * so the coefficients do not depend on the JavaScript engine's maths library. Each quantized coefficient\n * is rounded half away from zero (`roundJpegCoefficient`).\n */\nfunction createJpegBlockCoder(q:number, emit:(value:number,count:number)=>void):{\n transform(samples:ArrayLike<number>,out:Float64Array):void; code(coefficients:Float64Array,previous:number[]|Float64Array):void;\n} {\n const amplitude = (value: number, max: number): number => {\n const size=value===0 ? 0 : Math.floor(Math.log2(Math.abs(value)))+1;\n if (size>max) throw new InvalidConfigurationError(\"JPEG coefficient exceeds baseline entropy range.\");\n return size;\n };\n const coefficient = (value: number, size: number): void => { if (size) emit(value>=0 ? value : value+(1<<size)-1,size); };\n const zigzag=new Int32Array(64);\n for (let diagonal=0,i=0;diagonal<=14;diagonal++) {\n const points: number[] = [];\n for (let y=0;y<8;y++) { const x=diagonal-y; if (x>=0 && x<8) points.push(y*8+x); }\n for (const point of diagonal%2===0 ? points.reverse() : points) zigzag[i++]=point;\n }\n // Huffman symbol index of each AC (run, size) pair; equals the index of the symbol in the DHT segment's AC list.\n const ac=[0,240];\n for (let run=0;run<16;run++) for (let size=1;size<=10;size++) ac.push(run*16+size);\n const acIndex=new Int16Array(256).fill(-1);\n for (let i=ac.length-1;i>=0;i--) acIndex[ac[i]!]=i;\n const cosine=JPEG_DCT_COSINES;\n const planes=[new Float64Array(64),new Float64Array(64),new Float64Array(64)];\n const blueScale=2*(1-.114), redScale=2*(1-.299);\n return {\n transform(samples:ArrayLike<number>,out:Float64Array):void {\n const [luma,blueDifference,redDifference]=planes as [Float64Array,Float64Array,Float64Array];\n for (let i=0;i<64;i++) {\n // JPEG pads only partial 8x8 blocks (MCUs, minimum coded units). The declared image and crop size never change.\n const p=i*3;\n const red=samples[p]!, green=samples[p+1]!, blue=samples[p+2]!, luminance=.299*red+.587*green+.114*blue;\n luma[i]=luminance-128; blueDifference[i]=(blue-luminance)/blueScale; redDifference[i]=(red-luminance)/redScale;\n }\n for (let channel=0;channel<3;channel++) {\n const block=planes[channel]!, o=channel*64;\n for (let u=0;u<8;u++) {\n const uOffset=u*8;\n const uFactor=u===0 ? Math.SQRT1_2 : 1;\n // The eight v sums in one pass over (y, x): each sum still adds the same products f(x,y)·C(u,x)·C(v,y) in the same\n // order (y, then x), and each row product is the same IEEE product, formed once per (x, y) instead of stored.\n let s0=0, s1=0, s2=0, s3=0, s4=0, s5=0, s6=0, s7=0;\n for (let y=0;y<8;y++) {\n const c0=cosine[y]!, c1=cosine[8+y]!, c2=cosine[16+y]!, c3=cosine[24+y]!, c4=cosine[32+y]!, c5=cosine[40+y]!, c6=cosine[48+y]!, c7=cosine[56+y]!;\n for (let x=0;x<8;x++) {\n const r=block[y*8+x]!*cosine[uOffset+x]!;\n s0+=r*c0; s1+=r*c1; s2+=r*c2; s3+=r*c3; s4+=r*c4; s5+=r*c5; s6+=r*c6; s7+=r*c7;\n }\n }\n // Scaled as before, left to right: sum·0.25·(u factor)·(v factor)/q.\n out[o+u]=roundJpegCoefficient(s0*.25*uFactor*Math.SQRT1_2/q); out[o+8+u]=roundJpegCoefficient(s1*.25*uFactor*1/q);\n out[o+16+u]=roundJpegCoefficient(s2*.25*uFactor*1/q); out[o+24+u]=roundJpegCoefficient(s3*.25*uFactor*1/q);\n out[o+32+u]=roundJpegCoefficient(s4*.25*uFactor*1/q); out[o+40+u]=roundJpegCoefficient(s5*.25*uFactor*1/q);\n out[o+48+u]=roundJpegCoefficient(s6*.25*uFactor*1/q); out[o+56+u]=roundJpegCoefficient(s7*.25*uFactor*1/q);\n }\n }\n },\n code(coefficients:Float64Array,previous:number[]|Float64Array):void {\n for (let channel=0;channel<3;channel++) {\n const o=channel*64, difference=coefficients[o]!-previous[channel]!, size=amplitude(difference,11); emit(size,4); coefficient(difference,size); previous[channel]=coefficients[o]!;\n let zeroes=0;\n for (let i=1;i<64;i++) {\n const value=coefficients[o+zigzag[i]!]!;\n if (value===0) { zeroes++; continue; }\n while (zeroes>=16) { emit(1,8); zeroes-=16; }\n const length=amplitude(value,10), symbol=zeroes*16+length; emit(acIndex[symbol]!,8); coefficient(value,length); zeroes=0;\n }\n if (zeroes) emit(0,8);\n }\n }\n };\n}\n/**\n * Codes `blockCount` consecutive blocks of an image (`block(i, out)` writes block i's 192 RGB samples, 0–255) apart from the\n * blocks before them, for writing an image's strips on separate workers; `createExportJpegEncoder`'s `appendStrip` joins\n * them into the bytes the whole image's `writeRgbBlock` calls would have written.\n */\nexport function encodeJpegStrip(quantizationStep:number, blockCount:number, block:(index:number,out:Uint8Array)=>void):JpegStripBits {\n if(!Number.isSafeInteger(quantizationStep)||quantizationStep<1||quantizationStep>255||!Number.isSafeInteger(blockCount)||blockCount<1)\n throw new InvalidConfigurationError(\"Invalid JPEG strip plan.\");\n let storage=new Uint8Array(65_536), length=0, accumulator=0, bits=0, bitLength=0;\n // Unstuffed bits, most-significant first.\n const emit=(value:number,count:number):void=>{\n accumulator=(accumulator<<count)|(value&((1<<count)-1)); bits+=count; bitLength+=count;\n while (bits>=8) {\n bits-=8;\n if(length===storage.length){const grown=new Uint8Array(storage.length*2);grown.set(storage);storage=grown;}\n storage[length++]=(accumulator>>>bits)&255;\n }\n accumulator&=(1<<bits)-1;\n };\n const coder=createJpegBlockCoder(quantizationStep,emit), samples=new Uint8Array(192), first=new Float64Array(192), coefficients=new Float64Array(192), lastDc=new Float64Array(3);\n block(0,samples); coder.transform(samples,first);\n lastDc[0]=first[0]!; lastDc[1]=first[64]!; lastDc[2]=first[128]!;\n for(let i=1;i<blockCount;i++){block(i,samples);coder.transform(samples,coefficients);coder.code(coefficients,lastDc);}\n if(bits){if(length===storage.length){const grown=new Uint8Array(storage.length+1);grown.set(storage);storage=grown;}storage[length++]=(accumulator<<(8-bits))&255;}\n return {first,bits:storage.slice(0,length),bitLength,blockCount,lastDc};\n}\n/**\n * Largest byte budget the internal writer accepts: the Print JPEG budget ceiling at the largest opt-in source\n * (256 000 000 bytes per 24 000 000 pixels at 2^27 pixels). Each caller enforces its own smaller budget.\n */\nconst EXPORT_JPEG_MAXIMUM_OUTPUT_BYTES=scaleBudgetCeiling(256_000_000,FULL_RESOLUTION_CEILING_PIXELS);\n/**\n * Internal size-limited JPEG writer. The reference export and the scalable export use exactly the same\n * DCT and entropy-coding equations.\n *\n * When `densityDotsPerInch` is supplied, it is written to the JFIF 1.02 APP0 segment as units=1 (dots\n * per inch) with equal X and Y density. JFIF density fields are 16-bit unsigned, so it must be an integer\n * in 1..65535; callers round any fractional density and store the exact value in EXIF. When omitted,\n * APP0 keeps units=0 with a 1:1 pixel aspect ratio and states no physical size.\n */\nexport function createExportJpegEncoder(input: Omit<ExportJpegInput,\"samples\"> & {maximumOutputBytes:number;icc?:Uint8Array;densityDotsPerInch?:number}): {\n writeRgbBlock(samples:readonly number[]):void; appendStrip(strip:JpegStripBits):void; finish():Uint8Array; dispose():void;\n} {\n const {width,height,quantizationStep:q}=input;\n if(![width,height,q,input.maximumOutputBytes].every(Number.isSafeInteger)||width<1||height<1||width>65535||height>65535||q<1||q>255||input.maximumOutputBytes<1||input.maximumOutputBytes>EXPORT_JPEG_MAXIMUM_OUTPUT_BYTES)\n throw new InvalidConfigurationError(\"Invalid bounded JPEG encoding plan.\");\n const density=input.densityDotsPerInch;\n if(density!==undefined&&(!Number.isSafeInteger(density)||density<1||density>65535))\n throw new InvalidConfigurationError(\"JFIF density requires an integer from 1 to 65535 dots per inch.\");\n // Growable output. Capacity starts at min(budget, 64 KiB) and doubles, but never beyond the budget. The budget\n // check is unchanged (offset + n > maximumOutputBytes fails), so the output bytes and failures are the same as\n // with a buffer allocated at full budget up front. An old buffer is zeroed after its bytes are copied over.\n const budget=input.maximumOutputBytes;\n let storage=new Uint8Array(Math.min(budget,65_536)),offset=0,disposed=false,blocks=0;\n const reserve=(count:number):void=>{\n if(disposed||offset+count>budget)throw new InvalidConfigurationError(\"JPEG output exceeds admitted byte budget or is disposed.\");\n if(offset+count<=storage.length)return;\n const grown=new Uint8Array(Math.min(budget,Math.max(storage.length*2,offset+count)));\n grown.set(storage.subarray(0,offset));storage.fill(0,0,offset);storage=grown;\n };\n const push=(...values:number[]):void=>{reserve(values.length);storage.set(values,offset);offset+=values.length;};\n // Fast path for one entropy-coded byte: the same budget/disposal check and byte order as push(), without an array per byte.\n const pushByte=(value:number):void=>{if(disposed||offset>=storage.length)reserve(1);storage[offset++]=value;};\n push(255,216);\n const marker = (id: number, payload: readonly number[]): void => {\n if (payload.length > 65533) throw new InvalidConfigurationError(\"JPEG metadata segment exceeds the standard APP limit.\");\n push(255,id,(payload.length+2)>>8,(payload.length+2)&255,...payload);\n };\n // JFIF 1.02 APP0: identifier, version 1.02, units (0 aspect ratio only, 1 dots per inch), Xdensity, Ydensity, no thumbnail.\n marker(224,density===undefined ? [74,70,73,70,0,1,2,0,0,1,0,1,0,0] : [74,70,73,70,0,1,2,1,density>>8,density&255,density>>8,density&255,0,0]);\n marker(225,[69,120,105,102,0,0,...input.exif]);\n marker(225,[...new TextEncoder().encode(\"http://ns.adobe.com/xap/1.0/\\0\"),...input.xmp]);\n if(input.icc){\n if(input.icc.length>65519)throw new InvalidConfigurationError(\"ICC profile exceeds the single-segment encoding envelope.\");\n marker(226,[...new TextEncoder().encode(\"ICC_PROFILE\\0\"),1,1,...input.icc]);\n }\n marker(219,[0,...Array<number>(64).fill(q)]);\n marker(192,[8,height>>8,height&255,width>>8,width&255,3,1,17,0,2,17,0,3,17,0]);\n // DC categories 0..11 use 4-bit codes; AC EOB/ZRL and all baseline run/category pairs use 8-bit codes.\n // Incomplete canonical Huffman trees reserve the all-ones code, so JPEG bit padding (1-bits) can never be read as a symbol.\n const dc = Array.from({length:12},(_,i) => i), ac = [0,240];\n for (let run=0;run<16;run++) for (let size=1;size<=10;size++) ac.push(run*16+size);\n marker(196,[0,...Array.from({length:16},(_,i) => i===3 ? 12 : 0),...dc,\n 16,...Array.from({length:16},(_,i) => i===7 ? ac.length : 0),...ac]);\n marker(218,[3,1,0,2,0,3,0,0,63,0]);\n let accumulator=0, bits=0;\n // Appends the low `count` bits (count <= 16) most-significant first, emitting each completed byte with 0xFF stuffing.\n const emit = (value: number, count: number): void => {\n accumulator=(accumulator<<count)|(value&((1<<count)-1)); bits+=count;\n while (bits>=8) { bits-=8; const byte=(accumulator>>>bits)&255; pushByte(byte); if (byte===255) pushByte(0); }\n accumulator&=(1<<bits)-1;\n };\n const coder=createJpegBlockCoder(q,emit), coefficients=new Float64Array(192);\n const previous=[0,0,0];\n const totalBlocks=Math.ceil(width/8)*Math.ceil(height/8);\n return {\n writeRgbBlock(samples:readonly number[]):void {\n let valid=!disposed&&blocks<totalBlocks&&samples.length===192;\n for(let i=0;valid&&i<192;i++){const v=samples[i]!;valid=Number.isInteger(v)&&v>=0&&v<=255;}\n if(!valid)throw new InvalidConfigurationError(\"JPEG requires complete bounded RGB coding blocks.\");\n coder.transform(samples,coefficients); coder.code(coefficients,previous);\n blocks++;\n },\n appendStrip(strip:JpegStripBits):void {\n if(disposed||blocks+strip.blockCount>totalBlocks||strip.first.length!==192||strip.lastDc.length!==3||strip.bits.length*8<strip.bitLength)\n throw new InvalidConfigurationError(\"JPEG strip does not continue this encoding.\");\n // The strip's first block, coded against the DC values before it; then its other blocks' bits, which only depend on\n // values inside the strip, as written (each byte's 0xFF stuffing happens here, as in writeRgbBlock).\n coder.code(strip.first,previous);\n const whole=strip.bitLength>>3;\n for(let i=0;i<whole;i++)emit(strip.bits[i]!,8);\n if(strip.bitLength&7)emit(strip.bits[whole]!>>(8-(strip.bitLength&7)),strip.bitLength&7);\n previous[0]=strip.lastDc[0]!; previous[1]=strip.lastDc[1]!; previous[2]=strip.lastDc[2]!;\n blocks+=strip.blockCount;\n },\n finish():Uint8Array {\n if(disposed||blocks!==Math.ceil(width/8)*Math.ceil(height/8))throw new InvalidConfigurationError(\"JPEG cannot finish incomplete or disposed encoding.\");\n if(bits)emit((1<<(8-bits))-1,8-bits);\n // Only the written prefix can hold data; zero it after the copy instead of filling the whole capacity.\n push(255,217);const output=storage.slice(0,offset);storage.fill(0,0,offset);storage=new Uint8Array(0);disposed=true;return output;\n },\n dispose():void {storage.fill(0,0,offset);storage=new Uint8Array(0);disposed=true;}\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"export-jpeg.js","sourceRoot":"","sources":["../../src/capture/export-jpeg.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Baseline JPEG encoder written for this project. It computes the DCT (discrete cosine transform)\n * directly and uses no third-party encoder source, default quantization tables or Huffman tables.\n * @see docs/SIMULATED_CAPTURE.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, scaleBudgetCeiling } from \"../core/pixel-limits.js\";\n\n/**\n * Identifies the exact byte output of the baseline encoder.\n *\n * Version 2 (engine 2.0.0) uses the fixed cosine table below instead of runtime `Math.cos`, and rounds\n * quantized coefficients half away from zero. Compared with version 1, bytes can differ only where a\n * coefficient before rounding was within about one ULP (unit in the last place) of a half-integer, or\n * was exactly a negative half-integer. The repository's test images are unchanged.\n */\nexport const EXPORT_JPEG_ENCODER_ID = \"photivra-baseline-jpeg-444-v2\" as const;\n/**\n * C(u,x) = cos((2x+1)·u·π/16) for u,x in 0..7, row-major by u.\n *\n * Each entry is the correctly rounded IEEE-754 double of the exact cosine. They were computed offline with\n * 130-digit decimal arithmetic and checked so that no neighbouring double is closer (see\n * docs/PHOTOGRAPHIC_EXPORT.md). Hard-coding them makes the DCT independent of each JavaScript engine's\n * `Math.cos`, which differs in the last bit between engines. These are mathematical facts, not third-party data.\n */\nexport const JPEG_DCT_COSINES: Readonly<Float64Array> = Float64Array.of(\n 1,1,1,1,1,1,1,1,\n 0.9807852804032304,0.8314696123025452,0.5555702330196022,0.19509032201612828,-0.19509032201612828,-0.5555702330196022,-0.8314696123025452,-0.9807852804032304,\n 0.9238795325112867,0.3826834323650898,-0.3826834323650898,-0.9238795325112867,-0.9238795325112867,-0.3826834323650898,0.3826834323650898,0.9238795325112867,\n 0.8314696123025452,-0.19509032201612828,-0.9807852804032304,-0.5555702330196022,0.5555702330196022,0.9807852804032304,0.19509032201612828,-0.8314696123025452,\n 0.7071067811865476,-0.7071067811865476,-0.7071067811865476,0.7071067811865476,0.7071067811865476,-0.7071067811865476,-0.7071067811865476,0.7071067811865476,\n 0.5555702330196022,-0.9807852804032304,0.19509032201612828,0.8314696123025452,-0.8314696123025452,-0.19509032201612828,0.9807852804032304,-0.5555702330196022,\n 0.3826834323650898,-0.9238795325112867,0.9238795325112867,-0.3826834323650898,-0.3826834323650898,0.9238795325112867,-0.9238795325112867,0.3826834323650898,\n 0.19509032201612828,-0.5555702330196022,0.8314696123025452,-0.9807852804032304,0.9807852804032304,-0.8314696123025452,0.5555702330196022,-0.19509032201612828\n);\n/**\n * Rounds a quantized coefficient to the nearest integer, with ties going away from zero (−2.5 → −3,\n * 2.5 → 3), so positive and negative values round the same way. `Math.round` alone sends −2.5 to −2.\n */\nexport function roundJpegCoefficient(value: number): number {\n return value<0 ? -Math.round(-value) : Math.round(value);\n}\n\n/** Internal baseline JPEG settings: 8-bit YCbCr 4:4:4, one explicit constant quantization step, and uniform Huffman tables written for this project. */\nexport interface ExportJpegInput { width: number; height: number; samples: readonly number[]; quantizationStep: number; exif: Uint8Array; xmp: Uint8Array }\n/** Encodes a baseline JPEG with a directly computed DCT. Uses no third-party encoder source, default quantization tables or Huffman tables. */\nexport function encodeExportJpeg(input: ExportJpegInput): Uint8Array {\n const { width, height, samples, quantizationStep: q } = input;\n if (![width,height,q].every(Number.isSafeInteger) || width < 1 || height < 1 || width*height > 4096 ||\n q < 1 || q > 255 || samples.length !== width*height*3 || Array.from(samples).some((v) => !Number.isInteger(v) || v < 0 || v > 255)) {\n throw new InvalidConfigurationError(\"Unsupported baseline JPEG input.\");\n }\n const encoder=createExportJpegEncoder({...input,maximumOutputBytes:1_000_000});\n for(let by=0;by<height;by+=8)for(let bx=0;bx<width;bx+=8){\n const block:number[]=[];\n for(let y=0;y<8;y++)for(let x=0;x<8;x++){\n const p=(Math.min(by+y,height-1)*width+Math.min(bx+x,width-1))*3;\n block.push(samples[p]!,samples[p+1]!,samples[p+2]!);\n }\n encoder.writeRgbBlock(block);\n }\n return encoder.finish();\n}\n/**\n * The entropy-coded bits of consecutive blocks of one image, coded apart from the blocks before them (`encodeJpegStrip`):\n * the first block's quantized coefficients (3 × 64, natural order), whose DC differences need the block before; the other\n * blocks' bits, unstuffed, most-significant first; and the last block's DC values, which the next strip's first block needs.\n */\nexport interface JpegStripBits { first: Float64Array; bits: Uint8Array; bitLength: number; blockCount: number; lastDc: Float64Array }\n/**\n * The DCT, quantization and entropy coding of one 8 × 8 RGB block, shared by the whole-image writer and strips so both\n * make the same bits.\n *\n * The 8×8 DCT, computed directly, with orthonormal DC factors and one chosen quantization step.\n *\n * This is a deliberately simple 4:4:4 reference encoder. Lossy quantization means exact RGB pixels are\n * not preserved. Decoding the JPEG and comparing is an interoperability check, not an exact scientific\n * check of pixel values.\n *\n * Each coefficient is the direct 64-term sum Σ_y Σ_x (f(x,y)·C(u,x))·C(v,y), summed over y, then x.\n * The row products f(x,y)·C(u,x) are computed once per u and reused for all eight v. This reuses the\n * identical IEEE-754 products and keeps the exact order of multiplication and summation. A factored\n * row/column DCT would reorder the sum, so it is deliberately not used.\n *\n * C(u,x) comes from the fixed table `JPEG_DCT_COSINES` (correctly rounded constants), not `Math.cos`,\n * so the coefficients do not depend on the JavaScript engine's maths library. Each quantized coefficient\n * is rounded half away from zero (`roundJpegCoefficient`).\n */\nfunction createJpegBlockCoder(q:number, emit:(value:number,count:number)=>void):{\n transform(samples:ArrayLike<number>,out:Float64Array):void; code(coefficients:Float64Array,previous:number[]|Float64Array):void;\n} {\n const amplitude = (value: number, max: number): number => {\n const size=value===0 ? 0 : Math.floor(Math.log2(Math.abs(value)))+1;\n if (size>max) throw new InvalidConfigurationError(\"JPEG coefficient exceeds baseline entropy range.\");\n return size;\n };\n const coefficient = (value: number, size: number): void => { if (size) emit(value>=0 ? value : value+(1<<size)-1,size); };\n const zigzag=new Int32Array(64);\n for (let diagonal=0,i=0;diagonal<=14;diagonal++) {\n const points: number[] = [];\n for (let y=0;y<8;y++) { const x=diagonal-y; if (x>=0 && x<8) points.push(y*8+x); }\n for (const point of diagonal%2===0 ? points.reverse() : points) zigzag[i++]=point;\n }\n // Huffman symbol index of each AC (run, size) pair; equals the index of the symbol in the DHT segment's AC list.\n const ac=[0,240];\n for (let run=0;run<16;run++) for (let size=1;size<=10;size++) ac.push(run*16+size);\n const acIndex=new Int16Array(256).fill(-1);\n for (let i=ac.length-1;i>=0;i--) acIndex[ac[i]!]=i;\n const cosine=JPEG_DCT_COSINES;\n const planes=[new Float64Array(64),new Float64Array(64),new Float64Array(64)];\n const blueScale=2*(1-.114), redScale=2*(1-.299);\n return {\n transform(samples:ArrayLike<number>,out:Float64Array):void {\n const [luma,blueDifference,redDifference]=planes as [Float64Array,Float64Array,Float64Array];\n for (let i=0;i<64;i++) {\n // JPEG pads only partial 8x8 blocks (MCUs, minimum coded units). The declared image and crop size never change.\n const p=i*3;\n const red=samples[p]!, green=samples[p+1]!, blue=samples[p+2]!, luminance=.299*red+.587*green+.114*blue;\n luma[i]=luminance-128; blueDifference[i]=(blue-luminance)/blueScale; redDifference[i]=(red-luminance)/redScale;\n }\n for (let channel=0;channel<3;channel++) {\n const block=planes[channel]!, o=channel*64;\n for (let u=0;u<8;u++) {\n const uOffset=u*8;\n const uFactor=u===0 ? Math.SQRT1_2 : 1;\n // The eight v sums in one pass over (y, x): each sum still adds the same products f(x,y)·C(u,x)·C(v,y) in the same\n // order (y, then x), and each row product is the same IEEE product, formed once per (x, y) instead of stored.\n let s0=0, s1=0, s2=0, s3=0, s4=0, s5=0, s6=0, s7=0;\n for (let y=0;y<8;y++) {\n const c0=cosine[y]!, c1=cosine[8+y]!, c2=cosine[16+y]!, c3=cosine[24+y]!, c4=cosine[32+y]!, c5=cosine[40+y]!, c6=cosine[48+y]!, c7=cosine[56+y]!;\n for (let x=0;x<8;x++) {\n const r=block[y*8+x]!*cosine[uOffset+x]!;\n s0+=r*c0; s1+=r*c1; s2+=r*c2; s3+=r*c3; s4+=r*c4; s5+=r*c5; s6+=r*c6; s7+=r*c7;\n }\n }\n // Scaled as before, left to right: sum·0.25·(u factor)·(v factor)/q.\n out[o+u]=roundJpegCoefficient(s0*.25*uFactor*Math.SQRT1_2/q); out[o+8+u]=roundJpegCoefficient(s1*.25*uFactor*1/q);\n out[o+16+u]=roundJpegCoefficient(s2*.25*uFactor*1/q); out[o+24+u]=roundJpegCoefficient(s3*.25*uFactor*1/q);\n out[o+32+u]=roundJpegCoefficient(s4*.25*uFactor*1/q); out[o+40+u]=roundJpegCoefficient(s5*.25*uFactor*1/q);\n out[o+48+u]=roundJpegCoefficient(s6*.25*uFactor*1/q); out[o+56+u]=roundJpegCoefficient(s7*.25*uFactor*1/q);\n }\n }\n },\n code(coefficients:Float64Array,previous:number[]|Float64Array):void {\n for (let channel=0;channel<3;channel++) {\n const o=channel*64, difference=coefficients[o]!-previous[channel]!, size=amplitude(difference,11); emit(size,4); coefficient(difference,size); previous[channel]=coefficients[o]!;\n let zeroes=0;\n for (let i=1;i<64;i++) {\n const value=coefficients[o+zigzag[i]!]!;\n if (value===0) { zeroes++; continue; }\n while (zeroes>=16) { emit(1,8); zeroes-=16; }\n const length=amplitude(value,10), symbol=zeroes*16+length; emit(acIndex[symbol]!,8); coefficient(value,length); zeroes=0;\n }\n if (zeroes) emit(0,8);\n }\n }\n };\n}\n/**\n * Codes `blockCount` consecutive blocks of an image (`block(i, out)` writes block i's 192 RGB samples, 0–255) apart from the\n * blocks before them, for writing an image's strips on separate workers; `createExportJpegEncoder`'s `appendStrip` joins\n * them into the bytes the whole image's `writeRgbBlock` calls would have written.\n */\nexport function encodeJpegStrip(quantizationStep:number, blockCount:number, block:(index:number,out:Uint8Array)=>void):JpegStripBits {\n if(!Number.isSafeInteger(quantizationStep)||quantizationStep<1||quantizationStep>255||!Number.isSafeInteger(blockCount)||blockCount<1)\n throw new InvalidConfigurationError(\"Invalid JPEG strip plan.\");\n let storage=new Uint8Array(65_536), length=0, accumulator=0, bits=0, bitLength=0;\n // Unstuffed bits, most-significant first.\n const emit=(value:number,count:number):void=>{\n accumulator=(accumulator<<count)|(value&((1<<count)-1)); bits+=count; bitLength+=count;\n while (bits>=8) {\n bits-=8;\n if(length===storage.length){const grown=new Uint8Array(storage.length*2);grown.set(storage);storage=grown;}\n storage[length++]=(accumulator>>>bits)&255;\n }\n accumulator&=(1<<bits)-1;\n };\n const coder=createJpegBlockCoder(quantizationStep,emit), samples=new Uint8Array(192), first=new Float64Array(192), coefficients=new Float64Array(192), lastDc=new Float64Array(3);\n block(0,samples); coder.transform(samples,first);\n lastDc[0]=first[0]!; lastDc[1]=first[64]!; lastDc[2]=first[128]!;\n for(let i=1;i<blockCount;i++){block(i,samples);coder.transform(samples,coefficients);coder.code(coefficients,lastDc);}\n if(bits){if(length===storage.length){const grown=new Uint8Array(storage.length+1);grown.set(storage);storage=grown;}storage[length++]=(accumulator<<(8-bits))&255;}\n return {first,bits:storage.slice(0,length),bitLength,blockCount,lastDc};\n}\n/**\n * Largest byte budget the internal writer accepts: the Print JPEG budget ceiling at the largest opt-in source\n * (256 000 000 bytes per 24 000 000 pixels at 2^27 pixels). Each caller enforces its own smaller budget.\n */\nconst EXPORT_JPEG_MAXIMUM_OUTPUT_BYTES=scaleBudgetCeiling(256_000_000,FULL_RESOLUTION_CEILING_PIXELS);\n/**\n * Internal size-limited JPEG writer. The reference export and the scalable export use exactly the same\n * DCT and entropy-coding equations.\n *\n * When `densityDotsPerInch` is supplied, it is written to the JFIF 1.02 APP0 segment as units=1 (dots\n * per inch) with equal X and Y density. JFIF density fields are 16-bit unsigned, so it must be an integer\n * in 1..65535; callers round any fractional density and store the exact value in EXIF. When omitted,\n * APP0 keeps units=0 with a 1:1 pixel aspect ratio and states no physical size.\n */\nexport function createExportJpegEncoder(input: Omit<ExportJpegInput,\"samples\"> & {maximumOutputBytes:number;icc?:Uint8Array;densityDotsPerInch?:number}): {\n writeRgbBlock(samples:readonly number[]|Uint8Array):void; appendStrip(strip:JpegStripBits):void; finish():Uint8Array; dispose():void;\n} {\n const {width,height,quantizationStep:q}=input;\n if(![width,height,q,input.maximumOutputBytes].every(Number.isSafeInteger)||width<1||height<1||width>65535||height>65535||q<1||q>255||input.maximumOutputBytes<1||input.maximumOutputBytes>EXPORT_JPEG_MAXIMUM_OUTPUT_BYTES)\n throw new InvalidConfigurationError(\"Invalid bounded JPEG encoding plan.\");\n const density=input.densityDotsPerInch;\n if(density!==undefined&&(!Number.isSafeInteger(density)||density<1||density>65535))\n throw new InvalidConfigurationError(\"JFIF density requires an integer from 1 to 65535 dots per inch.\");\n // Growable output. Capacity starts at min(budget, 64 KiB) and doubles, but never beyond the budget. The budget\n // check is unchanged (offset + n > maximumOutputBytes fails), so the output bytes and failures are the same as\n // with a buffer allocated at full budget up front. An old buffer is zeroed after its bytes are copied over.\n const budget=input.maximumOutputBytes;\n let storage=new Uint8Array(Math.min(budget,65_536)),offset=0,disposed=false,blocks=0;\n const reserve=(count:number):void=>{\n if(disposed||offset+count>budget)throw new InvalidConfigurationError(\"JPEG output exceeds admitted byte budget or is disposed.\");\n if(offset+count<=storage.length)return;\n const grown=new Uint8Array(Math.min(budget,Math.max(storage.length*2,offset+count)));\n grown.set(storage.subarray(0,offset));storage.fill(0,0,offset);storage=grown;\n };\n const push=(...values:number[]):void=>{reserve(values.length);storage.set(values,offset);offset+=values.length;};\n // Fast path for one entropy-coded byte: the same budget/disposal check and byte order as push(), without an array per byte.\n const pushByte=(value:number):void=>{if(disposed||offset>=storage.length)reserve(1);storage[offset++]=value;};\n push(255,216);\n const marker = (id: number, payload: readonly number[]): void => {\n if (payload.length > 65533) throw new InvalidConfigurationError(\"JPEG metadata segment exceeds the standard APP limit.\");\n push(255,id,(payload.length+2)>>8,(payload.length+2)&255,...payload);\n };\n // JFIF 1.02 APP0: identifier, version 1.02, units (0 aspect ratio only, 1 dots per inch), Xdensity, Ydensity, no thumbnail.\n marker(224,density===undefined ? [74,70,73,70,0,1,2,0,0,1,0,1,0,0] : [74,70,73,70,0,1,2,1,density>>8,density&255,density>>8,density&255,0,0]);\n marker(225,[69,120,105,102,0,0,...input.exif]);\n marker(225,[...new TextEncoder().encode(\"http://ns.adobe.com/xap/1.0/\\0\"),...input.xmp]);\n if(input.icc){\n if(input.icc.length>65519)throw new InvalidConfigurationError(\"ICC profile exceeds the single-segment encoding envelope.\");\n marker(226,[...new TextEncoder().encode(\"ICC_PROFILE\\0\"),1,1,...input.icc]);\n }\n marker(219,[0,...Array<number>(64).fill(q)]);\n marker(192,[8,height>>8,height&255,width>>8,width&255,3,1,17,0,2,17,0,3,17,0]);\n // DC categories 0..11 use 4-bit codes; AC EOB/ZRL and all baseline run/category pairs use 8-bit codes.\n // Incomplete canonical Huffman trees reserve the all-ones code, so JPEG bit padding (1-bits) can never be read as a symbol.\n const dc = Array.from({length:12},(_,i) => i), ac = [0,240];\n for (let run=0;run<16;run++) for (let size=1;size<=10;size++) ac.push(run*16+size);\n marker(196,[0,...Array.from({length:16},(_,i) => i===3 ? 12 : 0),...dc,\n 16,...Array.from({length:16},(_,i) => i===7 ? ac.length : 0),...ac]);\n marker(218,[3,1,0,2,0,3,0,0,63,0]);\n let accumulator=0, bits=0;\n // Appends the low `count` bits (count <= 16) most-significant first, emitting each completed byte with 0xFF stuffing.\n const emit = (value: number, count: number): void => {\n accumulator=(accumulator<<count)|(value&((1<<count)-1)); bits+=count;\n while (bits>=8) { bits-=8; const byte=(accumulator>>>bits)&255; pushByte(byte); if (byte===255) pushByte(0); }\n accumulator&=(1<<bits)-1;\n };\n const coder=createJpegBlockCoder(q,emit), coefficients=new Float64Array(192);\n const previous=[0,0,0];\n const totalBlocks=Math.ceil(width/8)*Math.ceil(height/8);\n return {\n writeRgbBlock(samples:readonly number[]|Uint8Array):void {\n let valid=!disposed&&blocks<totalBlocks&&samples.length===192;\n // A Uint8Array holds only integers 0–255, so only an array's entries need the scan.\n if(!(samples instanceof Uint8Array))for(let i=0;valid&&i<192;i++){const v=samples[i]!;valid=Number.isInteger(v)&&v>=0&&v<=255;}\n if(!valid)throw new InvalidConfigurationError(\"JPEG requires complete bounded RGB coding blocks.\");\n coder.transform(samples,coefficients); coder.code(coefficients,previous);\n blocks++;\n },\n appendStrip(strip:JpegStripBits):void {\n if(disposed||blocks+strip.blockCount>totalBlocks||strip.first.length!==192||strip.lastDc.length!==3||strip.bits.length*8<strip.bitLength)\n throw new InvalidConfigurationError(\"JPEG strip does not continue this encoding.\");\n // The strip's first block, coded against the DC values before it; then its other blocks' bits, which only depend on\n // values inside the strip, as written (each byte's 0xFF stuffing happens here, as in writeRgbBlock).\n coder.code(strip.first,previous);\n const whole=strip.bitLength>>3;\n for(let i=0;i<whole;i++)emit(strip.bits[i]!,8);\n if(strip.bitLength&7)emit(strip.bits[whole]!>>(8-(strip.bitLength&7)),strip.bitLength&7);\n previous[0]=strip.lastDc[0]!; previous[1]=strip.lastDc[1]!; previous[2]=strip.lastDc[2]!;\n blocks+=strip.blockCount;\n },\n finish():Uint8Array {\n if(disposed||blocks!==Math.ceil(width/8)*Math.ceil(height/8))throw new InvalidConfigurationError(\"JPEG cannot finish incomplete or disposed encoding.\");\n if(bits)emit((1<<(8-bits))-1,8-bits);\n // Only the written prefix can hold data; zero it after the copy instead of filling the whole capacity.\n push(255,217);const output=storage.slice(0,offset);storage.fill(0,0,offset);storage=new Uint8Array(0);disposed=true;return output;\n },\n dispose():void {storage.fill(0,0,offset);storage=new Uint8Array(0);disposed=true;}\n };\n}\n"]}
|
package/dist/core/version.d.ts
CHANGED
package/dist/core/version.js
CHANGED
package/dist/core/version.js.map
CHANGED
|
@@ -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.
|
|
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.13.0\" as const;\n"]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #504: the automatic slowest preferred shutter for Auto ISO ("Auto" minimum shutter speed), derived
|
|
3
|
+
* from the engine's camera-shake model (`estimateCameraShakeBlur()`), not from the 1/focal-length rule
|
|
4
|
+
* of thumb.
|
|
5
|
+
*
|
|
6
|
+
* The camera turns at a constant angular velocity ω (yaw, pitch) during the exposure, reduced by the
|
|
7
|
+
* stabilization factor r = 2^−stops. A still point on the optical axis then moves
|
|
8
|
+
* b(t) = v·hypot(tan(r·ω_yaw·t), tan(r·ω_pitch·t)) on the sensor, where v is the projection distance (the
|
|
9
|
+
* focal length, or the thin-lens image distance with a focus distance). The derived shutter is the
|
|
10
|
+
* exposure time at which b(t) equals the caller's blur budget. b(t) grows strictly with t, so the
|
|
11
|
+
* solution is unique; the whole-stop bias (as in makers' Auto minimum-shutter settings: faster or
|
|
12
|
+
* slower in 1 EV steps) is applied after the derivation, and the optional shutter grid last.
|
|
13
|
+
*
|
|
14
|
+
* This is an approximation: the hand's motion is a constant-velocity profile supplied by the caller,
|
|
15
|
+
* and stabilization stops scale the motion by 2^−stops (the educational model of
|
|
16
|
+
* `estimateCameraShakeBlur()`, not a CIPA DC-011 rating).
|
|
17
|
+
* @see docs/USAGE.md ("Automatic slowest shutter (#504)") for the equations, the cited generic
|
|
18
|
+
* hand-shake default and the support limits.
|
|
19
|
+
*/
|
|
20
|
+
import { type CalculationResult } from "../core/calculation-result.js";
|
|
21
|
+
import type { ResolvedGenericEquipmentExposureCapabilities } from "../equipment/exposure-capabilities.js";
|
|
22
|
+
export declare const AUTO_ISO_SLOWEST_SHUTTER_MODEL_VERSION: "1.0.0";
|
|
23
|
+
/**
|
|
24
|
+
* A generic handheld angular velocity, labelled as a default and not a measurement of any camera or
|
|
25
|
+
* photographer: 4.39 °/s (≈ 0.0766 rad/s), the linear camera-motion rate Xiao, Farrell, Catrysse and
|
|
26
|
+
* Wandell use for "an average user" holding "a typical 100g mobile handset with two hands", from their
|
|
27
|
+
* earlier gyroscope measurements (F. Xiao, J. Farrell, P. Catrysse, B. Wandell, "Mobile imaging: the
|
|
28
|
+
* big challenge of the small pixel", Proc. SPIE 7250, Digital Photography V, 2009, §2; author copy:
|
|
29
|
+
* https://web.stanford.edu/~wandell/data/papers/2009-CameraShake-Xiao.pdf; they cite F. Xiao et al.,
|
|
30
|
+
* "Camera-motion and mobile imaging", Proc. SPIE 6502, 2007). The value is one rate magnitude; it is
|
|
31
|
+
* placed on the yaw axis (for small angles the blur length does not depend on the direction). A
|
|
32
|
+
* heavier camera, another grip or another photographer moves differently: pass your own profile.
|
|
33
|
+
*/
|
|
34
|
+
export declare const GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC: Readonly<{
|
|
35
|
+
yaw: number;
|
|
36
|
+
pitch: number;
|
|
37
|
+
}>;
|
|
38
|
+
/** The largest whole-stop bias accepted, either way (makers offer up to 2 stops faster or slower). */
|
|
39
|
+
export declare const AUTO_ISO_SLOWEST_SHUTTER_MAXIMUM_BIAS_STOPS: 2;
|
|
40
|
+
/** The blur allowed during the exposure, on the sensor. */
|
|
41
|
+
export type AutoIsoSlowestShutterBlurBudget = {
|
|
42
|
+
/** The blur trace length in pixels of the given pitch. */
|
|
43
|
+
kind: "pixels";
|
|
44
|
+
pixels: number;
|
|
45
|
+
pixelPitchMicrometers: number;
|
|
46
|
+
} | {
|
|
47
|
+
/** The blur trace length as a fraction of the image diagonal (width × height in millimetres). */
|
|
48
|
+
kind: "image-diagonal-fraction";
|
|
49
|
+
fraction: number;
|
|
50
|
+
imageWidthMm: number;
|
|
51
|
+
imageHeightMm: number;
|
|
52
|
+
};
|
|
53
|
+
export interface EstimateAutoIsoSlowestShutterInput {
|
|
54
|
+
focalLengthMm: number;
|
|
55
|
+
/** Optional focus distance in metres: the thin-lens image distance becomes the projection distance, as in `estimateCameraShakeBlur()`. */
|
|
56
|
+
focusDistanceM?: number;
|
|
57
|
+
/**
|
|
58
|
+
* The hand's constant angular velocity in radians per second, the explicit shake profile (signs as in
|
|
59
|
+
* `estimateCameraShakeBlur()`; only the magnitude matters here). At least one axis must be non-zero.
|
|
60
|
+
* `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC` is a cited generic default, not a measurement of you.
|
|
61
|
+
*/
|
|
62
|
+
angularVelocityRadPerSec: {
|
|
63
|
+
yaw: number;
|
|
64
|
+
pitch: number;
|
|
65
|
+
};
|
|
66
|
+
/** Stabilization in equivalent stops (≥ 0); the motion is scaled by 2^−stops. Default 0. */
|
|
67
|
+
stabilizationStopsEquivalent?: number;
|
|
68
|
+
blurBudget: AutoIsoSlowestShutterBlurBudget;
|
|
69
|
+
/**
|
|
70
|
+
* The bias in whole stops, applied after the derivation: +1 is one stop faster (half the time), −1 one
|
|
71
|
+
* stop slower (twice the time). An integer from −2 to +2. Default 0.
|
|
72
|
+
*/
|
|
73
|
+
fasterByStops?: number;
|
|
74
|
+
/** Optional: the body's resolved shutter capability. The biased shutter then snaps to it, never longer than the biased value, and is held at its ends. */
|
|
75
|
+
shutterCapability?: ResolvedGenericEquipmentExposureCapabilities["shutter"];
|
|
76
|
+
}
|
|
77
|
+
export interface AutoIsoSlowestShutterEstimate {
|
|
78
|
+
/** The exposure time whose shake blur equals the budget, before the bias and the grid. */
|
|
79
|
+
derivedShutterSeconds: number;
|
|
80
|
+
fasterByStops: number;
|
|
81
|
+
/** derivedShutterSeconds · 2^−fasterByStops. */
|
|
82
|
+
biasedShutterSeconds: number;
|
|
83
|
+
/** The slowest preferred shutter: the biased value, snapped to `shutterCapability` when given. */
|
|
84
|
+
shutterSeconds: number;
|
|
85
|
+
shutterResolution: {
|
|
86
|
+
kind: "unconstrained" | "continuous" | "discrete";
|
|
87
|
+
selectionPolicy: "not-longer-than-target";
|
|
88
|
+
quantized: boolean;
|
|
89
|
+
clamped: false | "minimum" | "maximum";
|
|
90
|
+
};
|
|
91
|
+
blurBudgetMm: number;
|
|
92
|
+
/** `estimateCameraShakeBlur()`'s stabilized blur at the derived shutter (equal to the budget within rounding). */
|
|
93
|
+
blurAtDerivedShutterMm: number;
|
|
94
|
+
/** `estimateCameraShakeBlur()`'s stabilized blur at `shutterSeconds`. */
|
|
95
|
+
blurAtShutterMm: number;
|
|
96
|
+
/** The same blur lengths in pixels, for a pixel budget. */
|
|
97
|
+
blurBudgetPixels?: number;
|
|
98
|
+
blurAtShutterPixels?: number;
|
|
99
|
+
projectionDistanceMm: number;
|
|
100
|
+
residualMotionFactor: number;
|
|
101
|
+
angularVelocityRadPerSec: {
|
|
102
|
+
yaw: number;
|
|
103
|
+
pitch: number;
|
|
104
|
+
};
|
|
105
|
+
stabilizationStopsEquivalent: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Estimates the slowest preferred shutter for Auto ISO from the lens, the sensor and the hand's
|
|
109
|
+
* shake: the exposure time at which `estimateCameraShakeBlur()`'s stabilized blur equals the blur
|
|
110
|
+
* budget, then shifted by a whole-stop bias and optionally snapped to the body's shutter grid (never
|
|
111
|
+
* longer than the biased value). Longer focal lengths give faster shutters; each stabilization stop
|
|
112
|
+
* doubles the time; each bias stop halves (+1) or doubles (−1) it.
|
|
113
|
+
*
|
|
114
|
+
* An approximation: constant angular velocity (a caller profile, or the labelled generic default
|
|
115
|
+
* `GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`), stabilization as 2^−stops, blur on the optical axis
|
|
116
|
+
* only. The 1/focal-length "reciprocal rule" is a rule of thumb and is not used.
|
|
117
|
+
* @param input - EstimateAutoIsoSlowestShutterInput.
|
|
118
|
+
* @returns The derived, biased and snapped shutter with the blur at each, as an approximation result.
|
|
119
|
+
*/
|
|
120
|
+
export declare function estimateAutoIsoSlowestShutter(input: EstimateAutoIsoSlowestShutterInput): CalculationResult<AutoIsoSlowestShutterEstimate>;
|