@realsee/hdr-toolbox 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/avif.js ADDED
@@ -0,0 +1,206 @@
1
+ /**
2
+ * AVIF reading and writing for HDR content.
3
+ *
4
+ * Two AVIF forms are supported:
5
+ * - gain map AVIF: an 8-bit SDR base, an 8-bit gain map and an ISO 21496-1
6
+ * `tmap` item that references both (`dimg`, base first, gain map second).
7
+ * - 10-bit HDR AVIF: one `av01` image in PQ or HLG (BT.2020), read as linear light.
8
+ *
9
+ * Plain 8-bit AVIF is not HDR, so it is rejected here. Tiled (`grid`) items are
10
+ * rejected too.
11
+ */
12
+ import { decodeAvif, encodeAvif10, encodeAvif8, subsample420, subsample444, } from "./avif-codec.js";
13
+ import { colrBox, itemBitDepth, itemColourInfo, itemPayload, itemPropertyBytes, parseAvif, writeAvifContainer, } from "./avif-container.js";
14
+ import { parseTmapMetadata, serializeTmapMetadata } from "./avif-gainmap.js";
15
+ import { CICP_MATRIX_BT601, CICP_PRIMARIES_BT2020, CICP_PRIMARIES_BT709, CICP_TRANSFER_HLG, CICP_TRANSFER_PQ, CICP_TRANSFER_SRGB, codeValuesToLinear, linearToPqCodes, } from "./hdr-transfer.js";
16
+ import { normalizeGainMapConfig } from "./xmp.js";
17
+ /** Default lossy quality for AVIF output (0-100). */
18
+ export const defaultAvifQuality = 90;
19
+ function findGainMapItems(parsed) {
20
+ const tmap = [...parsed.items.values()].find((item) => item.type === "tmap");
21
+ if (!tmap)
22
+ return undefined;
23
+ const reference = parsed.references.find((entry) => entry.type === "dimg" && entry.from === tmap.id);
24
+ if (!reference || reference.to.length < 2)
25
+ return undefined;
26
+ const base = parsed.items.get(reference.to[0]);
27
+ const gain = parsed.items.get(reference.to[1]);
28
+ if (!base || !gain)
29
+ throw new Error("tmap item references a missing image item.");
30
+ return { tmap, base, gain };
31
+ }
32
+ function requireAv1Item(item) {
33
+ if (item.type !== "av01")
34
+ throw new Error(`Unsupported AVIF item type "${item.type}" (only av01 image items are supported; tiled AVIF is not).`);
35
+ }
36
+ /**
37
+ * Decode one `av01` item at `bitDepth`. The item is repackaged as a standalone
38
+ * AVIF around its AV1 payload and its codec properties, so the decoder sees the
39
+ * same codec configuration and colour information as the original file.
40
+ */
41
+ function standaloneItem(parsed, item) {
42
+ requireAv1Item(item);
43
+ const properties = ["av1C", "ispe", "pixi", "colr"]
44
+ .map((type) => itemPropertyBytes(parsed, item, type))
45
+ .filter((box) => box !== undefined);
46
+ return writeAvifContainer({
47
+ primaryItemId: 1,
48
+ items: [{ id: 1, type: "av01", payload: itemPayload(parsed, item), properties }],
49
+ });
50
+ }
51
+ async function decodeItem8(parsed, item) {
52
+ return decodeAvif(standaloneItem(parsed, item), 8);
53
+ }
54
+ async function decodeItemCodes(parsed, item, bitDepth) {
55
+ return decodeAvif(standaloneItem(parsed, item), bitDepth);
56
+ }
57
+ function rgbaToRgb(pixels) {
58
+ const pixelCount = pixels.width * pixels.height;
59
+ const data = Buffer.alloc(pixelCount * 3);
60
+ for (let pixel = 0; pixel < pixelCount; pixel++) {
61
+ data[pixel * 3] = pixels.data[pixel * 4];
62
+ data[pixel * 3 + 1] = pixels.data[pixel * 4 + 1];
63
+ data[pixel * 3 + 2] = pixels.data[pixel * 4 + 2];
64
+ }
65
+ return { width: pixels.width, height: pixels.height, data };
66
+ }
67
+ function rgbToRgba(image) {
68
+ const pixelCount = image.width * image.height;
69
+ const data = new Uint8ClampedArray(pixelCount * 4);
70
+ for (let pixel = 0; pixel < pixelCount; pixel++) {
71
+ data[pixel * 4] = image.data[pixel * 3];
72
+ data[pixel * 4 + 1] = image.data[pixel * 3 + 1];
73
+ data[pixel * 4 + 2] = image.data[pixel * 3 + 2];
74
+ data[pixel * 4 + 3] = 255;
75
+ }
76
+ return { width: image.width, height: image.height, data };
77
+ }
78
+ /** Read an AVIF file as either a gain map pair or linear HDR, whichever it is. */
79
+ export async function readAvif(buffer) {
80
+ const parsed = parseAvif(buffer);
81
+ const gainMap = findGainMapItems(parsed);
82
+ if (gainMap) {
83
+ const [sdr, gain] = await Promise.all([
84
+ decodeItem8(parsed, gainMap.base),
85
+ decodeItem8(parsed, gainMap.gain),
86
+ ]);
87
+ const config = normalizeGainMapConfig(parseTmapMetadata(itemPayload(parsed, gainMap.tmap)));
88
+ return {
89
+ kind: "gainmap",
90
+ pair: { sdr: rgbaToRgb(sdr), gain: rgbaToRgb(gain), config },
91
+ };
92
+ }
93
+ const primaryId = parsed.primaryItemId;
94
+ const primary = primaryId === undefined ? undefined : parsed.items.get(primaryId);
95
+ if (!primary)
96
+ throw new Error("AVIF file has no primary image item.");
97
+ requireAv1Item(primary);
98
+ const depth = itemBitDepth(parsed, primary) ?? 8;
99
+ if (depth <= 8)
100
+ throw new Error("AVIF is 8-bit SDR and has no gain map, so it holds no HDR data. Use a 10-bit PQ/HLG AVIF or a gain map AVIF.");
101
+ if (depth !== 10 && depth !== 12)
102
+ throw new Error(`Unsupported AVIF bit depth ${depth} (only 10 and 12 bits are supported).`);
103
+ const colour = itemColourInfo(parsed, primary);
104
+ if (!colour)
105
+ throw new Error("AVIF has no CICP colour information, so its HDR transfer is unknown.");
106
+ if (colour.transfer !== CICP_TRANSFER_PQ && colour.transfer !== CICP_TRANSFER_HLG)
107
+ throw new Error(`Unsupported AVIF transfer characteristic ${colour.transfer} (only PQ and HLG are supported).`);
108
+ if (colour.primaries !== CICP_PRIMARIES_BT709 && colour.primaries !== CICP_PRIMARIES_BT2020)
109
+ throw new Error(`Unsupported AVIF colour primaries ${colour.primaries} (only BT.709 and BT.2020 are supported).`);
110
+ const decoded = await decodeItemCodes(parsed, primary, depth);
111
+ if (decoded.depth !== depth)
112
+ throw new Error("AVIF decoder returned an unexpected bit depth.");
113
+ const linear = codeValuesToLinear(decoded.data, decoded.width, decoded.height, depth, colour.transfer, colour.primaries);
114
+ return { kind: "hdr10", image: linear };
115
+ }
116
+ /** Pull the AV1 payload and codec properties out of an encoded AVIF file. */
117
+ function encodedImageParts(encoded) {
118
+ const parsed = parseAvif(encoded);
119
+ const item = parsed.primaryItemId === undefined ? undefined : parsed.items.get(parsed.primaryItemId);
120
+ if (!item)
121
+ throw new Error("Encoder produced no primary image item.");
122
+ const properties = ["av1C", "ispe", "pixi"]
123
+ .map((type) => itemPropertyBytes(parsed, item, type))
124
+ .filter((box) => box !== undefined);
125
+ if (!properties.some((box) => box.toString("latin1", 4, 8) === "av1C"))
126
+ throw new Error("Encoder produced an AVIF without an av1C property.");
127
+ return {
128
+ payload: itemPayload(parsed, item),
129
+ properties: properties.map((box) => Buffer.from(box)),
130
+ };
131
+ }
132
+ /**
133
+ * Colour tag for the 8-bit sRGB base and gain map. jsquash does not expose
134
+ * CICP, and its YUV conversion uses BT.601 (matrix 6), so the tag says 6 to
135
+ * match the bitstream.
136
+ */
137
+ const srgbColour = {
138
+ primaries: CICP_PRIMARIES_BT709,
139
+ transfer: CICP_TRANSFER_SRGB,
140
+ matrix: CICP_MATRIX_BT601,
141
+ fullRange: true,
142
+ };
143
+ /** Encode a gain map pair as a gain map AVIF (ISO 21496-1 `tmap`). */
144
+ export async function encodeAvifGainMap(pair, options = {}) {
145
+ const quality = options.quality ?? defaultAvifQuality;
146
+ const config = normalizeGainMapConfig(pair.config);
147
+ const [base, gain] = await Promise.all([
148
+ encodeAvif8(rgbToRgba(pair.sdr), { quality, subsample: subsample420 }),
149
+ encodeAvif8(rgbToRgba(pair.gain), { quality, subsample: subsample444 }),
150
+ ]);
151
+ const baseParts = encodedImageParts(base);
152
+ const gainParts = encodedImageParts(gain);
153
+ const colr = colrBox(srgbColour);
154
+ const baseSize = baseParts.properties.find((box) => box.toString("latin1", 4, 8) === "ispe");
155
+ const basePixelInfo = baseParts.properties.find((box) => box.toString("latin1", 4, 8) === "pixi");
156
+ return writeAvifContainer({
157
+ primaryItemId: 1,
158
+ items: [
159
+ {
160
+ id: 1,
161
+ type: "av01",
162
+ payload: baseParts.payload,
163
+ properties: [...baseParts.properties, colr],
164
+ },
165
+ {
166
+ id: 2,
167
+ type: "tmap",
168
+ payload: serializeTmapMetadata(config),
169
+ properties: [baseSize, basePixelInfo, colr].filter((box) => box !== undefined),
170
+ },
171
+ {
172
+ id: 3,
173
+ type: "av01",
174
+ payload: gainParts.payload,
175
+ properties: [...gainParts.properties, colr],
176
+ },
177
+ ],
178
+ references: [{ type: "dimg", from: 2, to: [1, 3] }],
179
+ alternatives: [{ entities: [2, 1] }],
180
+ });
181
+ }
182
+ /**
183
+ * Encode linear HDR as a 10-bit PQ AVIF (BT.2020 primaries, full range, 4:2:0).
184
+ * Values above 10000 nits are clipped; SDR white (linear 1) is 203 nits. The
185
+ * 10-bit 4:4:4 encoder fails above about 30 megapixels (7680x3840 encodes,
186
+ * 8000x4000 does not), so 4:2:0 is used at every size.
187
+ */
188
+ export async function encodeAvifHdr10(image, options = {}) {
189
+ const quality = options.quality ?? defaultAvifQuality;
190
+ const codes = linearToPqCodes({ width: image.width, height: image.height, data: image.data }, 10);
191
+ const encoded = await encodeAvif10({ width: image.width, height: image.height, data: codes, depth: 10 }, { quality, subsample: subsample420 });
192
+ const parts = encodedImageParts(encoded);
193
+ const colr = colrBox({
194
+ primaries: CICP_PRIMARIES_BT2020,
195
+ transfer: CICP_TRANSFER_PQ,
196
+ matrix: CICP_MATRIX_BT601,
197
+ fullRange: true,
198
+ });
199
+ return writeAvifContainer({
200
+ primaryItemId: 1,
201
+ items: [
202
+ { id: 1, type: "av01", payload: parts.payload, properties: [...parts.properties, colr] },
203
+ ],
204
+ });
205
+ }
206
+ //# sourceMappingURL=avif.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avif.js","sourceRoot":"","sources":["../src/avif.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,aAAa,IAAI,OAAO,CAkJvC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,aAAa,IAAI,OAAO,CAiJvC"}
package/dist/cli.js CHANGED
@@ -2,19 +2,15 @@
2
2
  import { Command } from "commander";
3
3
  import { realpathSync } from "node:fs";
4
4
  import { pathToFileURL } from "node:url";
5
- import { linearHdrToUltraHdr, ultraHdrToLinearHdr } from "./convert.js";
5
+ import { convertHdrImage } from "./convert.js";
6
6
  import { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
7
7
  import { composeUltraHdr, extractUltraHdr } from "./ultrahdr.js";
8
- /** Linear HDR float containers accepted on one side of `convert`. */
9
- function isLinearHdrPath(path) {
10
- return /\.(exr|hdr|pic)$/i.test(path);
11
- }
12
8
  export function createProgram() {
13
9
  const program = new Command();
14
10
  program
15
11
  .name("hdr-toolbox")
16
12
  .description("Compose, extract, and convert Android Ultra HDR JPEG images")
17
- .version("1.1.3");
13
+ .version("1.1.4");
18
14
  program
19
15
  .command("compose")
20
16
  .description("Compose an SDR image, gain map image (avif/png/jpg/jpeg), and JSON/XMP config into Ultra HDR")
@@ -75,38 +71,37 @@ export function createProgram() {
75
71
  });
76
72
  program
77
73
  .command("convert")
78
- .description("Convert between a linear HDR file (.exr or .hdr) and an Ultra HDR JPEG (direction inferred from extensions)")
79
- .requiredOption("-i, --input <path>", "input image (.exr, .hdr, or Ultra HDR .jpg/.jpeg)")
80
- .requiredOption("-o, --output <path>", "output image (.exr, .hdr, or Ultra HDR .jpg/.jpeg)")
81
- .option("--max-content-boost <ratio>", "HDR→Ultra HDR: linear HDR headroom to encode")
82
- .option("--sdr-quality <quality>", "HDR→Ultra HDR: SDR base JPEG quality (1-100)")
83
- .option("--gainmap-quality <quality>", "HDR→Ultra HDR: gain map JPEG quality (1-100)")
84
- .option("--tone-map <operator>", "HDR→Ultra HDR: SDR tone map (fusion | aces | agx | reinhard; default fusion)")
85
- .option("--ev-step <stops>", "HDR→Ultra HDR: exposure-fusion EV spacing (default 2)")
86
- .option("--exposure-count <n>", "HDR→Ultra HDR: exposure-fusion exposure count, odd (default 5)")
74
+ .description("Convert between linear HDR (.exr, .hdr), Ultra HDR (.jpg, .jpeg) and AVIF (.avif); formats come from the extensions")
75
+ .requiredOption("-i, --input <path>", "input image (.exr, .hdr, .jpg, .jpeg or .avif)")
76
+ .requiredOption("-o, --output <path>", "output image (.exr, .hdr, .jpg, .jpeg or .avif)")
77
+ .option("--max-content-boost <ratio>", "HDR to gain map: linear HDR headroom to encode")
78
+ .option("--sdr-quality <quality>", "HDR to Ultra HDR: SDR base JPEG quality (1-100)")
79
+ .option("--gainmap-quality <quality>", "HDR to Ultra HDR: gain map JPEG quality (1-100)")
80
+ .option("--tone-map <operator>", "HDR to gain map: SDR tone map (fusion | aces | agx | reinhard; default fusion)")
81
+ .option("--ev-step <stops>", "HDR to gain map: exposure-fusion EV spacing (default 2)")
82
+ .option("--exposure-count <n>", "HDR to gain map: exposure-fusion exposure count, odd (default 5)")
83
+ .option("--avif-mode <mode>", "AVIF output: gainmap (SDR base + gain map, default) | hdr10 (10-bit PQ)")
84
+ .option("--avif-quality <quality>", "AVIF output: lossy quality (0-100, default 90)")
87
85
  .action(async (options) => {
88
- const inputIsLinearHdr = isLinearHdrPath(options.input);
89
- const outputIsLinearHdr = isLinearHdrPath(options.output);
90
- if (inputIsLinearHdr === outputIsLinearHdr)
91
- throw new Error("convert needs exactly one linear HDR side: use a .exr/.hdr input with an Ultra HDR JPEG output, or vice versa.");
92
- if (inputIsLinearHdr) {
93
- if (options.toneMap !== undefined &&
94
- !["fusion", "aces", "agx", "reinhard"].includes(options.toneMap))
95
- throw new Error(`Unsupported tone map "${options.toneMap}". Use "fusion", "aces", "agx" or "reinhard".`);
96
- await linearHdrToUltraHdr({
97
- input: options.input,
98
- output: options.output,
99
- maxContentBoost: options.maxContentBoost === undefined ? undefined : Number(options.maxContentBoost),
100
- sdrQuality: options.sdrQuality === undefined ? undefined : Number(options.sdrQuality),
101
- gainMapQuality: options.gainmapQuality === undefined ? undefined : Number(options.gainmapQuality),
102
- toneMap: options.toneMap,
103
- evStep: options.evStep === undefined ? undefined : Number(options.evStep),
104
- exposureCount: options.exposureCount === undefined ? undefined : Number(options.exposureCount),
105
- });
106
- }
107
- else {
108
- await ultraHdrToLinearHdr({ input: options.input, output: options.output });
109
- }
86
+ const toneMaps = ["fusion", "aces", "agx", "reinhard"];
87
+ if (options.toneMap !== undefined && !toneMaps.includes(options.toneMap))
88
+ throw new Error(`Unsupported tone map "${options.toneMap}". Use "fusion", "aces", "agx" or "reinhard".`);
89
+ const avifModes = ["gainmap", "hdr10"];
90
+ if (options.avifMode !== undefined && !avifModes.includes(options.avifMode))
91
+ throw new Error(`Unsupported AVIF mode "${options.avifMode}". Use "gainmap" or "hdr10".`);
92
+ const optionalNumber = (value) => value === undefined ? undefined : Number(value);
93
+ await convertHdrImage({
94
+ input: options.input,
95
+ output: options.output,
96
+ maxContentBoost: optionalNumber(options.maxContentBoost),
97
+ sdrQuality: optionalNumber(options.sdrQuality),
98
+ gainMapQuality: optionalNumber(options.gainmapQuality),
99
+ toneMap: options.toneMap,
100
+ evStep: optionalNumber(options.evStep),
101
+ exposureCount: optionalNumber(options.exposureCount),
102
+ avifMode: options.avifMode,
103
+ avifQuality: optionalNumber(options.avifQuality),
104
+ });
110
105
  });
111
106
  return program;
112
107
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/convert.d.ts CHANGED
@@ -1,5 +1,14 @@
1
- /** Linear HDR float container formats that `convert` reads and writes. */
1
+ /** Linear HDR float container formats: OpenEXR and Radiance HDR. */
2
2
  export type LinearHdrFormat = "exr" | "hdr";
3
+ /** Container families that `convert` reads and writes. */
4
+ export type ContainerKind = "linear" | "ultrahdr" | "avif";
5
+ /**
6
+ * AVIF output form.
7
+ * - `"gainmap"` (default): 8-bit SDR base and gain map with an ISO 21496-1 `tmap`.
8
+ * Viewers without gain-map support show the SDR base.
9
+ * - `"hdr10"`: one 10-bit PQ (BT.2020) image. Has no SDR fallback.
10
+ */
11
+ export type AvifMode = "gainmap" | "hdr10";
3
12
  /**
4
13
  * SDR tone-mapping operator for the Ultra HDR base image.
5
14
  * - `"fusion"` (default): exposure-fusion local tone map; keeps shadow and
@@ -9,29 +18,34 @@ export type LinearHdrFormat = "exr" | "hdr";
9
18
  * - `"reinhard"`: cheap global Reinhard curve.
10
19
  */
11
20
  export type ToneMapOperator = "fusion" | "aces" | "agx" | "reinhard";
12
- export interface UltraHdrToLinearHdrOptions {
21
+ export interface ConvertOptions {
13
22
  input: string;
14
23
  output: string;
15
24
  /** Linear HDR output format; defaults to the output path extension. */
16
25
  format?: LinearHdrFormat;
17
- }
18
- export interface LinearHdrToUltraHdrOptions {
19
- input: string;
20
- output: string;
21
- /** Linear HDR input format; defaults to the input path extension. */
22
- format?: LinearHdrFormat;
26
+ /** Linear HDR input format when the input is EXR or HDR; defaults to the input extension. */
27
+ inputFormat?: LinearHdrFormat;
28
+ /** Linear ratio of HDR headroom to encode (max_content_boost, default auto). */
29
+ maxContentBoost?: number;
23
30
  /** JPEG quality for the generated SDR base image (1-100, default 95). */
24
31
  sdrQuality?: number;
25
32
  /** JPEG quality for the generated gain map image (1-100, default 95). */
26
33
  gainMapQuality?: number;
27
- /** Linear ratio of HDR headroom to encode (max_content_boost, default auto). */
28
- maxContentBoost?: number;
29
34
  /** SDR tone-mapping operator (default "fusion"). */
30
35
  toneMap?: ToneMapOperator;
31
36
  /** Exposure fusion: spacing between synthetic exposures in stops (default 2). */
32
37
  evStep?: number;
33
38
  /** Exposure fusion: number of synthetic exposures, odd (default 5). */
34
39
  exposureCount?: number;
40
+ /** AVIF output form (default "gainmap"). */
41
+ avifMode?: AvifMode;
42
+ /** AVIF lossy quality, 0-100 (default 90). */
43
+ avifQuality?: number;
44
+ }
45
+ export type UltraHdrToLinearHdrOptions = Pick<ConvertOptions, "input" | "output" | "format">;
46
+ /** Linear HDR input (EXR or HDR) to Ultra HDR. `format` is the input format. */
47
+ export interface LinearHdrToUltraHdrOptions extends Pick<ConvertOptions, "input" | "output" | "sdrQuality" | "gainMapQuality" | "maxContentBoost" | "toneMap" | "evStep" | "exposureCount"> {
48
+ format?: LinearHdrFormat;
35
49
  }
36
50
  /** Back-compat alias for {@link UltraHdrToLinearHdrOptions}. */
37
51
  export type UltraHdrToExrOptions = UltraHdrToLinearHdrOptions;
@@ -39,16 +53,21 @@ export type UltraHdrToExrOptions = UltraHdrToLinearHdrOptions;
39
53
  export type ExrToUltraHdrOptions = LinearHdrToUltraHdrOptions;
40
54
  /** Resolves a linear HDR format from an explicit option, then the path extension. */
41
55
  export declare function resolveLinearHdrFormat(explicit: LinearHdrFormat | undefined, path: string): LinearHdrFormat;
56
+ /** Resolves the container family from the file extension. */
57
+ export declare function resolveContainerKind(path: string): ContainerKind;
42
58
  /**
43
- * Reconstructs a linear-light HDR image from an Ultra HDR JPEG and writes it as
44
- * a linear float EXR or Radiance HDR file (chosen by the output extension).
59
+ * Converts between linear HDR (EXR, Radiance HDR), Ultra HDR JPEG and AVIF. The
60
+ * input and output formats come from their extensions.
45
61
  *
46
- * Applies the Adobe/Android gain map recovery per channel:
47
- * logBoost = lerp(log2(min), log2(max), gain^(1/gamma))
48
- * hdr = (sdr_linear + offsetSdr) * 2^logBoost - offsetHdr
49
- * at full display headroom (weight = 1), so the output captures the complete HDR
50
- * intent rather than a headroom-limited rendition.
62
+ * - Linear HDR input is tone-mapped into an SDR base and gain map when the
63
+ * output needs one. The tone-map options apply to that step.
64
+ * - Gain map input (Ultra HDR JPEG or gain map AVIF) is reconstructed to linear
65
+ * light for linear output. For 10-bit PQ AVIF output it is limited to the PQ
66
+ * peak. For Ultra HDR and gain map AVIF output it is passed through.
67
+ * - 10-bit PQ AVIF input is decoded to linear light.
51
68
  */
69
+ export declare function convertHdrImage(options: ConvertOptions): Promise<void>;
70
+ /** Reconstructs a linear-light HDR image from an Ultra HDR JPEG at full headroom. */
52
71
  export declare function ultraHdrToLinearHdr(options: UltraHdrToLinearHdrOptions): Promise<void>;
53
72
  /**
54
73
  * Builds an Ultra HDR JPEG from a linear float EXR or Radiance HDR file (chosen
@@ -1 +1 @@
1
- {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAWA,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;AAErE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oDAAoD;IACpD,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,gEAAgE;AAChE,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAC9D,gEAAgE;AAChE,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAE9D,qFAAqF;AACrF,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,IAAI,EAAE,MAAM,GACX,eAAe,CAQjB;AAwBD;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC5F;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAuE5F;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,4BAAsB,CAAC;AACjD,+EAA+E;AAC/E,eAAO,MAAM,aAAa,4BAAsB,CAAC"}
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAmBA,oEAAoE;AACpE,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5C,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,6FAA6F;IAC7F,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAE7F,gFAAgF;AAChF,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CACtD,cAAc,EACZ,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,gBAAgB,GAChB,iBAAiB,GACjB,SAAS,GACT,QAAQ,GACR,eAAe,CAClB;IACC,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,gEAAgE;AAChE,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAC9D,gEAAgE;AAChE,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAE9D,qFAAqF;AACrF,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,IAAI,EAAE,MAAM,GACX,eAAe,CAQjB;AAED,6DAA6D;AAC7D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAQhE;AA+ND;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAc5E;AAED,qFAAqF;AACrF,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5F;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,4BAAsB,CAAC;AACjD,+EAA+E;AAC/E,eAAO,MAAM,aAAa,4BAAsB,CAAC"}