@realsee/hdr-toolbox 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +32 -1
- package/dist/cli.js.map +1 -1
- package/dist/convert.d.ts +49 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +174 -0
- package/dist/convert.js.map +1 -0
- package/dist/exr.d.ts +26 -0
- package/dist/exr.d.ts.map +1 -0
- package/dist/exr.js +291 -0
- package/dist/exr.js.map +1 -0
- package/dist/hdr.d.ts +6 -0
- package/dist/hdr.d.ts.map +1 -0
- package/dist/hdr.js +263 -0
- package/dist/hdr.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,7 +87,38 @@ hdr-toolbox cube-to-equirect \
|
|
|
87
87
|
|
|
88
88
|
SDR 文件名为 `<prefix>_[r,l,u,d,f,b].jpg`。gain map 同时兼容 `<prefix>_<face>_gainmap.jpg` 和示例里的 `<prefix>_<face>.gainmap.jpg`。配置自动读取输入目录下的 `<prefix>_gainmap_cfg.json`(找不到时回退 `<prefix>_gainmap_cfg.xmp`)。六面必须是同尺寸、正方形且边长为 2 的幂。输出尺寸是面宽的 4×2 倍。
|
|
89
89
|
|
|
90
|
-
### 4.
|
|
90
|
+
### 4. 线性 HDR(EXR / Radiance HDR)↔ Ultra HDR
|
|
91
|
+
|
|
92
|
+
`convert` 在线性浮点 HDR 文件和 Ultra HDR JPEG 之间互转,方向由输入/输出扩展名推断:一侧是线性 HDR(`.exr` 或 `.hdr`/`.pic`),另一侧是 Ultra HDR(`.jpg`/`.jpeg`)。
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Ultra HDR → EXR:按增益图重建线性 HDR,写成 32-bit float EXR
|
|
96
|
+
hdr-toolbox convert --input examples/ultra-hdr.jpg --output output/ultra-hdr.exr
|
|
97
|
+
|
|
98
|
+
# Ultra HDR → Radiance HDR:同样的重建,写成 RGBE 编码的 .hdr(体积更小)
|
|
99
|
+
hdr-toolbox convert --input examples/ultra-hdr.jpg --output output/ultra-hdr.hdr
|
|
100
|
+
|
|
101
|
+
# EXR / HDR → Ultra HDR:色调映射出 SDR 基图,反算增益图,封装成 Ultra HDR
|
|
102
|
+
hdr-toolbox convert --input output/ultra-hdr.exr --output output/from-exr.uhdr.jpg
|
|
103
|
+
hdr-toolbox convert --input output/ultra-hdr.hdr --output output/from-hdr.uhdr.jpg
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
支持两种线性 HDR 容器:
|
|
107
|
+
|
|
108
|
+
- **EXR**(OpenEXR):读取支持 HALF/FLOAT 通道、NO_COMPRESSION 与 ZIP/ZIPS 压缩;写入固定为单层、未压缩的 scanline FLOAT RGB,任意 EXR 读取器都能打开。
|
|
109
|
+
- **Radiance HDR**(RGBE,`.hdr`/`.pic`):读取支持 flat、旧式与新式 RLE 编码;写入新式 RLE。RGBE 的共享指数带来 ~0.4% 的量化,但体积明显小于未压缩 EXR。
|
|
110
|
+
|
|
111
|
+
`Ultra HDR → 线性 HDR` 按 Adobe/Android 增益图恢复公式逐像素重建,在满显示余量(weight = 1)下还原完整 HDR 意图:`hdr = (sdr_linear + offset_sdr) * 2^lerp(log2(min), log2(max), gain^(1/gamma)) - offset_hdr`。
|
|
112
|
+
|
|
113
|
+
`线性 HDR → Ultra HDR` 用 Reinhard 曲线把线性 HDR 压成 SDR 基图,再把 `HDR/SDR` 比值编码成增益图。可选项(仅此方向生效):
|
|
114
|
+
|
|
115
|
+
| 选项 | 说明 |
|
|
116
|
+
| --------------------- | ----------------------------------------------- |
|
|
117
|
+
| `--max-content-boost` | 要编码的线性 HDR 余量,默认取输入中的最大线性值 |
|
|
118
|
+
| `--sdr-quality` | SDR 基图 JPEG 质量(1-100,默认 95) |
|
|
119
|
+
| `--gainmap-quality` | 增益图 JPEG 质量(1-100,默认 95) |
|
|
120
|
+
|
|
121
|
+
### 5. equirect Ultra HDR → cubemap
|
|
91
122
|
|
|
92
123
|
```bash
|
|
93
124
|
hdr-toolbox equirect-to-cube \
|
|
@@ -118,6 +149,23 @@ await extractUltraHdr({
|
|
|
118
149
|
});
|
|
119
150
|
```
|
|
120
151
|
|
|
152
|
+
线性 HDR 互转(EXR / Radiance HDR,方向中立的函数名;旧的 `exrToUltraHdr` / `ultraHdrToExr` 作为别名保留):
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { linearHdrToUltraHdr, ultraHdrToLinearHdr } from "@realsee/hdr-toolbox";
|
|
156
|
+
|
|
157
|
+
// 输出格式由扩展名推断:.exr 或 .hdr
|
|
158
|
+
await ultraHdrToLinearHdr({ input: "image.uhdr.jpg", output: "image.hdr" });
|
|
159
|
+
|
|
160
|
+
await linearHdrToUltraHdr({
|
|
161
|
+
input: "image.exr",
|
|
162
|
+
output: "image.uhdr.jpg",
|
|
163
|
+
maxContentBoost: 8, // 可选,不填则按输入峰值自动推断
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
底层的编解码函数 `readExr` / `writeExr` 和 `readHdr` / `writeHdr` 也一并导出,都以交错的线性浮点 RGB(`LinearHdrImage`)作为统一的像素表示。
|
|
168
|
+
|
|
121
169
|
## 校验
|
|
122
170
|
|
|
123
171
|
```bash
|
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;
|
|
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,CA2HvC"}
|
package/dist/cli.js
CHANGED
|
@@ -2,14 +2,19 @@
|
|
|
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
6
|
import { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
|
|
6
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
|
+
}
|
|
7
12
|
export function createProgram() {
|
|
8
13
|
const program = new Command();
|
|
9
14
|
program
|
|
10
15
|
.name("hdr-toolbox")
|
|
11
16
|
.description("Compose, extract, and convert Android Ultra HDR JPEG images")
|
|
12
|
-
.version("1.0
|
|
17
|
+
.version("1.1.0");
|
|
13
18
|
program
|
|
14
19
|
.command("compose")
|
|
15
20
|
.description("Compose an SDR image, gain map image (avif/png/jpg/jpeg), and JSON/XMP config into Ultra HDR")
|
|
@@ -68,6 +73,32 @@ export function createProgram() {
|
|
|
68
73
|
prefix: options.prefix,
|
|
69
74
|
});
|
|
70
75
|
});
|
|
76
|
+
program
|
|
77
|
+
.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
|
+
.action(async (options) => {
|
|
85
|
+
const inputIsLinearHdr = isLinearHdrPath(options.input);
|
|
86
|
+
const outputIsLinearHdr = isLinearHdrPath(options.output);
|
|
87
|
+
if (inputIsLinearHdr === outputIsLinearHdr)
|
|
88
|
+
throw new Error("convert needs exactly one linear HDR side: use a .exr/.hdr input with an Ultra HDR JPEG output, or vice versa.");
|
|
89
|
+
if (inputIsLinearHdr) {
|
|
90
|
+
await linearHdrToUltraHdr({
|
|
91
|
+
input: options.input,
|
|
92
|
+
output: options.output,
|
|
93
|
+
maxContentBoost: options.maxContentBoost === undefined ? undefined : Number(options.maxContentBoost),
|
|
94
|
+
sdrQuality: options.sdrQuality === undefined ? undefined : Number(options.sdrQuality),
|
|
95
|
+
gainMapQuality: options.gainmapQuality === undefined ? undefined : Number(options.gainmapQuality),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
await ultraHdrToLinearHdr({ input: options.input, output: options.output });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
71
102
|
return program;
|
|
72
103
|
}
|
|
73
104
|
function isMainModule() {
|
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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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Linear HDR float container formats that `convert` reads and writes. */
|
|
2
|
+
export type LinearHdrFormat = "exr" | "hdr";
|
|
3
|
+
export interface UltraHdrToLinearHdrOptions {
|
|
4
|
+
input: string;
|
|
5
|
+
output: string;
|
|
6
|
+
/** Linear HDR output format; defaults to the output path extension. */
|
|
7
|
+
format?: LinearHdrFormat;
|
|
8
|
+
}
|
|
9
|
+
export interface LinearHdrToUltraHdrOptions {
|
|
10
|
+
input: string;
|
|
11
|
+
output: string;
|
|
12
|
+
/** Linear HDR input format; defaults to the input path extension. */
|
|
13
|
+
format?: LinearHdrFormat;
|
|
14
|
+
/** JPEG quality for the generated SDR base image (1-100, default 95). */
|
|
15
|
+
sdrQuality?: number;
|
|
16
|
+
/** JPEG quality for the generated gain map image (1-100, default 95). */
|
|
17
|
+
gainMapQuality?: number;
|
|
18
|
+
/** Linear ratio of HDR headroom to encode (max_content_boost, default auto). */
|
|
19
|
+
maxContentBoost?: number;
|
|
20
|
+
}
|
|
21
|
+
/** Back-compat alias for {@link UltraHdrToLinearHdrOptions}. */
|
|
22
|
+
export type UltraHdrToExrOptions = UltraHdrToLinearHdrOptions;
|
|
23
|
+
/** Back-compat alias for {@link LinearHdrToUltraHdrOptions}. */
|
|
24
|
+
export type ExrToUltraHdrOptions = LinearHdrToUltraHdrOptions;
|
|
25
|
+
/** Resolves a linear HDR format from an explicit option, then the path extension. */
|
|
26
|
+
export declare function resolveLinearHdrFormat(explicit: LinearHdrFormat | undefined, path: string): LinearHdrFormat;
|
|
27
|
+
/**
|
|
28
|
+
* Reconstructs a linear-light HDR image from an Ultra HDR JPEG and writes it as
|
|
29
|
+
* a linear float EXR or Radiance HDR file (chosen by the output extension).
|
|
30
|
+
*
|
|
31
|
+
* Applies the Adobe/Android gain map recovery per channel:
|
|
32
|
+
* logBoost = lerp(log2(min), log2(max), gain^(1/gamma))
|
|
33
|
+
* hdr = (sdr_linear + offsetSdr) * 2^logBoost - offsetHdr
|
|
34
|
+
* at full display headroom (weight = 1), so the output captures the complete HDR
|
|
35
|
+
* intent rather than a headroom-limited rendition.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ultraHdrToLinearHdr(options: UltraHdrToLinearHdrOptions): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Builds an Ultra HDR JPEG from a linear float EXR or Radiance HDR file (chosen
|
|
40
|
+
* by the input extension). Tone maps the HDR data to an SDR base, derives a gain
|
|
41
|
+
* map as the per-pixel quotient between HDR and SDR, and composes the three into
|
|
42
|
+
* an Ultra HDR container.
|
|
43
|
+
*/
|
|
44
|
+
export declare function linearHdrToUltraHdr(options: LinearHdrToUltraHdrOptions): Promise<void>;
|
|
45
|
+
/** @deprecated Use {@link ultraHdrToLinearHdr}; retained for compatibility. */
|
|
46
|
+
export declare const ultraHdrToExr: typeof ultraHdrToLinearHdr;
|
|
47
|
+
/** @deprecated Use {@link linearHdrToUltraHdr}; retained for compatibility. */
|
|
48
|
+
export declare const exrToUltraHdr: typeof linearHdrToUltraHdr;
|
|
49
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAUA,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,CAAC;AAE5C,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;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;AA6CD;;;;;;;;;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,CAwE5F;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,4BAAsB,CAAC;AACjD,+EAA+E;AAC/E,eAAO,MAAM,aAAa,4BAAsB,CAAC"}
|
package/dist/convert.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname } from "node:path";
|
|
3
|
+
import sharp from "sharp";
|
|
4
|
+
import { readExr, writeExr } from "./exr.js";
|
|
5
|
+
import { readHdr, writeHdr } from "./hdr.js";
|
|
6
|
+
import { composeUltraHdrBuffers, extractUltraHdrBuffers } from "./ultrahdr.js";
|
|
7
|
+
import { normalizeGainMapConfig } from "./xmp.js";
|
|
8
|
+
/** Resolves a linear HDR format from an explicit option, then the path extension. */
|
|
9
|
+
export function resolveLinearHdrFormat(explicit, path) {
|
|
10
|
+
if (explicit)
|
|
11
|
+
return explicit;
|
|
12
|
+
const extension = extname(path).replace(/^\./, "").toLowerCase();
|
|
13
|
+
if (extension === "exr")
|
|
14
|
+
return "exr";
|
|
15
|
+
if (extension === "hdr" || extension === "pic")
|
|
16
|
+
return "hdr";
|
|
17
|
+
throw new Error(`Unable to infer a linear HDR format from "${path}". Use a .exr or .hdr extension.`);
|
|
18
|
+
}
|
|
19
|
+
function decodeLinearHdr(buffer, format) {
|
|
20
|
+
return format === "exr" ? readExr(buffer) : readHdr(buffer);
|
|
21
|
+
}
|
|
22
|
+
function encodeLinearHdr(image, format) {
|
|
23
|
+
return format === "exr" ? writeExr(image) : writeHdr(image);
|
|
24
|
+
}
|
|
25
|
+
/** Decode an 8-bit sRGB-encoded value (0-1) to linear light. */
|
|
26
|
+
function srgbToLinear(value) {
|
|
27
|
+
return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
|
|
28
|
+
}
|
|
29
|
+
/** Encode linear light (0-1) back to an 8-bit sRGB value (0-1). */
|
|
30
|
+
function linearToSrgb(value) {
|
|
31
|
+
const clamped = value < 0 ? 0 : value > 1 ? 1 : value;
|
|
32
|
+
return clamped <= 0.0031308 ? clamped * 12.92 : 1.055 * clamped ** (1 / 2.4) - 0.055;
|
|
33
|
+
}
|
|
34
|
+
/** Rec. 709 relative luminance of a linear RGB triple. */
|
|
35
|
+
function luminance(r, g, b) {
|
|
36
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reinhard tone map: `x / (1 + x)`. Simple and reversible, it maps any linear
|
|
40
|
+
* luminance into [0, 1) without hard clipping. It compresses bright highlights
|
|
41
|
+
* aggressively, so the SDR base favours a well-exposed midrange; the full HDR
|
|
42
|
+
* detail is preserved in the gain map and recovered on HDR displays.
|
|
43
|
+
*/
|
|
44
|
+
function reinhard(value) {
|
|
45
|
+
return value / (1 + value);
|
|
46
|
+
}
|
|
47
|
+
async function decodeRgb(jpeg) {
|
|
48
|
+
const { data, info } = await sharp(jpeg)
|
|
49
|
+
.toColorspace("srgb")
|
|
50
|
+
.removeAlpha()
|
|
51
|
+
.raw()
|
|
52
|
+
.toBuffer({ resolveWithObject: true });
|
|
53
|
+
return { data, width: info.width, height: info.height };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Reconstructs a linear-light HDR image from an Ultra HDR JPEG and writes it as
|
|
57
|
+
* a linear float EXR or Radiance HDR file (chosen by the output extension).
|
|
58
|
+
*
|
|
59
|
+
* Applies the Adobe/Android gain map recovery per channel:
|
|
60
|
+
* logBoost = lerp(log2(min), log2(max), gain^(1/gamma))
|
|
61
|
+
* hdr = (sdr_linear + offsetSdr) * 2^logBoost - offsetHdr
|
|
62
|
+
* at full display headroom (weight = 1), so the output captures the complete HDR
|
|
63
|
+
* intent rather than a headroom-limited rendition.
|
|
64
|
+
*/
|
|
65
|
+
export async function ultraHdrToLinearHdr(options) {
|
|
66
|
+
const format = resolveLinearHdrFormat(options.format, options.output);
|
|
67
|
+
const extracted = extractUltraHdrBuffers(await readFile(options.input));
|
|
68
|
+
const config = normalizeGainMapConfig(extracted.config);
|
|
69
|
+
const sdr = await decodeRgb(extracted.sdr);
|
|
70
|
+
const gain = await decodeRgb(extracted.gainMap);
|
|
71
|
+
const width = sdr.width;
|
|
72
|
+
const height = sdr.height;
|
|
73
|
+
const output = new Float32Array(width * height * 3);
|
|
74
|
+
const logMin = Math.log2(config.minContentBoost);
|
|
75
|
+
const logMax = Math.log2(config.maxContentBoost);
|
|
76
|
+
const inverseGamma = 1 / config.gamma;
|
|
77
|
+
// The gain map is often downsampled; map SDR coordinates onto it by ratio.
|
|
78
|
+
const gainScaleX = gain.width / width;
|
|
79
|
+
const gainScaleY = gain.height / height;
|
|
80
|
+
for (let y = 0; y < height; y++) {
|
|
81
|
+
const gainY = Math.min(gain.height - 1, Math.floor(y * gainScaleY));
|
|
82
|
+
for (let x = 0; x < width; x++) {
|
|
83
|
+
const gainX = Math.min(gain.width - 1, Math.floor(x * gainScaleX));
|
|
84
|
+
const sdrIndex = (y * width + x) * 3;
|
|
85
|
+
const gainIndex = (gainY * gain.width + gainX) * 3;
|
|
86
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
87
|
+
const sdrLinear = srgbToLinear(sdr.data[sdrIndex + channel] / 255);
|
|
88
|
+
const gainValue = gain.data[gainIndex + channel] / 255;
|
|
89
|
+
const logRecovery = gainValue ** inverseGamma;
|
|
90
|
+
const logBoost = logMin + (logMax - logMin) * logRecovery;
|
|
91
|
+
const hdr = (sdrLinear + config.offsetSdr) * 2 ** logBoost - config.offsetHdr;
|
|
92
|
+
output[sdrIndex + channel] = hdr;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
await mkdir(dirname(options.output), { recursive: true });
|
|
97
|
+
await writeFile(options.output, encodeLinearHdr({ width, height, data: output }, format));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Builds an Ultra HDR JPEG from a linear float EXR or Radiance HDR file (chosen
|
|
101
|
+
* by the input extension). Tone maps the HDR data to an SDR base, derives a gain
|
|
102
|
+
* map as the per-pixel quotient between HDR and SDR, and composes the three into
|
|
103
|
+
* an Ultra HDR container.
|
|
104
|
+
*/
|
|
105
|
+
export async function linearHdrToUltraHdr(options) {
|
|
106
|
+
const format = resolveLinearHdrFormat(options.format, options.input);
|
|
107
|
+
const { width, height, data } = decodeLinearHdr(await readFile(options.input), format);
|
|
108
|
+
// Determine the HDR headroom from the brightest linear value so the gain map
|
|
109
|
+
// range covers the content without clipping.
|
|
110
|
+
let peak = 1;
|
|
111
|
+
for (let index = 0; index < data.length; index++) {
|
|
112
|
+
if (data[index] > peak)
|
|
113
|
+
peak = data[index];
|
|
114
|
+
}
|
|
115
|
+
const maxContentBoost = Math.max(1.0001, options.maxContentBoost ?? Math.min(peak, 2 ** 14));
|
|
116
|
+
const logMax = Math.log2(maxContentBoost);
|
|
117
|
+
const sdrPixels = Buffer.alloc(width * height * 3);
|
|
118
|
+
const gainPixels = Buffer.alloc(width * height * 3);
|
|
119
|
+
const offset = 0.015625;
|
|
120
|
+
for (let pixel = 0; pixel < width * height; pixel++) {
|
|
121
|
+
const base = pixel * 3;
|
|
122
|
+
const r = Math.max(0, data[base]);
|
|
123
|
+
const g = Math.max(0, data[base + 1]);
|
|
124
|
+
const b = Math.max(0, data[base + 2]);
|
|
125
|
+
// Drive the Reinhard compression by luminance and scale the chroma by the
|
|
126
|
+
// same factor, so hue and saturation survive tone mapping (a per-channel
|
|
127
|
+
// curve would desaturate bright, saturated highlights).
|
|
128
|
+
const y = luminance(r, g, b);
|
|
129
|
+
const ySdr = reinhard(y);
|
|
130
|
+
const scale = y > 1e-6 ? ySdr / y : 0;
|
|
131
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
132
|
+
const hdr = Math.max(0, data[base + channel]);
|
|
133
|
+
// The quantised 8-bit code is what actually ships, so derive the gain map
|
|
134
|
+
// from the exact SDR light it decodes to, keeping reconstruction consistent.
|
|
135
|
+
const code = Math.round(linearToSrgb(Math.min(1, hdr * scale)) * 255);
|
|
136
|
+
sdrPixels[base + channel] = code;
|
|
137
|
+
const sdrLinear = srgbToLinear(code / 255);
|
|
138
|
+
// Gain is the ratio of HDR to SDR light, encoded in log2 space and
|
|
139
|
+
// normalised to [0,1] against the chosen max boost.
|
|
140
|
+
const ratio = (hdr + offset) / (sdrLinear + offset);
|
|
141
|
+
const logBoost = Math.log2(Math.max(1, ratio));
|
|
142
|
+
const normalized = logMax > 0 ? Math.min(1, logBoost / logMax) : 0;
|
|
143
|
+
gainPixels[base + channel] = Math.round(normalized * 255);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const sdrQuality = options.sdrQuality ?? 95;
|
|
147
|
+
const gainMapQuality = options.gainMapQuality ?? 95;
|
|
148
|
+
const [sdrJpeg, gainMapJpeg] = await Promise.all([
|
|
149
|
+
sharp(sdrPixels, { raw: { width, height, channels: 3 } })
|
|
150
|
+
.jpeg({ quality: sdrQuality })
|
|
151
|
+
.toBuffer(),
|
|
152
|
+
sharp(gainPixels, { raw: { width, height, channels: 3 } })
|
|
153
|
+
.jpeg({ quality: gainMapQuality })
|
|
154
|
+
.toBuffer(),
|
|
155
|
+
]);
|
|
156
|
+
const config = {
|
|
157
|
+
maxContentBoost,
|
|
158
|
+
minContentBoost: 1,
|
|
159
|
+
gamma: 1,
|
|
160
|
+
offsetSdr: offset,
|
|
161
|
+
offsetHdr: offset,
|
|
162
|
+
hdrCapacityMin: 1,
|
|
163
|
+
hdrCapacityMax: maxContentBoost,
|
|
164
|
+
useBaseColorSpace: true,
|
|
165
|
+
};
|
|
166
|
+
const container = await composeUltraHdrBuffers(sdrJpeg, gainMapJpeg, config);
|
|
167
|
+
await mkdir(dirname(options.output), { recursive: true });
|
|
168
|
+
await writeFile(options.output, container);
|
|
169
|
+
}
|
|
170
|
+
/** @deprecated Use {@link ultraHdrToLinearHdr}; retained for compatibility. */
|
|
171
|
+
export const ultraHdrToExr = ultraHdrToLinearHdr;
|
|
172
|
+
/** @deprecated Use {@link linearHdrToUltraHdr}; retained for compatibility. */
|
|
173
|
+
export const exrToUltraHdr = linearHdrToUltraHdr;
|
|
174
|
+
//# sourceMappingURL=convert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.js","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"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"}
|
package/dist/exr.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal OpenEXR reader/writer for linear scanline RGB(A) images.
|
|
3
|
+
*
|
|
4
|
+
* This is intentionally small: it is only meant to move linear floating point
|
|
5
|
+
* HDR pixels in and out of the UltraHDR converter, not to be a general EXR
|
|
6
|
+
* implementation. On read it accepts single-part scanline files with HALF or
|
|
7
|
+
* FLOAT channels and NO_COMPRESSION, ZIPS or ZIP compression. On write it emits
|
|
8
|
+
* a single-part scanline FLOAT RGB file with NO_COMPRESSION, which every EXR
|
|
9
|
+
* reader understands.
|
|
10
|
+
*/
|
|
11
|
+
/** An in-memory linear HDR image: interleaved RGB, 3 floats per pixel, top row first. */
|
|
12
|
+
export interface LinearHdrImage {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
data: Float32Array;
|
|
16
|
+
}
|
|
17
|
+
/** @deprecated Use {@link LinearHdrImage}; kept as an alias for compatibility. */
|
|
18
|
+
export type ExrImage = LinearHdrImage;
|
|
19
|
+
/** Reads a linear RGB EXR into interleaved float RGB, dropping any alpha. */
|
|
20
|
+
export declare function readExr(buffer: Buffer): LinearHdrImage;
|
|
21
|
+
/**
|
|
22
|
+
* Writes interleaved linear float RGB as an uncompressed single-part scanline
|
|
23
|
+
* EXR. Channels are emitted alphabetically (B, G, R) as the format requires.
|
|
24
|
+
*/
|
|
25
|
+
export declare function writeExr(image: LinearHdrImage): Buffer;
|
|
26
|
+
//# sourceMappingURL=exr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exr.d.ts","sourceRoot":"","sources":["../src/exr.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,kFAAkF;AAClF,MAAM,MAAM,QAAQ,GAAG,cAAc,CAAC;AA0ItC,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CA0FtD;AASD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAsFtD"}
|
package/dist/exr.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { inflateSync } from "node:zlib";
|
|
2
|
+
const MAGIC = 20000630;
|
|
3
|
+
const PIXEL_TYPE_HALF = 1;
|
|
4
|
+
const PIXEL_TYPE_FLOAT = 2;
|
|
5
|
+
const COMPRESSION_NONE = 0;
|
|
6
|
+
const COMPRESSION_RLE = 1;
|
|
7
|
+
const COMPRESSION_ZIPS = 2;
|
|
8
|
+
const COMPRESSION_ZIP = 3;
|
|
9
|
+
/** ZIP/ZIPS pack 16 scanlines per chunk; ZIPS packs a single scanline. */
|
|
10
|
+
const ZIP_ROWS_PER_CHUNK = 16;
|
|
11
|
+
function halfToFloat(half) {
|
|
12
|
+
const sign = (half & 0x8000) >> 15;
|
|
13
|
+
const exponent = (half & 0x7c00) >> 10;
|
|
14
|
+
const fraction = half & 0x03ff;
|
|
15
|
+
if (exponent === 0) {
|
|
16
|
+
return (sign ? -1 : 1) * 2 ** -14 * (fraction / 1024);
|
|
17
|
+
}
|
|
18
|
+
if (exponent === 0x1f) {
|
|
19
|
+
return fraction ? Number.NaN : (sign ? -1 : 1) * Number.POSITIVE_INFINITY;
|
|
20
|
+
}
|
|
21
|
+
return (sign ? -1 : 1) * 2 ** (exponent - 15) * (1 + fraction / 1024);
|
|
22
|
+
}
|
|
23
|
+
class ByteReader {
|
|
24
|
+
view;
|
|
25
|
+
offset = 0;
|
|
26
|
+
constructor(view) {
|
|
27
|
+
this.view = view;
|
|
28
|
+
}
|
|
29
|
+
uint8() {
|
|
30
|
+
return this.view.getUint8(this.offset++);
|
|
31
|
+
}
|
|
32
|
+
int32() {
|
|
33
|
+
const value = this.view.getInt32(this.offset, true);
|
|
34
|
+
this.offset += 4;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
uint32() {
|
|
38
|
+
const value = this.view.getUint32(this.offset, true);
|
|
39
|
+
this.offset += 4;
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
uint64() {
|
|
43
|
+
const low = this.view.getUint32(this.offset, true);
|
|
44
|
+
const high = this.view.getUint32(this.offset + 4, true);
|
|
45
|
+
this.offset += 8;
|
|
46
|
+
return high * 0x1_0000_0000 + low;
|
|
47
|
+
}
|
|
48
|
+
nullString() {
|
|
49
|
+
let result = "";
|
|
50
|
+
for (let byte = this.uint8(); byte !== 0; byte = this.uint8()) {
|
|
51
|
+
result += String.fromCharCode(byte);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
skip(count) {
|
|
56
|
+
this.offset += count;
|
|
57
|
+
}
|
|
58
|
+
get position() {
|
|
59
|
+
return this.offset;
|
|
60
|
+
}
|
|
61
|
+
set position(value) {
|
|
62
|
+
this.offset = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function parseChannels(reader) {
|
|
66
|
+
const channels = [];
|
|
67
|
+
let byteOffset = 0;
|
|
68
|
+
// The channel list ends with an empty channel name (a lone null byte).
|
|
69
|
+
while (true) {
|
|
70
|
+
const name = reader.nullString();
|
|
71
|
+
if (name === "")
|
|
72
|
+
break;
|
|
73
|
+
const pixelType = reader.int32();
|
|
74
|
+
reader.skip(4); // pLinear + reserved
|
|
75
|
+
reader.skip(8); // xSampling + ySampling
|
|
76
|
+
const byteSize = pixelType === PIXEL_TYPE_FLOAT ? 4 : pixelType === PIXEL_TYPE_HALF ? 2 : 0;
|
|
77
|
+
if (byteSize === 0)
|
|
78
|
+
throw new Error(`Unsupported EXR channel pixel type for "${name}": ${pixelType}.`);
|
|
79
|
+
channels.push({ name, pixelType, byteOffset, byteSize });
|
|
80
|
+
byteOffset += byteSize;
|
|
81
|
+
}
|
|
82
|
+
// EXR stores channels alphabetically; byte offsets within a pixel follow that
|
|
83
|
+
// same order, which is exactly how we accumulated them above.
|
|
84
|
+
return channels;
|
|
85
|
+
}
|
|
86
|
+
function decompressChunk(compression, payload, expectedSize) {
|
|
87
|
+
if (compression === COMPRESSION_NONE)
|
|
88
|
+
return payload;
|
|
89
|
+
if (compression === COMPRESSION_ZIP || compression === COMPRESSION_ZIPS) {
|
|
90
|
+
const inflated = inflateSync(payload);
|
|
91
|
+
return reconstructZip(inflated, expectedSize);
|
|
92
|
+
}
|
|
93
|
+
throw new Error(`Unsupported EXR compression type: ${compression}.`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Undoes the two reversible transforms the EXR ZIP codec applies before
|
|
97
|
+
* deflate: a per-byte delta (predictor) and an interleave of the two byte
|
|
98
|
+
* halves. Mirrors the reference OpenEXR implementation.
|
|
99
|
+
*/
|
|
100
|
+
function reconstructZip(source, expectedSize) {
|
|
101
|
+
const buffer = Uint8Array.prototype.slice.call(source, 0, expectedSize);
|
|
102
|
+
for (let index = 1; index < buffer.length; index++) {
|
|
103
|
+
const delta = buffer[index - 1] + buffer[index] - 128;
|
|
104
|
+
buffer[index] = delta & 0xff;
|
|
105
|
+
}
|
|
106
|
+
const result = new Uint8Array(buffer.length);
|
|
107
|
+
const half = Math.floor((buffer.length + 1) / 2);
|
|
108
|
+
let low = 0;
|
|
109
|
+
let high = half;
|
|
110
|
+
let out = 0;
|
|
111
|
+
while (out < result.length) {
|
|
112
|
+
result[out++] = buffer[low++];
|
|
113
|
+
if (out < result.length)
|
|
114
|
+
result[out++] = buffer[high++];
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
/** Reads a linear RGB EXR into interleaved float RGB, dropping any alpha. */
|
|
119
|
+
export function readExr(buffer) {
|
|
120
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
121
|
+
const reader = new ByteReader(view);
|
|
122
|
+
if (reader.uint32() !== MAGIC)
|
|
123
|
+
throw new Error("Not an OpenEXR file (bad magic number).");
|
|
124
|
+
reader.skip(4); // version + flags; single-part scanline only
|
|
125
|
+
let channels;
|
|
126
|
+
let compression = COMPRESSION_NONE;
|
|
127
|
+
let dataWindow;
|
|
128
|
+
// Header: a sequence of (name,type,size,value) attributes ending at a null byte.
|
|
129
|
+
while (true) {
|
|
130
|
+
const attributeName = reader.nullString();
|
|
131
|
+
if (attributeName === "")
|
|
132
|
+
break;
|
|
133
|
+
reader.nullString(); // attribute type
|
|
134
|
+
const size = reader.int32();
|
|
135
|
+
const next = reader.position + size;
|
|
136
|
+
if (attributeName === "channels") {
|
|
137
|
+
channels = parseChannels(reader);
|
|
138
|
+
}
|
|
139
|
+
else if (attributeName === "compression") {
|
|
140
|
+
compression = reader.uint8();
|
|
141
|
+
}
|
|
142
|
+
else if (attributeName === "dataWindow") {
|
|
143
|
+
dataWindow = {
|
|
144
|
+
xMin: reader.int32(),
|
|
145
|
+
yMin: reader.int32(),
|
|
146
|
+
xMax: reader.int32(),
|
|
147
|
+
yMax: reader.int32(),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
reader.position = next;
|
|
151
|
+
}
|
|
152
|
+
if (!channels || !dataWindow)
|
|
153
|
+
throw new Error("EXR header is missing channels or dataWindow.");
|
|
154
|
+
if (compression === COMPRESSION_RLE)
|
|
155
|
+
throw new Error("RLE-compressed EXR files are not supported.");
|
|
156
|
+
const width = dataWindow.xMax - dataWindow.xMin + 1;
|
|
157
|
+
const height = dataWindow.yMax - dataWindow.yMin + 1;
|
|
158
|
+
if (width <= 0 || height <= 0)
|
|
159
|
+
throw new Error("EXR data window is empty.");
|
|
160
|
+
const channelByName = new Map(channels.map((channel) => [channel.name, channel]));
|
|
161
|
+
const red = channelByName.get("R");
|
|
162
|
+
const green = channelByName.get("G");
|
|
163
|
+
const blue = channelByName.get("B");
|
|
164
|
+
if (!red || !green || !blue)
|
|
165
|
+
throw new Error("EXR file must contain R, G and B channels for HDR conversion.");
|
|
166
|
+
const bytesPerPixel = channels.reduce((sum, channel) => sum + channel.byteSize, 0);
|
|
167
|
+
const rowsPerChunk = compression === COMPRESSION_ZIP ? ZIP_ROWS_PER_CHUNK : 1;
|
|
168
|
+
const chunkCount = Math.ceil(height / rowsPerChunk);
|
|
169
|
+
// Offset table: one uint64 file offset per chunk, in scanline order.
|
|
170
|
+
const chunkOffsets = [];
|
|
171
|
+
for (let index = 0; index < chunkCount; index++)
|
|
172
|
+
chunkOffsets.push(reader.uint64());
|
|
173
|
+
const output = new Float32Array(width * height * 3);
|
|
174
|
+
const readSample = (block, offset, pixelType) => pixelType === PIXEL_TYPE_FLOAT
|
|
175
|
+
? block.getFloat32(offset, true)
|
|
176
|
+
: halfToFloat(block.getUint16(offset, true));
|
|
177
|
+
for (let chunk = 0; chunk < chunkCount; chunk++) {
|
|
178
|
+
reader.position = chunkOffsets[chunk];
|
|
179
|
+
const firstRow = reader.int32();
|
|
180
|
+
const dataSize = reader.int32();
|
|
181
|
+
const start = reader.position;
|
|
182
|
+
const rowsInChunk = Math.min(rowsPerChunk, height - (firstRow - dataWindow.yMin));
|
|
183
|
+
const expectedSize = rowsInChunk * width * bytesPerPixel;
|
|
184
|
+
const payload = new Uint8Array(buffer.buffer, buffer.byteOffset + start, dataSize);
|
|
185
|
+
const pixels = decompressChunk(compression, payload, expectedSize);
|
|
186
|
+
const block = new DataView(pixels.buffer, pixels.byteOffset, pixels.byteLength);
|
|
187
|
+
for (let row = 0; row < rowsInChunk; row++) {
|
|
188
|
+
const imageRow = firstRow - dataWindow.yMin + row;
|
|
189
|
+
const rowStart = row * width * bytesPerPixel;
|
|
190
|
+
for (let channel of channels) {
|
|
191
|
+
if (channel.name !== "R" && channel.name !== "G" && channel.name !== "B")
|
|
192
|
+
continue;
|
|
193
|
+
const target = channel.name === "R" ? 0 : channel.name === "G" ? 1 : 2;
|
|
194
|
+
let sampleOffset = rowStart + channel.byteOffset * width;
|
|
195
|
+
let pixelIndex = imageRow * width * 3 + target;
|
|
196
|
+
for (let x = 0; x < width; x++) {
|
|
197
|
+
output[pixelIndex] = readSample(block, sampleOffset, channel.pixelType);
|
|
198
|
+
sampleOffset += channel.byteSize;
|
|
199
|
+
pixelIndex += 3;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { width, height, data: output };
|
|
205
|
+
}
|
|
206
|
+
function writeAttribute(parts, name, type, value) {
|
|
207
|
+
parts.push(Buffer.from(`${name}\0${type}\0`, "latin1"));
|
|
208
|
+
const size = Buffer.alloc(4);
|
|
209
|
+
size.writeInt32LE(value.length, 0);
|
|
210
|
+
parts.push(size, value);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Writes interleaved linear float RGB as an uncompressed single-part scanline
|
|
214
|
+
* EXR. Channels are emitted alphabetically (B, G, R) as the format requires.
|
|
215
|
+
*/
|
|
216
|
+
export function writeExr(image) {
|
|
217
|
+
const { width, height, data } = image;
|
|
218
|
+
if (data.length !== width * height * 3)
|
|
219
|
+
throw new Error("EXR pixel data length does not match width * height * 3.");
|
|
220
|
+
const header = [];
|
|
221
|
+
const magic = Buffer.alloc(8);
|
|
222
|
+
magic.writeUInt32LE(MAGIC, 0);
|
|
223
|
+
magic.writeUInt32LE(2, 4); // version 2, scanline, single-part
|
|
224
|
+
header.push(magic);
|
|
225
|
+
// channels: alphabetical B, G, R, each FLOAT with xSampling=ySampling=1.
|
|
226
|
+
const channelParts = [];
|
|
227
|
+
for (const name of ["B", "G", "R"]) {
|
|
228
|
+
const entry = Buffer.alloc(name.length + 1 + 16);
|
|
229
|
+
entry.write(`${name}\0`, 0, "latin1");
|
|
230
|
+
let p = name.length + 1;
|
|
231
|
+
entry.writeInt32LE(PIXEL_TYPE_FLOAT, p); // pixelType
|
|
232
|
+
p += 4;
|
|
233
|
+
entry.writeInt32LE(0, p); // pLinear + reserved
|
|
234
|
+
p += 4;
|
|
235
|
+
entry.writeInt32LE(1, p); // xSampling
|
|
236
|
+
p += 4;
|
|
237
|
+
entry.writeInt32LE(1, p); // ySampling
|
|
238
|
+
channelParts.push(entry);
|
|
239
|
+
}
|
|
240
|
+
channelParts.push(Buffer.from([0]));
|
|
241
|
+
writeAttribute(header, "channels", "chlist", Buffer.concat(channelParts));
|
|
242
|
+
writeAttribute(header, "compression", "compression", Buffer.from([COMPRESSION_NONE]));
|
|
243
|
+
const window = Buffer.alloc(16);
|
|
244
|
+
window.writeInt32LE(0, 0);
|
|
245
|
+
window.writeInt32LE(0, 4);
|
|
246
|
+
window.writeInt32LE(width - 1, 8);
|
|
247
|
+
window.writeInt32LE(height - 1, 12);
|
|
248
|
+
writeAttribute(header, "dataWindow", "box2i", window);
|
|
249
|
+
writeAttribute(header, "displayWindow", "box2i", window);
|
|
250
|
+
const lineOrder = Buffer.from([0]); // INCREASING_Y
|
|
251
|
+
writeAttribute(header, "lineOrder", "lineOrder", lineOrder);
|
|
252
|
+
const screenWindowCenter = Buffer.alloc(8); // 0,0 floats
|
|
253
|
+
writeAttribute(header, "screenWindowCenter", "v2f", screenWindowCenter);
|
|
254
|
+
const screenWindowWidth = Buffer.alloc(4);
|
|
255
|
+
screenWindowWidth.writeFloatLE(1, 0);
|
|
256
|
+
writeAttribute(header, "screenWindowWidth", "float", screenWindowWidth);
|
|
257
|
+
const pixelAspectRatio = Buffer.alloc(4);
|
|
258
|
+
pixelAspectRatio.writeFloatLE(1, 0);
|
|
259
|
+
writeAttribute(header, "pixelAspectRatio", "float", pixelAspectRatio);
|
|
260
|
+
header.push(Buffer.from([0])); // end of header
|
|
261
|
+
const bytesPerChannelRow = width * 4;
|
|
262
|
+
const scanlineDataSize = bytesPerChannelRow * 3;
|
|
263
|
+
const scanlineRecord = 8 + scanlineDataSize; // y (int) + size (int) + data
|
|
264
|
+
const headerBuffer = Buffer.concat(header);
|
|
265
|
+
const offsetTableSize = height * 8;
|
|
266
|
+
const pixelDataStart = headerBuffer.length + offsetTableSize;
|
|
267
|
+
const offsetTable = Buffer.alloc(offsetTableSize);
|
|
268
|
+
for (let y = 0; y < height; y++) {
|
|
269
|
+
offsetTable.writeBigUInt64LE(BigInt(pixelDataStart + y * scanlineRecord), y * 8);
|
|
270
|
+
}
|
|
271
|
+
const pixelData = Buffer.alloc(height * scanlineRecord);
|
|
272
|
+
for (let y = 0; y < height; y++) {
|
|
273
|
+
const base = y * scanlineRecord;
|
|
274
|
+
pixelData.writeInt32LE(y, base);
|
|
275
|
+
pixelData.writeInt32LE(scanlineDataSize, base + 4);
|
|
276
|
+
const rowStart = base + 8;
|
|
277
|
+
// Channel order within a scanline matches the (alphabetical) channel list.
|
|
278
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
279
|
+
const source = channel === 0 ? 2 : channel === 1 ? 1 : 0; // B,G,R -> data index
|
|
280
|
+
let out = rowStart + channel * bytesPerChannelRow;
|
|
281
|
+
let pixel = y * width * 3 + source;
|
|
282
|
+
for (let x = 0; x < width; x++) {
|
|
283
|
+
pixelData.writeFloatLE(data[pixel], out);
|
|
284
|
+
out += 4;
|
|
285
|
+
pixel += 3;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return Buffer.concat([headerBuffer, offsetTable, pixelData]);
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=exr.js.map
|
package/dist/exr.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exr.js","sourceRoot":"","sources":["../src/exr.ts"],"names":[],"mappings":"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"}
|
package/dist/hdr.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LinearHdrImage } from "./exr.js";
|
|
2
|
+
/** Reads a Radiance HDR file into interleaved linear float RGB. */
|
|
3
|
+
export declare function readHdr(buffer: Buffer): LinearHdrImage;
|
|
4
|
+
/** Writes interleaved linear float RGB as a new-style RLE Radiance HDR file. */
|
|
5
|
+
export declare function writeHdr(image: LinearHdrImage): Buffer;
|
|
6
|
+
//# sourceMappingURL=hdr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hdr.d.ts","sourceRoot":"","sources":["../src/hdr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAsH/C,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAwBtD;AA6ED,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CA6BtD"}
|
package/dist/hdr.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Radiance HDR (RGBE, ".hdr"/".pic") reader and writer for linear
|
|
3
|
+
* scanline RGB images.
|
|
4
|
+
*
|
|
5
|
+
* RGBE stores three 8-bit mantissas plus one shared 8-bit exponent per pixel,
|
|
6
|
+
* giving a wide dynamic range in 32 bits. This module reads the flat and
|
|
7
|
+
* new-style (adaptive) RLE encodings and always writes the new-style RLE form,
|
|
8
|
+
* which every Radiance reader understands. Pixels are exchanged as interleaved
|
|
9
|
+
* linear float RGB, matching the EXR codec so both share one conversion path.
|
|
10
|
+
*/
|
|
11
|
+
const EXPONENT_BIAS = 128;
|
|
12
|
+
/**
|
|
13
|
+
* Converts one RGBE quadruple to linear float RGB, writing into `out`.
|
|
14
|
+
*
|
|
15
|
+
* With the shared exponent byte `e`, each mantissa byte decodes as
|
|
16
|
+
* `byte * 2^(e - 128 - 8)`, where the -8 undoes the 0-255 mantissa scale. This
|
|
17
|
+
* matches the common three.js/parse-hdr convention (no half-bucket bias), which
|
|
18
|
+
* keeps near-zero channels at zero.
|
|
19
|
+
*/
|
|
20
|
+
function rgbeToFloat(r, g, b, e, out, offset) {
|
|
21
|
+
if (e === 0) {
|
|
22
|
+
out[offset] = 0;
|
|
23
|
+
out[offset + 1] = 0;
|
|
24
|
+
out[offset + 2] = 0;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const scale = 2 ** (e - (EXPONENT_BIAS + 8));
|
|
28
|
+
out[offset] = r * scale;
|
|
29
|
+
out[offset + 1] = g * scale;
|
|
30
|
+
out[offset + 2] = b * scale;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Converts one linear float RGB pixel to an RGBE quadruple.
|
|
34
|
+
*
|
|
35
|
+
* Mirrors the reference Radiance encoder: decompose the channel maximum as
|
|
36
|
+
* `max = mantissa * 2^exponent` with `mantissa` in [0.5, 1) (i.e. frexp), then
|
|
37
|
+
* scale each channel by `mantissa / max * 256` and store `exponent + 128`.
|
|
38
|
+
*/
|
|
39
|
+
function floatToRgbe(r, g, b) {
|
|
40
|
+
const max = Math.max(r, g, b);
|
|
41
|
+
if (max <= 1e-32)
|
|
42
|
+
return [0, 0, 0, 0];
|
|
43
|
+
// frexp exponent: the e with max / 2^e in [0.5, 1).
|
|
44
|
+
const exponent = Math.floor(Math.log2(max)) + 1;
|
|
45
|
+
const factor = 2 ** -exponent * 256;
|
|
46
|
+
// Round (not floor) so the quantisation error is centred, since the decoder
|
|
47
|
+
// does not add a half-bucket bias.
|
|
48
|
+
const clampByte = (value) => {
|
|
49
|
+
const byte = Math.round(value * factor);
|
|
50
|
+
return byte < 0 ? 0 : byte > 255 ? 255 : byte;
|
|
51
|
+
};
|
|
52
|
+
return [clampByte(r), clampByte(g), clampByte(b), exponent + EXPONENT_BIAS];
|
|
53
|
+
}
|
|
54
|
+
function readHeader(buffer) {
|
|
55
|
+
let offset = 0;
|
|
56
|
+
const readLine = () => {
|
|
57
|
+
let line = "";
|
|
58
|
+
while (offset < buffer.length) {
|
|
59
|
+
const byte = buffer[offset++];
|
|
60
|
+
if (byte === 0x0a)
|
|
61
|
+
break;
|
|
62
|
+
line += String.fromCharCode(byte);
|
|
63
|
+
}
|
|
64
|
+
return line;
|
|
65
|
+
};
|
|
66
|
+
const magic = readLine();
|
|
67
|
+
if (!magic.startsWith("#?"))
|
|
68
|
+
throw new Error("Not a Radiance HDR file (missing #? signature).");
|
|
69
|
+
let format;
|
|
70
|
+
// Header lines continue until a blank line separates them from the resolution.
|
|
71
|
+
while (offset < buffer.length) {
|
|
72
|
+
const line = readLine();
|
|
73
|
+
if (line === "")
|
|
74
|
+
break;
|
|
75
|
+
const match = /^FORMAT=(.+)$/.exec(line);
|
|
76
|
+
if (match)
|
|
77
|
+
format = match[1].trim();
|
|
78
|
+
}
|
|
79
|
+
if (format && format !== "32-bit_rle_rgbe")
|
|
80
|
+
throw new Error(`Unsupported Radiance HDR format "${format}" (only 32-bit_rle_rgbe).`);
|
|
81
|
+
const resolution = readLine();
|
|
82
|
+
// Standard orientation is "-Y height +X width"; accept the common variants.
|
|
83
|
+
const match = /([+-][XY])\s+(\d+)\s+([+-][XY])\s+(\d+)/.exec(resolution);
|
|
84
|
+
if (!match)
|
|
85
|
+
throw new Error(`Unsupported Radiance HDR resolution line: "${resolution}".`);
|
|
86
|
+
const [, axis1, size1, axis2, size2] = match;
|
|
87
|
+
let width;
|
|
88
|
+
let height;
|
|
89
|
+
let flipY = false;
|
|
90
|
+
if (axis1.endsWith("Y")) {
|
|
91
|
+
height = Number(size1);
|
|
92
|
+
width = Number(size2);
|
|
93
|
+
flipY = axis1.startsWith("+");
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
width = Number(size1);
|
|
97
|
+
height = Number(size2);
|
|
98
|
+
flipY = axis2.startsWith("+");
|
|
99
|
+
}
|
|
100
|
+
if (axis1.endsWith(axis2.charAt(1)))
|
|
101
|
+
throw new Error("Radiance HDR resolution line must specify one X and one Y axis.");
|
|
102
|
+
return { width, height, flipY, dataStart: offset };
|
|
103
|
+
}
|
|
104
|
+
/** Reads a Radiance HDR file into interleaved linear float RGB. */
|
|
105
|
+
export function readHdr(buffer) {
|
|
106
|
+
const { width, height, flipY, dataStart } = readHeader(buffer);
|
|
107
|
+
const data = new Float32Array(width * height * 3);
|
|
108
|
+
let offset = dataStart;
|
|
109
|
+
const scanline = new Uint8Array(width * 4);
|
|
110
|
+
for (let row = 0; row < height; row++) {
|
|
111
|
+
offset = readScanline(buffer, offset, width, scanline);
|
|
112
|
+
const targetRow = flipY ? height - 1 - row : row;
|
|
113
|
+
let out = targetRow * width * 3;
|
|
114
|
+
for (let x = 0; x < width; x++) {
|
|
115
|
+
rgbeToFloat(scanline[x * 4], scanline[x * 4 + 1], scanline[x * 4 + 2], scanline[x * 4 + 3], data, out);
|
|
116
|
+
out += 3;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { width, height, data };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Decodes one scanline into `scanline` as width*4 RGBE bytes and returns the new
|
|
123
|
+
* read offset. Handles new-style adaptive RLE, old-style RLE, and flat pixels.
|
|
124
|
+
*/
|
|
125
|
+
function readScanline(buffer, start, width, scanline) {
|
|
126
|
+
let offset = start;
|
|
127
|
+
// New-style RLE scanlines begin with the marker 0x02 0x02 and a 16-bit width.
|
|
128
|
+
const isNewStyle = width >= 8 &&
|
|
129
|
+
width <= 0x7fff &&
|
|
130
|
+
buffer[offset] === 2 &&
|
|
131
|
+
buffer[offset + 1] === 2 &&
|
|
132
|
+
((buffer[offset + 2] << 8) | buffer[offset + 3]) === width;
|
|
133
|
+
if (!isNewStyle)
|
|
134
|
+
return readFlatOrOldScanline(buffer, offset, width, scanline);
|
|
135
|
+
offset += 4;
|
|
136
|
+
// Each of the four RGBE components is run-length encoded separately.
|
|
137
|
+
for (let channel = 0; channel < 4; channel++) {
|
|
138
|
+
let x = 0;
|
|
139
|
+
while (x < width) {
|
|
140
|
+
let count = buffer[offset++];
|
|
141
|
+
if (count > 128) {
|
|
142
|
+
// A run: the next byte repeats (count - 128) times.
|
|
143
|
+
const value = buffer[offset++];
|
|
144
|
+
count -= 128;
|
|
145
|
+
while (count-- > 0)
|
|
146
|
+
scanline[(x++ << 2) + channel] = value;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// A dump: `count` literal bytes follow.
|
|
150
|
+
while (count-- > 0)
|
|
151
|
+
scanline[(x++ << 2) + channel] = buffer[offset++];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return offset;
|
|
156
|
+
}
|
|
157
|
+
/** Reads a flat (uncompressed) or old-style RLE scanline. */
|
|
158
|
+
function readFlatOrOldScanline(buffer, start, width, scanline) {
|
|
159
|
+
let offset = start;
|
|
160
|
+
let x = 0;
|
|
161
|
+
let repeatShift = 0;
|
|
162
|
+
while (x < width) {
|
|
163
|
+
const r = buffer[offset++];
|
|
164
|
+
const g = buffer[offset++];
|
|
165
|
+
const b = buffer[offset++];
|
|
166
|
+
const e = buffer[offset++];
|
|
167
|
+
// Old-style RLE: an (1,1,1,count) pixel repeats the previous one count<<shift times.
|
|
168
|
+
if (r === 1 && g === 1 && b === 1 && x > 0) {
|
|
169
|
+
let count = e << repeatShift;
|
|
170
|
+
const base = (x - 1) * 4;
|
|
171
|
+
while (count-- > 0 && x < width) {
|
|
172
|
+
scanline[x * 4] = scanline[base];
|
|
173
|
+
scanline[x * 4 + 1] = scanline[base + 1];
|
|
174
|
+
scanline[x * 4 + 2] = scanline[base + 2];
|
|
175
|
+
scanline[x * 4 + 3] = scanline[base + 3];
|
|
176
|
+
x++;
|
|
177
|
+
}
|
|
178
|
+
repeatShift += 8;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
scanline[x * 4] = r;
|
|
182
|
+
scanline[x * 4 + 1] = g;
|
|
183
|
+
scanline[x * 4 + 2] = b;
|
|
184
|
+
scanline[x * 4 + 3] = e;
|
|
185
|
+
x++;
|
|
186
|
+
repeatShift = 0;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return offset;
|
|
190
|
+
}
|
|
191
|
+
/** Writes interleaved linear float RGB as a new-style RLE Radiance HDR file. */
|
|
192
|
+
export function writeHdr(image) {
|
|
193
|
+
const { width, height, data } = image;
|
|
194
|
+
if (data.length !== width * height * 3)
|
|
195
|
+
throw new Error("HDR pixel data length does not match width * height * 3.");
|
|
196
|
+
const header = Buffer.from(`#?RADIANCE\nFORMAT=32-bit_rle_rgbe\n\n-Y ${height} +X ${width}\n`, "latin1");
|
|
197
|
+
const chunks = [header];
|
|
198
|
+
const rgbe = new Uint8Array(width * 4);
|
|
199
|
+
// New-style RLE requires widths in [8, 32767]; otherwise write flat pixels.
|
|
200
|
+
const useRle = width >= 8 && width <= 0x7fff;
|
|
201
|
+
for (let row = 0; row < height; row++) {
|
|
202
|
+
let source = row * width * 3;
|
|
203
|
+
for (let x = 0; x < width; x++) {
|
|
204
|
+
const [r, g, b, e] = floatToRgbe(data[source], data[source + 1], data[source + 2]);
|
|
205
|
+
rgbe[x * 4] = r;
|
|
206
|
+
rgbe[x * 4 + 1] = g;
|
|
207
|
+
rgbe[x * 4 + 2] = b;
|
|
208
|
+
rgbe[x * 4 + 3] = e;
|
|
209
|
+
source += 3;
|
|
210
|
+
}
|
|
211
|
+
chunks.push(useRle ? encodeRleScanline(rgbe, width) : Buffer.from(rgbe.slice()));
|
|
212
|
+
}
|
|
213
|
+
return Buffer.concat(chunks);
|
|
214
|
+
}
|
|
215
|
+
/** Length of the run starting at `index` for one interleaved RGBE channel. */
|
|
216
|
+
function runLengthAt(rgbe, channel, index, width) {
|
|
217
|
+
const value = rgbe[index * 4 + channel];
|
|
218
|
+
let length = 1;
|
|
219
|
+
while (index + length < width && rgbe[(index + length) * 4 + channel] === value)
|
|
220
|
+
length++;
|
|
221
|
+
return length;
|
|
222
|
+
}
|
|
223
|
+
/** Encodes one width*4 RGBE scanline using new-style adaptive RLE. */
|
|
224
|
+
function encodeRleScanline(rgbe, width) {
|
|
225
|
+
const out = [2, 2, (width >> 8) & 0xff, width & 0xff];
|
|
226
|
+
// Runs of >= 4 bytes are worth encoding; shorter spans go in literal dumps.
|
|
227
|
+
const minRun = 4;
|
|
228
|
+
for (let channel = 0; channel < 4; channel++) {
|
|
229
|
+
let x = 0;
|
|
230
|
+
while (x < width) {
|
|
231
|
+
// Scan forward over bytes that do not start a worthwhile run; those bytes
|
|
232
|
+
// become a literal dump. `runStart` always advances, so this terminates.
|
|
233
|
+
let runStart = x;
|
|
234
|
+
let run = 0;
|
|
235
|
+
while (runStart < width) {
|
|
236
|
+
run = runLengthAt(rgbe, channel, runStart, width);
|
|
237
|
+
if (run >= minRun)
|
|
238
|
+
break;
|
|
239
|
+
runStart += run;
|
|
240
|
+
}
|
|
241
|
+
// Emit the literal span [x, runStart) in chunks of at most 128 bytes.
|
|
242
|
+
while (x < runStart) {
|
|
243
|
+
const dumpLength = Math.min(128, runStart - x);
|
|
244
|
+
out.push(dumpLength);
|
|
245
|
+
for (let i = 0; i < dumpLength; i++)
|
|
246
|
+
out.push(rgbe[(x + i) * 4 + channel]);
|
|
247
|
+
x += dumpLength;
|
|
248
|
+
}
|
|
249
|
+
// Emit the run [runStart, runStart + run) in chunks of at most 127 repeats.
|
|
250
|
+
if (runStart < width) {
|
|
251
|
+
const value = rgbe[runStart * 4 + channel];
|
|
252
|
+
while (run > 0) {
|
|
253
|
+
const chunk = Math.min(127, run);
|
|
254
|
+
out.push(128 + chunk, value);
|
|
255
|
+
run -= chunk;
|
|
256
|
+
x += chunk;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return Buffer.from(out);
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=hdr.js.map
|
package/dist/hdr.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hdr.js","sourceRoot":"","sources":["../src/hdr.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export type { ComposeUltraHdrOptions, ExtractUltraHdrOptions } from "./ultrahdr.js";
|
|
2
2
|
export { composeUltraHdr, composeUltraHdrBuffers, extractUltraHdr, extractUltraHdrBuffers, } from "./ultrahdr.js";
|
|
3
|
+
export type { ExrToUltraHdrOptions, LinearHdrFormat, LinearHdrToUltraHdrOptions, UltraHdrToExrOptions, UltraHdrToLinearHdrOptions, } from "./convert.js";
|
|
4
|
+
export { exrToUltraHdr, linearHdrToUltraHdr, resolveLinearHdrFormat, ultraHdrToExr, ultraHdrToLinearHdr, } from "./convert.js";
|
|
5
|
+
export type { ExrImage, LinearHdrImage } from "./exr.js";
|
|
6
|
+
export { readExr, writeExr } from "./exr.js";
|
|
7
|
+
export { readHdr, writeHdr } from "./hdr.js";
|
|
3
8
|
export type { CubeToEquirectOptions, EquirectToCubeOptions } from "./panorama.js";
|
|
4
9
|
export { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
|
|
5
10
|
export type { CubeFaceKey, CubeManifest, GainMapConfig } from "./types.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,0BAA0B,EAC1B,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { composeUltraHdr, composeUltraHdrBuffers, extractUltraHdr, extractUltraHdrBuffers, } from "./ultrahdr.js";
|
|
2
|
+
export { exrToUltraHdr, linearHdrToUltraHdr, resolveLinearHdrFormat, ultraHdrToExr, ultraHdrToLinearHdr, } from "./convert.js";
|
|
3
|
+
export { readExr, writeExr } from "./exr.js";
|
|
4
|
+
export { readHdr, writeHdr } from "./hdr.js";
|
|
2
5
|
export { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
|
|
3
6
|
export { createGainMapXmp, createPrimaryXmp, normalizeGainMapConfig, parseGainMapXmp, readGainMapConfig, writeGainMapConfig, } from "./xmp.js";
|
|
4
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACvB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAQvB,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,UAAU,CAAC"}
|