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,215 @@
1
+ import { createElement } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { captureImage } from './capture.js';
4
+ import { DEFAULT_IMAGE_VIEWER_SETTINGS, ImageViewer, TONE_MAPPING_OPTIONS, } from './ImageViewer.js';
5
+ import { ViewerReadiness } from './readiness.js';
6
+ const HOST_CSS = ':host{display:block;height:480px;position:relative;min-width:0}:host([hidden]){display:none}';
7
+ function oneOf(value, allowed) {
8
+ return allowed.find((option) => option === value);
9
+ }
10
+ // Importing this module on an SSR server is safe; registration occurs only in a browser.
11
+ // oxlint-disable-next-line typescript/no-extraneous-class
12
+ const ElementBase = typeof HTMLElement === 'undefined' ? class {
13
+ } : HTMLElement;
14
+ /**
15
+ * `<image-viewer>`: displays an EXR, HDR, JPEG XL or gain map JPEG with tone mapping. A web component wrapping
16
+ * {@link ImageViewer}; it works in plain HTML and any framework.
17
+ *
18
+ * Attributes: `src`, `tone-mapping`, `exposure` (stops), `fit`, `settings-panel`, `exposure-control`.
19
+ * Events: `progress` ({@link ImageViewerProgress}), `load` (`{ image }`), `error` (`{ message, error }`),
20
+ * `settingschange` (`{ settings }`). Children with `slot="progress-bar"` replace the default loading bar.
21
+ */
22
+ export class ImageViewerElement extends ElementBase {
23
+ static observedAttributes = ['src', 'tone-mapping', 'exposure', 'fit', 'settings-panel', 'exposure-control'];
24
+ #root;
25
+ #mount;
26
+ #generation = 0;
27
+ #reflecting = false;
28
+ #image;
29
+ #data;
30
+ #settings = { ...DEFAULT_IMAGE_VIEWER_SETTINGS };
31
+ #readiness = new ViewerReadiness();
32
+ /** Incremented on every source change, so callbacks from a superseded load are ignored. */
33
+ #revision = 0;
34
+ /** The image currently drawn, for toBlob(). */
35
+ #shown;
36
+ /** The source of the current load: what ImageViewer loads, by precedence. */
37
+ #source;
38
+ /** URL to load; reflects the `src` attribute. */
39
+ get src() {
40
+ return this.getAttribute('src') ?? '';
41
+ }
42
+ set src(value) {
43
+ this.setAttribute('src', value);
44
+ }
45
+ /** A decoded image to display; takes precedence over `data` and `src`. */
46
+ get image() {
47
+ return this.#image;
48
+ }
49
+ set image(value) {
50
+ this.#image = value;
51
+ this.#sourceChanged();
52
+ this.#render();
53
+ }
54
+ /** Encoded EXR, HDR, JPEG XL or gain map JPEG bytes; takes precedence over `src`. */
55
+ get data() {
56
+ return this.#data;
57
+ }
58
+ set data(value) {
59
+ this.#data = value;
60
+ this.#sourceChanged();
61
+ this.#render();
62
+ }
63
+ /** The current display settings. Assign a partial object to change them. */
64
+ get settings() {
65
+ return { ...this.#settings };
66
+ }
67
+ set settings(patch) {
68
+ const next = { ...this.#settings, ...patch };
69
+ this.#reflect([
70
+ ['tone-mapping', next.toneMapping],
71
+ ['exposure', String(next.exposure)],
72
+ ['fit', next.fit],
73
+ ]);
74
+ this.#settings = next;
75
+ this.#render();
76
+ }
77
+ connectedCallback() {
78
+ ++this.#generation;
79
+ if (!this.shadowRoot) {
80
+ const shadow = this.attachShadow({ mode: 'open' });
81
+ const style = document.createElement('style');
82
+ style.textContent = HOST_CSS;
83
+ this.#mount = document.createElement('div');
84
+ this.#mount.style.height = '100%';
85
+ shadow.append(style, this.#mount);
86
+ }
87
+ // A moved element keeps its React root and image; a new root loads the source again.
88
+ if (!this.#root) {
89
+ this.#root = createRoot(this.#mount);
90
+ this.#sourceChanged(true);
91
+ }
92
+ this.#render();
93
+ }
94
+ /**
95
+ * Resolve once the current source is loaded and drawn (immediately with no source). If the source changes first,
96
+ * it waits for the new source instead. Rejects with the load's error, or if the element is disconnected.
97
+ */
98
+ whenReady() {
99
+ return this.#readiness.whenReady();
100
+ }
101
+ /**
102
+ * Wait for {@link whenReady}, then encode the tone-mapped image with the current settings, at the image's own
103
+ * size unless `width`/`height` are given. Only the image is included, not the viewer's controls.
104
+ */
105
+ async toBlob(options) {
106
+ await this.whenReady();
107
+ if (!this.#shown)
108
+ throw new Error('No image is loaded.');
109
+ return captureImage(this.#shown, this.#settings.toneMapping ?? 'neutral', 2 ** this.#settings.exposure, options);
110
+ }
111
+ disconnectedCallback() {
112
+ const generation = ++this.#generation;
113
+ // A parent React tree may be removing this element right now: unmount after that commit, and keep the root
114
+ // if the element is moved (disconnected and reconnected synchronously).
115
+ queueMicrotask(() => {
116
+ if (generation !== this.#generation || this.isConnected)
117
+ return;
118
+ this.#root?.unmount();
119
+ this.#root = undefined;
120
+ this.#readiness.disconnect();
121
+ ++this.#revision;
122
+ });
123
+ }
124
+ attributeChangedCallback(name) {
125
+ if (this.#reflecting)
126
+ return;
127
+ if (name === 'src')
128
+ this.#sourceChanged();
129
+ const exposure = this.getAttribute('exposure');
130
+ const toneMapping = oneOf(this.getAttribute('tone-mapping'), TONE_MAPPING_OPTIONS.map((option) => option.value));
131
+ const fit = oneOf(this.getAttribute('fit'), ['contain', 'actual']);
132
+ if (name === 'tone-mapping')
133
+ this.#settings.toneMapping = toneMapping;
134
+ if (fit)
135
+ this.#settings.fit = fit;
136
+ if (exposure !== null && Number.isFinite(Number(exposure)))
137
+ this.#settings.exposure = Number(exposure);
138
+ this.#render();
139
+ }
140
+ // Mark a new load synchronously, so whenReady() called right after a change waits for the new source.
141
+ #sourceChanged(reload = false) {
142
+ const source = this.#image ?? this.#data ?? this.getAttribute('src') ?? undefined;
143
+ // Setting the same source again does not reload, so it must not start waiting for a load either.
144
+ if (!this.#root || (source === this.#source && !reload))
145
+ return;
146
+ this.#source = source;
147
+ ++this.#revision;
148
+ this.#shown = undefined;
149
+ this.#readiness.pending();
150
+ this.setAttribute('aria-busy', String(source !== undefined));
151
+ if (source === undefined)
152
+ this.#readiness.finish();
153
+ }
154
+ // Write attributes without re-entering attributeChangedCallback.
155
+ #reflect(entries) {
156
+ this.#reflecting = true;
157
+ try {
158
+ for (const [name, value] of entries) {
159
+ if (value === undefined)
160
+ this.removeAttribute(name);
161
+ else if (this.getAttribute(name) !== value)
162
+ this.setAttribute(name, value);
163
+ }
164
+ }
165
+ finally {
166
+ this.#reflecting = false;
167
+ }
168
+ }
169
+ #dispatch(type, detail) {
170
+ this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));
171
+ }
172
+ #render() {
173
+ const exposureControl = this.getAttribute('exposure-control');
174
+ const revision = this.#revision;
175
+ const current = () => revision === this.#revision;
176
+ this.#root?.render(createElement(ImageViewer, {
177
+ src: this.getAttribute('src') ?? undefined,
178
+ data: this.#data,
179
+ image: this.#image,
180
+ ...this.#settings,
181
+ settingsPanel: oneOf(this.getAttribute('settings-panel'), ['open', 'closed', 'hidden']),
182
+ exposureControl: exposureControl !== null && exposureControl !== 'false',
183
+ style: { height: '100%' },
184
+ onProgress: (progress) => {
185
+ if (!current())
186
+ return;
187
+ this.setAttribute('aria-busy', String(progress.totalProgress < 1));
188
+ this.#dispatch('progress', progress);
189
+ },
190
+ onLoad: (image) => {
191
+ if (!current())
192
+ return;
193
+ this.#shown = image;
194
+ this.setAttribute('aria-busy', 'false');
195
+ this.#readiness.finish();
196
+ this.#dispatch('load', { image });
197
+ },
198
+ onError: (error) => {
199
+ if (!current())
200
+ return;
201
+ this.setAttribute('aria-busy', 'false');
202
+ this.#readiness.finish(error);
203
+ this.#dispatch('error', { message: error.message, error });
204
+ },
205
+ onSettingsChange: (settings) => {
206
+ this.settings = settings;
207
+ this.#dispatch('settingschange', { settings: this.settings });
208
+ },
209
+ onSettingsPanelChange: (mode) => this.#reflect([['settings-panel', mode]]),
210
+ }));
211
+ }
212
+ }
213
+ if (typeof customElements !== 'undefined' && !customElements.get('image-viewer'))
214
+ customElements.define('image-viewer', ImageViewerElement);
215
+ //# sourceMappingURL=element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.js","sources":["../src/element.ts"],"names":[],"mappings":"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"}