hdrify-react 1.3.0 → 2.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.
Files changed (48) hide show
  1. package/README.md +57 -29
  2. package/dist/HdrifyCanvas.d.ts +31 -4
  3. package/dist/HdrifyCanvas.d.ts.map +1 -1
  4. package/dist/HdrifyCanvas.js +197 -38
  5. package/dist/HdrifyCanvas.js.map +1 -1
  6. package/dist/ImageViewer.d.ts +86 -0
  7. package/dist/ImageViewer.d.ts.map +1 -0
  8. package/dist/ImageViewer.js +241 -0
  9. package/dist/ImageViewer.js.map +1 -0
  10. package/dist/capture.d.ts +22 -0
  11. package/dist/capture.d.ts.map +1 -0
  12. package/dist/capture.js +62 -0
  13. package/dist/capture.js.map +1 -0
  14. package/dist/decode.d.ts +7 -0
  15. package/dist/decode.d.ts.map +1 -0
  16. package/dist/decode.js +25 -0
  17. package/dist/decode.js.map +1 -0
  18. package/dist/display.d.ts +17 -0
  19. package/dist/display.d.ts.map +1 -0
  20. package/dist/display.js +37 -0
  21. package/dist/display.js.map +1 -0
  22. package/dist/element.d.ts +51 -0
  23. package/dist/element.d.ts.map +1 -0
  24. package/dist/element.js +215 -0
  25. package/dist/element.js.map +1 -0
  26. package/dist/image-viewer.js +174 -0
  27. package/dist/image-viewer.js.map +7 -0
  28. package/dist/index.d.ts +7 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +4 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/progress.d.ts +19 -0
  33. package/dist/progress.d.ts.map +1 -0
  34. package/dist/progress.js +47 -0
  35. package/dist/progress.js.map +1 -0
  36. package/dist/readiness.d.ts +15 -0
  37. package/dist/readiness.d.ts.map +1 -0
  38. package/dist/readiness.js +46 -0
  39. package/dist/readiness.js.map +1 -0
  40. package/dist/styles.d.ts +6 -0
  41. package/dist/styles.d.ts.map +1 -0
  42. package/dist/styles.js +84 -0
  43. package/dist/styles.js.map +1 -0
  44. package/dist/webgpuDisplay.d.ts +4 -0
  45. package/dist/webgpuDisplay.d.ts.map +1 -0
  46. package/dist/webgpuDisplay.js +208 -0
  47. package/dist/webgpuDisplay.js.map +1 -0
  48. package/package.json +42 -13
@@ -0,0 +1,241 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { resolveToneMapping } from './display.js';
3
+ import { useEffect, useId, useImperativeHandle, useRef, useState } from 'react';
4
+ import { captureImage } from './capture.js';
5
+ import { decodeHdrifyImage } from './decode.js';
6
+ import { HdrifyCanvas } from './HdrifyCanvas.js';
7
+ import { readResponse } from './progress.js';
8
+ import { ViewerReadiness } from './readiness.js';
9
+ import { IMAGE_VIEWER_CSS } from './styles.js';
10
+ export const DEFAULT_IMAGE_VIEWER_SETTINGS = {
11
+ toneMapping: undefined,
12
+ exposure: 0,
13
+ fit: 'contain',
14
+ };
15
+ export const TONE_MAPPING_OPTIONS = [
16
+ { value: 'none', label: 'None' },
17
+ { value: 'neutral', label: 'Neutral' },
18
+ { value: 'agx', label: 'AgX' },
19
+ { value: 'aces', label: 'ACES' },
20
+ { value: 'reinhard', label: 'Reinhard' },
21
+ ];
22
+ /** Range of the exposure slider, in stops. The options panel accepts any value. */
23
+ export const EXPOSURE_SLIDER_RANGE = { min: -10, max: 10 };
24
+ function definedSettings(settings) {
25
+ return Object.fromEntries(Object.entries(settings).filter(([, value]) => value !== undefined));
26
+ }
27
+ function formatStops(stops) {
28
+ return `${stops > 0 ? '+' : ''}${Number(stops.toFixed(1))} EV`;
29
+ }
30
+ /** Wait until the browser has painted, so the progress bar shows before decoding blocks the main thread. */
31
+ const afterPaint = () => new Promise((resolve) => requestAnimationFrame(() => setTimeout(resolve, 0)));
32
+ /** Share of the progress bar for the download; decoding and drawing take the rest. */
33
+ const DOWNLOAD_SHARE = 0.8;
34
+ const NO_DOWNLOAD = { loaded: 0, total: null, progress: null };
35
+ let loadCount = 0;
36
+ /**
37
+ * Loads and displays an HDR image with tone mapping, a loading bar, an optional options panel and an optional
38
+ * exposure slider. Accepts every format hdrify reads; see {@link decodeHdrifyImage}.
39
+ * Uses {@link HdrifyCanvas} for HDR presentation and SDR fallback. None is offered
40
+ * and selected by default only after extended FP16 presentation succeeds; otherwise
41
+ * Neutral is the default and None is hidden. There is no Automatic menu item.
42
+ * `fit="actual"` shows one source pixel per CSS pixel. Loading progress is reported
43
+ * through `onProgress`; the imperative handle exposes readiness and SDR capture.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * <ImageViewer src="/images/memorial.exr" exposureControl toneMapping="agx" style={{ height: 600 }} />
48
+ * ```
49
+ */
50
+ export function ImageViewer({ src, data, image, toneMapping, exposure, fit, settingsPanel = 'closed', exposureControl = false, className, style, onLoad, onError, onProgress, onSettingsChange, onSettingsPanelChange, ref, }) {
51
+ const callbacks = useRef({ onLoad, onError, onProgress, onSettingsChange, onSettingsPanelChange });
52
+ useEffect(() => {
53
+ callbacks.current = { onLoad, onError, onProgress, onSettingsChange, onSettingsPanelChange };
54
+ });
55
+ // Props seed the state and override it whenever they change; the user can change it in between.
56
+ const [settings, setSettings] = useState(() => ({
57
+ ...DEFAULT_IMAGE_VIEWER_SETTINGS,
58
+ ...definedSettings({ toneMapping, exposure, fit }),
59
+ }));
60
+ const [provided, setProvided] = useState({ toneMapping, exposure, fit, settingsPanel });
61
+ const [panelMode, setPanelMode] = useState(settingsPanel);
62
+ if (provided.toneMapping !== toneMapping ||
63
+ provided.exposure !== exposure ||
64
+ provided.fit !== fit ||
65
+ provided.settingsPanel !== settingsPanel) {
66
+ setProvided({ toneMapping, exposure, fit, settingsPanel });
67
+ setSettings((current) => ({
68
+ ...current,
69
+ ...definedSettings({ exposure, fit }),
70
+ ...(provided.toneMapping !== toneMapping ? { toneMapping } : {}),
71
+ }));
72
+ if (provided.settingsPanel !== settingsPanel)
73
+ setPanelMode(settingsPanel);
74
+ }
75
+ const change = (patch) => {
76
+ const next = { ...settings, ...patch };
77
+ setSettings(next);
78
+ callbacks.current.onSettingsChange?.(next);
79
+ };
80
+ const changePanel = (mode) => {
81
+ setPanelMode(mode);
82
+ callbacks.current.onSettingsPanelChange?.(mode);
83
+ };
84
+ const [readiness] = useState(() => new ViewerReadiness());
85
+ const [rendered, setRendered] = useState();
86
+ const [renderError, setRenderError] = useState();
87
+ const announced = useRef(undefined);
88
+ useEffect(() => () => readiness.disconnect(), [readiness]);
89
+ // The latest fetch/decode result, tagged with the source it came from; the rest is derived during render.
90
+ const source = image ? undefined : (data ?? src);
91
+ const [loaded, setLoaded] = useState({});
92
+ // Progress of the current load; `id` remounts the bar so it never animates backwards into a new load.
93
+ const [bar, setBar] = useState(null);
94
+ const download = useRef(NO_DOWNLOAD);
95
+ useEffect(() => {
96
+ readiness.pending();
97
+ announced.current = undefined;
98
+ download.current = NO_DOWNLOAD;
99
+ if (image)
100
+ return; // Drawn below.
101
+ if (!source) {
102
+ readiness.finish();
103
+ return;
104
+ }
105
+ const controller = new AbortController();
106
+ const { signal } = controller;
107
+ const id = ++loadCount;
108
+ let overall = 0;
109
+ const report = (stage, totalProgress) => {
110
+ if (signal.aborted)
111
+ return;
112
+ overall = Math.max(overall, totalProgress);
113
+ setBar({ id, value: overall });
114
+ callbacks.current.onProgress?.({ ...download.current, totalProgress: overall, stage });
115
+ };
116
+ const fetchWithProgress = async (url) => {
117
+ report('download', 0);
118
+ const response = await fetch(url, { signal });
119
+ if (!response.ok)
120
+ throw new Error(`Failed to load ${url}: HTTP ${response.status}`);
121
+ return readResponse(response, signal, (progress) => {
122
+ download.current = progress;
123
+ report('download', DOWNLOAD_SHARE * (progress.progress ?? 0));
124
+ });
125
+ };
126
+ (async () => {
127
+ const bytes = typeof source === 'string' ? await fetchWithProgress(source) : source;
128
+ report('decode', typeof source === 'string' ? DOWNLOAD_SHARE : 0);
129
+ await afterPaint();
130
+ signal.throwIfAborted();
131
+ const decoded = await decodeHdrifyImage(bytes);
132
+ signal.throwIfAborted();
133
+ setLoaded({ source, image: decoded });
134
+ })().catch((reason) => {
135
+ if (signal.aborted)
136
+ return;
137
+ const error = reason instanceof Error ? reason : new Error(String(reason));
138
+ readiness.finish(error);
139
+ setBar(null);
140
+ setLoaded({ source, error: error.message });
141
+ callbacks.current.onError?.(error);
142
+ });
143
+ return () => controller.abort();
144
+ }, [image, source, readiness]);
145
+ const loading = source !== undefined && loaded.source !== source;
146
+ // While a new source loads, keep showing the previous image.
147
+ const shownImage = image ?? (source === undefined ? undefined : loaded.image);
148
+ const error = !loading && source !== undefined ? loaded.error : undefined;
149
+ // Readiness follows the asynchronous renderer, including its first completed GPU draw.
150
+ const drawn = loading ? undefined : shownImage;
151
+ const displayMode = rendered?.mode ?? 'sdr';
152
+ const renderReady = !!drawn &&
153
+ rendered?.image === drawn &&
154
+ rendered.exposure === settings.exposure &&
155
+ rendered.toneMapping === settings.toneMapping;
156
+ const barValue = bar && !loading && renderReady ? 1 : bar?.value;
157
+ if (!shownImage && rendered)
158
+ setRendered(undefined);
159
+ const latest = useRef({ image: drawn, settings });
160
+ useEffect(() => {
161
+ latest.current = { image: drawn, settings };
162
+ });
163
+ const handleDraw = (current, mode) => {
164
+ setRenderError(undefined);
165
+ if (mode === 'sdr' && settings.toneMapping === 'none')
166
+ change({ toneMapping: 'neutral' });
167
+ if (current === drawn)
168
+ setBar((currentBar) => (currentBar && currentBar.value < 1 ? { ...currentBar, value: 1 } : currentBar));
169
+ setRendered((previous) => previous?.image === current &&
170
+ previous.mode === mode &&
171
+ previous.exposure === settings.exposure &&
172
+ previous.toneMapping === settings.toneMapping
173
+ ? previous
174
+ : { image: current, mode, exposure: settings.exposure, toneMapping: settings.toneMapping });
175
+ };
176
+ useEffect(() => {
177
+ if (!drawn || !renderReady || announced.current === drawn)
178
+ return;
179
+ announced.current = drawn;
180
+ readiness.finish();
181
+ callbacks.current.onProgress?.({ ...download.current, totalProgress: 1, stage: 'render' });
182
+ callbacks.current.onLoad?.(drawn);
183
+ }, [drawn, renderReady, readiness]);
184
+ useImperativeHandle(ref, () => ({
185
+ whenReady: () => readiness.whenReady(),
186
+ toBlob: async (options) => {
187
+ await readiness.whenReady();
188
+ const { image: current, settings: currentSettings } = latest.current;
189
+ if (!current)
190
+ throw new Error('No image is loaded.');
191
+ return captureImage(current, currentSettings.toneMapping ?? 'neutral', 2 ** currentSettings.exposure, options);
192
+ },
193
+ }), [readiness]);
194
+ return (_jsxs("div", { className: className ? `hdrify-viewer ${className}` : 'hdrify-viewer', style: { height: 480, ...style }, "data-fit": settings.fit, "data-display-mode": displayMode, "aria-busy": loading || (!!drawn && !renderReady), children: [_jsx("style", { children: IMAGE_VIEWER_CSS }), _jsx("div", { className: "hdrify-viewer-viewport", children: shownImage && (_jsx(HdrifyCanvas, { hdrifyImage: shownImage, toneMapping: settings.toneMapping, exposure: 2 ** settings.exposure, className: "hdrify-viewer-canvas", onDraw: handleDraw, onError: (failure) => {
195
+ readiness.finish(failure);
196
+ setRenderError(failure.message);
197
+ callbacks.current.onError?.(failure);
198
+ } })) }), _jsx("div", { className: "hdrify-viewer-progress", hidden: barValue === undefined, children: _jsx("slot", { name: "progress-bar", children: bar && barValue !== undefined && (_jsx("div", { className: barValue === 1 ? 'hdrify-viewer-progress-fill complete' : 'hdrify-viewer-progress-fill', part: "default-progress-bar",
199
+ // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- a scaled fill, styleable via ::part like <material-viewer>'s
200
+ role: "progressbar", "aria-label": "Loading image", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(barValue * 100), "aria-hidden": barValue === 1, style: { transform: `scaleX(${Math.max(0.02, barValue)})` } }, bar.id)) }) }), (error || renderError) && (_jsx("p", { role: "alert", className: "hdrify-viewer-error", children: error || renderError })), exposureControl && (_jsxs("div", { className: "hdrify-viewer-exposure hdrify-viewer-surface", title: "Exposure (double-click to reset)", children: [_jsx("output", { children: formatStops(settings.exposure) }), _jsx("input", { type: "range", "aria-label": "Exposure in stops", min: EXPOSURE_SLIDER_RANGE.min, max: EXPOSURE_SLIDER_RANGE.max, step: 0.1, value: settings.exposure, onChange: (event) => change({ exposure: event.currentTarget.valueAsNumber }), onDoubleClick: () => change({ exposure: 0 }) })] })), panelMode !== 'hidden' && (_jsx(OptionsPanel, { settings: settings, image: shownImage, displayMode: displayMode, open: panelMode === 'open', onChange: change, onOpenChange: (open) => changePanel(open ? 'open' : 'closed') }))] }));
201
+ }
202
+ function OptionsPanel({ settings, image, displayMode, open, onChange, onOpenChange }) {
203
+ const id = useId();
204
+ const button = useRef(null);
205
+ const panel = useRef(null);
206
+ const close = useRef(() => onOpenChange(false));
207
+ useEffect(() => {
208
+ close.current = () => onOpenChange(false);
209
+ });
210
+ // Close on Escape or a pointer press outside; composedPath sees through the element's shadow root.
211
+ useEffect(() => {
212
+ const document = button.current?.ownerDocument;
213
+ if (!open || !document)
214
+ return;
215
+ const outside = (event) => {
216
+ const path = event.composedPath();
217
+ if (!path.includes(panel.current) && !path.includes(button.current))
218
+ close.current();
219
+ };
220
+ const escape = (event) => {
221
+ if (event.key !== 'Escape')
222
+ return;
223
+ close.current();
224
+ button.current?.focus();
225
+ };
226
+ document.addEventListener('pointerdown', outside);
227
+ document.addEventListener('keydown', escape);
228
+ return () => {
229
+ document.removeEventListener('pointerdown', outside);
230
+ document.removeEventListener('keydown', escape);
231
+ };
232
+ }, [open]);
233
+ return (_jsxs(_Fragment, { children: [_jsx("button", { ref: button, type: "button", className: "hdrify-viewer-toggle hdrify-viewer-surface", "aria-label": "Viewer options", title: "Viewer options", "aria-controls": id, "aria-expanded": open, onClick: () => onOpenChange(!open), children: _jsxs("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "none", stroke: "currentColor", strokeWidth: "1.6", "aria-hidden": "true", children: [_jsx("path", { d: "m9 3-.8 2.2-2 .9L4 5.5 2.5 8l1.6 1.7-.2 2.3L2 13.5 3.5 16l2.3-.4 1.8 1.4.4 2.4h3l.8-2.2 2-.9 2.2.6 1.5-2.5-1.6-1.7.2-2.3L18 8.5 16.5 6l-2.3.4-1.8-1.4L12 3Z", transform: "translate(2 1)" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }) }), _jsxs("section", { ref: panel, id: id, className: "hdrify-viewer-panel hdrify-viewer-surface", "aria-label": "Viewer options", hidden: !open, children: [_jsxs("header", { children: [_jsx("strong", { children: "Viewer options" }), _jsx("button", { type: "button", "aria-label": "Close viewer options", onClick: () => onOpenChange(false), children: "\u00D7" })] }), _jsxs("label", { children: ["Tone mapping", _jsx("select", { "aria-label": "Tone mapping", value: resolveToneMapping(settings.toneMapping, displayMode), onChange: (event) => onChange({
234
+ toneMapping: event.currentTarget.value ? event.currentTarget.value : undefined,
235
+ }), children: TONE_MAPPING_OPTIONS.filter((option) => option.value !== 'none' || displayMode === 'hdr').map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) })] }), _jsxs("label", { children: ["Exposure (EV)", _jsx("input", { type: "number", step: 0.1, value: Number(settings.exposure.toFixed(2)), onChange: (event) => {
236
+ const value = event.currentTarget.valueAsNumber;
237
+ if (Number.isFinite(value))
238
+ onChange({ exposure: value });
239
+ } })] }), _jsxs("label", { children: ["Size", _jsxs("select", { value: settings.fit, onChange: (event) => onChange({ fit: event.currentTarget.value }), children: [_jsx("option", { value: "contain", children: "Fit to view" }), _jsx("option", { value: "actual", children: "Actual size" })] })] }), image && (_jsxs("dl", { children: [_jsx("dt", { children: "Dimensions" }), _jsxs("dd", { children: [image.width, " \u00D7 ", image.height] }), _jsx("dt", { children: "Color space" }), _jsx("dd", { children: image.linearColorSpace }), typeof image.metadata?.format === 'string' && (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Format" }), _jsx("dd", { children: image.metadata.format })] }))] }))] })] }));
240
+ }
241
+ //# sourceMappingURL=ImageViewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageViewer.js","sources":["../src/ImageViewer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type HdrifyImage } from 'hdrify';
2
+ import { type ViewerToneMapping } from './display.js';
3
+ /** Options for `toBlob()` on `<image-viewer>` and the {@link ImageViewer} handle. */
4
+ export interface ImageViewerCaptureOptions {
5
+ /** `image/png` (default), `image/jpeg` or `image/webp`. Browsers that cannot encode a type return a PNG. */
6
+ type?: 'image/png' | 'image/jpeg' | 'image/webp';
7
+ /** Encoding quality from 0 to 1 for JPEG and WebP. */
8
+ quality?: number;
9
+ /** Output size in pixels. Without either, the image's own size; with one, the other keeps the aspect ratio. */
10
+ width?: number;
11
+ height?: number;
12
+ }
13
+ /** Tone map `image` into `canvas`, resizing the canvas to the image. The result is opaque sRGB. */
14
+ export declare function drawToneMapped(canvas: HTMLCanvasElement, image: HdrifyImage, toneMapping: ViewerToneMapping, exposure: number): void;
15
+ /** Output size for a capture; throws on sizes that are not positive integers up to 16384 pixels. */
16
+ export declare function captureSize(options: ImageViewerCaptureOptions, imageWidth: number, imageHeight: number): {
17
+ width: number;
18
+ height: number;
19
+ };
20
+ /** Encode `image` tone mapped with the given settings, independently of what is on screen. */
21
+ export declare function captureImage(image: HdrifyImage, toneMapping: ViewerToneMapping, exposure: number, options?: ImageViewerCaptureOptions): Promise<Blob>;
22
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sources":["../src/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1E,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAErE,qFAAqF;AACrF,MAAM,WAAW,yBAAyB;IACxC,4GAA4G;IAC5G,IAAI,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;IACjD,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+GAA+G;IAC/G,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mGAAmG;AACnG,wBAAgB,cAAc,CAC5B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,iBAAiB,EAC9B,QAAQ,EAAE,MAAM,GACf,IAAI,CAgCN;AAED,oGAAoG;AACpG,wBAAgB,WAAW,CAAC,OAAO,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;;;EAMtG;AAED,8FAA8F;AAC9F,wBAAsB,YAAY,CAChC,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,iBAAiB,EAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,IAAI,CAAC,CAoBf"}
@@ -0,0 +1,62 @@
1
+ import { applyToneMapping, linearTosRGB } from 'hdrify';
2
+ import { displayPixels } from './display.js';
3
+ /** Tone map `image` into `canvas`, resizing the canvas to the image. The result is opaque sRGB. */
4
+ export function drawToneMapped(canvas, image, toneMapping, exposure) {
5
+ const { width, height } = image;
6
+ canvas.width = width;
7
+ canvas.height = height;
8
+ // LDR from applyToneMapping is sRGB; use an srgb canvas so it displays correctly.
9
+ const ctx = canvas.getContext('2d', { colorSpace: 'srgb' }) ?? canvas.getContext('2d');
10
+ if (!ctx)
11
+ return;
12
+ if (toneMapping === 'none') {
13
+ const linear = displayPixels(image, 'none', exposure);
14
+ const imageData = ctx.createImageData(width, height);
15
+ for (let i = 0; i < linear.length; i += 4) {
16
+ for (let c = 0; c < 3; c++)
17
+ imageData.data[i + c] = Math.round(Math.max(0, Math.min(1, linearTosRGB(linear[i + c]))) * 255);
18
+ imageData.data[i + 3] = 255;
19
+ }
20
+ ctx.putImageData(imageData, 0, 0);
21
+ return;
22
+ }
23
+ const ldrRgb = applyToneMapping(image.data.slice(), width, height, {
24
+ toneMapping,
25
+ exposure,
26
+ sourceColorSpace: image.linearColorSpace,
27
+ });
28
+ const imageData = ctx.createImageData(width, height);
29
+ const pixels = imageData.data;
30
+ for (let destIndex = 0, sourceIndex = 0; sourceIndex < ldrRgb.length; destIndex += 4, sourceIndex += 3) {
31
+ pixels[destIndex] = ldrRgb[sourceIndex];
32
+ pixels[destIndex + 1] = ldrRgb[sourceIndex + 1];
33
+ pixels[destIndex + 2] = ldrRgb[sourceIndex + 2];
34
+ pixels[destIndex + 3] = 255;
35
+ }
36
+ ctx.putImageData(imageData, 0, 0);
37
+ }
38
+ /** Output size for a capture; throws on sizes that are not positive integers up to 16384 pixels. */
39
+ export function captureSize(options, imageWidth, imageHeight) {
40
+ const width = options.width ?? Math.round(((options.height ?? imageHeight) * imageWidth) / imageHeight);
41
+ const height = options.height ?? Math.round((width * imageHeight) / imageWidth);
42
+ if (![width, height].every((value) => Number.isInteger(value) && value > 0 && value <= 16384))
43
+ throw new RangeError('Capture width and height must be positive integers up to 16384.');
44
+ return { width, height };
45
+ }
46
+ /** Encode `image` tone mapped with the given settings, independently of what is on screen. */
47
+ export async function captureImage(image, toneMapping, exposure, options = {}) {
48
+ const { width, height } = captureSize(options, image.width, image.height);
49
+ let canvas = document.createElement('canvas');
50
+ drawToneMapped(canvas, image, toneMapping, exposure);
51
+ if (width !== image.width || height !== image.height) {
52
+ const scaled = document.createElement('canvas');
53
+ scaled.width = width;
54
+ scaled.height = height;
55
+ const ctx = scaled.getContext('2d');
56
+ ctx.imageSmoothingQuality = 'high';
57
+ ctx.drawImage(canvas, 0, 0, width, height);
58
+ canvas = scaled;
59
+ }
60
+ return new Promise((resolve, reject) => canvas.toBlob((blob) => (blob ? resolve(blob) : reject(new Error('The browser could not encode the image.'))), options.type ?? 'image/png', options.quality));
61
+ }
62
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type HdrifyImage } from 'hdrify';
2
+ /**
3
+ * Decode an OpenEXR, Radiance HDR, JPEG XL or JPEG gain map (Ultra HDR / Adobe) file, detected from its content, not its
4
+ * name. Gzip-compressed files (such as `.hdr.gz`) are decompressed first.
5
+ */
6
+ export declare function decodeHdrifyImage(input: ArrayBuffer | Uint8Array): Promise<HdrifyImage>;
7
+ //# sourceMappingURL=decode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.d.ts","sources":["../src/decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAqD,MAAM,QAAQ,CAAC;AAS7F;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAQ7F"}
package/dist/decode.js ADDED
@@ -0,0 +1,25 @@
1
+ import { isJxl, readExr, readHdr, readJpegGainMap, readJxl } from 'hdrify';
2
+ const startsWith = (bytes, magic) => magic.every((byte, i) => bytes[i] === byte);
3
+ async function gunzip(bytes) {
4
+ const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream('gzip'));
5
+ return new Uint8Array(await new Response(stream).arrayBuffer());
6
+ }
7
+ /**
8
+ * Decode an OpenEXR, Radiance HDR, JPEG XL or JPEG gain map (Ultra HDR / Adobe) file, detected from its content, not its
9
+ * name. Gzip-compressed files (such as `.hdr.gz`) are decompressed first.
10
+ */
11
+ export async function decodeHdrifyImage(input) {
12
+ let bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
13
+ if (startsWith(bytes, [0x1f, 0x8b]))
14
+ bytes = await gunzip(bytes);
15
+ if (startsWith(bytes, [0x76, 0x2f, 0x31, 0x01]))
16
+ return readExr(bytes);
17
+ if (startsWith(bytes, [0x23, 0x3f]))
18
+ return readHdr(bytes); // "#?RADIANCE" / "#?RGBE"
19
+ if (isJxl(bytes))
20
+ return readJxl(bytes);
21
+ if (startsWith(bytes, [0xff, 0xd8]))
22
+ return readJpegGainMap(bytes);
23
+ throw new Error('Unsupported image: expected OpenEXR, Radiance HDR, JPEG XL or a JPEG gain map');
24
+ }
25
+ //# sourceMappingURL=decode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.js","sources":["../src/decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAE7F,MAAM,UAAU,GAAG,CAAC,KAAiB,EAAE,KAAe,EAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AAEhH,KAAK,UAAU,MAAM,CAAC,KAAiB;IACrC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,KAAgC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;IAClH,OAAO,IAAI,UAAU,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAA+B;IACrE,IAAI,KAAK,GAAG,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACxE,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IACjE,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACvE,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,0BAA0B;IACtF,IAAI,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;IACnE,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;AACnG,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type HdrifyImage, type ToneMappingType } from 'hdrify';
2
+ /** `none` preserves HDR values; omitting the setting chooses None for HDR and Neutral for SDR. */
3
+ export type ViewerToneMapping = ToneMappingType | 'none';
4
+ export type DisplayMode = 'hdr' | 'sdr';
5
+ /** None is valid only after the renderer enables extended FP16 HDR presentation. */
6
+ export declare function resolveToneMapping(toneMapping: ViewerToneMapping | undefined, mode: DisplayMode): ViewerToneMapping;
7
+ /** Prepare display pixels without changing the decoded image. Output is linear Rec.709 RGBA. */
8
+ export declare function displayPixels(image: HdrifyImage, toneMapping: ViewerToneMapping, exposure?: number): Float32Array;
9
+ /** Rendering surface owned by HdrifyCanvas. Draws on demand, without an animation loop. */
10
+ export interface ImageDisplay {
11
+ readonly mode: DisplayMode;
12
+ draw(image: HdrifyImage, toneMapping: ViewerToneMapping, exposure: number): void;
13
+ resize(width: number, height: number, pixelRatio: number): void;
14
+ complete(): Promise<void>;
15
+ dispose(): void;
16
+ }
17
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sources":["../src/display.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAElH,kGAAkG;AAClG,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG,MAAM,CAAC;AACzD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,CAAC;AAExC,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,iBAAiB,GAAG,SAAS,EAAE,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAGnH;AAED,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,SAAI,GAAG,YAAY,CA8B5G;AAED,2FAA2F;AAC3F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,IAAI,IAAI,CAAC;CACjB"}
@@ -0,0 +1,37 @@
1
+ import { convertFloat32ToLinearColorSpace, getToneMapping } from 'hdrify';
2
+ /** None is valid only after the renderer enables extended FP16 HDR presentation. */
3
+ export function resolveToneMapping(toneMapping, mode) {
4
+ if (toneMapping === undefined || toneMapping === 'none')
5
+ return mode === 'hdr' ? 'none' : 'neutral';
6
+ return toneMapping;
7
+ }
8
+ /** Prepare display pixels without changing the decoded image. Output is linear Rec.709 RGBA. */
9
+ export function displayPixels(image, toneMapping, exposure = 1) {
10
+ const source = image.data.slice();
11
+ for (let i = 0; i < source.length; i++)
12
+ if (!Number.isFinite(source[i]))
13
+ source[i] = 0;
14
+ const pixels = convertFloat32ToLinearColorSpace(source, image.width, image.height, image.linearColorSpace, 'linear-rec709');
15
+ if (toneMapping === 'none') {
16
+ for (let i = 0; i < pixels.length; i += 4) {
17
+ pixels[i] = pixels[i] * exposure;
18
+ pixels[i + 1] = pixels[i + 1] * exposure;
19
+ pixels[i + 2] = pixels[i + 2] * exposure;
20
+ pixels[i + 3] = 1;
21
+ }
22
+ }
23
+ else {
24
+ const rgb = new Float32Array(image.width * image.height * 3);
25
+ for (let i = 0, j = 0; i < pixels.length; i += 4, j += 3) {
26
+ rgb[j] = Math.max(0, pixels[i]) * exposure;
27
+ rgb[j + 1] = Math.max(0, pixels[i + 1]) * exposure;
28
+ rgb[j + 2] = Math.max(0, pixels[i + 2]) * exposure;
29
+ }
30
+ getToneMapping(toneMapping)(rgb, rgb, image.width * image.height);
31
+ for (let i = 0, j = 0; i < pixels.length; i += 4, j += 3) {
32
+ pixels.set([rgb[j], rgb[j + 1], rgb[j + 2], 1], i);
33
+ }
34
+ }
35
+ return pixels;
36
+ }
37
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sources":["../src/display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { HdrifyImage } from 'hdrify';
2
+ import { type ImageViewerCaptureOptions } from './capture.js';
3
+ import { type ImageViewerSettings } from './ImageViewer.js';
4
+ declare const ElementBase: {
5
+ new (): HTMLElement;
6
+ prototype: HTMLElement;
7
+ };
8
+ /**
9
+ * `<image-viewer>`: displays an EXR, HDR, JPEG XL or gain map JPEG with tone mapping. A web component wrapping
10
+ * {@link ImageViewer}; it works in plain HTML and any framework.
11
+ *
12
+ * Attributes: `src`, `tone-mapping`, `exposure` (stops), `fit`, `settings-panel`, `exposure-control`.
13
+ * Events: `progress` ({@link ImageViewerProgress}), `load` (`{ image }`), `error` (`{ message, error }`),
14
+ * `settingschange` (`{ settings }`). Children with `slot="progress-bar"` replace the default loading bar.
15
+ */
16
+ export declare class ImageViewerElement extends ElementBase {
17
+ #private;
18
+ static observedAttributes: string[];
19
+ /** URL to load; reflects the `src` attribute. */
20
+ get src(): string;
21
+ set src(value: string);
22
+ /** A decoded image to display; takes precedence over `data` and `src`. */
23
+ get image(): HdrifyImage | undefined;
24
+ set image(value: HdrifyImage | undefined);
25
+ /** Encoded EXR, HDR, JPEG XL or gain map JPEG bytes; takes precedence over `src`. */
26
+ get data(): ArrayBuffer | Uint8Array | undefined;
27
+ set data(value: ArrayBuffer | Uint8Array | undefined);
28
+ /** The current display settings. Assign a partial object to change them. */
29
+ get settings(): ImageViewerSettings;
30
+ set settings(patch: Partial<ImageViewerSettings>);
31
+ connectedCallback(): void;
32
+ /**
33
+ * Resolve once the current source is loaded and drawn (immediately with no source). If the source changes first,
34
+ * it waits for the new source instead. Rejects with the load's error, or if the element is disconnected.
35
+ */
36
+ whenReady(): Promise<void>;
37
+ /**
38
+ * Wait for {@link whenReady}, then encode the tone-mapped image with the current settings, at the image's own
39
+ * size unless `width`/`height` are given. Only the image is included, not the viewer's controls.
40
+ */
41
+ toBlob(options?: ImageViewerCaptureOptions): Promise<Blob>;
42
+ disconnectedCallback(): void;
43
+ attributeChangedCallback(name: string): void;
44
+ }
45
+ declare global {
46
+ interface HTMLElementTagNameMap {
47
+ 'image-viewer': ImageViewerElement;
48
+ }
49
+ }
50
+ export {};
51
+ //# sourceMappingURL=element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.d.ts","sources":["../src/element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAG1C,OAAO,EAAgB,KAAK,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAIL,KAAK,mBAAmB,EAGzB,MAAM,kBAAkB,CAAC;AAW1B,QAAA,MAAM,WAAW;;;CAAsF,CAAC;AAExG;;;;;;;GAOG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;;IACjD,MAAM,CAAC,kBAAkB,WAAoF;IAgB7G,iDAAiD;IACjD,IAAI,GAAG,IAAI,MAAM,CAEhB;IACD,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,EAEpB;IACD,0EAA0E;IAC1E,IAAI,KAAK,IAAI,WAAW,GAAG,SAAS,CAEnC;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAIvC;IACD,qFAAqF;IACrF,IAAI,IAAI,IAAI,WAAW,GAAG,UAAU,GAAG,SAAS,CAE/C;IACD,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,EAInD;IACD,4EAA4E;IAC5E,IAAI,QAAQ,IAAI,mBAAmB,CAElC;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,mBAAmB,CAAC,EAS/C;IAED,iBAAiB,IAAI,IAAI,CAgBxB;IAED;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAEzB;IAED;;;OAGG;IACG,MAAM,CAAC,OAAO,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/D;IAED,oBAAoB,IAAI,IAAI,CAW3B;IAED,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAa3C;CAuEF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,kBAAkB,CAAC;KACpC;CACF"}