@photivra/engine 2.12.0 → 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 +77 -1
- package/CITATION.cff +1 -1
- 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 +93 -10
- package/dist/facade/simulate-capture.js +146 -22
- 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 +21 -1
- package/docs/QUICK_START.md +65 -5
- package/docs/USAGE.md +207 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +67 -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 +90 -9
- package/docs/api/output-text-metadata.md +34 -0
- package/package.json +1 -1
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { InvalidScientificInputError } from "../core/validation.js";
|
|
18
18
|
import { EXPOSURE_METER_TARGET_SCHEMA_VERSION } from "./metering-target.js";
|
|
19
19
|
import { parseExposureProgramLineProfile } from "./program-line.js";
|
|
20
|
-
import { requireInputKeys } from "../core/record-validation.js";
|
|
20
|
+
import { rejectUnknownFields, requireInputKeys } from "../core/record-validation.js";
|
|
21
21
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
22
22
|
export const EXPOSURE_MODE_RESOLVER_VERSION = "0.5.0";
|
|
23
23
|
function requireRecord(value, path) {
|
|
@@ -328,7 +328,7 @@ function nearestDiscreteIso(idealIso, values) {
|
|
|
328
328
|
: "none"
|
|
329
329
|
};
|
|
330
330
|
}
|
|
331
|
-
function
|
|
331
|
+
function bodyAutoIsoBounds(capabilities) {
|
|
332
332
|
return {
|
|
333
333
|
minimum: capabilities.iso
|
|
334
334
|
.autoIsoMinimum ??
|
|
@@ -338,9 +338,75 @@ function autoIsoBounds(capabilities) {
|
|
|
338
338
|
capabilities.iso.maximum
|
|
339
339
|
};
|
|
340
340
|
}
|
|
341
|
-
|
|
341
|
+
/**
|
|
342
|
+
* #505: the Auto ISO range a resolver chooses in: the body's Auto ISO range, narrowed by the
|
|
343
|
+
* photographer's validated limits when given. A limit outside the body's range, or off a discrete
|
|
344
|
+
* ISO grid, fails; it is never clipped.
|
|
345
|
+
*/
|
|
346
|
+
function autoIsoBounds(capabilities, limits, path = "autoIsoLimits") {
|
|
347
|
+
const body = bodyAutoIsoBounds(capabilities);
|
|
348
|
+
if (limits === undefined) {
|
|
349
|
+
return {
|
|
350
|
+
...body,
|
|
351
|
+
minimumConstraint: "iso-minimum",
|
|
352
|
+
maximumConstraint: "iso-maximum"
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
const record = requireRecord(limits, path);
|
|
356
|
+
rejectUnknownFields(record, ["maximum", "minimum"], path);
|
|
357
|
+
const check = (value, field) => {
|
|
358
|
+
const iso = requirePositiveFinite(value, path + "." + field);
|
|
359
|
+
if (iso < body.minimum ||
|
|
360
|
+
iso > body.maximum) {
|
|
361
|
+
throw new InvalidScientificInputError(path +
|
|
362
|
+
"." +
|
|
363
|
+
field +
|
|
364
|
+
" (ISO " +
|
|
365
|
+
iso +
|
|
366
|
+
") lies outside the body's Auto ISO range, ISO " +
|
|
367
|
+
body.minimum +
|
|
368
|
+
" to " +
|
|
369
|
+
body.maximum +
|
|
370
|
+
".");
|
|
371
|
+
}
|
|
372
|
+
const grid = capabilities.iso.settingGrid;
|
|
373
|
+
if (grid.kind ===
|
|
374
|
+
"discrete-values" &&
|
|
375
|
+
!grid.values.some((candidate) => settingEquals(candidate, iso))) {
|
|
376
|
+
throw new InvalidScientificInputError(path +
|
|
377
|
+
"." +
|
|
378
|
+
field +
|
|
379
|
+
" (ISO " +
|
|
380
|
+
iso +
|
|
381
|
+
") is not a selectable ISO of the resolved discrete ISO grid.");
|
|
382
|
+
}
|
|
383
|
+
return iso;
|
|
384
|
+
};
|
|
385
|
+
const maximum = check(record.maximum, "maximum");
|
|
386
|
+
const minimum = record.minimum === undefined
|
|
387
|
+
? body.minimum
|
|
388
|
+
: check(record.minimum, "minimum");
|
|
389
|
+
if (minimum > maximum) {
|
|
390
|
+
throw new InvalidScientificInputError(path +
|
|
391
|
+
".minimum must not exceed " +
|
|
392
|
+
path +
|
|
393
|
+
".maximum.");
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
minimum,
|
|
397
|
+
maximum,
|
|
398
|
+
minimumConstraint: minimum > body.minimum &&
|
|
399
|
+
!settingEquals(minimum, body.minimum)
|
|
400
|
+
? "user-iso-minimum"
|
|
401
|
+
: "iso-minimum",
|
|
402
|
+
maximumConstraint: maximum < body.maximum &&
|
|
403
|
+
!settingEquals(maximum, body.maximum)
|
|
404
|
+
? "user-iso-maximum"
|
|
405
|
+
: "iso-maximum"
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function resolveAutomaticIso(idealIso, capabilities, bounds) {
|
|
342
409
|
const grid = capabilities.iso.settingGrid;
|
|
343
|
-
const bounds = autoIsoBounds(capabilities);
|
|
344
410
|
if (grid.kind ===
|
|
345
411
|
"discrete-values") {
|
|
346
412
|
const autoValues = grid.values.filter((value) => value >= bounds.minimum &&
|
|
@@ -351,6 +417,13 @@ function resolveAutomaticIso(idealIso, capabilities) {
|
|
|
351
417
|
const discrete = nearestDiscreteIso(idealIso, autoValues);
|
|
352
418
|
return {
|
|
353
419
|
...discrete,
|
|
420
|
+
limitingConstraint: discrete.clamped ===
|
|
421
|
+
"minimum"
|
|
422
|
+
? bounds.minimumConstraint
|
|
423
|
+
: discrete.clamped ===
|
|
424
|
+
"maximum"
|
|
425
|
+
? bounds.maximumConstraint
|
|
426
|
+
: discrete.limitingConstraint,
|
|
354
427
|
kind: "discrete"
|
|
355
428
|
};
|
|
356
429
|
}
|
|
@@ -361,7 +434,7 @@ function resolveAutomaticIso(idealIso, capabilities) {
|
|
|
361
434
|
kind: "continuous",
|
|
362
435
|
quantized: false,
|
|
363
436
|
clamped: "minimum",
|
|
364
|
-
limitingConstraint:
|
|
437
|
+
limitingConstraint: bounds.minimumConstraint
|
|
365
438
|
};
|
|
366
439
|
}
|
|
367
440
|
if (idealIso >
|
|
@@ -371,7 +444,7 @@ function resolveAutomaticIso(idealIso, capabilities) {
|
|
|
371
444
|
kind: "continuous",
|
|
372
445
|
quantized: false,
|
|
373
446
|
clamped: "maximum",
|
|
374
|
-
limitingConstraint:
|
|
447
|
+
limitingConstraint: bounds.maximumConstraint
|
|
375
448
|
};
|
|
376
449
|
}
|
|
377
450
|
return {
|
|
@@ -471,9 +544,8 @@ function resolveAutomaticShutter(idealShutterSeconds, capabilities) {
|
|
|
471
544
|
limitingConstraint: "none"
|
|
472
545
|
};
|
|
473
546
|
}
|
|
474
|
-
function minimumSelectableIso(capabilities) {
|
|
547
|
+
function minimumSelectableIso(capabilities, bounds) {
|
|
475
548
|
const grid = capabilities.iso.settingGrid;
|
|
476
|
-
const bounds = autoIsoBounds(capabilities);
|
|
477
549
|
if (grid.kind ===
|
|
478
550
|
"continuous-within-range") {
|
|
479
551
|
return bounds.minimum;
|
|
@@ -978,6 +1050,11 @@ export function resolveManualExposureMode(input) {
|
|
|
978
1050
|
"nearest-log2-lower-on-tie") {
|
|
979
1051
|
throw new InvalidConfigurationError('isoControl.quantizationPolicy must be "nearest-log2-lower-on-tie".');
|
|
980
1052
|
}
|
|
1053
|
+
const autoBounds = input.isoControl.kind ===
|
|
1054
|
+
"automatic"
|
|
1055
|
+
? autoIsoBounds(input.capabilities, input.isoControl
|
|
1056
|
+
.autoIsoLimits, "isoControl.autoIsoLimits")
|
|
1057
|
+
: undefined;
|
|
981
1058
|
if (input.isoControl.kind ===
|
|
982
1059
|
"manual") {
|
|
983
1060
|
const manualIso = requirePositiveFinite(input.isoControl.iso, "isoControl.iso");
|
|
@@ -1052,7 +1129,7 @@ export function resolveManualExposureMode(input) {
|
|
|
1052
1129
|
idealIso <= 0) {
|
|
1053
1130
|
throw new InvalidScientificInputError("Ideal Auto ISO must remain finite and greater than zero.");
|
|
1054
1131
|
}
|
|
1055
|
-
const automatic = resolveAutomaticIso(idealIso, input.capabilities);
|
|
1132
|
+
const automatic = resolveAutomaticIso(idealIso, input.capabilities, autoBounds);
|
|
1056
1133
|
const achievedScale = opticalFactor *
|
|
1057
1134
|
(automatic.iso /
|
|
1058
1135
|
referenceExposure.iso);
|
|
@@ -1265,6 +1342,7 @@ export function resolveAperturePriorityAutoIsoExposureMode(input) {
|
|
|
1265
1342
|
.maximumSeconds) {
|
|
1266
1343
|
throw new InvalidScientificInputError("policy.slowestPreferredShutterSeconds lies outside the resolved shutter capability range.");
|
|
1267
1344
|
}
|
|
1345
|
+
const autoBounds = autoIsoBounds(input.capabilities, policy.autoIsoLimits, "policy.autoIsoLimits");
|
|
1268
1346
|
const availability = validateAutoIsoAvailability(input.capabilities);
|
|
1269
1347
|
const commonBlocked = (blocker) => {
|
|
1270
1348
|
const raw = buildPriorityAutoIsoBlocked("aperture-priority", target, referenceExposure, blocker, { aperture: manualAperture });
|
|
@@ -1292,7 +1370,7 @@ export function resolveAperturePriorityAutoIsoExposureMode(input) {
|
|
|
1292
1370
|
if (target.status === "no-signal") {
|
|
1293
1371
|
return commonBlocked("target-no-signal");
|
|
1294
1372
|
}
|
|
1295
|
-
const baselineIso = minimumSelectableIso(input.capabilities);
|
|
1373
|
+
const baselineIso = minimumSelectableIso(input.capabilities, autoBounds);
|
|
1296
1374
|
const factorAtReferenceShutter = opticalExposureFactor(manualAperture, referenceExposure
|
|
1297
1375
|
.shutterSeconds, referenceExposure) *
|
|
1298
1376
|
(baselineIso /
|
|
@@ -1316,7 +1394,13 @@ export function resolveAperturePriorityAutoIsoExposureMode(input) {
|
|
|
1316
1394
|
manualShutterSeconds: shutter.shutterSeconds,
|
|
1317
1395
|
isoControl: {
|
|
1318
1396
|
kind: "automatic",
|
|
1319
|
-
quantizationPolicy: policy.isoQuantizationPolicy
|
|
1397
|
+
quantizationPolicy: policy.isoQuantizationPolicy,
|
|
1398
|
+
...(policy.autoIsoLimits ===
|
|
1399
|
+
undefined
|
|
1400
|
+
? {}
|
|
1401
|
+
: {
|
|
1402
|
+
autoIsoLimits: policy.autoIsoLimits
|
|
1403
|
+
})
|
|
1320
1404
|
}
|
|
1321
1405
|
});
|
|
1322
1406
|
if (isoPass.status !== "resolved" ||
|
|
@@ -1547,6 +1631,7 @@ export function resolveShutterPriorityExposureMode(input) {
|
|
|
1547
1631
|
"not-wider-than-target") {
|
|
1548
1632
|
throw new InvalidConfigurationError("Shutter Priority Auto ISO policy is invalid.");
|
|
1549
1633
|
}
|
|
1634
|
+
const autoBounds = autoIsoBounds(input.capabilities, policy.autoIsoLimits, "isoControl.policy.autoIsoLimits");
|
|
1550
1635
|
const availability = validateAutoIsoAvailability(input.capabilities);
|
|
1551
1636
|
if (availability !== "supported") {
|
|
1552
1637
|
const raw = buildPriorityAutoIsoBlocked("shutter-priority", target, referenceExposure, availability === "unknown"
|
|
@@ -1586,7 +1671,7 @@ export function resolveShutterPriorityExposureMode(input) {
|
|
|
1586
1671
|
}
|
|
1587
1672
|
};
|
|
1588
1673
|
}
|
|
1589
|
-
const baselineIso = minimumSelectableIso(input.capabilities);
|
|
1674
|
+
const baselineIso = minimumSelectableIso(input.capabilities, autoBounds);
|
|
1590
1675
|
const idealAtBaseline = idealApertureForTarget(target
|
|
1591
1676
|
.requiredExposureScaleToTarget, manualShutterSeconds, baselineIso, referenceExposure);
|
|
1592
1677
|
const aperture = selectApertureNotWiderThanTarget(idealAtBaseline, input.capabilities);
|
|
@@ -1598,7 +1683,13 @@ export function resolveShutterPriorityExposureMode(input) {
|
|
|
1598
1683
|
manualShutterSeconds,
|
|
1599
1684
|
isoControl: {
|
|
1600
1685
|
kind: "automatic",
|
|
1601
|
-
quantizationPolicy: policy.isoQuantizationPolicy
|
|
1686
|
+
quantizationPolicy: policy.isoQuantizationPolicy,
|
|
1687
|
+
...(policy.autoIsoLimits ===
|
|
1688
|
+
undefined
|
|
1689
|
+
? {}
|
|
1690
|
+
: {
|
|
1691
|
+
autoIsoLimits: policy.autoIsoLimits
|
|
1692
|
+
})
|
|
1602
1693
|
}
|
|
1603
1694
|
});
|
|
1604
1695
|
if (isoPass.status !== "resolved" ||
|
|
@@ -1738,6 +1829,10 @@ export function resolveProgramAutoExposureMode(input) {
|
|
|
1738
1829
|
"nearest-log2-lower-on-tie") {
|
|
1739
1830
|
throw new InvalidConfigurationError("Program Auto ISO policy is invalid.");
|
|
1740
1831
|
}
|
|
1832
|
+
const autoBounds = autoIsoBounds(input.capabilities, input.isoControl
|
|
1833
|
+
.autoIsoLimits, "isoControl.autoIsoLimits");
|
|
1834
|
+
const holdPolicy = validateProgramSlowestPreferredShutter(input.isoControl
|
|
1835
|
+
.slowestPreferredShutter, input.capabilities);
|
|
1741
1836
|
const availability = validateAutoIsoAvailability(input.capabilities);
|
|
1742
1837
|
if (availability !== "supported") {
|
|
1743
1838
|
return {
|
|
@@ -1767,28 +1862,94 @@ export function resolveProgramAutoExposureMode(input) {
|
|
|
1767
1862
|
safetyShiftApplied: false
|
|
1768
1863
|
};
|
|
1769
1864
|
}
|
|
1770
|
-
const baselineIso = minimumSelectableIso(input.capabilities);
|
|
1865
|
+
const baselineIso = minimumSelectableIso(input.capabilities, autoBounds);
|
|
1771
1866
|
const requestedOpticalStops = target
|
|
1772
1867
|
.exposureOffsetStopsToTarget -
|
|
1773
1868
|
Math.log2(baselineIso /
|
|
1774
1869
|
referenceExposure.iso);
|
|
1775
1870
|
const selection = selectProgramLineSettings(requestedOpticalStops, programLine, input.capabilities);
|
|
1776
|
-
const
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
.
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1871
|
+
const isoControl = input.isoControl;
|
|
1872
|
+
const autoIsoPass = (shutterSeconds) => {
|
|
1873
|
+
const pass = resolveManualExposureMode({
|
|
1874
|
+
target,
|
|
1875
|
+
capabilities: input.capabilities,
|
|
1876
|
+
referenceExposure,
|
|
1877
|
+
manualAperture: selection.resolvedAperture,
|
|
1878
|
+
manualShutterSeconds: shutterSeconds,
|
|
1879
|
+
isoControl: {
|
|
1880
|
+
kind: "automatic",
|
|
1881
|
+
quantizationPolicy: isoControl
|
|
1882
|
+
.isoQuantizationPolicy,
|
|
1883
|
+
...(isoControl
|
|
1884
|
+
.autoIsoLimits ===
|
|
1885
|
+
undefined
|
|
1886
|
+
? {}
|
|
1887
|
+
: {
|
|
1888
|
+
autoIsoLimits: isoControl
|
|
1889
|
+
.autoIsoLimits
|
|
1890
|
+
})
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
if (pass.status !== "resolved" ||
|
|
1894
|
+
pass.isoControl !== "automatic") {
|
|
1895
|
+
throw new InvalidScientificInputError("Program Auto could not resolve its Auto ISO pass.");
|
|
1787
1896
|
}
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1897
|
+
return pass;
|
|
1898
|
+
};
|
|
1899
|
+
// #504: hold the line's shutter at or faster than the slowest preferred shutter before the ISO rises.
|
|
1900
|
+
const lineShutterSeconds = selection
|
|
1901
|
+
.resolvedShutterSeconds;
|
|
1902
|
+
const holdApplied = holdPolicy !== undefined &&
|
|
1903
|
+
lineShutterSeconds >
|
|
1904
|
+
holdPolicy
|
|
1905
|
+
.slowestPreferredShutterSeconds &&
|
|
1906
|
+
!settingEquals(lineShutterSeconds, holdPolicy
|
|
1907
|
+
.slowestPreferredShutterSeconds);
|
|
1908
|
+
const heldShutterSeconds = holdApplied
|
|
1909
|
+
? selectShutterNotLongerThanTarget(holdPolicy
|
|
1910
|
+
.slowestPreferredShutterSeconds, input.capabilities).shutterSeconds
|
|
1911
|
+
: lineShutterSeconds;
|
|
1912
|
+
const isoPass = autoIsoPass(heldShutterSeconds);
|
|
1913
|
+
let resolvedSettings = isoPass.resolvedSettings;
|
|
1914
|
+
let residual = isoPass.targetResidual;
|
|
1915
|
+
let fallbackUsed = false;
|
|
1916
|
+
if (holdApplied &&
|
|
1917
|
+
holdPolicy.afterMaximumIso ===
|
|
1918
|
+
"allow-slower-shutter" &&
|
|
1919
|
+
isoPass.isoResolution.clamped ===
|
|
1920
|
+
"maximum" &&
|
|
1921
|
+
isoPass.targetResidual.state ===
|
|
1922
|
+
"under-target") {
|
|
1923
|
+
// At the Auto ISO maximum the shutter may lengthen toward the target, but not past the line's own shutter.
|
|
1924
|
+
const maxIso = isoPass.resolvedSettings.iso;
|
|
1925
|
+
const atReference = opticalExposureFactor(selection.resolvedAperture, referenceExposure
|
|
1926
|
+
.shutterSeconds, referenceExposure) *
|
|
1927
|
+
(maxIso /
|
|
1928
|
+
referenceExposure.iso);
|
|
1929
|
+
const idealShutter = referenceExposure
|
|
1930
|
+
.shutterSeconds *
|
|
1931
|
+
(target
|
|
1932
|
+
.requiredExposureScaleToTarget /
|
|
1933
|
+
atReference);
|
|
1934
|
+
const beyondLine = idealShutter >=
|
|
1935
|
+
lineShutterSeconds;
|
|
1936
|
+
const shutter = beyondLine
|
|
1937
|
+
? {
|
|
1938
|
+
shutterSeconds: lineShutterSeconds,
|
|
1939
|
+
limitingConstraint: isoPass.targetResidual
|
|
1940
|
+
.limitingConstraint
|
|
1941
|
+
}
|
|
1942
|
+
: resolveAutomaticShutter(idealShutter, input.capabilities);
|
|
1943
|
+
fallbackUsed = true;
|
|
1944
|
+
resolvedSettings = {
|
|
1945
|
+
aperture: selection.resolvedAperture,
|
|
1946
|
+
shutterSeconds: shutter.shutterSeconds,
|
|
1947
|
+
iso: maxIso
|
|
1948
|
+
};
|
|
1949
|
+
residual =
|
|
1950
|
+
targetResidual(target, opticalExposureFactor(selection.resolvedAperture, shutter.shutterSeconds, referenceExposure) *
|
|
1951
|
+
(maxIso /
|
|
1952
|
+
referenceExposure.iso), shutter.limitingConstraint);
|
|
1792
1953
|
}
|
|
1793
1954
|
return {
|
|
1794
1955
|
resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
|
|
@@ -1814,8 +1975,43 @@ export function resolveProgramAutoExposureMode(input) {
|
|
|
1814
1975
|
idealIsoBeforeConstraints: isoPass
|
|
1815
1976
|
.idealIsoBeforeConstraints,
|
|
1816
1977
|
isoResolution: isoPass.isoResolution,
|
|
1817
|
-
resolvedSettings
|
|
1818
|
-
targetResidual:
|
|
1978
|
+
resolvedSettings,
|
|
1979
|
+
targetResidual: residual,
|
|
1980
|
+
...(holdPolicy === undefined
|
|
1981
|
+
? {}
|
|
1982
|
+
: {
|
|
1983
|
+
slowestPreferredShutter: {
|
|
1984
|
+
...holdPolicy,
|
|
1985
|
+
applied: holdApplied,
|
|
1986
|
+
afterMaximumIsoFallbackUsed: fallbackUsed
|
|
1987
|
+
}
|
|
1988
|
+
})
|
|
1989
|
+
};
|
|
1990
|
+
}
|
|
1991
|
+
function validateProgramSlowestPreferredShutter(value, capabilities) {
|
|
1992
|
+
if (value === undefined) {
|
|
1993
|
+
return undefined;
|
|
1994
|
+
}
|
|
1995
|
+
const record = requireRecord(value, "isoControl.slowestPreferredShutter");
|
|
1996
|
+
rejectUnknownFields(record, ["slowestPreferredShutterSeconds", "afterMaximumIso"], "isoControl.slowestPreferredShutter");
|
|
1997
|
+
if (record.afterMaximumIso !==
|
|
1998
|
+
"allow-slower-shutter" &&
|
|
1999
|
+
record.afterMaximumIso !==
|
|
2000
|
+
"hold-preferred-shutter") {
|
|
2001
|
+
throw new InvalidConfigurationError('isoControl.slowestPreferredShutter.afterMaximumIso must be "allow-slower-shutter" or "hold-preferred-shutter".');
|
|
2002
|
+
}
|
|
2003
|
+
const seconds = requirePositiveFinite(record.slowestPreferredShutterSeconds, "isoControl.slowestPreferredShutter.slowestPreferredShutterSeconds");
|
|
2004
|
+
if (seconds <
|
|
2005
|
+
capabilities.shutter
|
|
2006
|
+
.minimumSeconds ||
|
|
2007
|
+
seconds >
|
|
2008
|
+
capabilities.shutter
|
|
2009
|
+
.maximumSeconds) {
|
|
2010
|
+
throw new InvalidScientificInputError("isoControl.slowestPreferredShutter.slowestPreferredShutterSeconds lies outside the resolved shutter capability range.");
|
|
2011
|
+
}
|
|
2012
|
+
return {
|
|
2013
|
+
slowestPreferredShutterSeconds: seconds,
|
|
2014
|
+
afterMaximumIso: record.afterMaximumIso
|
|
1819
2015
|
};
|
|
1820
2016
|
}
|
|
1821
2017
|
/**
|
|
@@ -1847,6 +2043,7 @@ export function resolveFullAutoExposureMode(input) {
|
|
|
1847
2043
|
"nearest-log2-lower-on-tie") {
|
|
1848
2044
|
throw new InvalidConfigurationError("Full Auto exposure policy is invalid.");
|
|
1849
2045
|
}
|
|
2046
|
+
const autoBounds = autoIsoBounds(input.capabilities, input.policy.autoIsoLimits, "policy.autoIsoLimits");
|
|
1850
2047
|
const programLine = validateProgramLineForResolution(input.policy.programLine, referenceExposure, input.capabilities);
|
|
1851
2048
|
const blocked = (blocker) => ({
|
|
1852
2049
|
resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
|
|
@@ -1890,7 +2087,7 @@ export function resolveFullAutoExposureMode(input) {
|
|
|
1890
2087
|
? "auto-iso-unknown"
|
|
1891
2088
|
: "auto-iso-unsupported");
|
|
1892
2089
|
}
|
|
1893
|
-
const baselineIso = minimumSelectableIso(input.capabilities);
|
|
2090
|
+
const baselineIso = minimumSelectableIso(input.capabilities, autoBounds);
|
|
1894
2091
|
const requestedOpticalStops = target
|
|
1895
2092
|
.exposureOffsetStopsToTarget -
|
|
1896
2093
|
Math.log2(baselineIso /
|
|
@@ -1906,7 +2103,15 @@ export function resolveFullAutoExposureMode(input) {
|
|
|
1906
2103
|
isoControl: {
|
|
1907
2104
|
kind: "automatic",
|
|
1908
2105
|
quantizationPolicy: input.policy
|
|
1909
|
-
.isoQuantizationPolicy
|
|
2106
|
+
.isoQuantizationPolicy,
|
|
2107
|
+
...(input.policy
|
|
2108
|
+
.autoIsoLimits ===
|
|
2109
|
+
undefined
|
|
2110
|
+
? {}
|
|
2111
|
+
: {
|
|
2112
|
+
autoIsoLimits: input.policy
|
|
2113
|
+
.autoIsoLimits
|
|
2114
|
+
})
|
|
1910
2115
|
}
|
|
1911
2116
|
});
|
|
1912
2117
|
if (isoPass.status !== "resolved" ||
|