@realsee/hdr-toolbox 1.0.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 +131 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/jpeg.d.ts +14 -0
- package/dist/jpeg.d.ts.map +1 -0
- package/dist/jpeg.js +364 -0
- package/dist/jpeg.js.map +1 -0
- package/dist/panorama.d.ts +13 -0
- package/dist/panorama.d.ts.map +1 -0
- package/dist/panorama.js +91 -0
- package/dist/panorama.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/ultrahdr.d.ts +23 -0
- package/dist/ultrahdr.d.ts.map +1 -0
- package/dist/ultrahdr.js +91 -0
- package/dist/ultrahdr.js.map +1 -0
- package/dist/xmp.d.ts +9 -0
- package/dist/xmp.d.ts.map +1 -0
- package/dist/xmp.js +140 -0
- package/dist/xmp.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @realsee/hdr-toolbox
|
|
2
|
+
|
|
3
|
+
用 TypeScript 合成、分解和转换 Android Ultra HDR JPEG。工具遵循 Android Ultra HDR Image Format v1.1 的 JPEG/R 封装:
|
|
4
|
+
|
|
5
|
+
- 主图是普通 SDR JPEG,旧版查看器可直接显示。
|
|
6
|
+
- 主图携带 GContainer XMP,声明 `Primary` 和 `GainMap` 两个资源。
|
|
7
|
+
- gain map JPEG 携带 Adobe HDR Gain Map XMP。
|
|
8
|
+
- MPF APP2 索引主图与第二张 JPEG;两张 JPEG 紧密拼接。
|
|
9
|
+
|
|
10
|
+
> 当前写入 Ultra HDR v1 XMP + MPF。v1.1 中提到的 ISO 21496-1 双重元数据属于增强的跨平台兼容建议,本工具暂不写入 ISO 21496-1 APP2。
|
|
11
|
+
|
|
12
|
+
## 环境与构建
|
|
13
|
+
|
|
14
|
+
需要 Node.js 20 或 22。`@realsee/equirect-toolbox` 使用原生 WebGL 依赖,因此不要使用 Node 24 运行全景命令。
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install
|
|
18
|
+
npm run build
|
|
19
|
+
node dist/cli.js --help
|
|
20
|
+
# 安装为包后也可直接运行:hdr-toolbox --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 配置
|
|
24
|
+
|
|
25
|
+
输入配置可以是示例中的 JSON,也可以是标准 HDR gain map XMP。JSON 数值使用**线性 boost**:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"maxContentBoost": "813.30419921875",
|
|
30
|
+
"minContentBoost": "1",
|
|
31
|
+
"gamma": "1.0",
|
|
32
|
+
"offsetSdr": "0",
|
|
33
|
+
"offsetHdr": "0",
|
|
34
|
+
"hdrCapacityMin": "1",
|
|
35
|
+
"hdrCapacityMax": "1000.0",
|
|
36
|
+
"useBaseColorSpace": "1"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
写入 XMP 时,`maxContentBoost`、`minContentBoost`、`hdrCapacityMin` 和 `hdrCapacityMax` 会自动转换为标准要求的 `log2` 值。分解时,`.json` 输出线性值,`.xmp` 输出标准 XMP。
|
|
41
|
+
|
|
42
|
+
## CLI
|
|
43
|
+
|
|
44
|
+
### 1. SDR + gain map + cfg → Ultra HDR
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
hdr-toolbox compose \
|
|
48
|
+
--sdr examples/cube/0_f.jpg \
|
|
49
|
+
--gainmap examples/cube/0_f_gainmap.jpg \
|
|
50
|
+
--config examples/cube/0_gainmap_cfg.json \
|
|
51
|
+
--output output/0_f.uhdr.jpg
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
合成只改写 JPEG metadata marker,不会重编码 SDR 或 gain map 像素。若 SDR 未携带规范要求的 ICC profile,会无重编码地补入 sRGB ICC marker。
|
|
55
|
+
|
|
56
|
+
### 2. Ultra HDR → SDR + gain map + cfg
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
hdr-toolbox extract \
|
|
60
|
+
--input output/0_f.uhdr.jpg \
|
|
61
|
+
--sdr output/0_f.jpg \
|
|
62
|
+
--gainmap output/0_f_gainmap.jpg \
|
|
63
|
+
--config output/0_gainmap_cfg.json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
将 `--config` 改成 `.xmp` 后缀即可输出原生 XMP 表达。
|
|
67
|
+
|
|
68
|
+
### 3. cubemap → equirect Ultra HDR
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
hdr-toolbox cube-to-equirect \
|
|
72
|
+
--input-dir examples/cube \
|
|
73
|
+
--prefix 0 \
|
|
74
|
+
--output output/0_equirect.uhdr.jpg
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
六面映射如下:
|
|
78
|
+
|
|
79
|
+
| 文件面名 | cubemap key | 方向 |
|
|
80
|
+
| -------- | ----------- | ------- |
|
|
81
|
+
| `r` | `px` | 右 / +X |
|
|
82
|
+
| `l` | `nx` | 左 / -X |
|
|
83
|
+
| `u` | `py` | 上 / +Y |
|
|
84
|
+
| `d` | `ny` | 下 / -Y |
|
|
85
|
+
| `f` | `pz` | 前 / +Z |
|
|
86
|
+
| `b` | `nz` | 后 / -Z |
|
|
87
|
+
|
|
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
|
+
|
|
90
|
+
### 4. equirect Ultra HDR → cubemap
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
hdr-toolbox equirect-to-cube \
|
|
94
|
+
--input output/0_equirect.uhdr.jpg \
|
|
95
|
+
--output-dir output/cube \
|
|
96
|
+
--prefix 0
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
输出 6 张 `<prefix>_<face>.jpg`、6 张 `<prefix>_<face>_gainmap.jpg` 和 `<prefix>_gainmap_cfg.json`。
|
|
100
|
+
|
|
101
|
+
## TypeScript API
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { composeUltraHdr, extractUltraHdr } from "@realsee/hdr-toolbox";
|
|
105
|
+
|
|
106
|
+
await composeUltraHdr({
|
|
107
|
+
sdr: "sdr.jpg",
|
|
108
|
+
gainMap: "gainmap.jpg",
|
|
109
|
+
config: "gainmap_cfg.json",
|
|
110
|
+
output: "image.uhdr.jpg",
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await extractUltraHdr({
|
|
114
|
+
input: "image.uhdr.jpg",
|
|
115
|
+
sdr: "sdr.jpg",
|
|
116
|
+
gainMap: "gainmap.jpg",
|
|
117
|
+
config: "gainmap_cfg.xmp",
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 校验
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npm run typecheck
|
|
125
|
+
npm test
|
|
126
|
+
npm run lint
|
|
127
|
+
npm run format:check
|
|
128
|
+
npm run build
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
规范参考:[Android Ultra HDR Image Format v1.1](https://developer.android.com/media/platform/hdr-image-format)。
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,aAAa,IAAI,OAAO,CAoEvC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
|
|
5
|
+
import { composeUltraHdr, extractUltraHdr } from "./ultrahdr.js";
|
|
6
|
+
export function createProgram() {
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("hdr-toolbox")
|
|
10
|
+
.description("Compose, extract, and convert Android Ultra HDR JPEG images")
|
|
11
|
+
.version("1.0.0");
|
|
12
|
+
program
|
|
13
|
+
.command("compose")
|
|
14
|
+
.description("Compose an SDR JPEG, gain map JPEG, and JSON/XMP config into Ultra HDR")
|
|
15
|
+
.requiredOption("--sdr <path>", "SDR primary JPEG")
|
|
16
|
+
.requiredOption("--gainmap <path>", "gain map JPEG")
|
|
17
|
+
.requiredOption("-c, --config <path>", "gain map config (.json or .xmp)")
|
|
18
|
+
.requiredOption("-o, --output <path>", "output Ultra HDR JPEG")
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
await composeUltraHdr({
|
|
21
|
+
sdr: options.sdr,
|
|
22
|
+
gainMap: options.gainmap,
|
|
23
|
+
config: options.config,
|
|
24
|
+
output: options.output,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command("extract")
|
|
29
|
+
.description("Extract an Ultra HDR JPEG into SDR, gain map, and JSON/XMP config")
|
|
30
|
+
.requiredOption("-i, --input <path>", "input Ultra HDR JPEG")
|
|
31
|
+
.requiredOption("--sdr <path>", "output SDR JPEG")
|
|
32
|
+
.requiredOption("--gainmap <path>", "output gain map JPEG")
|
|
33
|
+
.requiredOption("-c, --config <path>", "output config (.json or .xmp)")
|
|
34
|
+
.action(async (options) => {
|
|
35
|
+
await extractUltraHdr({
|
|
36
|
+
input: options.input,
|
|
37
|
+
sdr: options.sdr,
|
|
38
|
+
gainMap: options.gainmap,
|
|
39
|
+
config: options.config,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
program
|
|
43
|
+
.command("cube-to-equirect")
|
|
44
|
+
.description("Convert six SDR/gain-map cube faces into one equirectangular Ultra HDR JPEG")
|
|
45
|
+
.requiredOption("-i, --input-dir <path>", "directory containing <prefix>_[r,l,u,d,f,b].jpg")
|
|
46
|
+
.option("-p, --prefix <name>", "cube face filename prefix", "0")
|
|
47
|
+
.requiredOption("-o, --output <path>", "output equirectangular Ultra HDR JPEG")
|
|
48
|
+
.action(async (options) => {
|
|
49
|
+
await cubeToEquirectUltraHdr({
|
|
50
|
+
inputDirectory: options.inputDir,
|
|
51
|
+
prefix: options.prefix,
|
|
52
|
+
output: options.output,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
program
|
|
56
|
+
.command("equirect-to-cube")
|
|
57
|
+
.description("Extract an equirectangular Ultra HDR JPEG into six SDR/gain-map cube faces")
|
|
58
|
+
.requiredOption("-i, --input <path>", "input equirectangular Ultra HDR JPEG")
|
|
59
|
+
.requiredOption("-o, --output-dir <path>", "output directory")
|
|
60
|
+
.option("-p, --prefix <name>", "output cube face filename prefix", "0")
|
|
61
|
+
.action(async (options) => {
|
|
62
|
+
await equirectUltraHdrToCube({
|
|
63
|
+
input: options.input,
|
|
64
|
+
outputDirectory: options.outputDir,
|
|
65
|
+
prefix: options.prefix,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
return program;
|
|
69
|
+
}
|
|
70
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
71
|
+
createProgram()
|
|
72
|
+
.parseAsync()
|
|
73
|
+
.catch((error) => {
|
|
74
|
+
console.error(error instanceof Error ? error.message : error);
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { ComposeUltraHdrOptions, ExtractUltraHdrOptions } from "./ultrahdr.js";
|
|
2
|
+
export { composeUltraHdr, composeUltraHdrBuffers, extractUltraHdr, extractUltraHdrBuffers, } from "./ultrahdr.js";
|
|
3
|
+
export type { CubeToEquirectOptions, EquirectToCubeOptions } from "./panorama.js";
|
|
4
|
+
export { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
|
|
5
|
+
export type { CubeFaceKey, CubeManifest, GainMapConfig } from "./types.js";
|
|
6
|
+
export { createGainMapXmp, createPrimaryXmp, normalizeGainMapConfig, parseGainMapXmp, readGainMapConfig, writeGainMapConfig, } from "./xmp.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { composeUltraHdr, composeUltraHdrBuffers, extractUltraHdr, extractUltraHdrBuffers, } from "./ultrahdr.js";
|
|
2
|
+
export { cubeToEquirectUltraHdr, equirectUltraHdrToCube } from "./panorama.js";
|
|
3
|
+
export { createGainMapXmp, createPrimaryXmp, normalizeGainMapConfig, parseGainMapXmp, readGainMapConfig, writeGainMapConfig, } from "./xmp.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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;AAEvB,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"}
|
package/dist/jpeg.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function createXmpSegment(xml: string): Buffer;
|
|
2
|
+
export declare function getIccProfileSegments(jpeg: Buffer): Buffer[];
|
|
3
|
+
export declare function addIccProfileSegments(jpeg: Buffer, iccSegments: readonly Buffer[]): Buffer;
|
|
4
|
+
export declare function createMpfSegment(primaryImageSize: number, mpfMarkerStart: number, secondaryImageSize: number): Buffer;
|
|
5
|
+
export declare function addGainMapXmp(jpeg: Buffer, xml: string): Buffer;
|
|
6
|
+
export declare function buildPrimaryJpeg(jpeg: Buffer, xml: string, secondaryImageSize: number): Buffer;
|
|
7
|
+
export declare function stripUltraHdrMetadata(jpeg: Buffer): Buffer;
|
|
8
|
+
export declare function getGainMapXmp(jpeg: Buffer): string | undefined;
|
|
9
|
+
export declare function findJpegEnd(buffer: Buffer, start?: number): number;
|
|
10
|
+
export declare function splitConcatenatedJpegs(container: Buffer): {
|
|
11
|
+
primary: Buffer;
|
|
12
|
+
gainMap: Buffer;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=jpeg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jpeg.d.ts","sourceRoot":"","sources":["../src/jpeg.ts"],"names":[],"mappings":"AA4EA,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD;AAwBD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI5D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAiB1F;AAwCD,wBAAgB,gBAAgB,CAC9B,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAwCR;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAO9F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU9D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAqC7D;AAsFD,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA4B9F"}
|
package/dist/jpeg.js
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { xmpNamespace } from "./xmp.js";
|
|
2
|
+
const SOI = 0xd8;
|
|
3
|
+
const EOI = 0xd9;
|
|
4
|
+
const SOS = 0xda;
|
|
5
|
+
const APP1 = 0xe1;
|
|
6
|
+
const APP2 = 0xe2;
|
|
7
|
+
function assertJpeg(buffer) {
|
|
8
|
+
if (buffer.length < 4 || buffer[0] !== 0xff || buffer[1] !== SOI)
|
|
9
|
+
throw new Error("Input is not a JPEG image (SOI marker is missing).");
|
|
10
|
+
}
|
|
11
|
+
function parseJpegParts(buffer) {
|
|
12
|
+
assertJpeg(buffer);
|
|
13
|
+
const segments = [];
|
|
14
|
+
let offset = 2;
|
|
15
|
+
while (offset + 1 < buffer.length) {
|
|
16
|
+
if (buffer[offset] !== 0xff)
|
|
17
|
+
throw new Error(`Malformed JPEG marker at byte ${offset}.`);
|
|
18
|
+
const markerPrefixStart = offset;
|
|
19
|
+
while (buffer[offset] === 0xff)
|
|
20
|
+
offset++;
|
|
21
|
+
const marker = buffer[offset];
|
|
22
|
+
const markerOffset = offset - 1;
|
|
23
|
+
if (marker === SOS)
|
|
24
|
+
return { segments, scanData: buffer.subarray(markerPrefixStart) };
|
|
25
|
+
if (marker === EOI)
|
|
26
|
+
return { segments, scanData: buffer.subarray(markerPrefixStart) };
|
|
27
|
+
if (marker === undefined)
|
|
28
|
+
break;
|
|
29
|
+
if (marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) {
|
|
30
|
+
const end = offset + 1;
|
|
31
|
+
segments.push({
|
|
32
|
+
marker,
|
|
33
|
+
markerOffset,
|
|
34
|
+
bytes: buffer.subarray(markerPrefixStart, end),
|
|
35
|
+
payload: Buffer.alloc(0),
|
|
36
|
+
});
|
|
37
|
+
offset = end;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (offset + 2 >= buffer.length)
|
|
41
|
+
throw new Error("Truncated JPEG segment length.");
|
|
42
|
+
const length = buffer.readUInt16BE(offset + 1);
|
|
43
|
+
if (length < 2)
|
|
44
|
+
throw new Error(`Invalid JPEG segment length ${length}.`);
|
|
45
|
+
const end = offset + 1 + length;
|
|
46
|
+
if (end > buffer.length)
|
|
47
|
+
throw new Error("Truncated JPEG segment payload.");
|
|
48
|
+
segments.push({
|
|
49
|
+
marker,
|
|
50
|
+
markerOffset,
|
|
51
|
+
bytes: buffer.subarray(markerPrefixStart, end),
|
|
52
|
+
payload: buffer.subarray(offset + 3, end),
|
|
53
|
+
});
|
|
54
|
+
offset = end;
|
|
55
|
+
}
|
|
56
|
+
throw new Error("JPEG SOS or EOI marker was not found.");
|
|
57
|
+
}
|
|
58
|
+
function createSegment(marker, payload) {
|
|
59
|
+
const length = payload.length + 2;
|
|
60
|
+
if (length > 0xffff)
|
|
61
|
+
throw new Error(`JPEG APP segment is too large: ${length} bytes.`);
|
|
62
|
+
const result = Buffer.allocUnsafe(payload.length + 4);
|
|
63
|
+
result[0] = 0xff;
|
|
64
|
+
result[1] = marker;
|
|
65
|
+
result.writeUInt16BE(length, 2);
|
|
66
|
+
payload.copy(result, 4);
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
export function createXmpSegment(xml) {
|
|
70
|
+
return createSegment(APP1, Buffer.concat([Buffer.from(xmpNamespace, "ascii"), Buffer.from(xml, "utf8")]));
|
|
71
|
+
}
|
|
72
|
+
function isUltraHdrSegment(segment) {
|
|
73
|
+
if (segment.marker === APP1 &&
|
|
74
|
+
segment.payload.subarray(0, xmpNamespace.length).toString("ascii") === xmpNamespace) {
|
|
75
|
+
const xml = segment.payload.subarray(xmpNamespace.length).toString("utf8");
|
|
76
|
+
return (xml.includes("http://ns.adobe.com/hdr-gain-map/1.0/") ||
|
|
77
|
+
xml.includes("http://ns.google.com/photos/1.0/container/"));
|
|
78
|
+
}
|
|
79
|
+
if (segment.marker !== APP2)
|
|
80
|
+
return false;
|
|
81
|
+
const signature = segment.payload.subarray(0, 32).toString("ascii");
|
|
82
|
+
return signature.startsWith("MPF\0") || signature.startsWith("urn:iso:std:iso:ts:21496:-1\0");
|
|
83
|
+
}
|
|
84
|
+
function isIccSegment(segment) {
|
|
85
|
+
return (segment.marker === APP2 && segment.payload.subarray(0, 12).toString("ascii") === "ICC_PROFILE\0");
|
|
86
|
+
}
|
|
87
|
+
export function getIccProfileSegments(jpeg) {
|
|
88
|
+
return parseJpegParts(jpeg)
|
|
89
|
+
.segments.filter(isIccSegment)
|
|
90
|
+
.map((segment) => Buffer.from(segment.bytes));
|
|
91
|
+
}
|
|
92
|
+
export function addIccProfileSegments(jpeg, iccSegments) {
|
|
93
|
+
const { segments, scanData } = parseJpegParts(jpeg);
|
|
94
|
+
if (segments.some(isIccSegment))
|
|
95
|
+
return jpeg;
|
|
96
|
+
if (iccSegments.length === 0)
|
|
97
|
+
throw new Error("No ICC profile segments were provided.");
|
|
98
|
+
let appEnd = 0;
|
|
99
|
+
while (appEnd < segments.length) {
|
|
100
|
+
const marker = segments[appEnd].marker;
|
|
101
|
+
if ((marker >= 0xe0 && marker <= 0xef) || marker === 0xfe)
|
|
102
|
+
appEnd++;
|
|
103
|
+
else
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
return Buffer.concat([
|
|
107
|
+
Buffer.from([0xff, SOI]),
|
|
108
|
+
...segments.slice(0, appEnd).map((segment) => segment.bytes),
|
|
109
|
+
...iccSegments,
|
|
110
|
+
...segments.slice(appEnd).map((segment) => segment.bytes),
|
|
111
|
+
scanData,
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
function headerWithXmp(buffer, xmp, includeMpf) {
|
|
115
|
+
const { segments, scanData } = parseJpegParts(buffer);
|
|
116
|
+
const kept = segments.filter((segment) => !isUltraHdrSegment(segment));
|
|
117
|
+
let appEnd = 0;
|
|
118
|
+
while (appEnd < kept.length) {
|
|
119
|
+
const marker = kept[appEnd].marker;
|
|
120
|
+
if ((marker >= 0xe0 && marker <= 0xef) || marker === 0xfe)
|
|
121
|
+
appEnd++;
|
|
122
|
+
else
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
const prefix = kept.slice(0, appEnd).map((segment) => segment.bytes);
|
|
126
|
+
const imageTables = kept.slice(appEnd).map((segment) => segment.bytes);
|
|
127
|
+
const beforeMpf = Buffer.concat([Buffer.from([0xff, SOI]), ...prefix, xmp, ...imageTables]);
|
|
128
|
+
if (!includeMpf)
|
|
129
|
+
return { buffer: Buffer.concat([beforeMpf, scanData]) };
|
|
130
|
+
return {
|
|
131
|
+
buffer: Buffer.concat([beforeMpf, includeMpf, scanData]),
|
|
132
|
+
mpfStart: beforeMpf.length,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function writeTag(buffer, offset, tag, type, count, value) {
|
|
136
|
+
buffer.writeUInt16BE(tag, offset);
|
|
137
|
+
buffer.writeUInt16BE(type, offset + 2);
|
|
138
|
+
buffer.writeUInt32BE(count, offset + 4);
|
|
139
|
+
buffer.writeUInt32BE(value, offset + 8);
|
|
140
|
+
return offset + 12;
|
|
141
|
+
}
|
|
142
|
+
export function createMpfSegment(primaryImageSize, mpfMarkerStart, secondaryImageSize) {
|
|
143
|
+
for (const [name, value] of Object.entries({
|
|
144
|
+
primaryImageSize,
|
|
145
|
+
mpfMarkerStart,
|
|
146
|
+
secondaryImageSize,
|
|
147
|
+
})) {
|
|
148
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 0xffffffff)
|
|
149
|
+
throw new Error(`${name} exceeds the MPF 32-bit range.`);
|
|
150
|
+
}
|
|
151
|
+
const payload = Buffer.alloc(86);
|
|
152
|
+
payload.write("MPF\0", 0, "ascii");
|
|
153
|
+
const tiff = 4;
|
|
154
|
+
payload.write("MM", tiff, "ascii");
|
|
155
|
+
payload.writeUInt16BE(0x002a, tiff + 2);
|
|
156
|
+
payload.writeUInt32BE(8, tiff + 4);
|
|
157
|
+
payload.writeUInt16BE(3, tiff + 8);
|
|
158
|
+
let offset = tiff + 10;
|
|
159
|
+
offset = writeTag(payload, offset, 0xb000, 7, 4, 0x30313030);
|
|
160
|
+
offset = writeTag(payload, offset, 0xb001, 4, 1, 2);
|
|
161
|
+
offset = writeTag(payload, offset, 0xb002, 7, 32, 50);
|
|
162
|
+
payload.writeUInt32BE(0, offset);
|
|
163
|
+
offset += 4;
|
|
164
|
+
payload.writeUInt32BE(0x00030000, offset);
|
|
165
|
+
payload.writeUInt32BE(primaryImageSize, offset + 4);
|
|
166
|
+
payload.writeUInt32BE(0, offset + 8);
|
|
167
|
+
payload.writeUInt16BE(0, offset + 12);
|
|
168
|
+
payload.writeUInt16BE(0, offset + 14);
|
|
169
|
+
offset += 16;
|
|
170
|
+
const tiffAbsoluteOffset = mpfMarkerStart + 8;
|
|
171
|
+
const secondaryOffset = primaryImageSize - tiffAbsoluteOffset;
|
|
172
|
+
if (secondaryOffset < 0)
|
|
173
|
+
throw new Error("Invalid MPF secondary image offset.");
|
|
174
|
+
payload.writeUInt32BE(0, offset);
|
|
175
|
+
payload.writeUInt32BE(secondaryImageSize, offset + 4);
|
|
176
|
+
payload.writeUInt32BE(secondaryOffset, offset + 8);
|
|
177
|
+
payload.writeUInt16BE(0, offset + 12);
|
|
178
|
+
payload.writeUInt16BE(0, offset + 14);
|
|
179
|
+
return createSegment(APP2, payload);
|
|
180
|
+
}
|
|
181
|
+
export function addGainMapXmp(jpeg, xml) {
|
|
182
|
+
return headerWithXmp(jpeg, createXmpSegment(xml)).buffer;
|
|
183
|
+
}
|
|
184
|
+
export function buildPrimaryJpeg(jpeg, xml, secondaryImageSize) {
|
|
185
|
+
const xmp = createXmpSegment(xml);
|
|
186
|
+
const placeholder = Buffer.alloc(90); // MPF APP2 has a fixed 90-byte serialized size.
|
|
187
|
+
const draft = headerWithXmp(jpeg, xmp, placeholder);
|
|
188
|
+
if (draft.mpfStart === undefined)
|
|
189
|
+
throw new Error("Unable to locate generated MPF segment.");
|
|
190
|
+
const mpf = createMpfSegment(draft.buffer.length, draft.mpfStart, secondaryImageSize);
|
|
191
|
+
return headerWithXmp(jpeg, xmp, mpf).buffer;
|
|
192
|
+
}
|
|
193
|
+
export function stripUltraHdrMetadata(jpeg) {
|
|
194
|
+
const { segments, scanData } = parseJpegParts(jpeg);
|
|
195
|
+
return Buffer.concat([
|
|
196
|
+
Buffer.from([0xff, SOI]),
|
|
197
|
+
...segments.filter((segment) => !isUltraHdrSegment(segment)).map((segment) => segment.bytes),
|
|
198
|
+
scanData,
|
|
199
|
+
]);
|
|
200
|
+
}
|
|
201
|
+
export function getGainMapXmp(jpeg) {
|
|
202
|
+
const { segments } = parseJpegParts(jpeg);
|
|
203
|
+
for (const segment of segments) {
|
|
204
|
+
if (segment.marker !== APP1)
|
|
205
|
+
continue;
|
|
206
|
+
if (segment.payload.subarray(0, xmpNamespace.length).toString("ascii") !== xmpNamespace)
|
|
207
|
+
continue;
|
|
208
|
+
const xml = segment.payload.subarray(xmpNamespace.length).toString("utf8");
|
|
209
|
+
if (xml.includes("http://ns.adobe.com/hdr-gain-map/1.0/"))
|
|
210
|
+
return xml;
|
|
211
|
+
}
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
export function findJpegEnd(buffer, start = 0) {
|
|
215
|
+
const image = buffer.subarray(start);
|
|
216
|
+
assertJpeg(image);
|
|
217
|
+
let offset = 2;
|
|
218
|
+
let inScan = false;
|
|
219
|
+
while (offset < image.length) {
|
|
220
|
+
if (!inScan) {
|
|
221
|
+
if (image[offset] !== 0xff)
|
|
222
|
+
throw new Error(`Malformed JPEG marker at byte ${start + offset}.`);
|
|
223
|
+
while (image[offset] === 0xff)
|
|
224
|
+
offset++;
|
|
225
|
+
const marker = image[offset++];
|
|
226
|
+
if (marker === EOI)
|
|
227
|
+
return start + offset;
|
|
228
|
+
if (marker === SOS) {
|
|
229
|
+
if (offset + 1 >= image.length)
|
|
230
|
+
throw new Error("Truncated SOS segment.");
|
|
231
|
+
const length = image.readUInt16BE(offset);
|
|
232
|
+
offset += length;
|
|
233
|
+
inScan = true;
|
|
234
|
+
}
|
|
235
|
+
else if (marker === 0x01 || (marker !== undefined && marker >= 0xd0 && marker <= 0xd7)) {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
if (offset + 1 >= image.length)
|
|
240
|
+
throw new Error("Truncated JPEG segment.");
|
|
241
|
+
const length = image.readUInt16BE(offset);
|
|
242
|
+
if (length < 2)
|
|
243
|
+
throw new Error("Invalid JPEG segment length.");
|
|
244
|
+
offset += length;
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (image[offset++] !== 0xff)
|
|
249
|
+
continue;
|
|
250
|
+
while (image[offset] === 0xff)
|
|
251
|
+
offset++;
|
|
252
|
+
const marker = image[offset++];
|
|
253
|
+
if (marker === 0x00 || (marker !== undefined && marker >= 0xd0 && marker <= 0xd7))
|
|
254
|
+
continue;
|
|
255
|
+
if (marker === EOI)
|
|
256
|
+
return start + offset;
|
|
257
|
+
inScan = false;
|
|
258
|
+
offset -= 2;
|
|
259
|
+
}
|
|
260
|
+
throw new Error("JPEG EOI marker was not found.");
|
|
261
|
+
}
|
|
262
|
+
function parseMpf(primary) {
|
|
263
|
+
const segment = parseJpegParts(primary).segments.find((candidate) => candidate.marker === APP2 && candidate.payload.subarray(0, 4).toString("ascii") === "MPF\0");
|
|
264
|
+
if (!segment)
|
|
265
|
+
throw new Error("Required Ultra HDR MPF APP2 index is missing.");
|
|
266
|
+
const payload = segment.payload;
|
|
267
|
+
const tiff = 4;
|
|
268
|
+
const byteOrder = payload.subarray(tiff, tiff + 2).toString("ascii");
|
|
269
|
+
if (byteOrder !== "MM" && byteOrder !== "II")
|
|
270
|
+
throw new Error("Invalid MPF TIFF byte order.");
|
|
271
|
+
const littleEndian = byteOrder === "II";
|
|
272
|
+
const read16 = (offset) => {
|
|
273
|
+
if (offset < 0 || offset + 2 > payload.length)
|
|
274
|
+
throw new Error("Truncated MPF APP2 data.");
|
|
275
|
+
return littleEndian ? payload.readUInt16LE(offset) : payload.readUInt16BE(offset);
|
|
276
|
+
};
|
|
277
|
+
const read32 = (offset) => {
|
|
278
|
+
if (offset < 0 || offset + 4 > payload.length)
|
|
279
|
+
throw new Error("Truncated MPF APP2 data.");
|
|
280
|
+
return littleEndian ? payload.readUInt32LE(offset) : payload.readUInt32BE(offset);
|
|
281
|
+
};
|
|
282
|
+
if (read16(tiff + 2) !== 0x2a)
|
|
283
|
+
throw new Error("Invalid MPF TIFF signature.");
|
|
284
|
+
const ifd = tiff + read32(tiff + 4);
|
|
285
|
+
const tagCount = read16(ifd);
|
|
286
|
+
let numberOfImages;
|
|
287
|
+
let entriesOffset;
|
|
288
|
+
let entriesByteLength;
|
|
289
|
+
for (let index = 0; index < tagCount; index++) {
|
|
290
|
+
const tagOffset = ifd + 2 + index * 12;
|
|
291
|
+
const tag = read16(tagOffset);
|
|
292
|
+
if (tag === 0xb001)
|
|
293
|
+
numberOfImages = read32(tagOffset + 8);
|
|
294
|
+
if (tag === 0xb002) {
|
|
295
|
+
entriesByteLength = read32(tagOffset + 4);
|
|
296
|
+
entriesOffset = read32(tagOffset + 8);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (numberOfImages !== 2 || entriesOffset === undefined || entriesByteLength !== 32)
|
|
300
|
+
throw new Error("Ultra HDR MPF index must describe exactly two 16-byte MP entries.");
|
|
301
|
+
const entries = tiff + entriesOffset;
|
|
302
|
+
const primarySize = read32(entries + 4);
|
|
303
|
+
const primaryDataOffset = read32(entries + 8);
|
|
304
|
+
const secondarySize = read32(entries + 20);
|
|
305
|
+
const secondaryDataOffset = read32(entries + 24);
|
|
306
|
+
if (primaryDataOffset !== 0 || primarySize === 0 || secondarySize === 0)
|
|
307
|
+
throw new Error("Invalid Ultra HDR MPF image sizes or primary offset.");
|
|
308
|
+
return {
|
|
309
|
+
tiffOffset: segment.markerOffset + 8,
|
|
310
|
+
primarySize,
|
|
311
|
+
secondarySize,
|
|
312
|
+
secondaryDataOffset,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function getContainerGainMapLength(primary) {
|
|
316
|
+
const segment = parseJpegParts(primary).segments.find((candidate) => {
|
|
317
|
+
if (candidate.marker !== APP1)
|
|
318
|
+
return false;
|
|
319
|
+
if (candidate.payload.subarray(0, xmpNamespace.length).toString("ascii") !== xmpNamespace)
|
|
320
|
+
return false;
|
|
321
|
+
return candidate.payload
|
|
322
|
+
.subarray(xmpNamespace.length)
|
|
323
|
+
.toString("utf8")
|
|
324
|
+
.includes("http://ns.google.com/photos/1.0/container/");
|
|
325
|
+
});
|
|
326
|
+
if (!segment)
|
|
327
|
+
throw new Error("Required Ultra HDR GContainer XMP is missing from the primary image.");
|
|
328
|
+
const xml = segment.payload.subarray(xmpNamespace.length).toString("utf8");
|
|
329
|
+
const items = [...xml.matchAll(/<Container:Item\b([^>]*)\/?\s*>/gi)].map((match) => match[1]);
|
|
330
|
+
const attribute = (attributes, name) => new RegExp(`Item:${name}\\s*=\\s*["']([^"']+)["']`, "i").exec(attributes)?.[1];
|
|
331
|
+
if (items.length < 2 || attribute(items[0], "Semantic") !== "Primary")
|
|
332
|
+
throw new Error("GContainer directory must start with the Primary image item.");
|
|
333
|
+
const gainMapItem = items.slice(1).find((item) => attribute(item, "Semantic") === "GainMap");
|
|
334
|
+
if (!gainMapItem || attribute(gainMapItem, "Mime") !== "image/jpeg")
|
|
335
|
+
throw new Error("GContainer directory does not contain a JPEG GainMap item.");
|
|
336
|
+
const length = Number(attribute(gainMapItem, "Length"));
|
|
337
|
+
if (!Number.isSafeInteger(length) || length <= 0)
|
|
338
|
+
throw new Error("GContainer GainMap Item:Length is missing or invalid.");
|
|
339
|
+
return length;
|
|
340
|
+
}
|
|
341
|
+
export function splitConcatenatedJpegs(container) {
|
|
342
|
+
const primaryEnd = findJpegEnd(container);
|
|
343
|
+
const primary = container.subarray(0, primaryEnd);
|
|
344
|
+
const mpf = parseMpf(primary);
|
|
345
|
+
if (mpf.primarySize !== primaryEnd)
|
|
346
|
+
throw new Error(`MPF primary image size ${mpf.primarySize} does not match JPEG size ${primaryEnd}.`);
|
|
347
|
+
const secondaryStart = mpf.tiffOffset + mpf.secondaryDataOffset;
|
|
348
|
+
if (secondaryStart < primaryEnd || secondaryStart + 2 > container.length)
|
|
349
|
+
throw new Error("MPF secondary image offset is outside the Ultra HDR container.");
|
|
350
|
+
if (container[secondaryStart] !== 0xff || container[secondaryStart + 1] !== SOI)
|
|
351
|
+
throw new Error("MPF does not point to a gain map JPEG SOI marker.");
|
|
352
|
+
const secondaryEnd = findJpegEnd(container, secondaryStart);
|
|
353
|
+
const actualSecondarySize = secondaryEnd - secondaryStart;
|
|
354
|
+
if (mpf.secondarySize !== actualSecondarySize)
|
|
355
|
+
throw new Error(`MPF gain map size ${mpf.secondarySize} does not match JPEG size ${actualSecondarySize}.`);
|
|
356
|
+
const containerLength = getContainerGainMapLength(primary);
|
|
357
|
+
if (containerLength !== actualSecondarySize)
|
|
358
|
+
throw new Error(`GContainer gain map length ${containerLength} does not match JPEG size ${actualSecondarySize}.`);
|
|
359
|
+
return {
|
|
360
|
+
primary,
|
|
361
|
+
gainMap: container.subarray(secondaryStart, secondaryEnd),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=jpeg.js.map
|
package/dist/jpeg.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jpeg.js","sourceRoot":"","sources":["../src/jpeg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CubeToEquirectOptions {
|
|
2
|
+
inputDirectory: string;
|
|
3
|
+
prefix: string;
|
|
4
|
+
output: string;
|
|
5
|
+
}
|
|
6
|
+
export interface EquirectToCubeOptions {
|
|
7
|
+
input: string;
|
|
8
|
+
outputDirectory: string;
|
|
9
|
+
prefix: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function cubeToEquirectUltraHdr(options: CubeToEquirectOptions): Promise<void>;
|
|
12
|
+
export declare function equirectUltraHdrToCube(options: EquirectToCubeOptions): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=panorama.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panorama.d.ts","sourceRoot":"","sources":["../src/panorama.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AA4DD,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B1F;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB1F"}
|
package/dist/panorama.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { convertCubeToEquirect } from "@realsee/equirect-toolbox/cube2equirect";
|
|
2
|
+
import { convertEquirectToCube } from "@realsee/equirect-toolbox/equirect2cube";
|
|
3
|
+
import { access, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { cubeFaceAliases, cubeFaceKeys } from "./types.js";
|
|
7
|
+
import { composeUltraHdrBuffers, extractUltraHdrBuffers } from "./ultrahdr.js";
|
|
8
|
+
import { readGainMapConfig, writeGainMapConfig } from "./xmp.js";
|
|
9
|
+
async function firstExisting(candidates, description) {
|
|
10
|
+
for (const candidate of candidates) {
|
|
11
|
+
try {
|
|
12
|
+
await access(candidate);
|
|
13
|
+
return candidate;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Try the next supported naming convention.
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`Unable to find ${description}. Tried:\n${candidates.join("\n")}`);
|
|
20
|
+
}
|
|
21
|
+
async function resolveInputManifests(directory, prefix) {
|
|
22
|
+
const root = resolve(directory);
|
|
23
|
+
const sdr = {};
|
|
24
|
+
const gainMap = {};
|
|
25
|
+
await Promise.all(cubeFaceKeys.map(async (face) => {
|
|
26
|
+
const alias = cubeFaceAliases[face];
|
|
27
|
+
sdr[face] = await firstExisting([join(root, `${prefix}_${alias}.jpg`), join(root, `${prefix}_${alias}.jpeg`)], `SDR ${alias} face`);
|
|
28
|
+
gainMap[face] = await firstExisting([
|
|
29
|
+
join(root, `${prefix}_${alias}_gainmap.jpg`),
|
|
30
|
+
join(root, `${prefix}_${alias}.gainmap.jpg`),
|
|
31
|
+
join(root, `${prefix}_${alias}_gainmap.jpeg`),
|
|
32
|
+
join(root, `${prefix}_${alias}.gainmap.jpeg`),
|
|
33
|
+
], `gain map ${alias} face`);
|
|
34
|
+
}));
|
|
35
|
+
return { sdr, gainMap };
|
|
36
|
+
}
|
|
37
|
+
function outputManifests(directory, prefix) {
|
|
38
|
+
const root = resolve(directory);
|
|
39
|
+
const sdr = {};
|
|
40
|
+
const gainMap = {};
|
|
41
|
+
for (const face of cubeFaceKeys) {
|
|
42
|
+
const alias = cubeFaceAliases[face];
|
|
43
|
+
sdr[face] = join(root, `${prefix}_${alias}.jpg`);
|
|
44
|
+
gainMap[face] = join(root, `${prefix}_${alias}_gainmap.jpg`);
|
|
45
|
+
}
|
|
46
|
+
return { sdr, gainMap };
|
|
47
|
+
}
|
|
48
|
+
export async function cubeToEquirectUltraHdr(options) {
|
|
49
|
+
const inputDirectory = resolve(options.inputDirectory);
|
|
50
|
+
const manifests = await resolveInputManifests(inputDirectory, options.prefix);
|
|
51
|
+
const configPath = await firstExisting([
|
|
52
|
+
join(inputDirectory, `${options.prefix}_gainmap_cfg.json`),
|
|
53
|
+
join(inputDirectory, `${options.prefix}_gainmap_cfg.xmp`),
|
|
54
|
+
], `gain map config for prefix "${options.prefix}"`);
|
|
55
|
+
const config = await readGainMapConfig(configPath);
|
|
56
|
+
const temporaryDirectory = await mkdtemp(join(tmpdir(), "hdr-toolbox-cube-"));
|
|
57
|
+
try {
|
|
58
|
+
const sdrPath = join(temporaryDirectory, "sdr.jpg");
|
|
59
|
+
const gainMapPath = join(temporaryDirectory, "gainmap.jpg");
|
|
60
|
+
await convertCubeToEquirect({ input: manifests.sdr, output: sdrPath });
|
|
61
|
+
await convertCubeToEquirect({ input: manifests.gainMap, output: gainMapPath });
|
|
62
|
+
const output = await composeUltraHdrBuffers(await readFile(sdrPath), await readFile(gainMapPath), config);
|
|
63
|
+
await mkdir(dirname(resolve(options.output)), { recursive: true });
|
|
64
|
+
await writeFile(options.output, output);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export async function equirectUltraHdrToCube(options) {
|
|
71
|
+
const outputDirectory = resolve(options.outputDirectory);
|
|
72
|
+
await mkdir(outputDirectory, { recursive: true });
|
|
73
|
+
const extracted = extractUltraHdrBuffers(await readFile(options.input));
|
|
74
|
+
const temporaryDirectory = await mkdtemp(join(tmpdir(), "hdr-toolbox-equirect-"));
|
|
75
|
+
try {
|
|
76
|
+
const sdrPath = join(temporaryDirectory, "sdr.jpg");
|
|
77
|
+
const gainMapPath = join(temporaryDirectory, "gainmap.jpg");
|
|
78
|
+
await Promise.all([
|
|
79
|
+
writeFile(sdrPath, extracted.sdr),
|
|
80
|
+
writeFile(gainMapPath, extracted.gainMap),
|
|
81
|
+
]);
|
|
82
|
+
const manifests = outputManifests(outputDirectory, options.prefix);
|
|
83
|
+
await convertEquirectToCube({ input: sdrPath, output: manifests.sdr });
|
|
84
|
+
await convertEquirectToCube({ input: gainMapPath, output: manifests.gainMap });
|
|
85
|
+
await writeGainMapConfig(join(outputDirectory, `${options.prefix}_gainmap_cfg.json`), extracted.config);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=panorama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panorama.js","sourceRoot":"","sources":["../src/panorama.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface GainMapConfig {
|
|
2
|
+
maxContentBoost: number;
|
|
3
|
+
minContentBoost: number;
|
|
4
|
+
gamma: number;
|
|
5
|
+
offsetSdr: number;
|
|
6
|
+
offsetHdr: number;
|
|
7
|
+
hdrCapacityMin: number;
|
|
8
|
+
hdrCapacityMax: number;
|
|
9
|
+
useBaseColorSpace: boolean;
|
|
10
|
+
}
|
|
11
|
+
export type CubeFaceKey = "px" | "nx" | "py" | "ny" | "pz" | "nz";
|
|
12
|
+
export type CubeManifest = Record<CubeFaceKey, string>;
|
|
13
|
+
export declare const cubeFaceKeys: readonly CubeFaceKey[];
|
|
14
|
+
export declare const cubeFaceAliases: Readonly<Record<CubeFaceKey, string>>;
|
|
15
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,YAAY,EAAE,SAAS,WAAW,EAAyC,CAAC;AAEzF,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAOjE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,YAAY,GAA2B,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEzF,MAAM,CAAC,MAAM,eAAe,GAA0C;IACpE,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;CACR,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { GainMapConfig } from "./types.js";
|
|
2
|
+
export interface ComposeUltraHdrOptions {
|
|
3
|
+
sdr: string;
|
|
4
|
+
gainMap: string;
|
|
5
|
+
config: string;
|
|
6
|
+
output: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ExtractUltraHdrOptions {
|
|
9
|
+
input: string;
|
|
10
|
+
sdr: string;
|
|
11
|
+
gainMap: string;
|
|
12
|
+
config: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function composeUltraHdrBuffers(sdr: Buffer, gainMap: Buffer, configInput: GainMapConfig): Promise<Buffer>;
|
|
15
|
+
export declare function extractUltraHdrBuffers(container: Buffer): {
|
|
16
|
+
sdr: Buffer;
|
|
17
|
+
gainMap: Buffer;
|
|
18
|
+
config: GainMapConfig;
|
|
19
|
+
xmp: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function composeUltraHdr(options: ComposeUltraHdrOptions): Promise<void>;
|
|
22
|
+
export declare function extractUltraHdr(options: ExtractUltraHdrOptions): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=ultrahdr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ultrahdr.d.ts","sourceRoot":"","sources":["../src/ultrahdr.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAUhD,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAgDD,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,aAAa,GACzB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb,CAWA;AAMD,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CASpF;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpF"}
|
package/dist/ultrahdr.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import sharp from "sharp";
|
|
4
|
+
import { addGainMapXmp, addIccProfileSegments, buildPrimaryJpeg, getGainMapXmp, getIccProfileSegments, splitConcatenatedJpegs, stripUltraHdrMetadata, } from "./jpeg.js";
|
|
5
|
+
import { createGainMapXmp, createPrimaryXmp, normalizeGainMapConfig, parseGainMapXmp, readGainMapConfig, writeGainMapConfig, } from "./xmp.js";
|
|
6
|
+
let defaultIccSegments;
|
|
7
|
+
function getDefaultIccSegments() {
|
|
8
|
+
defaultIccSegments ??= sharp({
|
|
9
|
+
create: { width: 1, height: 1, channels: 3, background: { r: 0, g: 0, b: 0 } },
|
|
10
|
+
})
|
|
11
|
+
.jpeg()
|
|
12
|
+
.withIccProfile("srgb")
|
|
13
|
+
.toBuffer()
|
|
14
|
+
.then((jpeg) => {
|
|
15
|
+
const segments = getIccProfileSegments(jpeg);
|
|
16
|
+
if (segments.length === 0)
|
|
17
|
+
throw new Error("Sharp did not provide the requested sRGB ICC profile.");
|
|
18
|
+
return segments;
|
|
19
|
+
});
|
|
20
|
+
return defaultIccSegments;
|
|
21
|
+
}
|
|
22
|
+
async function ensurePrimaryIccProfile(sdr) {
|
|
23
|
+
if (getIccProfileSegments(sdr).length > 0)
|
|
24
|
+
return sdr;
|
|
25
|
+
return addIccProfileSegments(sdr, await getDefaultIccSegments());
|
|
26
|
+
}
|
|
27
|
+
async function validateJpegPair(sdr, gainMap) {
|
|
28
|
+
const [sdrMetadata, gainMetadata] = await Promise.all([
|
|
29
|
+
sharp(sdr).metadata(),
|
|
30
|
+
sharp(gainMap).metadata(),
|
|
31
|
+
]);
|
|
32
|
+
if (sdrMetadata.format !== "jpeg" || gainMetadata.format !== "jpeg")
|
|
33
|
+
throw new Error("Both the SDR primary image and gain map must be JPEG files.");
|
|
34
|
+
if (!sdrMetadata.width || !sdrMetadata.height || !gainMetadata.width || !gainMetadata.height)
|
|
35
|
+
throw new Error("Unable to determine JPEG dimensions.");
|
|
36
|
+
const sdrOrientation = sdrMetadata.orientation ?? 1;
|
|
37
|
+
const gainOrientation = gainMetadata.orientation ?? 1;
|
|
38
|
+
if (sdrOrientation !== gainOrientation)
|
|
39
|
+
throw new Error(`SDR and gain map EXIF orientations differ (${sdrOrientation} vs ${gainOrientation}).`);
|
|
40
|
+
const sdrRatio = sdrMetadata.width / sdrMetadata.height;
|
|
41
|
+
const gainRatio = gainMetadata.width / gainMetadata.height;
|
|
42
|
+
if (Math.abs(sdrRatio - gainRatio) > 0.001)
|
|
43
|
+
throw new Error(`SDR and gain map aspect ratios differ (${sdrMetadata.width}x${sdrMetadata.height} vs ${gainMetadata.width}x${gainMetadata.height}).`);
|
|
44
|
+
}
|
|
45
|
+
export async function composeUltraHdrBuffers(sdr, gainMap, configInput) {
|
|
46
|
+
const config = normalizeGainMapConfig(configInput);
|
|
47
|
+
await validateJpegPair(sdr, gainMap);
|
|
48
|
+
const sdrWithIcc = await ensurePrimaryIccProfile(sdr);
|
|
49
|
+
const gainMapWithXmp = addGainMapXmp(gainMap, createGainMapXmp(config));
|
|
50
|
+
const primary = buildPrimaryJpeg(sdrWithIcc, createPrimaryXmp(gainMapWithXmp.length), gainMapWithXmp.length);
|
|
51
|
+
return Buffer.concat([primary, gainMapWithXmp]);
|
|
52
|
+
}
|
|
53
|
+
export function extractUltraHdrBuffers(container) {
|
|
54
|
+
const { primary, gainMap } = splitConcatenatedJpegs(container);
|
|
55
|
+
const xmp = getGainMapXmp(gainMap);
|
|
56
|
+
if (!xmp)
|
|
57
|
+
throw new Error("The secondary JPEG does not contain required HDR gain map XMP metadata.");
|
|
58
|
+
return {
|
|
59
|
+
sdr: stripUltraHdrMetadata(primary),
|
|
60
|
+
gainMap: stripUltraHdrMetadata(gainMap),
|
|
61
|
+
config: parseGainMapXmp(xmp),
|
|
62
|
+
xmp,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function ensureParent(path) {
|
|
66
|
+
await mkdir(dirname(path), { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
export async function composeUltraHdr(options) {
|
|
69
|
+
const [sdr, gainMap, config] = await Promise.all([
|
|
70
|
+
readFile(options.sdr),
|
|
71
|
+
readFile(options.gainMap),
|
|
72
|
+
readGainMapConfig(options.config),
|
|
73
|
+
]);
|
|
74
|
+
const output = await composeUltraHdrBuffers(sdr, gainMap, config);
|
|
75
|
+
await ensureParent(options.output);
|
|
76
|
+
await writeFile(options.output, output);
|
|
77
|
+
}
|
|
78
|
+
export async function extractUltraHdr(options) {
|
|
79
|
+
const extracted = extractUltraHdrBuffers(await readFile(options.input));
|
|
80
|
+
await Promise.all([
|
|
81
|
+
ensureParent(options.sdr),
|
|
82
|
+
ensureParent(options.gainMap),
|
|
83
|
+
ensureParent(options.config),
|
|
84
|
+
]);
|
|
85
|
+
await Promise.all([
|
|
86
|
+
writeFile(options.sdr, extracted.sdr),
|
|
87
|
+
writeFile(options.gainMap, extracted.gainMap),
|
|
88
|
+
writeGainMapConfig(options.config, extracted.config),
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=ultrahdr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ultrahdr.js","sourceRoot":"","sources":["../src/ultrahdr.ts"],"names":[],"mappings":"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"}
|
package/dist/xmp.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GainMapConfig } from "./types.js";
|
|
2
|
+
export declare const xmpNamespace = "http://ns.adobe.com/xap/1.0/\0";
|
|
3
|
+
export declare function normalizeGainMapConfig(value: unknown): GainMapConfig;
|
|
4
|
+
export declare function parseGainMapXmp(xml: string): GainMapConfig;
|
|
5
|
+
export declare function createGainMapXmp(configInput: GainMapConfig): string;
|
|
6
|
+
export declare function createPrimaryXmp(gainMapLength: number): string;
|
|
7
|
+
export declare function readGainMapConfig(path: string): Promise<GainMapConfig>;
|
|
8
|
+
export declare function writeGainMapConfig(path: string, config: GainMapConfig): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=xmp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xmp.d.ts","sourceRoot":"","sources":["../src/xmp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,YAAY,mCAAmC,CAAC;AA4B7D,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CA8BpE;AAiCD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAqB1D;AAMD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,CAKnE;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAM5E;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3F"}
|
package/dist/xmp.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname } from "node:path";
|
|
3
|
+
export const xmpNamespace = "http://ns.adobe.com/xap/1.0/\0";
|
|
4
|
+
const hdrGainMapNamespace = "http://ns.adobe.com/hdr-gain-map/1.0/";
|
|
5
|
+
const defaults = {
|
|
6
|
+
maxContentBoost: 1,
|
|
7
|
+
minContentBoost: 1,
|
|
8
|
+
gamma: 1,
|
|
9
|
+
offsetSdr: 0.015625,
|
|
10
|
+
offsetHdr: 0.015625,
|
|
11
|
+
hdrCapacityMin: 1,
|
|
12
|
+
hdrCapacityMax: 1,
|
|
13
|
+
useBaseColorSpace: true,
|
|
14
|
+
};
|
|
15
|
+
function finiteNumber(value, name, fallback) {
|
|
16
|
+
if (value === undefined && fallback !== undefined)
|
|
17
|
+
return fallback;
|
|
18
|
+
const number = typeof value === "number" ? value : Number(value);
|
|
19
|
+
if (!Number.isFinite(number))
|
|
20
|
+
throw new Error(`Invalid ${name}: expected a finite number.`);
|
|
21
|
+
return number;
|
|
22
|
+
}
|
|
23
|
+
function booleanValue(value, fallback) {
|
|
24
|
+
if (value === undefined)
|
|
25
|
+
return fallback;
|
|
26
|
+
if (typeof value === "boolean")
|
|
27
|
+
return value;
|
|
28
|
+
if (typeof value === "number")
|
|
29
|
+
return value !== 0;
|
|
30
|
+
return !["0", "false", "no"].includes(String(value).toLowerCase());
|
|
31
|
+
}
|
|
32
|
+
export function normalizeGainMapConfig(value) {
|
|
33
|
+
if (typeof value !== "object" || value === null)
|
|
34
|
+
throw new Error("Gain map config must be an object.");
|
|
35
|
+
const input = value;
|
|
36
|
+
const config = {
|
|
37
|
+
maxContentBoost: finiteNumber(input.maxContentBoost, "maxContentBoost"),
|
|
38
|
+
minContentBoost: finiteNumber(input.minContentBoost, "minContentBoost", defaults.minContentBoost),
|
|
39
|
+
gamma: finiteNumber(input.gamma, "gamma", defaults.gamma),
|
|
40
|
+
offsetSdr: finiteNumber(input.offsetSdr, "offsetSdr", defaults.offsetSdr),
|
|
41
|
+
offsetHdr: finiteNumber(input.offsetHdr, "offsetHdr", defaults.offsetHdr),
|
|
42
|
+
hdrCapacityMin: finiteNumber(input.hdrCapacityMin, "hdrCapacityMin", defaults.hdrCapacityMin),
|
|
43
|
+
hdrCapacityMax: finiteNumber(input.hdrCapacityMax, "hdrCapacityMax"),
|
|
44
|
+
useBaseColorSpace: booleanValue(input.useBaseColorSpace, defaults.useBaseColorSpace),
|
|
45
|
+
};
|
|
46
|
+
if (config.maxContentBoost < 1)
|
|
47
|
+
throw new Error("maxContentBoost must be >= 1.");
|
|
48
|
+
if (config.minContentBoost <= 0 || config.minContentBoost > 1)
|
|
49
|
+
throw new Error("minContentBoost must be > 0 and <= 1.");
|
|
50
|
+
if (config.minContentBoost > config.maxContentBoost)
|
|
51
|
+
throw new Error("minContentBoost must be <= maxContentBoost.");
|
|
52
|
+
if (config.gamma <= 0)
|
|
53
|
+
throw new Error("gamma must be > 0.");
|
|
54
|
+
if (config.offsetSdr < 0 || config.offsetHdr < 0)
|
|
55
|
+
throw new Error("offsets must be >= 0.");
|
|
56
|
+
if (config.hdrCapacityMin < 1)
|
|
57
|
+
throw new Error("hdrCapacityMin must be >= 1.");
|
|
58
|
+
if (config.hdrCapacityMax <= config.hdrCapacityMin)
|
|
59
|
+
throw new Error("hdrCapacityMax must be greater than hdrCapacityMin.");
|
|
60
|
+
return config;
|
|
61
|
+
}
|
|
62
|
+
function propertyValues(xml, name) {
|
|
63
|
+
const attribute = new RegExp(`(?:hdrgm:)?${name}\\s*=\\s*["']([^"']+)["']`, "i").exec(xml);
|
|
64
|
+
if (attribute)
|
|
65
|
+
return [attribute[1]];
|
|
66
|
+
const element = new RegExp(`<hdrgm:${name}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/hdrgm:${name}>`, "i").exec(xml);
|
|
67
|
+
if (!element)
|
|
68
|
+
return undefined;
|
|
69
|
+
const listValues = [...element[1].matchAll(/<rdf:li(?:\s[^>]*)?>([\s\S]*?)<\/rdf:li>/gi)].map((match) => match[1].replace(/<[^>]+>/g, "").trim());
|
|
70
|
+
if (listValues.length > 0)
|
|
71
|
+
return listValues;
|
|
72
|
+
const value = element[1].replace(/<[^>]+>/g, "").trim();
|
|
73
|
+
if (!value)
|
|
74
|
+
throw new Error(`Invalid empty HDR gain map XMP property: ${name}.`);
|
|
75
|
+
return [value];
|
|
76
|
+
}
|
|
77
|
+
function scalarProperty(xml, name, fallback) {
|
|
78
|
+
const values = propertyValues(xml, name);
|
|
79
|
+
if (!values) {
|
|
80
|
+
if (fallback !== undefined)
|
|
81
|
+
return fallback;
|
|
82
|
+
throw new Error(`Missing required HDR gain map XMP property: ${name}.`);
|
|
83
|
+
}
|
|
84
|
+
if (![1, 3].includes(values.length))
|
|
85
|
+
throw new Error(`${name} must contain either one value or three channel values.`);
|
|
86
|
+
const numbers = values.map((value) => finiteNumber(value, name));
|
|
87
|
+
if (numbers.some((value) => value !== numbers[0]))
|
|
88
|
+
throw new Error(`Per-channel ${name} arrays are not supported by the scalar config model.`);
|
|
89
|
+
return numbers[0];
|
|
90
|
+
}
|
|
91
|
+
export function parseGainMapXmp(xml) {
|
|
92
|
+
const version = propertyValues(xml, "Version")?.[0];
|
|
93
|
+
if (version !== "1.0" || !xml.includes(hdrGainMapNamespace))
|
|
94
|
+
throw new Error("The XMP packet is not an Ultra HDR 1.0 gain map packet.");
|
|
95
|
+
if (propertyValues(xml, "BaseRenditionIsHDR")?.[0]?.toLowerCase() === "true")
|
|
96
|
+
throw new Error("BaseRenditionIsHDR=True is not supported by the Ultra HDR JPEG profile.");
|
|
97
|
+
const gainMapMin = scalarProperty(xml, "GainMapMin", 0);
|
|
98
|
+
const gainMapMax = scalarProperty(xml, "GainMapMax");
|
|
99
|
+
const capacityMin = scalarProperty(xml, "HDRCapacityMin", 0);
|
|
100
|
+
const capacityMax = scalarProperty(xml, "HDRCapacityMax");
|
|
101
|
+
return normalizeGainMapConfig({
|
|
102
|
+
minContentBoost: 2 ** gainMapMin,
|
|
103
|
+
maxContentBoost: 2 ** gainMapMax,
|
|
104
|
+
gamma: scalarProperty(xml, "Gamma", 1),
|
|
105
|
+
offsetSdr: scalarProperty(xml, "OffsetSDR", 0.015625),
|
|
106
|
+
offsetHdr: scalarProperty(xml, "OffsetHDR", 0.015625),
|
|
107
|
+
hdrCapacityMin: 2 ** capacityMin,
|
|
108
|
+
hdrCapacityMax: 2 ** capacityMax,
|
|
109
|
+
useBaseColorSpace: true,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function formatNumber(value) {
|
|
113
|
+
return Number(value.toPrecision(12)).toString();
|
|
114
|
+
}
|
|
115
|
+
export function createGainMapXmp(configInput) {
|
|
116
|
+
const config = normalizeGainMapConfig(configInput);
|
|
117
|
+
if (!config.useBaseColorSpace)
|
|
118
|
+
throw new Error("Ultra HDR v1 XMP requires gain map application in the base color space.");
|
|
119
|
+
return `<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="@realsee/hdr-toolbox"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:hdrgm="${hdrGainMapNamespace}" hdrgm:Version="1.0" hdrgm:BaseRenditionIsHDR="False" hdrgm:GainMapMin="${formatNumber(Math.log2(config.minContentBoost))}" hdrgm:GainMapMax="${formatNumber(Math.log2(config.maxContentBoost))}" hdrgm:Gamma="${formatNumber(config.gamma)}" hdrgm:OffsetSDR="${formatNumber(config.offsetSdr)}" hdrgm:OffsetHDR="${formatNumber(config.offsetHdr)}" hdrgm:HDRCapacityMin="${formatNumber(Math.log2(config.hdrCapacityMin))}" hdrgm:HDRCapacityMax="${formatNumber(Math.log2(config.hdrCapacityMax))}"/></rdf:RDF></x:xmpmeta>`;
|
|
120
|
+
}
|
|
121
|
+
export function createPrimaryXmp(gainMapLength) {
|
|
122
|
+
if (!Number.isSafeInteger(gainMapLength) || gainMapLength <= 0)
|
|
123
|
+
throw new Error("Gain map JPEG length must be a positive integer.");
|
|
124
|
+
return `<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="@realsee/hdr-toolbox"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:Container="http://ns.google.com/photos/1.0/container/" xmlns:Item="http://ns.google.com/photos/1.0/container/item/" xmlns:hdrgm="${hdrGainMapNamespace}" hdrgm:Version="1.0"><Container:Directory><rdf:Seq><rdf:li rdf:parseType="Resource"><Container:Item Item:Semantic="Primary" Item:Mime="image/jpeg"/></rdf:li><rdf:li rdf:parseType="Resource"><Container:Item Item:Semantic="GainMap" Item:Mime="image/jpeg" Item:Length="${gainMapLength}"/></rdf:li></rdf:Seq></Container:Directory></rdf:Description></rdf:RDF></x:xmpmeta>`;
|
|
125
|
+
}
|
|
126
|
+
export async function readGainMapConfig(path) {
|
|
127
|
+
const text = await readFile(path, "utf8");
|
|
128
|
+
const trimmed = text.trim();
|
|
129
|
+
if (trimmed.startsWith("{") || extname(path).toLowerCase() === ".json")
|
|
130
|
+
return normalizeGainMapConfig(JSON.parse(trimmed));
|
|
131
|
+
return parseGainMapXmp(trimmed);
|
|
132
|
+
}
|
|
133
|
+
export async function writeGainMapConfig(path, config) {
|
|
134
|
+
const contents = extname(path).toLowerCase() === ".xmp"
|
|
135
|
+
? `${createGainMapXmp(config)}\n`
|
|
136
|
+
: `${JSON.stringify(normalizeGainMapConfig(config), null, 2)}\n`;
|
|
137
|
+
await mkdir(dirname(path), { recursive: true });
|
|
138
|
+
await writeFile(path, contents, "utf8");
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=xmp.js.map
|
package/dist/xmp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xmp.js","sourceRoot":"","sources":["../src/xmp.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@realsee/hdr-toolbox",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Compose, extract, and convert Android Ultra HDR JPEG images",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"bin": {
|
|
8
|
+
"hdr-toolbox": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.build.json",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"test": "node --import tsx --test test/*.test.ts",
|
|
30
|
+
"lint": "oxlint src test",
|
|
31
|
+
"format": "oxfmt src test README.md package.json",
|
|
32
|
+
"format:check": "oxfmt --check src test README.md package.json",
|
|
33
|
+
"prepack": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@realsee/equirect-toolbox": "^1.0.5",
|
|
37
|
+
"commander": "^15.0.0",
|
|
38
|
+
"sharp": "^0.35.4"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.20.1",
|
|
42
|
+
"oxfmt": "^0.64.0",
|
|
43
|
+
"oxlint": "^1.79.0",
|
|
44
|
+
"tsx": "^4.19.0",
|
|
45
|
+
"typescript": "^5.6.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": "^20 || ^22"
|
|
49
|
+
}
|
|
50
|
+
}
|