@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +94 -1
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +2 -4
  4. package/README.md +6 -6
  5. package/SECURITY.md +1 -1
  6. package/THIRD_PARTY.md +1 -0
  7. package/dist/capture/export-jpeg.d.ts +1 -1
  8. package/dist/capture/export-jpeg.js +6 -4
  9. package/dist/capture/export-jpeg.js.map +1 -1
  10. package/dist/core/version.d.ts +1 -1
  11. package/dist/core/version.js +1 -1
  12. package/dist/core/version.js.map +1 -1
  13. package/dist/exposure/auto-iso-slowest-shutter.d.ts +120 -0
  14. package/dist/exposure/auto-iso-slowest-shutter.js +216 -0
  15. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -0
  16. package/dist/exposure/exposure-mode-resolver.d.ts +57 -1
  17. package/dist/exposure/exposure-mode-resolver.js +238 -33
  18. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  19. package/dist/facade/diffraction-provider.js +12 -13
  20. package/dist/facade/diffraction-provider.js.map +1 -1
  21. package/dist/facade/display-view.d.ts +27 -0
  22. package/dist/facade/display-view.js +234 -65
  23. package/dist/facade/display-view.js.map +1 -1
  24. package/dist/facade/simulate-capture.d.ts +159 -3
  25. package/dist/facade/simulate-capture.js +203 -10
  26. package/dist/facade/simulate-capture.js.map +1 -1
  27. package/dist/facade/simulate-display-view.js +2 -2
  28. package/dist/facade/simulate-display-view.js.map +1 -1
  29. package/dist/gpu/display-view-quality-gpu.d.ts +2 -1
  30. package/dist/gpu/display-view-quality-gpu.js +24 -14
  31. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  32. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +13 -1
  33. package/dist/gpu/wgsl-display-view-quality-kernel.js +36 -2
  34. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  35. package/dist/index.d.ts +4 -3
  36. package/dist/index.js +2 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/optics/irradiance-convolution.d.ts +10 -0
  39. package/dist/optics/irradiance-convolution.js +48 -13
  40. package/dist/optics/irradiance-convolution.js.map +1 -1
  41. package/dist/output/print-jpeg.js +12 -9
  42. package/dist/output/print-jpeg.js.map +1 -1
  43. package/dist/output/text-metadata.d.ts +22 -2
  44. package/dist/output/text-metadata.js +58 -9
  45. package/dist/output/text-metadata.js.map +1 -1
  46. package/docs/API_REFERENCE.md +23 -1
  47. package/docs/QUICK_START.md +109 -3
  48. package/docs/USAGE.md +234 -1
  49. package/docs/api/core-version.md +1 -1
  50. package/docs/api/exports.json +77 -2
  51. package/docs/api/exposure-auto-iso-slowest-shutter.md +139 -0
  52. package/docs/api/exposure-exposure-mode-resolver.md +68 -0
  53. package/docs/api/facade-simulate-capture.md +153 -5
  54. package/docs/api/output-text-metadata.md +34 -0
  55. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"irradiance-convolution.js","sourceRoot":"","sources":["../../src/optics/irradiance-convolution.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Blurs a sampled image-plane quantity with caller-supplied PSF (point-spread function) kernels, one\n * kernel per patch of the image. The quantity must be linear and additive (for example irradiance).\n * Each patch is treated as shift-invariant (\"isoplanatic\"): the same PSF applies everywhere inside it.\n * The PSFs are incoherent intensity PSFs.\n *\n * This is the CPU float64 reference for the optics-as-convolution step (#277). The `webgpu-f32`\n * path runs the same equation; see docs/WEBGPU.md.\n *\n * Equation (indexed by source site; an energy-conserving scatter written as a gather):\n * out(x, y) = Σ_{v=-r..r} Σ_{u=-r..r} in(x − u, y − v) · K_{p(x − u, y − v)}(u, v)\n * where `p(s)` is the patch containing the **source** site and `K_p(u, v)` is the fraction of the source\n * site's quantity that lands at displacement (+u right, +v down), in grid sites.\n *\n * Incoherent imaging is a linear sum of intensity PSFs: the output intensity is the input intensity\n * convolved with the intensity PSF (MIT OpenCourseWare 2.71 Optics, Spring 2009, lecture 22, free).\n * A PSF that varies across the field is approximated as constant inside each patch, as in methods\n * that divide the image into isoplanatic subsections (van de Ketterij et al., arXiv:2011.01738,\n * sec. 1, free). Also see: Goodman, Introduction to Fourier Optics, 4th ed., 2017, §7.1. Camera\n * simulators such as ISETCam use the same piecewise shift-invariant method\n * (Farrell et al., Proc. SPIE 8299, 2012). The caller chooses the patch size and kernels, and so\n * owns the patch approximation.\n *\n * Edges: the grid holds every source. Sources outside the grid are not represented. Anything\n * scattered outside the grid is lost; compare `inputSum` with `outputSum` to see how much. There is no\n * padding, reflection or renormalization.\n */\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit } from \"../core/pixel-limits.js\";\n\nexport const IRRADIANCE_CONVOLUTION_SCHEMA_VERSION = \"0.1.0\" as const;\n/** `maximumPixels` is the default grid limit; a request may raise it with its own `maximumPixels`, up to `ceilingPixels`. */\nexport const IRRADIANCE_CONVOLUTION_LIMITS = Object.freeze({\n maximumPixels: 24_000_000,\n ceilingPixels: FULL_RESOLUTION_CEILING_PIXELS,\n maximumDimension: 16_384,\n maximumKernelRadius: 32,\n maximumPatchCount: 4_096,\n maximumKernelWeights: 4_194_304,\n /** A kernel may lose energy (vignetting, transmission) but may not create it, beyond rounding slack. */\n maximumKernelSum: 1 + 2 ** -20,\n /** Inputs larger than this are rejected so that float32 execution cannot overflow. */\n maximumSampleMagnitude: 2 ** 100\n});\n\nexport interface IrradianceConvolutionInput {\n schemaVersion: typeof IRRADIANCE_CONVOLUTION_SCHEMA_VERSION;\n width: number;\n height: number;\n /** Row-major samples. Finite, non-negative, linear and additive (for example irradiance, or expected photons per site). */\n samples: Float32Array | Float64Array;\n /** Kernel half-width in grid sites. Each kernel is (2r+1)×(2r+1). */\n kernelRadius: number;\n /** Patch size in grid sites. The last row and column of patches may be partial. */\n patchWidth: number;\n patchHeight: number;\n /**\n * Finite non-negative weights, `[patchRow][patchColumn][v + r][u + r]`, one kernel per patch in\n * row-major patch order. Each kernel sums to at most 1 (+2^-20 rounding slack).\n */\n kernels: Float32Array | Float64Array;\n boundary: \"zero-outside-grid\";\n /**\n * Optional opt-in grid limit for large images: an integer from 1 to `IRRADIANCE_CONVOLUTION_LIMITS.ceilingPixels`.\n * Default `IRRADIANCE_CONVOLUTION_LIMITS.maximumPixels` (24 000 000). It does not change the result.\n */\n maximumPixels?: number;\n}\n\n/** Validated, immutable geometry of a convolution request. Sample arrays are borrowed, not copied. */\nexport interface IrradianceConvolutionPlan {\n width: number;\n height: number;\n kernelRadius: number;\n kernelSize: number;\n tapCount: number;\n patchWidth: number;\n patchHeight: number;\n patchColumns: number;\n patchRows: number;\n /** Largest kernel sum and largest input magnitude. The float32 error bound uses them. */\n maximumKernelSum: number;\n maximumSampleMagnitude: number;\n}\n\nfunction positiveInteger(value: unknown, maximum: number): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0 || value > maximum) {\n throw new InvalidConfigurationError(\"Invalid irradiance convolution geometry.\");\n }\n return value;\n}\n\n/** Checks every sample (finite, non-negative, within the declared magnitude) and returns the largest. */\nfunction checkedMaximumSampleMagnitude(samples: Float32Array | Float64Array): number {\n let maximumSampleMagnitude = 0;\n for (let i = 0; i < samples.length; i++) {\n const v = samples[i]!;\n // Negated comparison also rejects NaN.\n if (!(v >= 0 && v <= IRRADIANCE_CONVOLUTION_LIMITS.maximumSampleMagnitude)) {\n throw new InvalidConfigurationError(\"Irradiance samples must be finite, non-negative and within the declared magnitude.\");\n }\n if (v > maximumSampleMagnitude) maximumSampleMagnitude = v;\n }\n return maximumSampleMagnitude;\n}\n\n/** Checks every kernel weight (finite, in [0, 1]) and kernel sum (at most 1 plus slack) and returns the largest sum. */\nfunction checkedMaximumKernelSum(kernels: Float32Array | Float64Array, patchCount: number, tapCount: number): number {\n let maximumKernelSum = 0;\n for (let p = 0; p < patchCount; p++) {\n let sum = 0;\n for (let t = p * tapCount, end = t + tapCount; t < end; t++) {\n const w = kernels[t]!;\n if (!(w >= 0 && w <= 1)) throw new InvalidConfigurationError(\"PSF kernel weights must be finite and within [0, 1].\");\n sum += w;\n }\n if (sum > IRRADIANCE_CONVOLUTION_LIMITS.maximumKernelSum) throw new InvalidConfigurationError(\"A PSF kernel may not create energy (sum exceeds 1).\");\n if (sum > maximumKernelSum) maximumKernelSum = sum;\n }\n return maximumKernelSum;\n}\n\n/** Validates the request and returns its plan. Every sample and weight is checked once. */\nexport function calculateIrradianceConvolutionPlan(input: IrradianceConvolutionInput): IrradianceConvolutionPlan {\n const r = requireAllowlistedRecord(input, [\"schemaVersion\", \"width\", \"height\", \"samples\", \"kernelRadius\", \"patchWidth\",\n \"patchHeight\", \"kernels\", \"boundary\", \"maximumPixels\"], \"Invalid irradiance convolution input.\");\n const L = IRRADIANCE_CONVOLUTION_LIMITS;\n if (r.schemaVersion !== IRRADIANCE_CONVOLUTION_SCHEMA_VERSION || r.boundary !== \"zero-outside-grid\") {\n throw new InvalidConfigurationError(\"Unsupported irradiance convolution schema or boundary.\");\n }\n const width = positiveInteger(r.width, L.maximumDimension), height = positiveInteger(r.height, L.maximumDimension);\n const maximumPixels = resolveRaisedLimit(r.maximumPixels, L.maximumPixels, L.ceilingPixels,\n \"Irradiance convolution maximumPixels must be an integer from 1 to \" + L.ceilingPixels + \".\");\n if (width * height > maximumPixels) throw new InvalidConfigurationError(\"Irradiance convolution grid exceeds the pixel limit.\");\n const radius = r.kernelRadius;\n if (typeof radius !== \"number\" || !Number.isSafeInteger(radius) || radius < 0 || radius > L.maximumKernelRadius) {\n throw new InvalidConfigurationError(\"Invalid irradiance convolution kernel radius.\");\n }\n const patchWidth = positiveInteger(r.patchWidth, width), patchHeight = positiveInteger(r.patchHeight, height);\n const patchColumns = Math.ceil(width / patchWidth), patchRows = Math.ceil(height / patchHeight);\n const kernelSize = 2 * radius + 1, tapCount = kernelSize * kernelSize, patchCount = patchColumns * patchRows;\n if (patchCount > L.maximumPatchCount || patchCount * tapCount > L.maximumKernelWeights) {\n throw new InvalidConfigurationError(\"Irradiance convolution kernels exceed the declared limits.\");\n }\n const samples = r.samples, kernels = r.kernels;\n if (!(samples instanceof Float32Array || samples instanceof Float64Array) || samples.length !== width * height ||\n !(kernels instanceof Float32Array || kernels instanceof Float64Array) || kernels.length !== patchCount * tapCount) {\n throw new InvalidConfigurationError(\"Irradiance convolution arrays do not match the declared geometry.\");\n }\n const maximumSampleMagnitude = checkedMaximumSampleMagnitude(samples);\n const maximumKernelSum = checkedMaximumKernelSum(kernels, patchCount, tapCount);\n return Object.freeze({ width, height, kernelRadius: radius, kernelSize, tapCount, patchWidth, patchHeight, patchColumns, patchRows,\n maximumKernelSum, maximumSampleMagnitude });\n}\n\n/**\n * Reference gather for output rows `[y0, y1)`, written into `output` at `(y - y0) * width + x`.\n * The summation order (v outer, u inner, both ascending) is part of the contract shared with the\n * WGSL (WebGPU shader) kernel.\n * @internal\n */\nexport function convolveIrradianceRows(plan: IrradianceConvolutionPlan, samples: Float32Array | Float64Array,\n kernels: Float32Array | Float64Array, y0: number, y1: number, output: Float64Array): void {\n const { width, height, kernelRadius: r, kernelSize, tapCount, patchWidth, patchHeight, patchColumns, patchRows } = plan;\n for (let y = y0; y < y1; y++) {\n for (let x = 0; x < width; x++) {\n let sum = 0;\n for (let v = -r; v <= r; v++) {\n const sy = y - v;\n if (sy < 0 || sy >= height) continue;\n const patchRowBase = Math.min(Math.floor(sy / patchHeight), patchRows - 1) * patchColumns;\n const kernelRow = (v + r) * kernelSize + r, sampleRow = sy * width;\n for (let u = -r; u <= r; u++) {\n const sx = x - u;\n if (sx < 0 || sx >= width) continue;\n const patch = patchRowBase + Math.min(Math.floor(sx / patchWidth), patchColumns - 1);\n sum += samples[sampleRow + sx]! * kernels[patch * tapCount + kernelRow + u]!;\n }\n }\n output[(y - y0) * width + x] = sum;\n }\n }\n}\n\n/** Synchronous float64 reference for bounded grids. Use the image-kernel accelerator for large grids. */\nexport function calculateIrradianceConvolution(input: IrradianceConvolutionInput): { plan: IrradianceConvolutionPlan; values: Float64Array } {\n const plan = calculateIrradianceConvolutionPlan(input);\n const values = new Float64Array(plan.width * plan.height);\n convolveIrradianceRows(plan, input.samples, input.kernels, 0, plan.height, values);\n return { plan, values };\n}\n\n/**\n * Internal (#453; not exported from the package): runs several convolutions that share one geometry (width, height,\n * kernel radius, patch size, boundary, pixel limit) with one validation of that geometry. The first call is\n * `calculateIrradianceConvolution` itself, with every check. Each later call checks its own arrays exactly as the plan\n * does (array types and lengths against the geometry, every sample, every kernel weight and kernel sum, with the same\n * messages) and then runs the same gather (`convolveIrradianceRows`) with the first call's plan, whose geometry fields are\n * the same numbers a full validation of this call would give. The values are therefore identical to one\n * `calculateIrradianceConvolution` per call; only the repeated record and geometry checks are skipped.\n * @internal\n */\nexport function createIrradianceConvolutionRunner(geometry: Omit<IrradianceConvolutionInput, \"samples\" | \"kernels\">):\n (samples: Float32Array | Float64Array, kernels: Float32Array | Float64Array) => Float64Array {\n let plan: IrradianceConvolutionPlan | undefined;\n return (samples, kernels) => {\n if (plan === undefined) {\n const first = calculateIrradianceConvolution({ ...geometry, samples, kernels });\n plan = first.plan;\n return first.values;\n }\n const patchCount = plan.patchColumns * plan.patchRows;\n if (!(samples instanceof Float32Array || samples instanceof Float64Array) || samples.length !== plan.width * plan.height ||\n !(kernels instanceof Float32Array || kernels instanceof Float64Array) || kernels.length !== patchCount * plan.tapCount) {\n throw new InvalidConfigurationError(\"Irradiance convolution arrays do not match the declared geometry.\");\n }\n checkedMaximumSampleMagnitude(samples);\n checkedMaximumKernelSum(kernels, patchCount, plan.tapCount);\n const values = new Float64Array(plan.width * plan.height);\n convolveIrradianceRows(plan, samples, kernels, 0, plan.height, values);\n return values;\n };\n}\n"]}
1
+ {"version":3,"file":"irradiance-convolution.js","sourceRoot":"","sources":["../../src/optics/irradiance-convolution.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Blurs a sampled image-plane quantity with caller-supplied PSF (point-spread function) kernels, one\n * kernel per patch of the image. The quantity must be linear and additive (for example irradiance).\n * Each patch is treated as shift-invariant (\"isoplanatic\"): the same PSF applies everywhere inside it.\n * The PSFs are incoherent intensity PSFs.\n *\n * This is the CPU float64 reference for the optics-as-convolution step (#277). The `webgpu-f32`\n * path runs the same equation; see docs/WEBGPU.md.\n *\n * Equation (indexed by source site; an energy-conserving scatter written as a gather):\n * out(x, y) = Σ_{v=-r..r} Σ_{u=-r..r} in(x − u, y − v) · K_{p(x − u, y − v)}(u, v)\n * where `p(s)` is the patch containing the **source** site and `K_p(u, v)` is the fraction of the source\n * site's quantity that lands at displacement (+u right, +v down), in grid sites.\n *\n * Incoherent imaging is a linear sum of intensity PSFs: the output intensity is the input intensity\n * convolved with the intensity PSF (MIT OpenCourseWare 2.71 Optics, Spring 2009, lecture 22, free).\n * A PSF that varies across the field is approximated as constant inside each patch, as in methods\n * that divide the image into isoplanatic subsections (van de Ketterij et al., arXiv:2011.01738,\n * sec. 1, free). Also see: Goodman, Introduction to Fourier Optics, 4th ed., 2017, §7.1. Camera\n * simulators such as ISETCam use the same piecewise shift-invariant method\n * (Farrell et al., Proc. SPIE 8299, 2012). The caller chooses the patch size and kernels, and so\n * owns the patch approximation.\n *\n * Edges: the grid holds every source. Sources outside the grid are not represented. Anything\n * scattered outside the grid is lost; compare `inputSum` with `outputSum` to see how much. There is no\n * padding, reflection or renormalization.\n */\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit } from \"../core/pixel-limits.js\";\n\nexport const IRRADIANCE_CONVOLUTION_SCHEMA_VERSION = \"0.1.0\" as const;\n/** `maximumPixels` is the default grid limit; a request may raise it with its own `maximumPixels`, up to `ceilingPixels`. */\nexport const IRRADIANCE_CONVOLUTION_LIMITS = Object.freeze({\n maximumPixels: 24_000_000,\n ceilingPixels: FULL_RESOLUTION_CEILING_PIXELS,\n maximumDimension: 16_384,\n maximumKernelRadius: 32,\n maximumPatchCount: 4_096,\n maximumKernelWeights: 4_194_304,\n /** A kernel may lose energy (vignetting, transmission) but may not create it, beyond rounding slack. */\n maximumKernelSum: 1 + 2 ** -20,\n /** Inputs larger than this are rejected so that float32 execution cannot overflow. */\n maximumSampleMagnitude: 2 ** 100\n});\n\nexport interface IrradianceConvolutionInput {\n schemaVersion: typeof IRRADIANCE_CONVOLUTION_SCHEMA_VERSION;\n width: number;\n height: number;\n /** Row-major samples. Finite, non-negative, linear and additive (for example irradiance, or expected photons per site). */\n samples: Float32Array | Float64Array;\n /** Kernel half-width in grid sites. Each kernel is (2r+1)×(2r+1). */\n kernelRadius: number;\n /** Patch size in grid sites. The last row and column of patches may be partial. */\n patchWidth: number;\n patchHeight: number;\n /**\n * Finite non-negative weights, `[patchRow][patchColumn][v + r][u + r]`, one kernel per patch in\n * row-major patch order. Each kernel sums to at most 1 (+2^-20 rounding slack).\n */\n kernels: Float32Array | Float64Array;\n boundary: \"zero-outside-grid\";\n /**\n * Optional opt-in grid limit for large images: an integer from 1 to `IRRADIANCE_CONVOLUTION_LIMITS.ceilingPixels`.\n * Default `IRRADIANCE_CONVOLUTION_LIMITS.maximumPixels` (24 000 000). It does not change the result.\n */\n maximumPixels?: number;\n}\n\n/** Validated, immutable geometry of a convolution request. Sample arrays are borrowed, not copied. */\nexport interface IrradianceConvolutionPlan {\n width: number;\n height: number;\n kernelRadius: number;\n kernelSize: number;\n tapCount: number;\n patchWidth: number;\n patchHeight: number;\n patchColumns: number;\n patchRows: number;\n /** Largest kernel sum and largest input magnitude. The float32 error bound uses them. */\n maximumKernelSum: number;\n maximumSampleMagnitude: number;\n}\n\nfunction positiveInteger(value: unknown, maximum: number): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0 || value > maximum) {\n throw new InvalidConfigurationError(\"Invalid irradiance convolution geometry.\");\n }\n return value;\n}\n\n/** Checks every sample (finite, non-negative, within the declared magnitude) and returns the largest. */\nfunction checkedMaximumSampleMagnitude(samples: Float32Array | Float64Array): number {\n let maximumSampleMagnitude = 0;\n for (let i = 0; i < samples.length; i++) {\n const v = samples[i]!;\n // Negated comparison also rejects NaN.\n if (!(v >= 0 && v <= IRRADIANCE_CONVOLUTION_LIMITS.maximumSampleMagnitude)) {\n throw new InvalidConfigurationError(\"Irradiance samples must be finite, non-negative and within the declared magnitude.\");\n }\n if (v > maximumSampleMagnitude) maximumSampleMagnitude = v;\n }\n return maximumSampleMagnitude;\n}\n\n/** Checks every kernel weight (finite, in [0, 1]) and kernel sum (at most 1 plus slack) and returns the largest sum. */\nfunction checkedMaximumKernelSum(kernels: Float32Array | Float64Array, patchCount: number, tapCount: number): number {\n let maximumKernelSum = 0;\n for (let p = 0; p < patchCount; p++) {\n let sum = 0;\n for (let t = p * tapCount, end = t + tapCount; t < end; t++) {\n const w = kernels[t]!;\n if (!(w >= 0 && w <= 1)) throw new InvalidConfigurationError(\"PSF kernel weights must be finite and within [0, 1].\");\n sum += w;\n }\n if (sum > IRRADIANCE_CONVOLUTION_LIMITS.maximumKernelSum) throw new InvalidConfigurationError(\"A PSF kernel may not create energy (sum exceeds 1).\");\n if (sum > maximumKernelSum) maximumKernelSum = sum;\n }\n return maximumKernelSum;\n}\n\n/** Validates the request and returns its plan. Every sample and weight is checked once. */\nexport function calculateIrradianceConvolutionPlan(input: IrradianceConvolutionInput): IrradianceConvolutionPlan {\n const r = requireAllowlistedRecord(input, [\"schemaVersion\", \"width\", \"height\", \"samples\", \"kernelRadius\", \"patchWidth\",\n \"patchHeight\", \"kernels\", \"boundary\", \"maximumPixels\"], \"Invalid irradiance convolution input.\");\n const L = IRRADIANCE_CONVOLUTION_LIMITS;\n if (r.schemaVersion !== IRRADIANCE_CONVOLUTION_SCHEMA_VERSION || r.boundary !== \"zero-outside-grid\") {\n throw new InvalidConfigurationError(\"Unsupported irradiance convolution schema or boundary.\");\n }\n const width = positiveInteger(r.width, L.maximumDimension), height = positiveInteger(r.height, L.maximumDimension);\n const maximumPixels = resolveRaisedLimit(r.maximumPixels, L.maximumPixels, L.ceilingPixels,\n \"Irradiance convolution maximumPixels must be an integer from 1 to \" + L.ceilingPixels + \".\");\n if (width * height > maximumPixels) throw new InvalidConfigurationError(\"Irradiance convolution grid exceeds the pixel limit.\");\n const radius = r.kernelRadius;\n if (typeof radius !== \"number\" || !Number.isSafeInteger(radius) || radius < 0 || radius > L.maximumKernelRadius) {\n throw new InvalidConfigurationError(\"Invalid irradiance convolution kernel radius.\");\n }\n const patchWidth = positiveInteger(r.patchWidth, width), patchHeight = positiveInteger(r.patchHeight, height);\n const patchColumns = Math.ceil(width / patchWidth), patchRows = Math.ceil(height / patchHeight);\n const kernelSize = 2 * radius + 1, tapCount = kernelSize * kernelSize, patchCount = patchColumns * patchRows;\n if (patchCount > L.maximumPatchCount || patchCount * tapCount > L.maximumKernelWeights) {\n throw new InvalidConfigurationError(\"Irradiance convolution kernels exceed the declared limits.\");\n }\n const samples = r.samples, kernels = r.kernels;\n if (!(samples instanceof Float32Array || samples instanceof Float64Array) || samples.length !== width * height ||\n !(kernels instanceof Float32Array || kernels instanceof Float64Array) || kernels.length !== patchCount * tapCount) {\n throw new InvalidConfigurationError(\"Irradiance convolution arrays do not match the declared geometry.\");\n }\n const maximumSampleMagnitude = checkedMaximumSampleMagnitude(samples);\n const maximumKernelSum = checkedMaximumKernelSum(kernels, patchCount, tapCount);\n return Object.freeze({ width, height, kernelRadius: radius, kernelSize, tapCount, patchWidth, patchHeight, patchColumns, patchRows,\n maximumKernelSum, maximumSampleMagnitude });\n}\n\n/**\n * Reference gather for output rows `[y0, y1)`, written into `output` at `(y - y0) * width + x`.\n * The summation order (v outer, u inner, both ascending) is part of the contract shared with the\n * WGSL (WebGPU shader) kernel.\n * @internal\n */\nexport function convolveIrradianceRows(plan: IrradianceConvolutionPlan, samples: Float32Array | Float64Array,\n kernels: Float32Array | Float64Array, y0: number, y1: number, output: Float64Array): void {\n const { width, height, kernelRadius: r, kernelSize, tapCount, patchWidth, patchHeight, patchColumns, patchRows } = plan;\n for (let y = y0; y < y1; y++) {\n for (let x = 0; x < width; x++) {\n let sum = 0;\n for (let v = -r; v <= r; v++) {\n const sy = y - v;\n if (sy < 0 || sy >= height) continue;\n const patchRowBase = Math.min(Math.floor(sy / patchHeight), patchRows - 1) * patchColumns;\n const kernelRow = (v + r) * kernelSize + r, sampleRow = sy * width;\n for (let u = -r; u <= r; u++) {\n const sx = x - u;\n if (sx < 0 || sx >= width) continue;\n const patch = patchRowBase + Math.min(Math.floor(sx / patchWidth), patchColumns - 1);\n sum += samples[sampleRow + sx]! * kernels[patch * tapCount + kernelRow + u]!;\n }\n }\n output[(y - y0) * width + x] = sum;\n }\n }\n}\n\n/** Synchronous float64 reference for bounded grids. Use the image-kernel accelerator for large grids. */\nexport function calculateIrradianceConvolution(input: IrradianceConvolutionInput): { plan: IrradianceConvolutionPlan; values: Float64Array } {\n const plan = calculateIrradianceConvolutionPlan(input);\n const values = new Float64Array(plan.width * plan.height);\n convolveIrradianceRows(plan, input.samples, input.kernels, 0, plan.height, values);\n return { plan, values };\n}\n\n/** Validates each call of a runner: the first in full, later ones by their own arrays against the first call's plan (#453). */\nfunction createRunnerValidation(geometry: Omit<IrradianceConvolutionInput, \"samples\" | \"kernels\">):\n (samples: Float32Array | Float64Array, kernels: Float32Array | Float64Array) => IrradianceConvolutionPlan {\n let plan: IrradianceConvolutionPlan | undefined;\n return (samples, kernels) => {\n if (plan === undefined) return (plan = calculateIrradianceConvolutionPlan({ ...geometry, samples, kernels }));\n const patchCount = plan.patchColumns * plan.patchRows;\n if (!(samples instanceof Float32Array || samples instanceof Float64Array) || samples.length !== plan.width * plan.height ||\n !(kernels instanceof Float32Array || kernels instanceof Float64Array) || kernels.length !== patchCount * plan.tapCount) {\n throw new InvalidConfigurationError(\"Irradiance convolution arrays do not match the declared geometry.\");\n }\n checkedMaximumSampleMagnitude(samples);\n checkedMaximumKernelSum(kernels, patchCount, plan.tapCount);\n return plan;\n };\n}\n\n/**\n * Internal (#453; not exported from the package): runs several convolutions that share one geometry (width, height,\n * kernel radius, patch size, boundary, pixel limit) with one validation of that geometry. The first call is\n * `calculateIrradianceConvolution` itself, with every check. Each later call checks its own arrays exactly as the plan\n * does (array types and lengths against the geometry, every sample, every kernel weight and kernel sum, with the same\n * messages) and then runs the same gather (`convolveIrradianceRows`) with the first call's plan, whose geometry fields are\n * the same numbers a full validation of this call would give. The values are therefore identical to one\n * `calculateIrradianceConvolution` per call; only the repeated record and geometry checks are skipped.\n * @internal\n */\nexport function createIrradianceConvolutionRunner(geometry: Omit<IrradianceConvolutionInput, \"samples\" | \"kernels\">):\n (samples: Float32Array | Float64Array, kernels: Float32Array | Float64Array) => Float64Array {\n const validate = createRunnerValidation(geometry);\n return (samples, kernels) => {\n const plan = validate(samples, kernels), values = new Float64Array(plan.width * plan.height);\n convolveIrradianceRows(plan, samples, kernels, 0, plan.height, values);\n return values;\n };\n}\n\n/**\n * Internal (#419; not exported from the package): `createIrradianceConvolutionRunner` for one patch (patch = grid), returning only\n * the interior, the values at least `kernelRadius` sites from every edge: (width − 2r) × (height − 2r), row-major. Every call is\n * validated exactly as the runner validates it (the first in full, with `calculateIrradianceConvolution`'s checks and messages).\n * Each interior value is the runner's value bit for bit: no tap of it leaves the grid, so `convolveIrradianceRows`'s boundary\n * tests skip nothing, its patch is the only one (index 0), and this gather adds the same products (sample × weight) in the same\n * order (v outer, u inner, both ascending, every tap). Only the 2r edge rows and columns, which the caller discards, are not computed.\n * @internal\n */\nexport function createIrradianceConvolutionInteriorRunner(geometry: Omit<IrradianceConvolutionInput, \"samples\" | \"kernels\">):\n (samples: Float32Array | Float64Array, kernels: Float32Array | Float64Array) => Float64Array {\n const validate = createRunnerValidation(geometry);\n return (samples, kernels) => {\n const plan = validate(samples, kernels), { width, height, kernelRadius: r, kernelSize } = plan;\n if (plan.patchColumns !== 1 || plan.patchRows !== 1 || width <= 2 * r || height <= 2 * r) {\n throw new InvalidConfigurationError(\"The interior convolution needs one patch and a grid wider and taller than 2r.\");\n }\n const innerWidth = width - 2 * r, values = new Float64Array(innerWidth * (height - 2 * r));\n for (let y = r; y < height - r; y++) {\n for (let x = r; x < width - r; x++) {\n let sum = 0;\n for (let v = -r; v <= r; v++) {\n const sampleRow = (y - v) * width + x, kernelRow = (v + r) * kernelSize + r;\n for (let u = -r; u <= r; u++) sum += samples[sampleRow - u]! * kernels[kernelRow + u]!;\n }\n values[(y - r) * innerWidth + x - r] = sum;\n }\n }\n return values;\n };\n}\n"]}
@@ -208,7 +208,8 @@ export function createPrintJpegTask(input, provider) {
208
208
  cacheBottom += bandHeight;
209
209
  }
210
210
  };
211
- const blocksX = Math.ceil(plan.outputWidth / 8), sums = new Float64Array(blocksX * 192);
211
+ // One block's 192 samples, reused for every block: each is an integer 0–255, written before the block is coded.
212
+ const blocksX = Math.ceil(plan.outputWidth / 8), sums = new Float64Array(blocksX * 192), samples = new Uint8Array(192);
212
213
  // At 1:1 every output pixel is one source pixel with weight exactly 1, so its sum is exactly lut[code] and its
213
214
  // sample is a function of the code alone: the same bytes from a 256-entry table, without the accumulation.
214
215
  const identity = scaleX === 1 && scaleY === 1;
@@ -220,12 +221,14 @@ export function createPrintJpegTask(input, provider) {
220
221
  await ensureRows(plan.crop.y + by, height);
221
222
  check();
222
223
  for (let bx = 0; bx < plan.outputWidth; bx += 8) {
223
- const width = Math.min(8, plan.outputWidth - bx), samples = [];
224
- for (let y = 0; y < 8; y++) {
224
+ const width = Math.min(8, plan.outputWidth - bx);
225
+ for (let y = 0, o = 0; y < 8; y++) {
225
226
  const row = (plan.crop.y + by + Math.min(y, height - 1) - cacheTop) * rowBytes + bx * 3;
226
- for (let x = 0; x < 8; x++) {
227
+ for (let x = 0; x < 8; x++, o += 3) {
227
228
  const index = row + Math.min(x, width - 1) * 3;
228
- samples.push(direct[cache[index]], direct[cache[index + 1]], direct[cache[index + 2]]);
229
+ samples[o] = direct[cache[index]];
230
+ samples[o + 1] = direct[cache[index + 1]];
231
+ samples[o + 2] = direct[cache[index + 2]];
229
232
  }
230
233
  }
231
234
  check();
@@ -271,13 +274,13 @@ export function createPrintJpegTask(input, provider) {
271
274
  }
272
275
  }
273
276
  for (let bx = 0, block = 0; bx < plan.outputWidth; bx += 8, block++) {
274
- const width = Math.min(8, plan.outputWidth - bx), base = block * 192, samples = [];
275
- for (let y = 0; y < 8; y++)
277
+ const width = Math.min(8, plan.outputWidth - bx), base = block * 192;
278
+ for (let y = 0, o = 0; y < 8; y++)
276
279
  for (let x = 0; x < 8; x++)
277
- for (let c = 0; c < 3; c++) {
280
+ for (let c = 0; c < 3; c++, o++) {
278
281
  const value = sums[base + (Math.min(y, height - 1) * 8 + Math.min(x, width - 1)) * 3 + c];
279
282
  // Nearest code, ties up. Math.round is used because floor(x+0.5) wrongly rounds 0.49999999999999994 up.
280
- samples.push(Math.min(255, Math.max(0, Math.round(encodeSrgbComponent(value) * 255))));
283
+ samples[o] = Math.min(255, Math.max(0, Math.round(encodeSrgbComponent(value) * 255)));
281
284
  }
282
285
  check();
283
286
  encoder.writeRgbBlock(samples);
@@ -1 +1 @@
1
- {"version":3,"file":"print-jpeg.js","sourceRoot":"","sources":["../../src/output/print-jpeg.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Print JPEG export: downsamples an SDR image by exact area averaging, then writes a baseline JPEG\n * with an ICC colour profile. Bounded in size; the encoder is written for this project.\n */\nimport { createExportJpegEncoder, encodeJpegStrip, EXPORT_JPEG_ENCODER_ID, type JpegStripBits } from \"../capture/export-jpeg.js\";\nimport { packExportJpegExif, exportTiffNumbers, exportTiffAscii, exportTiffRationals, type ExportTiffTag } from \"../capture/export-tiff.js\";\nimport { createSrgbIccProfile, SRGB_ICC_PROFILE_VERSION } from \"../color/srgb-icc.js\";\nimport { decodeSrgbComponent, encodeSrgbComponent } from \"../color/srgb-transfer.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord, requirePublicOpaqueId } from \"../core/record-validation.js\";\nimport { freezeOwnedData } from \"../core/owned-data.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit, scaleBudgetCeiling } from \"../core/pixel-limits.js\";\nimport type { NativeRawTaskState } from \"../capture/native-raw.js\";\nimport type { RasterRect } from \"./capture-geometry.js\";\nexport const PRINT_JPEG_SCHEMA_VERSION=\"0.2.0\" as const;\n/**\n * Admission limits. `maximumPixels` is the default source limit; a request may raise it with its own\n * `maximumPixels`, up to `ceilingPixels`. A raised limit raises the `maximumEncodedBytes` ceiling in proportion\n * (256 000 000 bytes per 24 000 000 source pixels).\n */\nexport const PRINT_JPEG_LIMITS=Object.freeze({maximumPixels:24_000_000,ceilingPixels:FULL_RESOLUTION_CEILING_PIXELS,maximumDimension:16_384,\n maximumEncodedBytes:256_000_000,maximumProviderReads:1_000_000});\nlet srgbDecode:Float64Array|undefined;\n/** decodeSrgbComponent(v/255) for every 8-bit code v, computed once with the same function (identical values). */\nfunction srgbDecodeTable():Float64Array{return srgbDecode??=Float64Array.from({length:256},(_,v)=>decodeSrgbComponent(v/255));}\nexport interface PrintJpegSource {\n captureId:string;imageStateId:string;artifactId:string;sha256:string;\n width:number;height:number;\n encoding:\"encoded-srgb-8-rgb\";\n}\nexport interface PrintJpegInput {\n source:PrintJpegSource;\n /** Integer crop in the oriented output source image, not in sensor or CFA (colour filter array) coordinates. */\n crop:RasterRect;\n outputWidth:number;outputHeight:number;\n quantizationStep:number;\n maximumEncodedBytes:number;\n /**\n * Maximum provider `readTile` calls. The task reads each crop pixel exactly once, in tiles of at most\n * 256 x 32 pixels aligned to the crop origin, so it needs ceil(crop.height/32) x ceil(crop.width/256)\n * reads; a smaller budget fails before the first read.\n */\n maximumProviderReads:number;\n /**\n * Optional physical print density in pixels per inch (1..65535) from the caller's print plan. When present,\n * EXIF IFD0 records XResolution = YResolution = this value as a RATIONAL with ResolutionUnit = 2 (inches),\n * and JFIF APP0 records units = 1 with the nearest integer density (JFIF density fields are uint16).\n * When omitted no physical size is claimed: JFIF keeps units = 0 with a 1:1 aspect ratio. Exif 2.32 makes\n * the IFD0 resolution tags mandatory and says an unknown resolution \"shall\" be recorded as 72 dpi, so IFD0\n * carries 72/1 with ResolutionUnit = 2; that is the standard's unknown-resolution marker, not a print size.\n */\n pixelsPerInch?:number;\n /**\n * Optional opt-in source pixel limit for large images: an integer from 1 to `PRINT_JPEG_LIMITS.ceilingPixels`.\n * Default `PRINT_JPEG_LIMITS.maximumPixels` (24 000 000). When given it is recorded in the XMP export plan, like the\n * other admission budgets; the image data are unchanged.\n */\n maximumPixels?:number;\n}\nexport interface PrintJpegTileRequest {source:PrintJpegSource;x:number;y:number;width:number;height:number}\nexport interface PrintJpegTile extends PrintJpegTileRequest {samples:Uint8Array}\nexport interface PrintJpegProvider {\n readTile(request:Readonly<PrintJpegTileRequest>,signal:AbortSignal):Promise<PrintJpegTile>;\n yieldControl(signal:AbortSignal):Promise<void>;\n}\nexport interface PrintJpegOutput {\n schemaVersion:typeof PRINT_JPEG_SCHEMA_VERSION;\n input:PrintJpegInput;\n mediaType:\"image/jpeg\";\n bytes:Uint8Array;\n iccProfileVersion:typeof SRGB_ICC_PROFILE_VERSION;\n width:number;height:number;\n resampling:\"exact-area-average-in-decoded-linear-light\";\n sourceStage:\"post-SDR-8-bit-quantization\";\n digitalUpscalingApplied:false;\n sourceBytesVerified:false;\n /** Provider calls made: ceil(crop.height/32) x ceil(crop.width/256) tiles, each crop pixel read once. */\n providerReads:number;\n /** Byte behaviour of the baseline encoder that produced `bytes`. */\n encoderId:typeof EXPORT_JPEG_ENCODER_ID;\n}\nexport interface PrintJpegTask {\n readonly state:NativeRawTaskState;\n run():Promise<void>;cancel():void;dispose():void;takeOutput():PrintJpegOutput;\n}\n/** Exactly n/1 for a whole-number density; otherwise the shared bounded decimal-fraction approximation. */\nfunction resolutionRational(id:number,ppi:number):ExportTiffTag {\n if(!Number.isSafeInteger(ppi))return exportTiffRationals(id,false,[ppi]);\n const data=new Uint8Array(8),view=new DataView(data.buffer);view.setUint32(0,ppi,true);view.setUint32(4,1,true);\n return {id,type:5,count:1,data};\n}\n/**\n * Exif 2.32 APP1 for a compressed primary image with every mandatory tag (CIPA DC-008-2019 Tables 17-18):\n * IFD0 Orientation, X/YResolution + ResolutionUnit, Software, YCbCrPositioning; Exif IFD ExifVersion \"0232\",\n * ComponentsConfiguration, FlashpixVersion \"0100\", ColorSpace sRGB, PixelX/YDimension. Without a planned\n * density the resolution tags carry the standard's \"unknown resolution\" value of 72 dpi.\n */\nfunction printExif(plan:PrintJpegInput):Uint8Array {\n const ppi=plan.pixelsPerInch;\n const resolution=ppi===undefined ? [] : [resolutionRational(282,ppi),resolutionRational(283,ppi),exportTiffNumbers(296,3,[2])];\n return packExportJpegExif([exportTiffNumbers(274,3,[1]),...resolution,exportTiffAscii(305,\"Photivra Print JPEG\")],\n [exportTiffNumbers(40961,3,[1])],{pixelWidth:plan.outputWidth,pixelHeight:plan.outputHeight});\n}\nfunction integer(v:unknown,min=1):number {\n if(typeof v!==\"number\"||!Number.isSafeInteger(v)||v<min)throw new InvalidConfigurationError(\"Print raster/budgets require safe integers.\");return v;\n}\n/** Validates the input only. Source detail, perception and printer suitability are checked by separate APIs. */\nexport function parsePrintJpegInput(input:PrintJpegInput):PrintJpegInput {\n const r=requireAllowlistedRecord(input,[\"source\",\"crop\",\"outputWidth\",\"outputHeight\",\"quantizationStep\",\"maximumEncodedBytes\",\"maximumProviderReads\",\"pixelsPerInch\",\"maximumPixels\"],\"Invalid Print JPEG input.\");\n const s=requireAllowlistedRecord(r.source,[\"captureId\",\"imageStateId\",\"artifactId\",\"sha256\",\"width\",\"height\",\"encoding\"],\"Invalid Print source.\");\n if(typeof s.sha256!==\"string\"||!/^[a-f0-9]{64}$/.test(s.sha256)||s.encoding!==\"encoded-srgb-8-rgb\")throw new InvalidConfigurationError(\"Print requires identified encoded sRGB source bytes.\");\n const source:PrintJpegSource={captureId:requirePublicOpaqueId(s.captureId,\"Invalid capture ID.\"),imageStateId:requirePublicOpaqueId(s.imageStateId,\"Invalid image state ID.\"),artifactId:requirePublicOpaqueId(s.artifactId,\"Invalid artifact ID.\"),sha256:s.sha256,width:integer(s.width),height:integer(s.height),encoding:s.encoding};\n const c=requireAllowlistedRecord(r.crop,[\"x\",\"y\",\"width\",\"height\"],\"Invalid Print crop.\"),crop={x:integer(c.x,0),y:integer(c.y,0),width:integer(c.width),height:integer(c.height)};\n const outputWidth=integer(r.outputWidth),outputHeight=integer(r.outputHeight),quantizationStep=integer(r.quantizationStep),maximumEncodedBytes=integer(r.maximumEncodedBytes),maximumProviderReads=integer(r.maximumProviderReads);\n const L=PRINT_JPEG_LIMITS,maximumPixels=resolveRaisedLimit(r.maximumPixels,L.maximumPixels,L.ceilingPixels,\"Print maximumPixels must be an integer from 1 to \"+L.ceilingPixels+\".\");\n const encodedBytesCeiling=r.maximumPixels===undefined?L.maximumEncodedBytes:scaleBudgetCeiling(L.maximumEncodedBytes,maximumPixels);\n if(source.width>L.maximumDimension||source.height>L.maximumDimension||source.width*source.height>maximumPixels||crop.x+crop.width>source.width||crop.y+crop.height>source.height||\n outputWidth>crop.width||outputHeight>crop.height||quantizationStep>255||maximumEncodedBytes>encodedBytesCeiling||maximumProviderReads>L.maximumProviderReads||\n Math.abs(outputWidth*crop.height-outputHeight*crop.width)>.5*(crop.width+crop.height))throw new InvalidConfigurationError(\"Print requires bounded native/downsampled aspect-preserving crop output.\");\n const ppi=r.pixelsPerInch;\n if(ppi!==undefined&&(typeof ppi!==\"number\"||!Number.isFinite(ppi)||ppi<1||ppi>65535))throw new InvalidConfigurationError(\"Print density requires finite pixels per inch from 1 to 65535.\");\n return freezeOwnedData({source,crop,outputWidth,outputHeight,quantizationStep,maximumEncodedBytes,maximumProviderReads,...(ppi===undefined ? {} : {pixelsPerInch:ppi}),\n ...(r.maximumPixels===undefined ? {} : {maximumPixels})});\n}\n/** The JPEG writer of a Print plan: its size, quantization, budget, ICC profile, EXIF, XMP plan record and density. */\nfunction printEncoder(plan:PrintJpegInput):ReturnType<typeof createExportJpegEncoder> {\n const exif=printExif(plan);\n const escaped=JSON.stringify(plan).replaceAll(\"&\",\"&amp;\").replaceAll('\"',\"&quot;\").replaceAll(\"<\",\"&lt;\").replaceAll(\">\",\"&gt;\");\n const xmp=new TextEncoder().encode('<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"><rdf:Description rdf:about=\"\" xmlns:photivra=\"https://photivra.com/ns/simulation/1.0/\" photivra:PrintExportPlan=\"'+escaped+'\" photivra:SourceBytesVerified=\"False\"/></rdf:RDF></x:xmpmeta>');\n return createExportJpegEncoder({width:plan.outputWidth,height:plan.outputHeight,quantizationStep:plan.quantizationStep,maximumOutputBytes:plan.maximumEncodedBytes,icc:createSrgbIccProfile(),exif,xmp,\n ...(plan.pixelsPerInch===undefined ? {} : {densityDotsPerInch:Math.round(plan.pixelsPerInch)})});\n}\n/** At 1:1, the output code of each source code (its decoded value re-encoded and rounded). */\nfunction directCodes():Uint8Array {\n return Uint8Array.from(srgbDecodeTable(),(value)=>Math.min(255,Math.max(0,Math.round(encodeSrgbComponent(value)*255))));\n}\n/** Rows of a 1:1 Print JPEG for `createPrintJpegStrip`: crop rows `y` to `y + height` (relative to the crop), crop-wide RGB. */\nexport interface PrintJpegStripInput {y:number;height:number;samples:Uint8Array}\n/** A strip of a 1:1 Print JPEG's coded blocks (`createPrintJpegStrip`), for `composePrintJpegStrips`. */\nexport interface PrintJpegStrip {readonly y:number;readonly height:number;readonly width:number;readonly quantizationStep:number;readonly bits:JpegStripBits}\nfunction requireIdentity(plan:PrintJpegInput):void {\n if(plan.outputWidth!==plan.crop.width||plan.outputHeight!==plan.crop.height)throw new InvalidConfigurationError(\"Print JPEG strips require a 1:1 plan (output size equal to the crop).\");\n}\n/**\n * Codes rows of a 1:1 Print JPEG (output size equal to the crop) apart from the rows before them, so a large file's strips\n * can be written on separate workers. `strip.y` is a multiple of 8 and `strip.height` a multiple of 8 unless the strip ends at\n * the image's bottom; `strip.samples` are those crop rows' 8-bit sRGB RGB, crop-wide. `composePrintJpegStrips` joins strips that\n * cover the image, in order, into the bytes `createPrintJpegTask` writes for the same plan and source pixels.\n */\nexport function createPrintJpegStrip(input:PrintJpegInput,strip:PrintJpegStripInput):PrintJpegStrip {\n const plan=parsePrintJpegInput(input);requireIdentity(plan);\n const r=requireAllowlistedRecord(strip,[\"y\",\"height\",\"samples\"],\"Invalid Print JPEG strip.\");\n const y=integer(r.y,0),height=integer(r.height),width=plan.outputWidth,samples=r.samples;\n if(y%8!==0||y+height>plan.outputHeight||(height%8!==0&&y+height!==plan.outputHeight))throw new InvalidConfigurationError(\"Print JPEG strips start on a block row and cover whole block rows.\");\n if(!(samples instanceof Uint8Array)||samples.length!==width*height*3)throw new InvalidConfigurationError(\"Print JPEG strip requires the crop rows' RGB samples.\");\n const direct=directCodes(),blocksX=Math.ceil(width/8),rowBytes=width*3;\n // The same block samples as createPrintJpegTask's 1:1 path: each block's edge pixels repeated into a partial block.\n const bits=encodeJpegStrip(plan.quantizationStep,blocksX*Math.ceil(height/8),(index,out)=>{\n const bx=(index%blocksX)*8,by=Math.floor(index/blocksX)*8,bw=Math.min(8,width-bx),bh=Math.min(8,plan.outputHeight-y-by);\n for(let yy=0,o=0;yy<8;yy++){\n const row=(by+Math.min(yy,bh-1))*rowBytes+bx*3;\n for(let x=0;x<8;x++,o+=3){const i=row+Math.min(x,bw-1)*3;out[o]=direct[samples[i]!]!;out[o+1]=direct[samples[i+1]!]!;out[o+2]=direct[samples[i+2]!]!;}\n }\n });\n return Object.freeze({y,height,width,quantizationStep:plan.quantizationStep,bits});\n}\n/**\n * Joins the strips of a 1:1 Print JPEG (`createPrintJpegStrip`), covering the image top to bottom in order, into its file:\n * the same bytes `createPrintJpegTask` writes for the plan and the same source pixels. No source is read, so the output's\n * `providerReads` is 0.\n */\nexport function composePrintJpegStrips(input:PrintJpegInput,strips:readonly PrintJpegStrip[]):PrintJpegOutput {\n const plan=parsePrintJpegInput(input);requireIdentity(plan);\n if(!Array.isArray(strips)||strips.length<1)throw new InvalidConfigurationError(\"Print JPEG assembly requires strips.\");\n const encoder=printEncoder(plan);\n try{\n let next=0;\n for(const strip of strips){\n if(strip.y!==next||strip.width!==plan.outputWidth||strip.quantizationStep!==plan.quantizationStep)throw new InvalidConfigurationError(\"Print JPEG strips must cover the plan's image in order.\");\n encoder.appendStrip(strip.bits);next+=strip.height;\n }\n if(next!==plan.outputHeight)throw new InvalidConfigurationError(\"Print JPEG strips must cover the plan's image in order.\");\n const bytes=encoder.finish();\n return {schemaVersion:PRINT_JPEG_SCHEMA_VERSION,input:plan,mediaType:\"image/jpeg\",bytes,iccProfileVersion:SRGB_ICC_PROFILE_VERSION,width:plan.outputWidth,height:plan.outputHeight,resampling:\"exact-area-average-in-decoded-linear-light\",sourceStage:\"post-SDR-8-bit-quantization\",digitalUpscalingApplied:false,sourceBytesVerified:false,providerReads:0,encoderId:EXPORT_JPEG_ENCODER_ID};\n }catch(error){encoder.dispose();throw error;}\n}\n/** Creates the export task. Filtering weights each source pixel by its exact area overlap, after decoding the declared 8-bit SDR source. */\nexport function createPrintJpegTask(input:PrintJpegInput,provider:PrintJpegProvider):PrintJpegTask {\n const plan=parsePrintJpegInput(input);\n if(!provider||typeof provider.readTile!==\"function\"||typeof provider.yieldControl!==\"function\")throw new InvalidConfigurationError(\"Print export requires source reader and host yields.\");\n const read=provider.readTile.bind(provider),yieldControl=provider.yieldControl.bind(provider),abort=new AbortController();\n let state:NativeRawTaskState=\"ready\",output:PrintJpegOutput|null=null,encoder:ReturnType<typeof createExportJpegEncoder>|undefined;\n function check():void{if(abort.signal.aborted)throw new InvalidConfigurationError(\"Print export aborted.\");}\n function release():void{encoder?.dispose();encoder=undefined;output?.bytes.fill(0);output=null;}\n return {get state():NativeRawTaskState{return state;},\n async run():Promise<void>{\n if(state!==\"ready\")throw new InvalidConfigurationError(\"Print export is single-use.\");state=\"running\";\n try{\n encoder=printEncoder(plan);\n const scaleX=plan.crop.width/plan.outputWidth,scaleY=plan.crop.height/plan.outputHeight,area=scaleX*scaleY;\n const cropRight=plan.crop.x+plan.crop.width,cropBottom=plan.crop.y+plan.crop.height,rowBytes=plan.crop.width*3;\n // Every crop pixel is read exactly once, in tiles of at most 256 x 32 aligned to the crop origin.\n const tilesPerBand=Math.ceil(plan.crop.width/256),requiredReads=Math.ceil(plan.crop.height/32)*tilesPerBand;\n if(requiredReads>plan.maximumProviderReads)throw new InvalidConfigurationError(\"Print source exceeds provider-read budget.\");\n // Rolling cache of whole crop-width source rows [cacheTop, cacheBottom): at most 63 rows are retained.\n const cache=new Uint8Array(Math.min(64,plan.crop.height)*rowBytes),lut=srgbDecodeTable();\n let reads=0,blocks=0,cacheTop=plan.crop.y,cacheBottom=plan.crop.y;\n const ensureRows=async(firstRow:number,rowCount:number):Promise<void>=>{\n const keepFrom=Math.min(Math.max(cacheTop,firstRow),cacheBottom);\n if(keepFrom>cacheTop){cache.copyWithin(0,(keepFrom-cacheTop)*rowBytes,(cacheBottom-cacheTop)*rowBytes);cacheTop=keepFrom;}\n while(cacheBottom<firstRow+rowCount){\n const bandHeight=Math.min(32,cropBottom-cacheBottom);\n if((cacheBottom+bandHeight-cacheTop)*rowBytes>cache.length)throw new InvalidConfigurationError(\"Print source traversal is not monotonic.\");\n for(let sx=plan.crop.x;sx<cropRight;sx+=256){\n check();++reads;\n const request=Object.freeze({source:plan.source,x:sx,y:cacheBottom,width:Math.min(256,cropRight-sx),height:bandHeight});\n const supplied=await read(request,abort.signal);check();\n const tile=requireAllowlistedRecord(supplied,[\"source\",\"x\",\"y\",\"width\",\"height\",\"samples\"],\"Invalid Print source tile.\");\n const source=requireAllowlistedRecord(tile.source,[\"captureId\",\"imageStateId\",\"artifactId\",\"sha256\",\"width\",\"height\",\"encoding\"],\"Invalid Print tile source.\");\n for(const key of Object.keys(plan.source) as (keyof PrintJpegSource)[])if(source[key]!==plan.source[key])throw new InvalidConfigurationError(\"Print source identity mismatch.\");\n for(const key of [\"x\",\"y\",\"width\",\"height\"] as const)if(tile[key]!==request[key])throw new InvalidConfigurationError(\"Print source rectangle mismatch.\");\n const samples=tile.samples;if(!(samples instanceof Uint8Array)||!(samples.buffer instanceof ArrayBuffer)||samples.length!==request.width*request.height*3||samples.buffer.byteLength!==samples.byteLength)throw new InvalidConfigurationError(\"Print source requires exact owned bounded RGB tile storage.\");\n for(let iy=0;iy<bandHeight;iy++)cache.set(samples.subarray(iy*request.width*3,(iy+1)*request.width*3),(cacheBottom-cacheTop+iy)*rowBytes+(sx-plan.crop.x)*3);\n // One output block can cover a megapixel of source, so also yield to the host while reading the source.\n if(reads%32===0){await yieldControl(abort.signal);check();}\n }\n cacheBottom+=bandHeight;\n }\n };\n const blocksX=Math.ceil(plan.outputWidth/8),sums=new Float64Array(blocksX*192);\n // At 1:1 every output pixel is one source pixel with weight exactly 1, so its sum is exactly lut[code] and its\n // sample is a function of the code alone: the same bytes from a 256-entry table, without the accumulation.\n const identity=scaleX===1&&scaleY===1;\n const direct=identity?directCodes():undefined;\n if(direct)for(let by=0;by<plan.outputHeight;by+=8){\n check();\n const height=Math.min(8,plan.outputHeight-by);await ensureRows(plan.crop.y+by,height);check();\n for(let bx=0;bx<plan.outputWidth;bx+=8){\n const width=Math.min(8,plan.outputWidth-bx),samples:number[]=[];\n for(let y=0;y<8;y++){\n const row=(plan.crop.y+by+Math.min(y,height-1)-cacheTop)*rowBytes+bx*3;\n for(let x=0;x<8;x++){const index=row+Math.min(x,width-1)*3;samples.push(direct[cache[index]!]!,direct[cache[index+1]!]!,direct[cache[index+2]!]!);}\n }\n check();encoder.writeRgbBlock(samples);if(++blocks%32===0){await yieldControl(abort.signal);check();}\n }\n }\n else for(let by=0;by<plan.outputHeight;by+=8){\n check();sums.fill(0);\n const height=Math.min(8,plan.outputHeight-by),top=plan.crop.y+by*scaleY,bottom=by+height===plan.outputHeight?cropBottom:plan.crop.y+(by+height)*scaleY;\n // Accumulation order per output pixel is unchanged from the per-block reader: 32-row bands from\n // floor(top), then 256-column chunks from floor(left), then rows, then columns. Identical IEEE sums.\n for(let sy=Math.floor(top);sy<Math.ceil(bottom);sy+=32){\n const bandHeight=Math.min(32,Math.ceil(bottom)-sy);await ensureRows(sy,bandHeight);check();\n for(let bx=0,block=0;bx<plan.outputWidth;bx+=8,block++){\n const width=Math.min(8,plan.outputWidth-bx),left=plan.crop.x+bx*scaleX,right=bx+width===plan.outputWidth?cropRight:plan.crop.x+(bx+width)*scaleX,base=block*192;\n for(let sx=Math.floor(left);sx<Math.ceil(right);sx+=256){\n const chunkWidth=Math.min(256,Math.ceil(right)-sx);\n for(let iy=0;iy<bandHeight;iy++)for(let ix=0;ix<chunkWidth;ix++){\n const px=sx+ix,py=sy+iy;\n const firstX=Math.max(0,Math.floor((px-plan.crop.x)/scaleX)-bx),lastX=Math.min(width-1,Math.ceil((px+1-plan.crop.x)/scaleX)-bx-1);\n const firstY=Math.max(0,Math.floor((py-plan.crop.y)/scaleY)-by),lastY=Math.min(height-1,Math.ceil((py+1-plan.crop.y)/scaleY)-by-1);\n const index=(py-cacheTop)*rowBytes+(px-plan.crop.x)*3,r=lut[cache[index]!]!,g=lut[cache[index+1]!]!,b=lut[cache[index+2]!]!;\n for(let oy=firstY;oy<=lastY;oy++)for(let ox=firstX;ox<=lastX;ox++){\n const x0=plan.crop.x+(bx+ox)*scaleX,y0=plan.crop.y+(by+oy)*scaleY;\n const weight=Math.max(0,Math.min(px+1,x0+scaleX)-Math.max(px,x0))*Math.max(0,Math.min(py+1,y0+scaleY)-Math.max(py,y0))/area;\n const i=base+(oy*8+ox)*3;sums[i]=sums[i]!+r*weight;sums[i+1]=sums[i+1]!+g*weight;sums[i+2]=sums[i+2]!+b*weight;\n }\n }\n }\n }\n }\n for(let bx=0,block=0;bx<plan.outputWidth;bx+=8,block++){\n const width=Math.min(8,plan.outputWidth-bx),base=block*192,samples:number[]=[];\n for(let y=0;y<8;y++)for(let x=0;x<8;x++)for(let c=0;c<3;c++){\n const value=sums[base+(Math.min(y,height-1)*8+Math.min(x,width-1))*3+c]!;\n // Nearest code, ties up. Math.round is used because floor(x+0.5) wrongly rounds 0.49999999999999994 up.\n samples.push(Math.min(255,Math.max(0,Math.round(encodeSrgbComponent(value)*255))));\n }\n check();encoder.writeRgbBlock(samples);if(++blocks%32===0){await yieldControl(abort.signal);check();}\n }\n }\n await yieldControl(abort.signal);check();const bytes=encoder.finish();encoder=undefined;\n output={schemaVersion:PRINT_JPEG_SCHEMA_VERSION,input:plan,mediaType:\"image/jpeg\",bytes,iccProfileVersion:SRGB_ICC_PROFILE_VERSION,width:plan.outputWidth,height:plan.outputHeight,resampling:\"exact-area-average-in-decoded-linear-light\",sourceStage:\"post-SDR-8-bit-quantization\",digitalUpscalingApplied:false,sourceBytesVerified:false,providerReads:reads,encoderId:EXPORT_JPEG_ENCODER_ID};state=\"completed\";\n }catch(error){release();if(!abort.signal.aborted){state=\"failed\";abort.abort();}throw error;}\n },cancel():void{if(state===\"ready\"||state===\"running\"||state===\"completed\"){state=\"cancelled\";abort.abort();release();}},\n dispose():void{if(state!==\"transferred\"){state=\"disposed\";abort.abort();release();}},\n takeOutput():PrintJpegOutput{if(state!==\"completed\"||!output)throw new InvalidConfigurationError(\"Print JPEG unavailable.\");const value=output;output=null;state=\"transferred\";return value;}\n };\n}\n"]}
1
+ {"version":3,"file":"print-jpeg.js","sourceRoot":"","sources":["../../src/output/print-jpeg.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Print JPEG export: downsamples an SDR image by exact area averaging, then writes a baseline JPEG\n * with an ICC colour profile. Bounded in size; the encoder is written for this project.\n */\nimport { createExportJpegEncoder, encodeJpegStrip, EXPORT_JPEG_ENCODER_ID, type JpegStripBits } from \"../capture/export-jpeg.js\";\nimport { packExportJpegExif, exportTiffNumbers, exportTiffAscii, exportTiffRationals, type ExportTiffTag } from \"../capture/export-tiff.js\";\nimport { createSrgbIccProfile, SRGB_ICC_PROFILE_VERSION } from \"../color/srgb-icc.js\";\nimport { decodeSrgbComponent, encodeSrgbComponent } from \"../color/srgb-transfer.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord, requirePublicOpaqueId } from \"../core/record-validation.js\";\nimport { freezeOwnedData } from \"../core/owned-data.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, resolveRaisedLimit, scaleBudgetCeiling } from \"../core/pixel-limits.js\";\nimport type { NativeRawTaskState } from \"../capture/native-raw.js\";\nimport type { RasterRect } from \"./capture-geometry.js\";\nexport const PRINT_JPEG_SCHEMA_VERSION=\"0.2.0\" as const;\n/**\n * Admission limits. `maximumPixels` is the default source limit; a request may raise it with its own\n * `maximumPixels`, up to `ceilingPixels`. A raised limit raises the `maximumEncodedBytes` ceiling in proportion\n * (256 000 000 bytes per 24 000 000 source pixels).\n */\nexport const PRINT_JPEG_LIMITS=Object.freeze({maximumPixels:24_000_000,ceilingPixels:FULL_RESOLUTION_CEILING_PIXELS,maximumDimension:16_384,\n maximumEncodedBytes:256_000_000,maximumProviderReads:1_000_000});\nlet srgbDecode:Float64Array|undefined;\n/** decodeSrgbComponent(v/255) for every 8-bit code v, computed once with the same function (identical values). */\nfunction srgbDecodeTable():Float64Array{return srgbDecode??=Float64Array.from({length:256},(_,v)=>decodeSrgbComponent(v/255));}\nexport interface PrintJpegSource {\n captureId:string;imageStateId:string;artifactId:string;sha256:string;\n width:number;height:number;\n encoding:\"encoded-srgb-8-rgb\";\n}\nexport interface PrintJpegInput {\n source:PrintJpegSource;\n /** Integer crop in the oriented output source image, not in sensor or CFA (colour filter array) coordinates. */\n crop:RasterRect;\n outputWidth:number;outputHeight:number;\n quantizationStep:number;\n maximumEncodedBytes:number;\n /**\n * Maximum provider `readTile` calls. The task reads each crop pixel exactly once, in tiles of at most\n * 256 x 32 pixels aligned to the crop origin, so it needs ceil(crop.height/32) x ceil(crop.width/256)\n * reads; a smaller budget fails before the first read.\n */\n maximumProviderReads:number;\n /**\n * Optional physical print density in pixels per inch (1..65535) from the caller's print plan. When present,\n * EXIF IFD0 records XResolution = YResolution = this value as a RATIONAL with ResolutionUnit = 2 (inches),\n * and JFIF APP0 records units = 1 with the nearest integer density (JFIF density fields are uint16).\n * When omitted no physical size is claimed: JFIF keeps units = 0 with a 1:1 aspect ratio. Exif 2.32 makes\n * the IFD0 resolution tags mandatory and says an unknown resolution \"shall\" be recorded as 72 dpi, so IFD0\n * carries 72/1 with ResolutionUnit = 2; that is the standard's unknown-resolution marker, not a print size.\n */\n pixelsPerInch?:number;\n /**\n * Optional opt-in source pixel limit for large images: an integer from 1 to `PRINT_JPEG_LIMITS.ceilingPixels`.\n * Default `PRINT_JPEG_LIMITS.maximumPixels` (24 000 000). When given it is recorded in the XMP export plan, like the\n * other admission budgets; the image data are unchanged.\n */\n maximumPixels?:number;\n}\nexport interface PrintJpegTileRequest {source:PrintJpegSource;x:number;y:number;width:number;height:number}\nexport interface PrintJpegTile extends PrintJpegTileRequest {samples:Uint8Array}\nexport interface PrintJpegProvider {\n readTile(request:Readonly<PrintJpegTileRequest>,signal:AbortSignal):Promise<PrintJpegTile>;\n yieldControl(signal:AbortSignal):Promise<void>;\n}\nexport interface PrintJpegOutput {\n schemaVersion:typeof PRINT_JPEG_SCHEMA_VERSION;\n input:PrintJpegInput;\n mediaType:\"image/jpeg\";\n bytes:Uint8Array;\n iccProfileVersion:typeof SRGB_ICC_PROFILE_VERSION;\n width:number;height:number;\n resampling:\"exact-area-average-in-decoded-linear-light\";\n sourceStage:\"post-SDR-8-bit-quantization\";\n digitalUpscalingApplied:false;\n sourceBytesVerified:false;\n /** Provider calls made: ceil(crop.height/32) x ceil(crop.width/256) tiles, each crop pixel read once. */\n providerReads:number;\n /** Byte behaviour of the baseline encoder that produced `bytes`. */\n encoderId:typeof EXPORT_JPEG_ENCODER_ID;\n}\nexport interface PrintJpegTask {\n readonly state:NativeRawTaskState;\n run():Promise<void>;cancel():void;dispose():void;takeOutput():PrintJpegOutput;\n}\n/** Exactly n/1 for a whole-number density; otherwise the shared bounded decimal-fraction approximation. */\nfunction resolutionRational(id:number,ppi:number):ExportTiffTag {\n if(!Number.isSafeInteger(ppi))return exportTiffRationals(id,false,[ppi]);\n const data=new Uint8Array(8),view=new DataView(data.buffer);view.setUint32(0,ppi,true);view.setUint32(4,1,true);\n return {id,type:5,count:1,data};\n}\n/**\n * Exif 2.32 APP1 for a compressed primary image with every mandatory tag (CIPA DC-008-2019 Tables 17-18):\n * IFD0 Orientation, X/YResolution + ResolutionUnit, Software, YCbCrPositioning; Exif IFD ExifVersion \"0232\",\n * ComponentsConfiguration, FlashpixVersion \"0100\", ColorSpace sRGB, PixelX/YDimension. Without a planned\n * density the resolution tags carry the standard's \"unknown resolution\" value of 72 dpi.\n */\nfunction printExif(plan:PrintJpegInput):Uint8Array {\n const ppi=plan.pixelsPerInch;\n const resolution=ppi===undefined ? [] : [resolutionRational(282,ppi),resolutionRational(283,ppi),exportTiffNumbers(296,3,[2])];\n return packExportJpegExif([exportTiffNumbers(274,3,[1]),...resolution,exportTiffAscii(305,\"Photivra Print JPEG\")],\n [exportTiffNumbers(40961,3,[1])],{pixelWidth:plan.outputWidth,pixelHeight:plan.outputHeight});\n}\nfunction integer(v:unknown,min=1):number {\n if(typeof v!==\"number\"||!Number.isSafeInteger(v)||v<min)throw new InvalidConfigurationError(\"Print raster/budgets require safe integers.\");return v;\n}\n/** Validates the input only. Source detail, perception and printer suitability are checked by separate APIs. */\nexport function parsePrintJpegInput(input:PrintJpegInput):PrintJpegInput {\n const r=requireAllowlistedRecord(input,[\"source\",\"crop\",\"outputWidth\",\"outputHeight\",\"quantizationStep\",\"maximumEncodedBytes\",\"maximumProviderReads\",\"pixelsPerInch\",\"maximumPixels\"],\"Invalid Print JPEG input.\");\n const s=requireAllowlistedRecord(r.source,[\"captureId\",\"imageStateId\",\"artifactId\",\"sha256\",\"width\",\"height\",\"encoding\"],\"Invalid Print source.\");\n if(typeof s.sha256!==\"string\"||!/^[a-f0-9]{64}$/.test(s.sha256)||s.encoding!==\"encoded-srgb-8-rgb\")throw new InvalidConfigurationError(\"Print requires identified encoded sRGB source bytes.\");\n const source:PrintJpegSource={captureId:requirePublicOpaqueId(s.captureId,\"Invalid capture ID.\"),imageStateId:requirePublicOpaqueId(s.imageStateId,\"Invalid image state ID.\"),artifactId:requirePublicOpaqueId(s.artifactId,\"Invalid artifact ID.\"),sha256:s.sha256,width:integer(s.width),height:integer(s.height),encoding:s.encoding};\n const c=requireAllowlistedRecord(r.crop,[\"x\",\"y\",\"width\",\"height\"],\"Invalid Print crop.\"),crop={x:integer(c.x,0),y:integer(c.y,0),width:integer(c.width),height:integer(c.height)};\n const outputWidth=integer(r.outputWidth),outputHeight=integer(r.outputHeight),quantizationStep=integer(r.quantizationStep),maximumEncodedBytes=integer(r.maximumEncodedBytes),maximumProviderReads=integer(r.maximumProviderReads);\n const L=PRINT_JPEG_LIMITS,maximumPixels=resolveRaisedLimit(r.maximumPixels,L.maximumPixels,L.ceilingPixels,\"Print maximumPixels must be an integer from 1 to \"+L.ceilingPixels+\".\");\n const encodedBytesCeiling=r.maximumPixels===undefined?L.maximumEncodedBytes:scaleBudgetCeiling(L.maximumEncodedBytes,maximumPixels);\n if(source.width>L.maximumDimension||source.height>L.maximumDimension||source.width*source.height>maximumPixels||crop.x+crop.width>source.width||crop.y+crop.height>source.height||\n outputWidth>crop.width||outputHeight>crop.height||quantizationStep>255||maximumEncodedBytes>encodedBytesCeiling||maximumProviderReads>L.maximumProviderReads||\n Math.abs(outputWidth*crop.height-outputHeight*crop.width)>.5*(crop.width+crop.height))throw new InvalidConfigurationError(\"Print requires bounded native/downsampled aspect-preserving crop output.\");\n const ppi=r.pixelsPerInch;\n if(ppi!==undefined&&(typeof ppi!==\"number\"||!Number.isFinite(ppi)||ppi<1||ppi>65535))throw new InvalidConfigurationError(\"Print density requires finite pixels per inch from 1 to 65535.\");\n return freezeOwnedData({source,crop,outputWidth,outputHeight,quantizationStep,maximumEncodedBytes,maximumProviderReads,...(ppi===undefined ? {} : {pixelsPerInch:ppi}),\n ...(r.maximumPixels===undefined ? {} : {maximumPixels})});\n}\n/** The JPEG writer of a Print plan: its size, quantization, budget, ICC profile, EXIF, XMP plan record and density. */\nfunction printEncoder(plan:PrintJpegInput):ReturnType<typeof createExportJpegEncoder> {\n const exif=printExif(plan);\n const escaped=JSON.stringify(plan).replaceAll(\"&\",\"&amp;\").replaceAll('\"',\"&quot;\").replaceAll(\"<\",\"&lt;\").replaceAll(\">\",\"&gt;\");\n const xmp=new TextEncoder().encode('<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"><rdf:Description rdf:about=\"\" xmlns:photivra=\"https://photivra.com/ns/simulation/1.0/\" photivra:PrintExportPlan=\"'+escaped+'\" photivra:SourceBytesVerified=\"False\"/></rdf:RDF></x:xmpmeta>');\n return createExportJpegEncoder({width:plan.outputWidth,height:plan.outputHeight,quantizationStep:plan.quantizationStep,maximumOutputBytes:plan.maximumEncodedBytes,icc:createSrgbIccProfile(),exif,xmp,\n ...(plan.pixelsPerInch===undefined ? {} : {densityDotsPerInch:Math.round(plan.pixelsPerInch)})});\n}\n/** At 1:1, the output code of each source code (its decoded value re-encoded and rounded). */\nfunction directCodes():Uint8Array {\n return Uint8Array.from(srgbDecodeTable(),(value)=>Math.min(255,Math.max(0,Math.round(encodeSrgbComponent(value)*255))));\n}\n/** Rows of a 1:1 Print JPEG for `createPrintJpegStrip`: crop rows `y` to `y + height` (relative to the crop), crop-wide RGB. */\nexport interface PrintJpegStripInput {y:number;height:number;samples:Uint8Array}\n/** A strip of a 1:1 Print JPEG's coded blocks (`createPrintJpegStrip`), for `composePrintJpegStrips`. */\nexport interface PrintJpegStrip {readonly y:number;readonly height:number;readonly width:number;readonly quantizationStep:number;readonly bits:JpegStripBits}\nfunction requireIdentity(plan:PrintJpegInput):void {\n if(plan.outputWidth!==plan.crop.width||plan.outputHeight!==plan.crop.height)throw new InvalidConfigurationError(\"Print JPEG strips require a 1:1 plan (output size equal to the crop).\");\n}\n/**\n * Codes rows of a 1:1 Print JPEG (output size equal to the crop) apart from the rows before them, so a large file's strips\n * can be written on separate workers. `strip.y` is a multiple of 8 and `strip.height` a multiple of 8 unless the strip ends at\n * the image's bottom; `strip.samples` are those crop rows' 8-bit sRGB RGB, crop-wide. `composePrintJpegStrips` joins strips that\n * cover the image, in order, into the bytes `createPrintJpegTask` writes for the same plan and source pixels.\n */\nexport function createPrintJpegStrip(input:PrintJpegInput,strip:PrintJpegStripInput):PrintJpegStrip {\n const plan=parsePrintJpegInput(input);requireIdentity(plan);\n const r=requireAllowlistedRecord(strip,[\"y\",\"height\",\"samples\"],\"Invalid Print JPEG strip.\");\n const y=integer(r.y,0),height=integer(r.height),width=plan.outputWidth,samples=r.samples;\n if(y%8!==0||y+height>plan.outputHeight||(height%8!==0&&y+height!==plan.outputHeight))throw new InvalidConfigurationError(\"Print JPEG strips start on a block row and cover whole block rows.\");\n if(!(samples instanceof Uint8Array)||samples.length!==width*height*3)throw new InvalidConfigurationError(\"Print JPEG strip requires the crop rows' RGB samples.\");\n const direct=directCodes(),blocksX=Math.ceil(width/8),rowBytes=width*3;\n // The same block samples as createPrintJpegTask's 1:1 path: each block's edge pixels repeated into a partial block.\n const bits=encodeJpegStrip(plan.quantizationStep,blocksX*Math.ceil(height/8),(index,out)=>{\n const bx=(index%blocksX)*8,by=Math.floor(index/blocksX)*8,bw=Math.min(8,width-bx),bh=Math.min(8,plan.outputHeight-y-by);\n for(let yy=0,o=0;yy<8;yy++){\n const row=(by+Math.min(yy,bh-1))*rowBytes+bx*3;\n for(let x=0;x<8;x++,o+=3){const i=row+Math.min(x,bw-1)*3;out[o]=direct[samples[i]!]!;out[o+1]=direct[samples[i+1]!]!;out[o+2]=direct[samples[i+2]!]!;}\n }\n });\n return Object.freeze({y,height,width,quantizationStep:plan.quantizationStep,bits});\n}\n/**\n * Joins the strips of a 1:1 Print JPEG (`createPrintJpegStrip`), covering the image top to bottom in order, into its file:\n * the same bytes `createPrintJpegTask` writes for the plan and the same source pixels. No source is read, so the output's\n * `providerReads` is 0.\n */\nexport function composePrintJpegStrips(input:PrintJpegInput,strips:readonly PrintJpegStrip[]):PrintJpegOutput {\n const plan=parsePrintJpegInput(input);requireIdentity(plan);\n if(!Array.isArray(strips)||strips.length<1)throw new InvalidConfigurationError(\"Print JPEG assembly requires strips.\");\n const encoder=printEncoder(plan);\n try{\n let next=0;\n for(const strip of strips){\n if(strip.y!==next||strip.width!==plan.outputWidth||strip.quantizationStep!==plan.quantizationStep)throw new InvalidConfigurationError(\"Print JPEG strips must cover the plan's image in order.\");\n encoder.appendStrip(strip.bits);next+=strip.height;\n }\n if(next!==plan.outputHeight)throw new InvalidConfigurationError(\"Print JPEG strips must cover the plan's image in order.\");\n const bytes=encoder.finish();\n return {schemaVersion:PRINT_JPEG_SCHEMA_VERSION,input:plan,mediaType:\"image/jpeg\",bytes,iccProfileVersion:SRGB_ICC_PROFILE_VERSION,width:plan.outputWidth,height:plan.outputHeight,resampling:\"exact-area-average-in-decoded-linear-light\",sourceStage:\"post-SDR-8-bit-quantization\",digitalUpscalingApplied:false,sourceBytesVerified:false,providerReads:0,encoderId:EXPORT_JPEG_ENCODER_ID};\n }catch(error){encoder.dispose();throw error;}\n}\n/** Creates the export task. Filtering weights each source pixel by its exact area overlap, after decoding the declared 8-bit SDR source. */\nexport function createPrintJpegTask(input:PrintJpegInput,provider:PrintJpegProvider):PrintJpegTask {\n const plan=parsePrintJpegInput(input);\n if(!provider||typeof provider.readTile!==\"function\"||typeof provider.yieldControl!==\"function\")throw new InvalidConfigurationError(\"Print export requires source reader and host yields.\");\n const read=provider.readTile.bind(provider),yieldControl=provider.yieldControl.bind(provider),abort=new AbortController();\n let state:NativeRawTaskState=\"ready\",output:PrintJpegOutput|null=null,encoder:ReturnType<typeof createExportJpegEncoder>|undefined;\n function check():void{if(abort.signal.aborted)throw new InvalidConfigurationError(\"Print export aborted.\");}\n function release():void{encoder?.dispose();encoder=undefined;output?.bytes.fill(0);output=null;}\n return {get state():NativeRawTaskState{return state;},\n async run():Promise<void>{\n if(state!==\"ready\")throw new InvalidConfigurationError(\"Print export is single-use.\");state=\"running\";\n try{\n encoder=printEncoder(plan);\n const scaleX=plan.crop.width/plan.outputWidth,scaleY=plan.crop.height/plan.outputHeight,area=scaleX*scaleY;\n const cropRight=plan.crop.x+plan.crop.width,cropBottom=plan.crop.y+plan.crop.height,rowBytes=plan.crop.width*3;\n // Every crop pixel is read exactly once, in tiles of at most 256 x 32 aligned to the crop origin.\n const tilesPerBand=Math.ceil(plan.crop.width/256),requiredReads=Math.ceil(plan.crop.height/32)*tilesPerBand;\n if(requiredReads>plan.maximumProviderReads)throw new InvalidConfigurationError(\"Print source exceeds provider-read budget.\");\n // Rolling cache of whole crop-width source rows [cacheTop, cacheBottom): at most 63 rows are retained.\n const cache=new Uint8Array(Math.min(64,plan.crop.height)*rowBytes),lut=srgbDecodeTable();\n let reads=0,blocks=0,cacheTop=plan.crop.y,cacheBottom=plan.crop.y;\n const ensureRows=async(firstRow:number,rowCount:number):Promise<void>=>{\n const keepFrom=Math.min(Math.max(cacheTop,firstRow),cacheBottom);\n if(keepFrom>cacheTop){cache.copyWithin(0,(keepFrom-cacheTop)*rowBytes,(cacheBottom-cacheTop)*rowBytes);cacheTop=keepFrom;}\n while(cacheBottom<firstRow+rowCount){\n const bandHeight=Math.min(32,cropBottom-cacheBottom);\n if((cacheBottom+bandHeight-cacheTop)*rowBytes>cache.length)throw new InvalidConfigurationError(\"Print source traversal is not monotonic.\");\n for(let sx=plan.crop.x;sx<cropRight;sx+=256){\n check();++reads;\n const request=Object.freeze({source:plan.source,x:sx,y:cacheBottom,width:Math.min(256,cropRight-sx),height:bandHeight});\n const supplied=await read(request,abort.signal);check();\n const tile=requireAllowlistedRecord(supplied,[\"source\",\"x\",\"y\",\"width\",\"height\",\"samples\"],\"Invalid Print source tile.\");\n const source=requireAllowlistedRecord(tile.source,[\"captureId\",\"imageStateId\",\"artifactId\",\"sha256\",\"width\",\"height\",\"encoding\"],\"Invalid Print tile source.\");\n for(const key of Object.keys(plan.source) as (keyof PrintJpegSource)[])if(source[key]!==plan.source[key])throw new InvalidConfigurationError(\"Print source identity mismatch.\");\n for(const key of [\"x\",\"y\",\"width\",\"height\"] as const)if(tile[key]!==request[key])throw new InvalidConfigurationError(\"Print source rectangle mismatch.\");\n const samples=tile.samples;if(!(samples instanceof Uint8Array)||!(samples.buffer instanceof ArrayBuffer)||samples.length!==request.width*request.height*3||samples.buffer.byteLength!==samples.byteLength)throw new InvalidConfigurationError(\"Print source requires exact owned bounded RGB tile storage.\");\n for(let iy=0;iy<bandHeight;iy++)cache.set(samples.subarray(iy*request.width*3,(iy+1)*request.width*3),(cacheBottom-cacheTop+iy)*rowBytes+(sx-plan.crop.x)*3);\n // One output block can cover a megapixel of source, so also yield to the host while reading the source.\n if(reads%32===0){await yieldControl(abort.signal);check();}\n }\n cacheBottom+=bandHeight;\n }\n };\n // One block's 192 samples, reused for every block: each is an integer 0–255, written before the block is coded.\n const blocksX=Math.ceil(plan.outputWidth/8),sums=new Float64Array(blocksX*192),samples=new Uint8Array(192);\n // At 1:1 every output pixel is one source pixel with weight exactly 1, so its sum is exactly lut[code] and its\n // sample is a function of the code alone: the same bytes from a 256-entry table, without the accumulation.\n const identity=scaleX===1&&scaleY===1;\n const direct=identity?directCodes():undefined;\n if(direct)for(let by=0;by<plan.outputHeight;by+=8){\n check();\n const height=Math.min(8,plan.outputHeight-by);await ensureRows(plan.crop.y+by,height);check();\n for(let bx=0;bx<plan.outputWidth;bx+=8){\n const width=Math.min(8,plan.outputWidth-bx);\n for(let y=0,o=0;y<8;y++){\n const row=(plan.crop.y+by+Math.min(y,height-1)-cacheTop)*rowBytes+bx*3;\n for(let x=0;x<8;x++,o+=3){const index=row+Math.min(x,width-1)*3;samples[o]=direct[cache[index]!]!;samples[o+1]=direct[cache[index+1]!]!;samples[o+2]=direct[cache[index+2]!]!;}\n }\n check();encoder.writeRgbBlock(samples);if(++blocks%32===0){await yieldControl(abort.signal);check();}\n }\n }\n else for(let by=0;by<plan.outputHeight;by+=8){\n check();sums.fill(0);\n const height=Math.min(8,plan.outputHeight-by),top=plan.crop.y+by*scaleY,bottom=by+height===plan.outputHeight?cropBottom:plan.crop.y+(by+height)*scaleY;\n // Accumulation order per output pixel is unchanged from the per-block reader: 32-row bands from\n // floor(top), then 256-column chunks from floor(left), then rows, then columns. Identical IEEE sums.\n for(let sy=Math.floor(top);sy<Math.ceil(bottom);sy+=32){\n const bandHeight=Math.min(32,Math.ceil(bottom)-sy);await ensureRows(sy,bandHeight);check();\n for(let bx=0,block=0;bx<plan.outputWidth;bx+=8,block++){\n const width=Math.min(8,plan.outputWidth-bx),left=plan.crop.x+bx*scaleX,right=bx+width===plan.outputWidth?cropRight:plan.crop.x+(bx+width)*scaleX,base=block*192;\n for(let sx=Math.floor(left);sx<Math.ceil(right);sx+=256){\n const chunkWidth=Math.min(256,Math.ceil(right)-sx);\n for(let iy=0;iy<bandHeight;iy++)for(let ix=0;ix<chunkWidth;ix++){\n const px=sx+ix,py=sy+iy;\n const firstX=Math.max(0,Math.floor((px-plan.crop.x)/scaleX)-bx),lastX=Math.min(width-1,Math.ceil((px+1-plan.crop.x)/scaleX)-bx-1);\n const firstY=Math.max(0,Math.floor((py-plan.crop.y)/scaleY)-by),lastY=Math.min(height-1,Math.ceil((py+1-plan.crop.y)/scaleY)-by-1);\n const index=(py-cacheTop)*rowBytes+(px-plan.crop.x)*3,r=lut[cache[index]!]!,g=lut[cache[index+1]!]!,b=lut[cache[index+2]!]!;\n for(let oy=firstY;oy<=lastY;oy++)for(let ox=firstX;ox<=lastX;ox++){\n const x0=plan.crop.x+(bx+ox)*scaleX,y0=plan.crop.y+(by+oy)*scaleY;\n const weight=Math.max(0,Math.min(px+1,x0+scaleX)-Math.max(px,x0))*Math.max(0,Math.min(py+1,y0+scaleY)-Math.max(py,y0))/area;\n const i=base+(oy*8+ox)*3;sums[i]=sums[i]!+r*weight;sums[i+1]=sums[i+1]!+g*weight;sums[i+2]=sums[i+2]!+b*weight;\n }\n }\n }\n }\n }\n for(let bx=0,block=0;bx<plan.outputWidth;bx+=8,block++){\n const width=Math.min(8,plan.outputWidth-bx),base=block*192;\n for(let y=0,o=0;y<8;y++)for(let x=0;x<8;x++)for(let c=0;c<3;c++,o++){\n const value=sums[base+(Math.min(y,height-1)*8+Math.min(x,width-1))*3+c]!;\n // Nearest code, ties up. Math.round is used because floor(x+0.5) wrongly rounds 0.49999999999999994 up.\n samples[o]=Math.min(255,Math.max(0,Math.round(encodeSrgbComponent(value)*255)));\n }\n check();encoder.writeRgbBlock(samples);if(++blocks%32===0){await yieldControl(abort.signal);check();}\n }\n }\n await yieldControl(abort.signal);check();const bytes=encoder.finish();encoder=undefined;\n output={schemaVersion:PRINT_JPEG_SCHEMA_VERSION,input:plan,mediaType:\"image/jpeg\",bytes,iccProfileVersion:SRGB_ICC_PROFILE_VERSION,width:plan.outputWidth,height:plan.outputHeight,resampling:\"exact-area-average-in-decoded-linear-light\",sourceStage:\"post-SDR-8-bit-quantization\",digitalUpscalingApplied:false,sourceBytesVerified:false,providerReads:reads,encoderId:EXPORT_JPEG_ENCODER_ID};state=\"completed\";\n }catch(error){release();if(!abort.signal.aborted){state=\"failed\";abort.abort();}throw error;}\n },cancel():void{if(state===\"ready\"||state===\"running\"||state===\"completed\"){state=\"cancelled\";abort.abort();release();}},\n dispose():void{if(state!==\"transferred\"){state=\"disposed\";abort.abort();release();}},\n takeOutput():PrintJpegOutput{if(state!==\"completed\"||!output)throw new InvalidConfigurationError(\"Print JPEG unavailable.\");const value=output;output=null;state=\"transferred\";return value;}\n };\n}\n"]}
@@ -23,10 +23,30 @@ export declare function xmpTextMetadataPacket(metadata: Readonly<OutputTextMetad
23
23
  /**
24
24
  * Returns a copy of a baseline JPEG with the text fields added: merged into its XMP APP1 packet (or a new packet
25
25
  * after the last leading APPn segment when it has none), plus a COM segment for `comment`. Every other byte,
26
- * including the entropy-coded data, is unchanged. Reads marker segments only up to SOS.
26
+ * including the entropy-coded data, is unchanged. Reads marker segments only up to SOS. The engine's own
27
+ * `output.metadata` path calls this function, so for the same JPEG and text the bytes are the same.
28
+ *
29
+ * Root export (#388). `metadata` is checked as `output.metadata` is (see the module notes); a JPEG without SOI,
30
+ * a malformed or truncated segment before SOS, an XMP APP1 segment after a non-APPn segment, an XMP packet that is
31
+ * not UTF-8 or has no `rdf:RDF`, or text that makes the packet larger than one APP1 segment fails with
32
+ * `InvalidConfigurationError`. The input is not changed.
33
+ * @param jpeg A baseline JPEG stream, for example `createPrintJpegTask`'s or `composePrintJpegStrips`'s bytes.
34
+ * @param metadata The text: at least one of description, software, copyright and comment.
35
+ * @returns A new array holding the JPEG with the text.
27
36
  */
28
37
  export declare function addJpegTextMetadata(jpeg: Uint8Array, metadata: Readonly<OutputTextMetadata>): Uint8Array;
29
38
  /** The text chunks for the given fields, in the order description, software, copyright, comment. */
30
39
  export declare function pngTextMetadataChunks(metadata: Readonly<OutputTextMetadata>): Uint8Array[];
31
- /** Returns a copy of a PNG with one text chunk per field inserted before the first IDAT chunk. Other chunks are unchanged. */
40
+ /**
41
+ * Returns a copy of a PNG with one text chunk per field inserted before the first IDAT chunk. Other chunks are
42
+ * unchanged. The engine's own `output.metadata` path calls this function, so for the same PNG and text the bytes
43
+ * are the same.
44
+ *
45
+ * Root export (#388). `metadata` is checked as `output.metadata` is (see the module notes); a file without the PNG
46
+ * signature, or without an IDAT chunk inside its bytes, fails with `InvalidConfigurationError`. Chunk CRCs before
47
+ * IDAT are not checked. The input is not changed.
48
+ * @param png A PNG file, for example `serializePngImage`'s bytes.
49
+ * @param metadata The text: at least one of description, software, copyright and comment.
50
+ * @returns A new array holding the PNG with the text.
51
+ */
32
52
  export declare function addPngTextMetadata(png: Uint8Array, metadata: Readonly<OutputTextMetadata>): Uint8Array;
@@ -24,6 +24,9 @@
24
24
  * bytes, with no unpaired UTF-16 surrogate (so it encodes to valid UTF-8 without replacement), no NUL or other
25
25
  * C0/C1 control character except line feed, and no U+FFFE/U+FFFF (not XML 1.0 characters). Line breaks are a
26
26
  * single line feed, as the PNG text chunks require.
27
+ * Root exports (#388): `addJpegTextMetadata` and `addPngTextMetadata` add the text to a JPEG or PNG that the caller
28
+ * encoded (for example a file assembled from `output.region` parts and `composePrintJpegStrips` or `serializePngImage`),
29
+ * with the same bytes as `simulateCapture`'s `output.metadata`, which calls the same two functions.
27
30
  * @see docs/QUICK_START.md "Text metadata (2.4)".
28
31
  */
29
32
  import { InvalidConfigurationError } from "../core/configuration-error.js";
@@ -113,12 +116,30 @@ function startsWith(bytes, offset, prefix) {
113
116
  return false;
114
117
  return true;
115
118
  }
119
+ /** The checked metadata of a root writer: an object of the given fields, `metadata` in the messages. */
120
+ function requireTextMetadata(value, writer) {
121
+ if (value === undefined)
122
+ throw new InvalidConfigurationError(writer + " metadata must be an object.");
123
+ return parseOutputTextMetadata(value, writer + " metadata");
124
+ }
116
125
  /**
117
126
  * Returns a copy of a baseline JPEG with the text fields added: merged into its XMP APP1 packet (or a new packet
118
127
  * after the last leading APPn segment when it has none), plus a COM segment for `comment`. Every other byte,
119
- * including the entropy-coded data, is unchanged. Reads marker segments only up to SOS.
128
+ * including the entropy-coded data, is unchanged. Reads marker segments only up to SOS. The engine's own
129
+ * `output.metadata` path calls this function, so for the same JPEG and text the bytes are the same.
130
+ *
131
+ * Root export (#388). `metadata` is checked as `output.metadata` is (see the module notes); a JPEG without SOI,
132
+ * a malformed or truncated segment before SOS, an XMP APP1 segment after a non-APPn segment, an XMP packet that is
133
+ * not UTF-8 or has no `rdf:RDF`, or text that makes the packet larger than one APP1 segment fails with
134
+ * `InvalidConfigurationError`. The input is not changed.
135
+ * @param jpeg A baseline JPEG stream, for example `createPrintJpegTask`'s or `composePrintJpegStrips`'s bytes.
136
+ * @param metadata The text: at least one of description, software, copyright and comment.
137
+ * @returns A new array holding the JPEG with the text.
120
138
  */
121
139
  export function addJpegTextMetadata(jpeg, metadata) {
140
+ if (!(jpeg instanceof Uint8Array))
141
+ throw new InvalidConfigurationError("addJpegTextMetadata jpeg must be a Uint8Array.");
142
+ const text = requireTextMetadata(metadata, "addJpegTextMetadata");
122
143
  if (jpeg.length < 4 || jpeg[0] !== 0xff || jpeg[1] !== 0xd8)
123
144
  throw new InvalidConfigurationError("JPEG text metadata needs a JPEG stream starting with SOI.");
124
145
  const identifier = encoder.encode(XMP_IDENTIFIER);
@@ -129,32 +150,46 @@ export function addJpegTextMetadata(jpeg, metadata) {
129
150
  const marker = jpeg[offset + 1];
130
151
  if (marker === 0xda)
131
152
  break;
132
- const end = offset + 2 + ((jpeg[offset + 2] << 8) | jpeg[offset + 3]);
153
+ // Before SOS every marker has a length (T.81 B.1.1.4): SOI, EOI, RSTm, TEM and fill bytes there are malformed.
154
+ const length = (jpeg[offset + 2] << 8) | jpeg[offset + 3];
155
+ if (marker === 0xff || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd9) || length < 2)
156
+ throw new InvalidConfigurationError("JPEG text metadata found a malformed marker segment.");
157
+ const end = offset + 2 + length;
133
158
  if (end > jpeg.length)
134
159
  throw new InvalidConfigurationError("JPEG text metadata found a truncated marker segment.");
135
- if (marker === 0xe1 && !xmp && startsWith(jpeg, offset + 4, identifier))
160
+ if (marker === 0xe1 && !xmp && startsWith(jpeg, offset + 4, identifier)) {
161
+ // The packet is rewritten in place, so it must lie in the leading APPn run that the COM segment follows.
162
+ if (!inLeadingApps)
163
+ throw new InvalidConfigurationError("JPEG text metadata found an XMP APP1 segment after a non-APPn segment.");
136
164
  xmp = { start: offset, end };
165
+ }
137
166
  if (inLeadingApps && marker >= 0xe0 && marker <= 0xef)
138
167
  appEnd = end;
139
168
  else
140
169
  inLeadingApps = false;
141
170
  offset = end;
142
171
  }
143
- const description = xmpTextMetadataDescription(metadata);
172
+ const description = xmpTextMetadataDescription(text);
144
173
  let xmpPacket;
145
174
  if (xmp) {
146
- const packet = new TextDecoder("utf-8", { fatal: true }).decode(jpeg.subarray(xmp.start + 4 + identifier.length, xmp.end));
175
+ let packet;
176
+ try {
177
+ packet = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(jpeg.subarray(xmp.start + 4 + identifier.length, xmp.end));
178
+ }
179
+ catch {
180
+ throw new InvalidConfigurationError("JPEG text metadata found an XMP packet that is not valid UTF-8.");
181
+ }
147
182
  const close = packet.lastIndexOf("</rdf:RDF>");
148
183
  if (close < 0)
149
184
  throw new InvalidConfigurationError("JPEG text metadata found an XMP packet without rdf:RDF.");
150
185
  xmpPacket = encoder.encode(packet.slice(0, close) + description + packet.slice(close));
151
186
  }
152
187
  else
153
- xmpPacket = xmpTextMetadataPacket(metadata);
188
+ xmpPacket = xmpTextMetadataPacket(text);
154
189
  if (xmpPacket.length > JPEG_XMP_MAXIMUM_PACKET_BYTES)
155
190
  throw new InvalidConfigurationError("The text metadata makes the JPEG XMP packet " + xmpPacket.length + " bytes; one APP1 segment holds at most " + JPEG_XMP_MAXIMUM_PACKET_BYTES + ".");
156
191
  const xmpSegment = segment(0xe1, concat([identifier, xmpPacket]));
157
- const com = metadata.comment === undefined ? new Uint8Array(0) : segment(0xfe, encoder.encode(metadata.comment));
192
+ const com = text.comment === undefined ? new Uint8Array(0) : segment(0xfe, encoder.encode(text.comment));
158
193
  if (xmp)
159
194
  return concat([jpeg.subarray(0, xmp.start), xmpSegment, jpeg.subarray(xmp.end, appEnd), com, jpeg.subarray(appEnd)]);
160
195
  return concat([jpeg.subarray(0, appEnd), xmpSegment, com, jpeg.subarray(appEnd)]);
@@ -184,8 +219,22 @@ export function pngTextMetadataChunks(metadata) {
184
219
  : pngChunk("iTXt", concat([keyword, Uint8Array.of(0, 0, 0, 0, 0), encoder.encode(text)]));
185
220
  });
186
221
  }
187
- /** Returns a copy of a PNG with one text chunk per field inserted before the first IDAT chunk. Other chunks are unchanged. */
222
+ /**
223
+ * Returns a copy of a PNG with one text chunk per field inserted before the first IDAT chunk. Other chunks are
224
+ * unchanged. The engine's own `output.metadata` path calls this function, so for the same PNG and text the bytes
225
+ * are the same.
226
+ *
227
+ * Root export (#388). `metadata` is checked as `output.metadata` is (see the module notes); a file without the PNG
228
+ * signature, or without an IDAT chunk inside its bytes, fails with `InvalidConfigurationError`. Chunk CRCs before
229
+ * IDAT are not checked. The input is not changed.
230
+ * @param png A PNG file, for example `serializePngImage`'s bytes.
231
+ * @param metadata The text: at least one of description, software, copyright and comment.
232
+ * @returns A new array holding the PNG with the text.
233
+ */
188
234
  export function addPngTextMetadata(png, metadata) {
235
+ if (!(png instanceof Uint8Array))
236
+ throw new InvalidConfigurationError("addPngTextMetadata png must be a Uint8Array.");
237
+ const text = requireTextMetadata(metadata, "addPngTextMetadata");
189
238
  const signature = [137, 80, 78, 71, 13, 10, 26, 10];
190
239
  if (png.length < 8 || signature.some((b, i) => png[i] !== b))
191
240
  throw new InvalidConfigurationError("PNG text metadata needs a PNG signature.");
@@ -193,7 +242,7 @@ export function addPngTextMetadata(png, metadata) {
193
242
  for (let offset = 8; offset + 12 <= png.length;) {
194
243
  const length = view.getUint32(offset), type = String.fromCharCode(...png.subarray(offset + 4, offset + 8));
195
244
  if (type === "IDAT")
196
- return concat([png.subarray(0, offset), ...pngTextMetadataChunks(metadata), png.subarray(offset)]);
245
+ return concat([png.subarray(0, offset), ...pngTextMetadataChunks(text), png.subarray(offset)]);
197
246
  offset += 12 + length;
198
247
  }
199
248
  throw new InvalidConfigurationError("PNG text metadata found no IDAT chunk.");