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
package/README.md CHANGED
@@ -1,18 +1,34 @@
1
+ <p align="center">
2
+ <a href="https://hdrify.ben3d.ca" target="_blank" rel="noopener noreferrer">
3
+ <img alt="hdrify-react logo" src="https://raw.githubusercontent.com/bhouston/hdrify/main/packages/hdrify-vscode-extension/images/icon.png" height="96">
4
+ </a>
5
+ </p>
6
+ <br/>
7
+ <p align="center">
8
+ <a href="https://npmjs.com/package/hdrify-react"><img src="https://img.shields.io/npm/v/hdrify-react.svg" alt="npm package"></a>
9
+ <a href="https://www.npmtrends.com/hdrify-react"><img src="https://img.shields.io/npm/dw/hdrify-react.svg" alt="npm downloads"></a>
10
+ <a href="https://codecov.io/gh/bhouston/hdrify"><img src="https://codecov.io/gh/bhouston/hdrify/branch/main/graph/badge.svg" alt="coverage"></a>
11
+ <a href="https://discord.gg/5J5Ur3F6Z2"><img src="https://img.shields.io/badge/chat-discord-blue?style=flat&logo=discord" alt="discord chat"></a>
12
+ <a href="https://hdrify.ben3d.ca"><img src="https://img.shields.io/badge/docs-read-blue?style=flat" alt="documentation"></a>
13
+ </p>
14
+ <br/>
15
+
1
16
  # hdrify-react
2
17
 
3
- <img src="https://hdrify.ben3d.ca/logo192.png" alt="HDRify logo" width="192" height="192">
18
+ > Display HDR images in React with configurable tone mapping.
4
19
 
5
- [![NPM Package][npm]][npm-url]
6
- [![NPM Downloads][npm-downloads]][npmtrends-url]
7
- [![Tests][tests-badge]][tests-url]
8
- [![Coverage][coverage-badge]][coverage-url]
9
- [![Discord][discord-badge]][discord-url]
20
+ - ๐Ÿ–ผ๏ธ `<image-viewer>` Web Component and `ImageViewer` React Component
21
+ - โš›๏ธ React Canvas Component
22
+ - ๐ŸŽจ Four Tone Mappers
23
+ - โ˜€๏ธ Adjustable Exposure
24
+ - ๐Ÿ–ผ๏ธ Works With hdrify Readers
25
+ - ๐Ÿ”ท Typed Props
10
26
 
11
- React component for displaying HDR images from [hdrify](https://www.npmjs.com/package/hdrify). Accepts `HdrifyImage` (returned by `readHdr`, `readExr`, `readJpegGainMap`) and renders with configurable tone mapping and exposure.
27
+ React component for displaying HDR images from [hdrify](https://www.npmjs.com/package/hdrify). Accepts `HdrifyImage` (returned by `readHdr`, `readExr`, `readJxl`, `readJpegGainMap`) and renders with configurable tone mapping and exposure.
12
28
 
13
29
  **Related packages:** [hdrify](https://www.npmjs.com/package/hdrify) (core library) ยท [hdrify-cli](https://www.npmjs.com/package/hdrify-cli) (CLI tool)
14
30
 
15
- An **online demo** is available at **[https://hdrify.ben3d.ca](https://hdrify.ben3d.ca)** โ€” HDR, EXR, and Ultra HDR viewer and converter built with this component; try it in your browser.
31
+ Try the **[online demo](https://hdrify.ben3d.ca/demo/)** โ€” HDR, EXR, and Ultra HDR viewer and converter built with this component; try it in your browser.
16
32
 
17
33
  ## Installation
18
34
 
@@ -28,18 +44,39 @@ import { readExr } from 'hdrify';
28
44
 
29
45
  const hdrifyImage: HdrifyImage = readExr(buffer);
30
46
 
31
- <HdrifyCanvas hdrifyImage={hdrifyImage} toneMapping="neutral" exposure={1.0} className="max-w-full" />;
47
+ <HdrifyCanvas hdrifyImage={hdrifyImage} exposure={1.0} className="max-w-full" />;
48
+ ```
49
+
50
+ See [`HdrifyCanvas`](https://hdrify.ben3d.ca/docs/api/react/functions/HdrifyCanvas/) and [`HdrifyCanvasProps`](https://hdrify.ben3d.ca/docs/api/react/interfaces/HdrifyCanvasProps/) for rendering behavior and props.
51
+
52
+ ### Image viewer
53
+
54
+ `ImageViewer` loads an EXR, HDR, JPEG XL or gain map JPEG (detected from its content, gzip allowed) and adds an options panel and an optional vertical exposure slider:
55
+
56
+ ```tsx
57
+ import { ImageViewer } from 'hdrify-react';
58
+
59
+ <ImageViewer src="/images/memorial.exr" exposureControl toneMapping="agx" style={{ height: 600 }} />;
32
60
  ```
33
61
 
34
- ### Props
62
+ The same viewer is available as a web component for plain HTML and other frameworks:
35
63
 
36
- | Prop | Type | Description |
37
- | -------------- | -------------------------------------------- | ----------------------------------------------------- |
38
- | `hdrifyImage` | `HdrifyImage` | Image from `readHdr`, `readExr`, or `readJpegGainMap` |
39
- | `toneMapping` | `'aces' \| 'reinhard' \| 'neutral' \| 'agx'` | Tone mapper to use |
40
- | `exposure` | `number` | Exposure value (1.0 = nominal) |
41
- | `className` | `string` | Optional CSS class for the canvas |
42
- | `forwardedRef` | `RefObject<HTMLCanvasElement \| null>` | Optional ref for canvas access (e.g. `toBlob`) |
64
+ ```html
65
+ <script type="module" src="https://cdn.jsdelivr.net/npm/hdrify-react/dist/image-viewer.js"></script>
66
+ <image-viewer src="/images/memorial.exr" exposure-control></image-viewer>
67
+ ```
68
+
69
+ API reference: [`ImageViewer`](https://hdrify.ben3d.ca/docs/api/react/functions/ImageViewer/) ยท [`ImageViewerProps`](https://hdrify.ben3d.ca/docs/api/react/interfaces/ImageViewerProps/) ยท [`ImageViewerHandle`](https://hdrify.ben3d.ca/docs/api/react/interfaces/ImageViewerHandle/).
70
+
71
+ With a bundler, `import 'hdrify-react/element'` to register the web component.
72
+
73
+ ## Documentation
74
+
75
+ Full documentation for the React components is available [on the HDRify documentation website](https://hdrify.ben3d.ca/docs/react/). See the [React guide](https://hdrify.ben3d.ca/docs/react/) and [`<image-viewer>` documentation](https://hdrify.ben3d.ca/docs/image-viewer/) for loading, capture, attributes, events, and theming.
76
+
77
+ ## Contribution
78
+
79
+ See [Contributing Guide](https://github.com/bhouston/hdrify/blob/main/CONTRIBUTING.md).
43
80
 
44
81
  ## License
45
82
 
@@ -47,15 +84,6 @@ MIT
47
84
 
48
85
  ## Author
49
86
 
50
- [Ben Houston](https://ben3d.ca), Sponsored by [Land of Assets](https://landofassets.com)
51
-
52
- [npm]: https://img.shields.io/npm/v/hdrify-react
53
- [npm-url]: https://www.npmjs.com/package/hdrify-react
54
- [npm-downloads]: https://img.shields.io/npm/dw/hdrify-react
55
- [npmtrends-url]: https://www.npmtrends.com/hdrify-react
56
- [tests-badge]: https://github.com/bhouston/hdrify/workflows/Tests/badge.svg
57
- [tests-url]: https://github.com/bhouston/hdrify/actions/workflows/test.yml
58
- [coverage-badge]: https://codecov.io/gh/bhouston/hdrify/branch/main/graph/badge.svg
59
- [coverage-url]: https://codecov.io/gh/bhouston/hdrify
60
- [discord-badge]: https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white
61
- [discord-url]: https://discord.gg/5J5Ur3F6Z2
87
+ [Ben Houston](https://ben3d.ca), Sponsored by [Land of Assets](https://landofassets.com).
88
+
89
+ Compare browser behavior at [hdr-capabilities.ben3d.ca](https://hdr-capabilities.ben3d.ca), maintained in the separate [hdr-capabilities repository](https://github.com/bhouston/hdr-capabilities).
@@ -1,12 +1,39 @@
1
- import { type HdrifyImage, type ToneMappingType } from 'hdrify';
1
+ import type { HdrifyImage } from 'hdrify';
2
2
  import type * as React from 'react';
3
+ import { type DisplayMode, type ViewerToneMapping } from './display.js';
3
4
  export interface HdrifyCanvasProps {
5
+ /** Decoded floating-point RGBA image from a hdrify reader. */
4
6
  hdrifyImage: HdrifyImage;
5
- toneMapping: ToneMappingType;
7
+ /** Omit to use None on HDR displays and Neutral on SDR displays. */
8
+ toneMapping?: ViewerToneMapping;
9
+ /** Linear exposure multiplier: 1 is nominal, 2 adds one stop. */
6
10
  exposure: number;
11
+ /** CSS class applied to the canvas wrapper. */
7
12
  className?: string;
8
- /** Optional ref so parent can access the canvas (e.g. for toBlob). */
13
+ /** Ref to the active canvas, updated when HDR/SDR fallback replaces it. */
9
14
  forwardedRef?: React.RefObject<HTMLCanvasElement | null>;
15
+ /** Called after the current image has finished rendering. */
16
+ onDraw?: (image: HdrifyImage, mode: DisplayMode) => void;
17
+ onError?: (error: Error) => void;
10
18
  }
11
- export declare function HdrifyCanvas({ hdrifyImage, toneMapping, exposure, className, forwardedRef, }: HdrifyCanvasProps): React.ReactElement;
19
+ /**
20
+ * Display a decoded HDR image with exposure and tone mapping.
21
+ * Uses native WebGPU only when an HDR-capable display and extended `rgba16float`
22
+ * presentation succeed. The capability probe caches success or failure per page;
23
+ * each mounted canvas owns its rendering resources. Otherwise a 2D SDR canvas is used.
24
+ * GPU resources are disposed on unmount; device loss falls back to SDR.
25
+ *
26
+ * Omitting `toneMapping` selects None for HDR and Neutral for SDR. Explicit `none`
27
+ * also falls back to Neutral on SDR; other explicit mappers are preserved.
28
+ * Display size follows the viewport and device pixel ratio. Pass a new image object
29
+ * after editing pixels to trigger a redraw. `onDraw` reports a completed render.
30
+ * Use {@link captureImage} for portable SDR export rather than serializing the GPU canvas.
31
+ *
32
+ * @param props - Image, display settings, and rendering callbacks.
33
+ * @example
34
+ * ```tsx
35
+ * <HdrifyCanvas hdrifyImage={image} exposure={1} toneMapping="agx" />
36
+ * ```
37
+ */
38
+ export declare function HdrifyCanvas(props: HdrifyCanvasProps): React.ReactElement;
12
39
  //# sourceMappingURL=HdrifyCanvas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HdrifyCanvas.d.ts","sourceRoot":"","sources":["../src/HdrifyCanvas.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAClF,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAGpC,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;CAC1D;AAED,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,WAAW,EACX,QAAQ,EACR,SAAS,EACT,YAAY,GACb,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CAiDxC"}
1
+ {"version":3,"file":"HdrifyCanvas.d.ts","sources":["../src/HdrifyCanvas.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAGpC,OAAO,EAAsB,KAAK,WAAW,EAAqB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE/G,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,WAAW,EAAE,WAAW,CAAC;IACzB,oEAAoE;IACpE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACzD,6DAA6D;IAC7D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CAiLzE"}
@@ -1,44 +1,203 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { applyToneMapping } from 'hdrify';
3
- import { useCallback, useEffect, useRef } from 'react';
4
- export function HdrifyCanvas({ hdrifyImage, toneMapping, exposure, className, forwardedRef, }) {
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import { drawToneMapped } from './capture.js';
4
+ import { resolveToneMapping } from './display.js';
5
+ const CSS = '.hdrify-canvas{display:grid;place-items:center;width:var(--hdrify-image-width);height:auto;aspect-ratio:var(--hdrify-image-aspect);min-height:0;flex:none;margin:auto;min-width:0}.hdrify-canvas>canvas{display:block;dynamic-range-limit:no-limit}';
6
+ /**
7
+ * Display a decoded HDR image with exposure and tone mapping.
8
+ * Uses native WebGPU only when an HDR-capable display and extended `rgba16float`
9
+ * presentation succeed. The capability probe caches success or failure per page;
10
+ * each mounted canvas owns its rendering resources. Otherwise a 2D SDR canvas is used.
11
+ * GPU resources are disposed on unmount; device loss falls back to SDR.
12
+ *
13
+ * Omitting `toneMapping` selects None for HDR and Neutral for SDR. Explicit `none`
14
+ * also falls back to Neutral on SDR; other explicit mappers are preserved.
15
+ * Display size follows the viewport and device pixel ratio. Pass a new image object
16
+ * after editing pixels to trigger a redraw. `onDraw` reports a completed render.
17
+ * Use {@link captureImage} for portable SDR export rather than serializing the GPU canvas.
18
+ *
19
+ * @param props - Image, display settings, and rendering callbacks.
20
+ * @example
21
+ * ```tsx
22
+ * <HdrifyCanvas hdrifyImage={image} exposure={1} toneMapping="agx" />
23
+ * ```
24
+ */
25
+ export function HdrifyCanvas(props) {
26
+ const hostRef = useRef(null);
5
27
  const canvasRef = useRef(null);
6
- const setRef = useCallback((el) => {
7
- canvasRef.current = el;
8
- if (forwardedRef) {
9
- forwardedRef.current = el;
28
+ const latest = useRef(props);
29
+ const redraw = useRef(() => { });
30
+ useEffect(() => {
31
+ latest.current = props;
32
+ });
33
+ useEffect(() => {
34
+ redraw.current();
35
+ }, [props.hdrifyImage, props.toneMapping, props.exposure]);
36
+ useEffect(() => {
37
+ const forwardedRef = props.forwardedRef;
38
+ if (!forwardedRef)
39
+ return undefined;
40
+ // oxlint-disable-next-line react/immutability -- forward the active canvas into the caller-owned ref
41
+ forwardedRef.current = canvasRef.current;
42
+ return () => {
43
+ // oxlint-disable-next-line react/immutability -- clear the caller-owned ref on replacement or unmount
44
+ forwardedRef.current = null;
45
+ };
46
+ }, [props.forwardedRef]);
47
+ useEffect(() => {
48
+ const host = hostRef.current;
49
+ const view = host.ownerDocument.defaultView;
50
+ const media = view.matchMedia('(dynamic-range: high)');
51
+ let active;
52
+ let canvas;
53
+ let disposed = false;
54
+ let generation = 0;
55
+ let drawRevision = 0;
56
+ let fallbackDrawing = '';
57
+ let fallbackImage;
58
+ const mount = (next) => {
59
+ canvas = next;
60
+ canvasRef.current = canvas;
61
+ // oxlint-disable-next-line react/immutability -- forwarding the internally created canvas
62
+ if (latest.current.forwardedRef)
63
+ latest.current.forwardedRef.current = canvas;
64
+ host.replaceChildren(canvas);
65
+ };
66
+ const draw = () => {
67
+ if (disposed || !active)
68
+ return;
69
+ const display = active;
70
+ const { hdrifyImage: image, toneMapping, exposure, onDraw, onError } = latest.current;
71
+ const mapper = resolveToneMapping(toneMapping, display.mode);
72
+ const revision = ++drawRevision;
73
+ try {
74
+ const scale = Math.min((host.clientWidth || image.width) / image.width, (host.clientHeight || image.height) / image.height);
75
+ const width = Math.max(1, image.width * scale);
76
+ const height = Math.max(1, image.height * scale);
77
+ canvas.style.width = `${width}px`;
78
+ canvas.style.height = `${height}px`;
79
+ display.resize(width, height, view.devicePixelRatio || 1);
80
+ display.draw(image, mapper, exposure);
81
+ canvas.dataset.displayMode = display.mode;
82
+ canvas.dataset.toneMapping = mapper;
83
+ void display
84
+ .complete()
85
+ .then(() => {
86
+ if (!disposed && revision === drawRevision && active === display)
87
+ onDraw?.(image, display.mode);
88
+ })
89
+ .catch((error) => {
90
+ if (!disposed && active === display) {
91
+ if (display.mode === 'hdr') {
92
+ fallback();
93
+ }
94
+ else
95
+ onError?.(error instanceof Error ? error : new Error(String(error)));
96
+ }
97
+ });
98
+ }
99
+ catch (error) {
100
+ if (display.mode === 'hdr') {
101
+ fallback();
102
+ }
103
+ else
104
+ onError?.(error instanceof Error ? error : new Error(String(error)));
105
+ }
106
+ };
107
+ const fallback = () => {
108
+ if (disposed)
109
+ return;
110
+ ++generation;
111
+ active?.dispose();
112
+ mount(host.ownerDocument.createElement('canvas'));
113
+ fallbackImage = undefined;
114
+ fallbackDrawing = '';
115
+ active = {
116
+ mode: 'sdr',
117
+ draw(image, mapper, exposure) {
118
+ const key = `${mapper}:${exposure}`;
119
+ if (fallbackImage === image && fallbackDrawing === key)
120
+ return;
121
+ drawToneMapped(canvas, image, mapper, exposure);
122
+ fallbackImage = image;
123
+ fallbackDrawing = key;
124
+ },
125
+ resize() { },
126
+ complete: () => Promise.resolve(),
127
+ dispose() { },
128
+ };
129
+ draw();
130
+ };
131
+ const select = async () => {
132
+ const request = ++generation;
133
+ if (!media.matches || !view.navigator.gpu) {
134
+ fallback();
135
+ return;
136
+ }
137
+ let next;
138
+ try {
139
+ const { createWebGPUDisplay } = await import('./webgpuDisplay.js');
140
+ if (disposed || request !== generation)
141
+ return;
142
+ const candidate = host.ownerDocument.createElement('canvas');
143
+ next = await createWebGPUDisplay(candidate, () => {
144
+ if (!disposed && request === generation)
145
+ fallback();
146
+ });
147
+ if (disposed || request !== generation) {
148
+ next.dispose();
149
+ return;
150
+ }
151
+ active?.dispose();
152
+ active = next;
153
+ mount(candidate);
154
+ draw();
155
+ }
156
+ catch {
157
+ next?.dispose();
158
+ if (!disposed && request === generation)
159
+ fallback();
160
+ }
161
+ };
162
+ redraw.current = draw;
163
+ const observer = new ResizeObserver(draw);
164
+ try {
165
+ observer.observe(host, { box: 'device-pixel-content-box' });
10
166
  }
11
- }, [forwardedRef]);
12
- const renderToCanvas = useCallback((data, exp, tone) => {
13
- const canvas = canvasRef.current;
14
- if (!canvas)
15
- return;
16
- const { width, height } = data;
17
- canvas.width = width;
18
- canvas.height = height;
19
- // LDR from applyToneMapping is sRGB; use srgb canvas so it displays correctly
20
- const ctx = canvas.getContext('2d', { colorSpace: 'srgb' }) ?? canvas.getContext('2d');
21
- if (!ctx)
22
- return;
23
- const ldrRgb = applyToneMapping(data.data, width, height, {
24
- toneMapping: tone,
25
- exposure: exp,
26
- sourceColorSpace: data.linearColorSpace,
27
- });
28
- const canvasImageData = ctx.createImageData(width, height);
29
- const pixels = canvasImageData.data;
30
- const sourceLength = width * height * 3;
31
- for (let destIndex = 0, sourceIndex = 0; sourceIndex < sourceLength; destIndex += 4, sourceIndex += 3) {
32
- pixels[destIndex] = ldrRgb[sourceIndex];
33
- pixels[destIndex + 1] = ldrRgb[sourceIndex + 1];
34
- pixels[destIndex + 2] = ldrRgb[sourceIndex + 2];
35
- pixels[destIndex + 3] = 255;
167
+ catch {
168
+ observer.observe(host);
36
169
  }
37
- ctx.putImageData(canvasImageData, 0, 0);
170
+ const onMediaChange = () => {
171
+ void select();
172
+ };
173
+ media.addEventListener('change', onMediaChange);
174
+ view.addEventListener('resize', draw);
175
+ let resolution = view.matchMedia(`(resolution: ${view.devicePixelRatio}dppx)`);
176
+ const onResolutionChange = () => {
177
+ resolution.removeEventListener('change', onResolutionChange);
178
+ resolution = view.matchMedia(`(resolution: ${view.devicePixelRatio}dppx)`);
179
+ resolution.addEventListener('change', onResolutionChange);
180
+ draw();
181
+ };
182
+ resolution.addEventListener('change', onResolutionChange);
183
+ void select();
184
+ return () => {
185
+ disposed = true;
186
+ ++generation;
187
+ ++drawRevision;
188
+ observer.disconnect();
189
+ media.removeEventListener('change', onMediaChange);
190
+ view.removeEventListener('resize', draw);
191
+ resolution.removeEventListener('change', onResolutionChange);
192
+ active?.dispose();
193
+ canvasRef.current = null;
194
+ redraw.current = () => { };
195
+ host.replaceChildren();
196
+ };
38
197
  }, []);
39
- useEffect(() => {
40
- renderToCanvas(hdrifyImage, exposure, toneMapping);
41
- }, [hdrifyImage, exposure, toneMapping, renderToCanvas]);
42
- return _jsx("canvas", { className: className, ref: setRef });
198
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: CSS }), _jsx("div", { ref: hostRef, className: `hdrify-canvas${props.className ? ` ${props.className}` : ''}`, style: {
199
+ '--hdrify-image-width': `${props.hdrifyImage.width}px`,
200
+ '--hdrify-image-aspect': `${props.hdrifyImage.width}/${props.hdrifyImage.height}`,
201
+ } })] }));
43
202
  }
44
203
  //# sourceMappingURL=HdrifyCanvas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HdrifyCanvas.js","sourceRoot":"","sources":["../src/HdrifyCanvas.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,gBAAgB,EAA0C,MAAM,QAAQ,CAAC;AAElF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAWvD,MAAM,UAAU,YAAY,CAAC,EAC3B,WAAW,EACX,WAAW,EACX,QAAQ,EACR,SAAS,EACT,YAAY,GACM;IAClB,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAElD,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,EAA4B,EAAE,EAAE;QAC9B,SAA8D,CAAC,OAAO,GAAG,EAAE,CAAC;QAC7E,IAAI,YAAY,EAAE,CAAC;YAChB,YAAiE,CAAC,OAAO,GAAG,EAAE,CAAC;QAClF,CAAC;IACH,CAAC,EACD,CAAC,YAAY,CAAC,CACf,CAAC;IAEF,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,IAAiB,EAAE,GAAW,EAAE,IAAqB,EAAQ,EAAE;QACjG,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC;QACjC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAC/B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,8EAA8E;QAC9E,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAEvF,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;YACxD,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,GAAG;YACb,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;SACxC,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC;QACpC,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;QACxC,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,WAAW,GAAG,CAAC,EAAE,WAAW,GAAG,YAAY,EAAE,SAAS,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC,EAAE,CAAC;YACtG,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,WAAW,CAAE,CAAC;YACzC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,GAAG,CAAC,CAAE,CAAC;YACjD,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,GAAG,CAAC,CAAE,CAAC;YACjD,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QAC9B,CAAC;QAED,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IACrD,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IAEzD,OAAO,iBAAQ,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAI,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"HdrifyCanvas.js","sources":["../src/HdrifyCanvas.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import type { HdrifyImage } from 'hdrify';
2
+ import { type ViewerToneMapping } from './display.js';
3
+ import { type CSSProperties, type Ref } from 'react';
4
+ import { type ImageViewerCaptureOptions } from './capture.js';
5
+ import { type ImageViewerProgress } from './progress.js';
6
+ /** `open` shows the options panel, `closed` shows only its gear button, and `hidden` shows neither. */
7
+ export type SettingsPanelMode = 'open' | 'closed' | 'hidden';
8
+ /** `contain` scales the image to fit the viewer; `actual` shows one image pixel per CSS pixel, scrolling if needed. */
9
+ export type ImageFit = 'contain' | 'actual';
10
+ /** User-adjustable display settings. */
11
+ export interface ImageViewerSettings {
12
+ /** Omit for None on HDR displays and Neutral on SDR; explicit None falls back to Neutral on SDR. */
13
+ toneMapping?: ViewerToneMapping;
14
+ /** Exposure in stops (EV): `0` is unchanged, `+1` doubles the brightness. */
15
+ exposure: number;
16
+ fit: ImageFit;
17
+ }
18
+ export declare const DEFAULT_IMAGE_VIEWER_SETTINGS: Readonly<ImageViewerSettings>;
19
+ export declare const TONE_MAPPING_OPTIONS: readonly {
20
+ value: ViewerToneMapping;
21
+ label: string;
22
+ }[];
23
+ /** Range of the exposure slider, in stops. The options panel accepts any value. */
24
+ export declare const EXPOSURE_SLIDER_RANGE: {
25
+ readonly min: -10;
26
+ readonly max: 10;
27
+ };
28
+ /** Imperative handle for {@link ImageViewer}, received through its `ref` (React 19). */
29
+ export interface ImageViewerHandle {
30
+ /**
31
+ * Resolve once the current source is loaded and drawn (immediately with no source). If the source changes first,
32
+ * it waits for the new source instead. Rejects with the load's error, or if the component unmounts.
33
+ */
34
+ whenReady(): Promise<void>;
35
+ /**
36
+ * Wait for {@link whenReady}, including the first completed render, then export
37
+ * an SDR PNG/JPEG/WebP without viewer controls. Capture is independent of display
38
+ * output: an omitted mapper uses Neutral; explicit `none` clips above-white values.
39
+ */
40
+ toBlob(options?: ImageViewerCaptureOptions): Promise<Blob>;
41
+ }
42
+ /** Props for {@link ImageViewer}. Settings props override the user's choice whenever they change. */
43
+ export interface ImageViewerProps extends Partial<ImageViewerSettings> {
44
+ /** URL of an EXR, HDR, JPEG XL or gain map JPEG (optionally gzipped). Fetching is cancelled when it changes. */
45
+ src?: string;
46
+ /** Encoded file bytes; takes precedence over `src`. */
47
+ data?: ArrayBuffer | Uint8Array;
48
+ /** An already decoded image; takes precedence over `data` and `src`. */
49
+ image?: HdrifyImage;
50
+ /** Initial state of the options panel. Defaults to `closed`. */
51
+ settingsPanel?: SettingsPanelMode;
52
+ /** Show the vertical exposure slider over the left edge. */
53
+ exposureControl?: boolean;
54
+ /** Wrapper class name. */
55
+ className?: string;
56
+ /** Wrapper style; the default height is 480 pixels. */
57
+ style?: CSSProperties;
58
+ /** Called after each image loads and is drawn. */
59
+ onLoad?: (image: HdrifyImage) => void;
60
+ /** Called with fetch and decode errors; they are also shown in the viewer. */
61
+ onError?: (error: Error) => void;
62
+ /** Called as the image downloads, decodes and is drawn. */
63
+ onProgress?: (progress: ImageViewerProgress) => void;
64
+ /** Called when the user changes a setting with the slider or the options panel. */
65
+ onSettingsChange?: (settings: ImageViewerSettings) => void;
66
+ /** Called when the user opens or closes the options panel. */
67
+ onSettingsPanelChange?: (mode: SettingsPanelMode) => void;
68
+ /** Receives an {@link ImageViewerHandle} for readiness and image capture. */
69
+ ref?: Ref<ImageViewerHandle>;
70
+ }
71
+ /**
72
+ * Loads and displays an HDR image with tone mapping, a loading bar, an optional options panel and an optional
73
+ * exposure slider. Accepts every format hdrify reads; see {@link decodeHdrifyImage}.
74
+ * Uses {@link HdrifyCanvas} for HDR presentation and SDR fallback. None is offered
75
+ * and selected by default only after extended FP16 presentation succeeds; otherwise
76
+ * Neutral is the default and None is hidden. There is no Automatic menu item.
77
+ * `fit="actual"` shows one source pixel per CSS pixel. Loading progress is reported
78
+ * through `onProgress`; the imperative handle exposes readiness and SDR capture.
79
+ *
80
+ * @example
81
+ * ```tsx
82
+ * <ImageViewer src="/images/memorial.exr" exposureControl toneMapping="agx" style={{ height: 600 }} />
83
+ * ```
84
+ */
85
+ export declare function ImageViewer({ src, data, image, toneMapping, exposure, fit, settingsPanel, exposureControl, className, style, onLoad, onError, onProgress, onSettingsChange, onSettingsPanelChange, ref, }: ImageViewerProps): import("react").JSX.Element;
86
+ //# sourceMappingURL=ImageViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageViewer.d.ts","sources":["../src/ImageViewer.tsx"],"names":[],"mappings":"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"}