open-ultrahdr 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +60 -1
- package/dist/index.d.ts +60 -1
- package/dist/index.js +34 -10
- package/dist/index.mjs +33 -10
- package/package.json +7 -6
- package/src/index.ts +88 -18
- package/src/types.ts +38 -0
package/dist/index.d.mts
CHANGED
|
@@ -28,6 +28,34 @@ interface GainMapMetadata {
|
|
|
28
28
|
/** Maximum HDR capacity (log2 scale) for full HDR output */
|
|
29
29
|
hdrCapacityMax: number;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Result of probing an image to check if it's UltraHDR.
|
|
33
|
+
*
|
|
34
|
+
* Provides detailed information about what components were found
|
|
35
|
+
* without fully decoding the image. Useful for batch processing and filtering.
|
|
36
|
+
*/
|
|
37
|
+
interface UltraHdrProbeResult {
|
|
38
|
+
/** Whether the image is a valid UltraHDR image (has all required components) */
|
|
39
|
+
isValid: boolean;
|
|
40
|
+
/** Whether a primary JPEG image was found */
|
|
41
|
+
hasPrimaryImage: boolean;
|
|
42
|
+
/** Whether a gain map image was found */
|
|
43
|
+
hasGainMap: boolean;
|
|
44
|
+
/** Whether gain map metadata (XMP) was found */
|
|
45
|
+
hasMetadata: boolean;
|
|
46
|
+
/** Primary image width in pixels (0 if not found) */
|
|
47
|
+
width: number;
|
|
48
|
+
/** Primary image height in pixels (0 if not found) */
|
|
49
|
+
height: number;
|
|
50
|
+
/** Gain map width in pixels (0 if not found) */
|
|
51
|
+
gainMapWidth: number;
|
|
52
|
+
/** Gain map height in pixels (0 if not found) */
|
|
53
|
+
gainMapHeight: number;
|
|
54
|
+
/** HDR capacity (max additional stops of dynamic range), 0 if not found */
|
|
55
|
+
hdrCapacity: number;
|
|
56
|
+
/** Metadata version string (empty if not found) */
|
|
57
|
+
metadataVersion: string;
|
|
58
|
+
}
|
|
31
59
|
/**
|
|
32
60
|
* Result of decoding an UltraHDR image.
|
|
33
61
|
*/
|
|
@@ -157,6 +185,37 @@ declare function setLocation(newLocation: string): void;
|
|
|
157
185
|
* ```
|
|
158
186
|
*/
|
|
159
187
|
declare function isUltraHdr(buffer: ArrayBuffer): Promise<boolean>;
|
|
188
|
+
/**
|
|
189
|
+
* Probes an image to check if it's UltraHDR and extracts component information.
|
|
190
|
+
*
|
|
191
|
+
* This function efficiently validates if an image is UltraHDR by checking for
|
|
192
|
+
* required components (primary image, gain map, metadata) without full decoding.
|
|
193
|
+
* Returns structured results useful for batch processing and filtering.
|
|
194
|
+
*
|
|
195
|
+
* Unlike `isUltraHdr`, this function provides detailed information about what
|
|
196
|
+
* was found, making it useful for diagnostics and filtering workflows.
|
|
197
|
+
*
|
|
198
|
+
* @param buffer - Image file contents.
|
|
199
|
+
* @return Probe result with detailed component information.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* const buffer = await file.arrayBuffer();
|
|
204
|
+
* const result = await probeUltraHdr(buffer);
|
|
205
|
+
*
|
|
206
|
+
* if (result.isValid) {
|
|
207
|
+
* console.log('UltraHDR image:', result.width, 'x', result.height);
|
|
208
|
+
* console.log('HDR capacity:', result.hdrCapacity, 'stops');
|
|
209
|
+
* console.log('Gain map:', result.gainMapWidth, 'x', result.gainMapHeight);
|
|
210
|
+
* } else {
|
|
211
|
+
* // Diagnose why it's not a valid UltraHDR
|
|
212
|
+
* if (!result.hasPrimaryImage) console.log('Not a valid JPEG');
|
|
213
|
+
* if (!result.hasGainMap) console.log('Missing gain map');
|
|
214
|
+
* if (!result.hasMetadata) console.log('Missing HDR metadata');
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
declare function probeUltraHdr(buffer: ArrayBuffer): Promise<UltraHdrProbeResult>;
|
|
160
219
|
/**
|
|
161
220
|
* Decodes an UltraHDR image, extracting all components.
|
|
162
221
|
*
|
|
@@ -263,4 +322,4 @@ declare function estimateHdrHeadroom(metadata: GainMapMetadata): Promise<number>
|
|
|
263
322
|
*/
|
|
264
323
|
declare function isMeaningfulHdr(metadata: GainMapMetadata): Promise<boolean>;
|
|
265
324
|
|
|
266
|
-
export { ColorGamut, type GainMapMetadata, type ItemId, TransferFunction, type UltraHdrDecodeResult, type UltraHdrEncodeOptions, decodeUltraHdr, defaultEncodeOptions, encodeUltraHdr, estimateHdrHeadroom, extractSdrBase, getMetadata, highQualityEncodeOptions, isMeaningfulHdr, isUltraHdr, setLocation, smallSizeEncodeOptions, validateMetadata };
|
|
325
|
+
export { ColorGamut, type GainMapMetadata, type ItemId, TransferFunction, type UltraHdrDecodeResult, type UltraHdrEncodeOptions, type UltraHdrProbeResult, decodeUltraHdr, defaultEncodeOptions, encodeUltraHdr, estimateHdrHeadroom, extractSdrBase, getMetadata, highQualityEncodeOptions, isMeaningfulHdr, isUltraHdr, probeUltraHdr, setLocation, smallSizeEncodeOptions, validateMetadata };
|
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,34 @@ interface GainMapMetadata {
|
|
|
28
28
|
/** Maximum HDR capacity (log2 scale) for full HDR output */
|
|
29
29
|
hdrCapacityMax: number;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Result of probing an image to check if it's UltraHDR.
|
|
33
|
+
*
|
|
34
|
+
* Provides detailed information about what components were found
|
|
35
|
+
* without fully decoding the image. Useful for batch processing and filtering.
|
|
36
|
+
*/
|
|
37
|
+
interface UltraHdrProbeResult {
|
|
38
|
+
/** Whether the image is a valid UltraHDR image (has all required components) */
|
|
39
|
+
isValid: boolean;
|
|
40
|
+
/** Whether a primary JPEG image was found */
|
|
41
|
+
hasPrimaryImage: boolean;
|
|
42
|
+
/** Whether a gain map image was found */
|
|
43
|
+
hasGainMap: boolean;
|
|
44
|
+
/** Whether gain map metadata (XMP) was found */
|
|
45
|
+
hasMetadata: boolean;
|
|
46
|
+
/** Primary image width in pixels (0 if not found) */
|
|
47
|
+
width: number;
|
|
48
|
+
/** Primary image height in pixels (0 if not found) */
|
|
49
|
+
height: number;
|
|
50
|
+
/** Gain map width in pixels (0 if not found) */
|
|
51
|
+
gainMapWidth: number;
|
|
52
|
+
/** Gain map height in pixels (0 if not found) */
|
|
53
|
+
gainMapHeight: number;
|
|
54
|
+
/** HDR capacity (max additional stops of dynamic range), 0 if not found */
|
|
55
|
+
hdrCapacity: number;
|
|
56
|
+
/** Metadata version string (empty if not found) */
|
|
57
|
+
metadataVersion: string;
|
|
58
|
+
}
|
|
31
59
|
/**
|
|
32
60
|
* Result of decoding an UltraHDR image.
|
|
33
61
|
*/
|
|
@@ -157,6 +185,37 @@ declare function setLocation(newLocation: string): void;
|
|
|
157
185
|
* ```
|
|
158
186
|
*/
|
|
159
187
|
declare function isUltraHdr(buffer: ArrayBuffer): Promise<boolean>;
|
|
188
|
+
/**
|
|
189
|
+
* Probes an image to check if it's UltraHDR and extracts component information.
|
|
190
|
+
*
|
|
191
|
+
* This function efficiently validates if an image is UltraHDR by checking for
|
|
192
|
+
* required components (primary image, gain map, metadata) without full decoding.
|
|
193
|
+
* Returns structured results useful for batch processing and filtering.
|
|
194
|
+
*
|
|
195
|
+
* Unlike `isUltraHdr`, this function provides detailed information about what
|
|
196
|
+
* was found, making it useful for diagnostics and filtering workflows.
|
|
197
|
+
*
|
|
198
|
+
* @param buffer - Image file contents.
|
|
199
|
+
* @return Probe result with detailed component information.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* const buffer = await file.arrayBuffer();
|
|
204
|
+
* const result = await probeUltraHdr(buffer);
|
|
205
|
+
*
|
|
206
|
+
* if (result.isValid) {
|
|
207
|
+
* console.log('UltraHDR image:', result.width, 'x', result.height);
|
|
208
|
+
* console.log('HDR capacity:', result.hdrCapacity, 'stops');
|
|
209
|
+
* console.log('Gain map:', result.gainMapWidth, 'x', result.gainMapHeight);
|
|
210
|
+
* } else {
|
|
211
|
+
* // Diagnose why it's not a valid UltraHDR
|
|
212
|
+
* if (!result.hasPrimaryImage) console.log('Not a valid JPEG');
|
|
213
|
+
* if (!result.hasGainMap) console.log('Missing gain map');
|
|
214
|
+
* if (!result.hasMetadata) console.log('Missing HDR metadata');
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
declare function probeUltraHdr(buffer: ArrayBuffer): Promise<UltraHdrProbeResult>;
|
|
160
219
|
/**
|
|
161
220
|
* Decodes an UltraHDR image, extracting all components.
|
|
162
221
|
*
|
|
@@ -263,4 +322,4 @@ declare function estimateHdrHeadroom(metadata: GainMapMetadata): Promise<number>
|
|
|
263
322
|
*/
|
|
264
323
|
declare function isMeaningfulHdr(metadata: GainMapMetadata): Promise<boolean>;
|
|
265
324
|
|
|
266
|
-
export { ColorGamut, type GainMapMetadata, type ItemId, TransferFunction, type UltraHdrDecodeResult, type UltraHdrEncodeOptions, decodeUltraHdr, defaultEncodeOptions, encodeUltraHdr, estimateHdrHeadroom, extractSdrBase, getMetadata, highQualityEncodeOptions, isMeaningfulHdr, isUltraHdr, setLocation, smallSizeEncodeOptions, validateMetadata };
|
|
325
|
+
export { ColorGamut, type GainMapMetadata, type ItemId, TransferFunction, type UltraHdrDecodeResult, type UltraHdrEncodeOptions, type UltraHdrProbeResult, decodeUltraHdr, defaultEncodeOptions, encodeUltraHdr, estimateHdrHeadroom, extractSdrBase, getMetadata, highQualityEncodeOptions, isMeaningfulHdr, isUltraHdr, probeUltraHdr, setLocation, smallSizeEncodeOptions, validateMetadata };
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ __export(index_exports, {
|
|
|
41
41
|
highQualityEncodeOptions: () => highQualityEncodeOptions,
|
|
42
42
|
isMeaningfulHdr: () => isMeaningfulHdr,
|
|
43
43
|
isUltraHdr: () => isUltraHdr,
|
|
44
|
+
probeUltraHdr: () => probeUltraHdr,
|
|
44
45
|
setLocation: () => setLocation,
|
|
45
46
|
smallSizeEncodeOptions: () => smallSizeEncodeOptions,
|
|
46
47
|
validateMetadata: () => validateMetadata
|
|
@@ -121,15 +122,27 @@ async function getWasm() {
|
|
|
121
122
|
return initPromise;
|
|
122
123
|
}
|
|
123
124
|
initPromise = (async () => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
try {
|
|
126
|
+
const UltraHdrWasm = await import("open-ultrahdr-wasm");
|
|
127
|
+
if (location) {
|
|
128
|
+
const base = location.endsWith("/") ? location : `${location}/`;
|
|
129
|
+
const wasmPath = base + "open_ultrahdr_bg.wasm";
|
|
130
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
131
|
+
const fs = await import("fs");
|
|
132
|
+
const wasmBytes = await fs.promises.readFile(wasmPath);
|
|
133
|
+
await UltraHdrWasm.default(wasmBytes);
|
|
134
|
+
} else {
|
|
135
|
+
await UltraHdrWasm.default(wasmPath);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
await UltraHdrWasm.default();
|
|
139
|
+
}
|
|
140
|
+
wasmInstance = UltraHdrWasm;
|
|
141
|
+
return wasmInstance;
|
|
142
|
+
} catch (err) {
|
|
143
|
+
initPromise = null;
|
|
144
|
+
throw err;
|
|
130
145
|
}
|
|
131
|
-
wasmInstance = UltraHdrWasm;
|
|
132
|
-
return wasmInstance;
|
|
133
146
|
})();
|
|
134
147
|
return initPromise;
|
|
135
148
|
}
|
|
@@ -137,6 +150,10 @@ async function isUltraHdr(buffer) {
|
|
|
137
150
|
const wasm = await getWasm();
|
|
138
151
|
return wasm.isUltraHdr(new Uint8Array(buffer));
|
|
139
152
|
}
|
|
153
|
+
async function probeUltraHdr(buffer) {
|
|
154
|
+
const wasm = await getWasm();
|
|
155
|
+
return wasm.probeUltraHdr(new Uint8Array(buffer));
|
|
156
|
+
}
|
|
140
157
|
async function decodeUltraHdr(id, buffer) {
|
|
141
158
|
const wasm = await getWasm();
|
|
142
159
|
return wasm.decodeUltraHdr(new Uint8Array(buffer));
|
|
@@ -156,12 +173,18 @@ async function encodeUltraHdr(id, sdrBuffer, hdrBuffer, options) {
|
|
|
156
173
|
new Float32Array(hdrBuffer),
|
|
157
174
|
wasmOpts
|
|
158
175
|
);
|
|
159
|
-
return result.buffer.slice(
|
|
176
|
+
return result.buffer.slice(
|
|
177
|
+
result.byteOffset,
|
|
178
|
+
result.byteOffset + result.byteLength
|
|
179
|
+
);
|
|
160
180
|
}
|
|
161
181
|
async function extractSdrBase(buffer) {
|
|
162
182
|
const wasm = await getWasm();
|
|
163
183
|
const result = wasm.extractSdrBase(new Uint8Array(buffer));
|
|
164
|
-
return result.buffer.slice(
|
|
184
|
+
return result.buffer.slice(
|
|
185
|
+
result.byteOffset,
|
|
186
|
+
result.byteOffset + result.byteLength
|
|
187
|
+
);
|
|
165
188
|
}
|
|
166
189
|
async function getMetadata(buffer) {
|
|
167
190
|
const wasm = await getWasm();
|
|
@@ -195,6 +218,7 @@ async function isMeaningfulHdr(metadata) {
|
|
|
195
218
|
highQualityEncodeOptions,
|
|
196
219
|
isMeaningfulHdr,
|
|
197
220
|
isUltraHdr,
|
|
221
|
+
probeUltraHdr,
|
|
198
222
|
setLocation,
|
|
199
223
|
smallSizeEncodeOptions,
|
|
200
224
|
validateMetadata
|
package/dist/index.mjs
CHANGED
|
@@ -72,15 +72,27 @@ async function getWasm() {
|
|
|
72
72
|
return initPromise;
|
|
73
73
|
}
|
|
74
74
|
initPromise = (async () => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
try {
|
|
76
|
+
const UltraHdrWasm = await import("open-ultrahdr-wasm");
|
|
77
|
+
if (location) {
|
|
78
|
+
const base = location.endsWith("/") ? location : `${location}/`;
|
|
79
|
+
const wasmPath = base + "open_ultrahdr_bg.wasm";
|
|
80
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
81
|
+
const fs = await import("fs");
|
|
82
|
+
const wasmBytes = await fs.promises.readFile(wasmPath);
|
|
83
|
+
await UltraHdrWasm.default(wasmBytes);
|
|
84
|
+
} else {
|
|
85
|
+
await UltraHdrWasm.default(wasmPath);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
await UltraHdrWasm.default();
|
|
89
|
+
}
|
|
90
|
+
wasmInstance = UltraHdrWasm;
|
|
91
|
+
return wasmInstance;
|
|
92
|
+
} catch (err) {
|
|
93
|
+
initPromise = null;
|
|
94
|
+
throw err;
|
|
81
95
|
}
|
|
82
|
-
wasmInstance = UltraHdrWasm;
|
|
83
|
-
return wasmInstance;
|
|
84
96
|
})();
|
|
85
97
|
return initPromise;
|
|
86
98
|
}
|
|
@@ -88,6 +100,10 @@ async function isUltraHdr(buffer) {
|
|
|
88
100
|
const wasm = await getWasm();
|
|
89
101
|
return wasm.isUltraHdr(new Uint8Array(buffer));
|
|
90
102
|
}
|
|
103
|
+
async function probeUltraHdr(buffer) {
|
|
104
|
+
const wasm = await getWasm();
|
|
105
|
+
return wasm.probeUltraHdr(new Uint8Array(buffer));
|
|
106
|
+
}
|
|
91
107
|
async function decodeUltraHdr(id, buffer) {
|
|
92
108
|
const wasm = await getWasm();
|
|
93
109
|
return wasm.decodeUltraHdr(new Uint8Array(buffer));
|
|
@@ -107,12 +123,18 @@ async function encodeUltraHdr(id, sdrBuffer, hdrBuffer, options) {
|
|
|
107
123
|
new Float32Array(hdrBuffer),
|
|
108
124
|
wasmOpts
|
|
109
125
|
);
|
|
110
|
-
return result.buffer.slice(
|
|
126
|
+
return result.buffer.slice(
|
|
127
|
+
result.byteOffset,
|
|
128
|
+
result.byteOffset + result.byteLength
|
|
129
|
+
);
|
|
111
130
|
}
|
|
112
131
|
async function extractSdrBase(buffer) {
|
|
113
132
|
const wasm = await getWasm();
|
|
114
133
|
const result = wasm.extractSdrBase(new Uint8Array(buffer));
|
|
115
|
-
return result.buffer.slice(
|
|
134
|
+
return result.buffer.slice(
|
|
135
|
+
result.byteOffset,
|
|
136
|
+
result.byteOffset + result.byteLength
|
|
137
|
+
);
|
|
116
138
|
}
|
|
117
139
|
async function getMetadata(buffer) {
|
|
118
140
|
const wasm = await getWasm();
|
|
@@ -145,6 +167,7 @@ export {
|
|
|
145
167
|
highQualityEncodeOptions,
|
|
146
168
|
isMeaningfulHdr,
|
|
147
169
|
isUltraHdr,
|
|
170
|
+
probeUltraHdr,
|
|
148
171
|
setLocation,
|
|
149
172
|
smallSizeEncodeOptions,
|
|
150
173
|
validateMetadata
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-ultrahdr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "UltraHDR (ISO 21496-1) gain map support for JavaScript/TypeScript",
|
|
5
5
|
"author": "Adam Silverstein",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
"homepage": "https://github.com/adamsilverstein/lib-open-ultrahdr",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/adamsilverstein/lib-open-ultrahdr.git",
|
|
18
|
+
"url": "git+https://github.com/adamsilverstein/lib-open-ultrahdr.git",
|
|
19
19
|
"directory": "js"
|
|
20
20
|
},
|
|
21
21
|
"bugs": {
|
|
22
22
|
"url": "https://github.com/adamsilverstein/lib-open-ultrahdr/issues"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=20.0.0"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
28
|
"src",
|
|
@@ -52,11 +52,12 @@
|
|
|
52
52
|
"lint:fix": "eslint src __tests__ --fix"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"open-ultrahdr-wasm": "^0.1.
|
|
55
|
+
"open-ultrahdr-wasm": "^0.1.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@eslint/js": "^9.0.0",
|
|
59
|
-
"@
|
|
59
|
+
"@types/node": "^25.1.0",
|
|
60
|
+
"@vitest/coverage-v8": "^4.0.0",
|
|
60
61
|
"eslint": "^9.0.0",
|
|
61
62
|
"eslint-config-prettier": "^9.0.0",
|
|
62
63
|
"tsup": "^8.0.0",
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
"typescript-eslint": "^8.0.0",
|
|
65
66
|
"vite-plugin-top-level-await": "^1.6.0",
|
|
66
67
|
"vite-plugin-wasm": "^3.5.0",
|
|
67
|
-
"vitest": "^
|
|
68
|
+
"vitest": "^4.0.0"
|
|
68
69
|
},
|
|
69
70
|
"publishConfig": {
|
|
70
71
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,13 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
// Re-export types
|
|
25
|
-
export type {
|
|
25
|
+
export type {
|
|
26
|
+
ItemId,
|
|
27
|
+
GainMapMetadata,
|
|
28
|
+
UltraHdrDecodeResult,
|
|
29
|
+
UltraHdrEncodeOptions,
|
|
30
|
+
UltraHdrProbeResult,
|
|
31
|
+
} from './types';
|
|
26
32
|
|
|
27
33
|
export {
|
|
28
34
|
ColorGamut,
|
|
@@ -32,7 +38,13 @@ export {
|
|
|
32
38
|
smallSizeEncodeOptions,
|
|
33
39
|
} from './types';
|
|
34
40
|
|
|
35
|
-
import type {
|
|
41
|
+
import type {
|
|
42
|
+
ItemId,
|
|
43
|
+
GainMapMetadata,
|
|
44
|
+
UltraHdrDecodeResult,
|
|
45
|
+
UltraHdrEncodeOptions,
|
|
46
|
+
UltraHdrProbeResult,
|
|
47
|
+
} from './types';
|
|
36
48
|
|
|
37
49
|
import { defaultEncodeOptions } from './types';
|
|
38
50
|
|
|
@@ -62,6 +74,7 @@ interface WasmGainMapMetadata {
|
|
|
62
74
|
interface UltraHdrWasmModule {
|
|
63
75
|
default: (moduleOrPath?: string | URL | Response | BufferSource) => Promise<unknown>;
|
|
64
76
|
isUltraHdr: (buffer: Uint8Array) => boolean;
|
|
77
|
+
probeUltraHdr: (buffer: Uint8Array) => UltraHdrProbeResult;
|
|
65
78
|
decodeUltraHdr: (buffer: Uint8Array) => UltraHdrDecodeResult;
|
|
66
79
|
encodeUltraHdr: (
|
|
67
80
|
sdrBuffer: Uint8Array,
|
|
@@ -159,21 +172,37 @@ async function getWasm(): Promise<UltraHdrWasmModule> {
|
|
|
159
172
|
}
|
|
160
173
|
|
|
161
174
|
initPromise = (async () => {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
175
|
+
try {
|
|
176
|
+
// Dynamic import of the WASM package
|
|
177
|
+
const UltraHdrWasm = (await import('open-ultrahdr-wasm')) as unknown as UltraHdrWasmModule;
|
|
178
|
+
|
|
179
|
+
// Initialize WASM with the location prefix for the .wasm file
|
|
180
|
+
// If location is set, construct the full URL to the WASM file
|
|
181
|
+
if (location) {
|
|
182
|
+
const base = location.endsWith('/') ? location : `${location}/`;
|
|
183
|
+
const wasmPath = base + 'open_ultrahdr_bg.wasm';
|
|
184
|
+
|
|
185
|
+
// In Node.js, load the WASM file from the filesystem
|
|
186
|
+
// instead of using fetch which doesn't work with file:// URLs
|
|
187
|
+
if (typeof process !== 'undefined' && process.versions && process.versions.node) {
|
|
188
|
+
const fs = await import('fs');
|
|
189
|
+
const wasmBytes = await fs.promises.readFile(wasmPath);
|
|
190
|
+
await UltraHdrWasm.default(wasmBytes);
|
|
191
|
+
} else {
|
|
192
|
+
// In browser, use the URL directly
|
|
193
|
+
await UltraHdrWasm.default(wasmPath);
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
// Let the WASM module use its default URL resolution (import.meta.url)
|
|
197
|
+
await UltraHdrWasm.default();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
wasmInstance = UltraHdrWasm as unknown as UltraHdrWasmModule;
|
|
201
|
+
return wasmInstance;
|
|
202
|
+
} catch (err) {
|
|
203
|
+
initPromise = null;
|
|
204
|
+
throw err;
|
|
173
205
|
}
|
|
174
|
-
|
|
175
|
-
wasmInstance = UltraHdrWasm as unknown as UltraHdrWasmModule;
|
|
176
|
-
return wasmInstance;
|
|
177
206
|
})();
|
|
178
207
|
|
|
179
208
|
return initPromise;
|
|
@@ -201,6 +230,41 @@ export async function isUltraHdr(buffer: ArrayBuffer): Promise<boolean> {
|
|
|
201
230
|
return wasm.isUltraHdr(new Uint8Array(buffer));
|
|
202
231
|
}
|
|
203
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Probes an image to check if it's UltraHDR and extracts component information.
|
|
235
|
+
*
|
|
236
|
+
* This function efficiently validates if an image is UltraHDR by checking for
|
|
237
|
+
* required components (primary image, gain map, metadata) without full decoding.
|
|
238
|
+
* Returns structured results useful for batch processing and filtering.
|
|
239
|
+
*
|
|
240
|
+
* Unlike `isUltraHdr`, this function provides detailed information about what
|
|
241
|
+
* was found, making it useful for diagnostics and filtering workflows.
|
|
242
|
+
*
|
|
243
|
+
* @param buffer - Image file contents.
|
|
244
|
+
* @return Probe result with detailed component information.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* const buffer = await file.arrayBuffer();
|
|
249
|
+
* const result = await probeUltraHdr(buffer);
|
|
250
|
+
*
|
|
251
|
+
* if (result.isValid) {
|
|
252
|
+
* console.log('UltraHDR image:', result.width, 'x', result.height);
|
|
253
|
+
* console.log('HDR capacity:', result.hdrCapacity, 'stops');
|
|
254
|
+
* console.log('Gain map:', result.gainMapWidth, 'x', result.gainMapHeight);
|
|
255
|
+
* } else {
|
|
256
|
+
* // Diagnose why it's not a valid UltraHDR
|
|
257
|
+
* if (!result.hasPrimaryImage) console.log('Not a valid JPEG');
|
|
258
|
+
* if (!result.hasGainMap) console.log('Missing gain map');
|
|
259
|
+
* if (!result.hasMetadata) console.log('Missing HDR metadata');
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
export async function probeUltraHdr(buffer: ArrayBuffer): Promise<UltraHdrProbeResult> {
|
|
264
|
+
const wasm = await getWasm();
|
|
265
|
+
return wasm.probeUltraHdr(new Uint8Array(buffer));
|
|
266
|
+
}
|
|
267
|
+
|
|
204
268
|
/**
|
|
205
269
|
* Decodes an UltraHDR image, extracting all components.
|
|
206
270
|
*
|
|
@@ -281,7 +345,10 @@ export async function encodeUltraHdr(
|
|
|
281
345
|
);
|
|
282
346
|
|
|
283
347
|
// Ensure we return a proper ArrayBuffer (not SharedArrayBuffer)
|
|
284
|
-
return result.buffer.slice(
|
|
348
|
+
return result.buffer.slice(
|
|
349
|
+
result.byteOffset,
|
|
350
|
+
result.byteOffset + result.byteLength
|
|
351
|
+
) as ArrayBuffer;
|
|
285
352
|
}
|
|
286
353
|
|
|
287
354
|
/**
|
|
@@ -306,7 +373,10 @@ export async function extractSdrBase(buffer: ArrayBuffer): Promise<ArrayBuffer>
|
|
|
306
373
|
const wasm = await getWasm();
|
|
307
374
|
const result = wasm.extractSdrBase(new Uint8Array(buffer));
|
|
308
375
|
// Ensure we return a proper ArrayBuffer (not SharedArrayBuffer)
|
|
309
|
-
return result.buffer.slice(
|
|
376
|
+
return result.buffer.slice(
|
|
377
|
+
result.byteOffset,
|
|
378
|
+
result.byteOffset + result.byteLength
|
|
379
|
+
) as ArrayBuffer;
|
|
310
380
|
}
|
|
311
381
|
|
|
312
382
|
/**
|
package/src/types.ts
CHANGED
|
@@ -38,6 +38,44 @@ export interface GainMapMetadata {
|
|
|
38
38
|
hdrCapacityMax: number;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Result of probing an image to check if it's UltraHDR.
|
|
43
|
+
*
|
|
44
|
+
* Provides detailed information about what components were found
|
|
45
|
+
* without fully decoding the image. Useful for batch processing and filtering.
|
|
46
|
+
*/
|
|
47
|
+
export interface UltraHdrProbeResult {
|
|
48
|
+
/** Whether the image is a valid UltraHDR image (has all required components) */
|
|
49
|
+
isValid: boolean;
|
|
50
|
+
|
|
51
|
+
/** Whether a primary JPEG image was found */
|
|
52
|
+
hasPrimaryImage: boolean;
|
|
53
|
+
|
|
54
|
+
/** Whether a gain map image was found */
|
|
55
|
+
hasGainMap: boolean;
|
|
56
|
+
|
|
57
|
+
/** Whether gain map metadata (XMP) was found */
|
|
58
|
+
hasMetadata: boolean;
|
|
59
|
+
|
|
60
|
+
/** Primary image width in pixels (0 if not found) */
|
|
61
|
+
width: number;
|
|
62
|
+
|
|
63
|
+
/** Primary image height in pixels (0 if not found) */
|
|
64
|
+
height: number;
|
|
65
|
+
|
|
66
|
+
/** Gain map width in pixels (0 if not found) */
|
|
67
|
+
gainMapWidth: number;
|
|
68
|
+
|
|
69
|
+
/** Gain map height in pixels (0 if not found) */
|
|
70
|
+
gainMapHeight: number;
|
|
71
|
+
|
|
72
|
+
/** HDR capacity (max additional stops of dynamic range), 0 if not found */
|
|
73
|
+
hdrCapacity: number;
|
|
74
|
+
|
|
75
|
+
/** Metadata version string (empty if not found) */
|
|
76
|
+
metadataVersion: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
41
79
|
/**
|
|
42
80
|
* Result of decoding an UltraHDR image.
|
|
43
81
|
*/
|