hdr-canvas 0.0.13 → 0.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.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  This module contains a collection of functions and classes to work with the HDR support for HTML `canvas` elements in chromium based (like Chrome, Edge, Opera and Brave) browsers.
4
4
 
5
+ All changes and a bit of context are part of the [release notes for 0.1.0](docs/release-notes-0.1.0.md).
6
+
5
7
  **This should only be considered as proof of concept or alpha code, don't use it in production environments!**
6
8
 
7
9
  **Even if the display of HDR images works, the HDR support for the `canvas` element needs the browser flag `enable-experimental-web-platform-features` to be enabled. For example, open chrome://flags#enable-experimental-web-platform-features in Chrome to activate it.**
@@ -16,7 +18,7 @@ Import the required function(s):
16
18
  import { checkHDR, checkHDRCanvas } from "hdr-canvas";
17
19
  ```
18
20
 
19
- ## Examples `checkHDRCanvas()`
21
+ ## Example `checkHDRCanvas()`
20
22
 
21
23
  The functions return `true` if HDR is supported, example:
22
24
 
@@ -35,12 +37,26 @@ This can be useful to add a warning (using the [`fillText()`](https://developer.
35
37
  ## Example `checkHDRCanvas()`
36
38
 
37
39
  ```javascript
40
+ const hdrCanvasStatus = document.getElementById("hdr-check-status")! as HTMLDivElement;
38
41
  if (checkHDRCanvas()) {
39
- hdrCanvas.innerText = "HDR Canvas are supported";
40
- hdrCanvas.style.color = "green";
42
+ hdrCanvasStatus.innerText = "HDR Canvas are supported";
43
+ hdrCanvasStatus.style.color = "green";
44
+ } else {
45
+ hdrCanvasStatus.innerText = "HDR Canvas are not supported";
46
+ hdrCanvasStatus.style.color = "red";
47
+ }
48
+ ```
49
+
50
+ ## Example `checkHDRVideo()`
51
+
52
+ ```javascript
53
+ const hdrCanvasStatus = document.getElementById("hdr-check-status")! as HTMLDivElement;
54
+ if (checkHDRVideo()) {
55
+ hdrCanvasStatus.innerText = "HDR Video is supported";
56
+ hdrCanvasStatus.style.color = "green";
41
57
  } else {
42
- hdrCanvas.innerText = "HDR Canvas are not supported";
43
- hdrCanvas.style.color = "red";
58
+ hdrCanvasStatus.innerText = "HDR Video is not supported";
59
+ hdrCanvasStatus.style.color = "red";
44
60
  }
45
61
  ```
46
62
 
@@ -55,7 +71,9 @@ const colorSpace = "rec2100-hlg";
55
71
  canvas.configureHighDynamicRange({ mode: "extended" });
56
72
  const ctx = canvas.getContext("2d", {
57
73
  colorSpace: colorSpace,
58
- pixelFormat: "float16"
74
+ colorType: "float16"
75
+ // Use this for Chrome < 133
76
+ //pixelFormat: "float16"
59
77
  });
60
78
  ```
61
79
 
@@ -71,12 +89,12 @@ import { initHDRCanvas } from "hdr-canvas";
71
89
 
72
90
  It's now also possible to use a HDR enabled Canvas by wrapping the browser internal `getContext()` function, by calling `defaultGetContextHDR()`.
73
91
 
74
- ```
75
- import {defaultGetContextHDR, checkHDR, checkHDRCanvas} from 'hdr-canvas';
92
+ ```javascript
93
+ import { defaultGetContextHDR, checkHDR, checkHDRCanvas } from "hdr-canvas";
76
94
 
77
95
  if (checkHDR() && checkHDRCanvas()) {
78
96
  defaultGetContextHDR();
79
- console.log('Enabled HDR Canvas');
97
+ console.log("Enabled HDR Canvas");
80
98
  }
81
99
  ```
82
100
 
@@ -86,18 +104,18 @@ if (checkHDR() && checkHDRCanvas()) {
86
104
 
87
105
  Use the method `resetGetContext()` to undo the changes by `defaultGetContextHDR()`.
88
106
 
89
- ```
90
- import {resetGetContext} from 'hdr-canvas';
107
+ ```javascript
108
+ import { resetGetContext } from "hdr-canvas";
91
109
 
92
110
  resetGetContext();
93
111
  ```
94
112
 
95
- ## Importing `Uint16Image`
113
+ ## Importing `Float16Image`
96
114
 
97
- Afterwards one can use [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) with a `float16` array, first the `Uint16Image` needs to be imported:
115
+ Afterwards one can use [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) with a `float16` array, first the `Float16Image` needs to be imported:
98
116
 
99
117
  ```javascript
100
- import { Uint16Image } from "hdr-canvas";
118
+ import { Float16Image } from "hdr-canvas";
101
119
  ```
102
120
 
103
121
  ## Example: Loading an image
@@ -115,7 +133,7 @@ var hdrCanvas = document.createElement("canvas");
115
133
  hdrCanvas.width = image.width;
116
134
  hdrCanvas.height = image.height;
117
135
 
118
- const rec210hglImage = Uint16Image.fromImageData(imData);
136
+ const rec210hglImage = Float16Image.fromImageData(imData);
119
137
 
120
138
  const ctx = initHDRCanvas(hdrCanvas);
121
139
  ctx.putImageData(rec210hglImage.getImageData(), 0, 0);
@@ -133,8 +151,8 @@ import HDRWebGPURenderer from "hdr-canvas/three/HDRWebGPURenderer.js";
133
151
 
134
152
  **Note:** Starting Three.js 167 the WebGPU renderer is the new default renderer. This has several consequences for the required imports. Use this import instead of the official one and if your using Vite _don't_ provide an import map of resolver alias configuration.
135
153
 
136
- ```
137
- import * as THREE from 'three/src/Three.js';
154
+ ```javascript
155
+ import * as THREE from "three/src/Three.js";
138
156
  ```
139
157
 
140
158
  Use it as you'll do with a `WebGPURenderer`.
@@ -147,7 +165,7 @@ renderer = new HDRWebGPURenderer({ canvas: canvas, antialias: true });
147
165
 
148
166
  Starting from Three.js version 167 you need to fix imported UHDR Textures, otherwise they will appear black:
149
167
 
150
- ```
168
+ ```javascript
151
169
  model = gltf.scene;
152
170
  model.traverse((element) => {
153
171
  if (element?.material?.type != undefined) {
@@ -164,22 +182,35 @@ scene.add(model);
164
182
  This currently doesn't work with Firefox, due to missing support for HDR and only partial WebGPU support.
165
183
  One can import `WebGPU` and use also a HDR check to guard from errors:
166
184
 
167
- ```
168
- import WebGPU from 'hdr-canvas/three/WebGPU.js';
185
+ ```javascript
186
+ import WebGPU from "hdr-canvas/three/WebGPU.js";
169
187
  ```
170
188
 
171
189
  Only use the provided renderer if the browser supports WebGPU and HDR:
172
190
 
173
- ```
191
+ ```javascript
174
192
  if (WebGPU.isAvailable() && checkHDRCanvas()) {
175
- renderer = new HDRWebGPURenderer({canvas: canvas, antialias: true});
193
+ renderer = new HDRWebGPURenderer({ canvas: canvas, antialias: true });
176
194
  } else {
177
- renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
195
+ renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
178
196
  }
179
197
  ```
180
198
 
181
199
  # Examples
182
200
 
201
+ ## Bundled examples
202
+
203
+ Some of the examples above are also part of this repository.
204
+
205
+ ```console
206
+ npm i
207
+ npm run dev
208
+ ```
209
+
210
+ Open This URL in your browser: [http://localhost:5173/](http://localhost:5173/), you can also access them directly from [GitHub](https://cmahnke.github.io/hdr-canvas/).
211
+
212
+ ## Old examples on my blog:
213
+
183
214
  All examples requires a Chromium based browser (like Chrome, Edge, Opera and Brave) and a HDR-enable monitor.
184
215
 
185
216
  - [Contrast enhancement for UV images using HDR](https://christianmahnke.de/en/post/hdr-image-analysis/)
@@ -192,9 +223,75 @@ All examples requires a Chromium based browser (like Chrome, Edge, Opera and Bra
192
223
 
193
224
  The following things might be improved:
194
225
 
195
- - Try to detect change of screen for HDR detection
196
- - Improve speed
197
- - Provide WebWorker
198
- - Documentation
199
- - Link to browser HDR support
200
- - Document `Uint16Image`
226
+ - [x] Change `pixelFormat` in `HTMLCanvasElement.getContext("2d")` to `colorType` (["unorm8", "float16"]) while keeping some downward compatibility - [#151](https://github.com/cmahnke/hdr-canvas/issues/151)
227
+ - [ ] Try to detect change of screen for HDR detection - [#107](https://github.com/cmahnke/hdr-canvas/issues/107)
228
+ - [ ] Remove `Uint16Image`
229
+ - [ ] Improve speed
230
+ - [ ] Provide WebWorker
231
+ - [ ] Documentation
232
+ - [ ] Link to browser HDR support
233
+ - [x] Document `Uint16Image`
234
+ - [ ] Tests and examples
235
+ - [x] Provide examples from blog
236
+ - [x] Provide simple sanity tests
237
+
238
+ # References
239
+
240
+ ## Browser HDR
241
+
242
+ - [`dynamic-range` Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/dynamic-range)
243
+ - [HDR Capability Detection](https://github.com/w3c/media-capabilities/blob/main/hdr_explainer.md)
244
+ - [HDR `HTMLCanvasElement`](https://github.com/w3c/ColorWeb-CG/blob/main/hdr_html_canvas_element.md)
245
+
246
+ ### Older
247
+
248
+ - [Adding support for High Dynamic Range (HDR) imagery to HTML Canvas: a baseline proposal](https://github.com/whatwg/html/issues/9461)
249
+ - [HDR Canvas Example](https://ccameron-chromium.github.io/webgl-examples/canvas-hdr.html)
250
+
251
+ ## Sources
252
+
253
+ This section contains different definitions, which can be helpful to impkement HDR related things
254
+
255
+ - [`CanvasRenderingContext2DSettings` in Chromium](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_settings.idl)
256
+ - [`ImageData` in Chromium](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/canvas/image_data.idl)
257
+ - [`TypeScript DOM reference`](https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/main/baselines/dom.generated.d.ts)
258
+
259
+ ## Workflow on related changes to web APIs
260
+
261
+ **This is considered to be experimental**, currently we're waiting for TypeSript to pick up the changes made to the web APIs. See [microsoft/TypeScript-DOM-lib-generator#2107](https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/2107)
262
+
263
+ ### Along the spec
264
+
265
+ 1. Change to the WhatsWG spec - [Issue Tracker](https://github.com/whatwg/html)
266
+ 2. Change apporoved
267
+ 3. MDN picks up spec change - [Create an issue](https://github.com/mdn/content/issues)
268
+ 4. Changes are popagated to the [TypeScript generated DOM library](https://github.com/microsoft/TypeScript-DOM-lib-generator)
269
+
270
+ ### By custom TypeScript types
271
+
272
+ 1. Extend `src/types`, try to extend existing interfaces
273
+
274
+ ## Generating updated TypeScript types
275
+
276
+ Starting with one of the next monor versions (maybe 0.2.0) the prefered way is to update the browser / DOM types instead of adding our own HDR types. The existing types will continue to exist for now. This change reflects improvements in browser support and should make transitioning to standard base types later on.
277
+
278
+ The basic workflow is as follows:
279
+
280
+ - [Update the definitions](https://github.com/microsoft/TypeScript-DOM-lib-generator?tab=readme-ov-file#contribution-guidelines)
281
+ - Regenerate the types (needs the MDN submodule to be checked out)
282
+
283
+ To make this repaetable add patches to this repository:
284
+
285
+ Edit the types, for example to change existing definitions, see [Update the definitions](https://github.com/microsoft/TypeScript-DOM-lib-generator?tab=readme-ov-file#contribution-guidelines)
286
+
287
+ ```
288
+ cd node_modules/@typescript/dom-lib-generator/
289
+ vi inputfiles/overridingTypes.jsonc
290
+ ```
291
+
292
+ To generate a patch pmake sure, that the Git submmodule is remove, otherwise `patch-package` will fail.
293
+
294
+ ```
295
+ node scripts/git-submodules.js -c -d node_modules/@typescript/dom-lib-generator/
296
+ npx patch-package @typescript/dom-lib-generator
297
+ ```
@@ -6,6 +6,8 @@ import { ColorTypes } from 'colorjs.io';
6
6
  type HDRHTMLCanvasOptionsType = "mode";
7
7
  type HDRHTMLCanvasOptions = { [key in HDRHTMLCanvasOptionsType]?: string };
8
8
 
9
+ type HDRImageDataArray = ImageDataArray | Float16Array | Uint16Array;
10
+
9
11
  interface HDRHTMLCanvasElement extends HTMLCanvasElement {
10
12
  configureHighDynamicRange(options: HDRHTMLCanvasOptions): void;
11
13
  _getContext(contextId: string, options?: object): RenderingContext | null;
@@ -13,45 +15,91 @@ interface HDRHTMLCanvasElement extends HTMLCanvasElement {
13
15
 
14
16
  interface HDRImageData {
15
17
  readonly colorSpace: PredefinedColorSpace;
16
- readonly data: Uint8ClampedArray | Uint16Array;
18
+ readonly data: HDRImageDataArray | Uint16Array;
17
19
  readonly height: number;
18
20
  readonly width: number;
19
21
  }
20
22
 
21
23
  // See https://github.com/w3c/ColorWeb-CG/blob/main/hdr_html_canvas_element.md
22
- // "rec2100-display-linear" is left out beacause of mapping issues
24
+ // "rec2100-display-linear" is left out because of mapping issues
23
25
  type HDRPredefinedColorSpace = "display-p3" | "srgb" | "rec2100-hlg" | "rec2100-pq";
24
26
 
25
- type Uint16ImagePixelCallback = (red: number, green: number, blue: number, alpha: number) => Uint16Array;
26
- declare class Uint16Image {
27
- height: number;
28
- width: number;
29
- data: Uint16Array;
27
+ //enum HDRPredefinedColorSpace {"display-p3", "srgb", "rec2100-hlg", "rec2100-pq", "rec2100-display-linear"};
28
+
29
+ /**
30
+ * A callback function that receives the red, green, blue, and alpha values of a pixel
31
+ * and returns a new `Float16Array` with the modified values.
32
+ *
33
+ * @callback HDRImagePixelCallback
34
+ * @param {number} red - The red channel value (0-65535).
35
+ * @param {number} green - The green channel value (0-65535).
36
+ * @param {number} blue - The blue channel value (0-65535).
37
+ * @param {number} alpha - The alpha channel value (0-65535).
38
+ * @returns {ImageDataArray} A new `Float16Array` containing the four channel values.
39
+ */
40
+ type HDRImagePixelCallback = (red: number, green: number, blue: number, alpha: number) => HDRImageDataArray;
41
+
42
+ interface CanvasRenderingContext2DHDR extends CanvasRenderingContext2D {}
43
+
44
+ declare abstract class HDRImage {
30
45
  static DEFAULT_COLORSPACE: HDRPredefinedColorSpace;
31
46
  static SDR_MULTIPLIER: number;
32
47
  static COLORSPACES: Record<HDRPredefinedColorSpace, ColorTypes>;
48
+ data: HDRImageDataArray;
49
+ height: number;
50
+ width: number;
51
+ constructor(width: number, height: number);
52
+ static fromImageData(imageData: HDRImageData | ImageData): HDRImage;
53
+ static fromImageDataArray(width: number, height: number, imageDataArray: Uint8ClampedArray | Uint8ClampedArray<ArrayBufferLike>): HDRImage;
54
+ static loadSDRImageData(url: URL): Promise<ImageData | undefined>;
55
+ getPixel(w: number, h: number): HDRImageDataArray;
56
+ setPixel(w: number, h: number, px: number[]): void;
57
+ abstract setImageData(imageData: HDRImageData | ImageData): void;
58
+ abstract getImageData(): ImageData | null;
59
+ abstract fill(color: number[]): this | undefined;
60
+ abstract pixelCallback(fn: HDRImagePixelCallback): void;
61
+ clone(): this;
62
+ }
63
+
64
+ declare class Uint16Image extends HDRImage {
65
+ data: Uint16Array;
33
66
  colorSpace: HDRPredefinedColorSpace;
34
67
  constructor(width: number, height: number, colorspace?: string);
35
- fill(color: number[]): Uint16Image | undefined;
36
- getPixel(w: number, h: number): Uint16Array;
37
- setPixel(w: number, h: number, px: number[]): void;
68
+ fill(color: number[]): this | undefined;
38
69
  static scaleUint8ToUint16(val: number): number;
39
70
  getImageData(): ImageData | null;
40
71
  static convertPixelToRec2100_hlg(pixel: Uint8ClampedArray): Uint16Array;
41
72
  static convertArrayToRec2100_hlg(data: Uint8ClampedArray): Uint16Array;
42
- pixelCallback(fn: Uint16ImagePixelCallback): void;
43
- static loadSDRImageData(url: URL): Promise<HDRImageData | undefined>;
73
+ pixelCallback(fn: HDRImagePixelCallback): void;
44
74
  static fromImageData(imageData: HDRImageData): Uint16Image;
45
75
  static fromURL(url: URL): Promise<Uint16Image | undefined>;
46
76
  setImageData(imageData: HDRImageData): void;
47
- clone(): Uint16Image;
77
+ }
78
+
79
+ declare class Float16Image extends HDRImage {
80
+ data: Float16Array;
81
+ static DEFAULT_PIXELFORMAT: ImageDataPixelFormat;
82
+ colorSpace: HDRPredefinedColorSpace;
83
+ pixelFormat: ImageDataPixelFormat;
84
+ constructor(width: number, height: number, colorspace?: string, pixelFormat?: string);
85
+ fill(color: number[]): this | undefined;
86
+ static scaleUint8ToFloat16(val: number): number;
87
+ getImageData(): ImageData | null;
88
+ static convertPixelToRec2100_hlg(pixel: Uint8ClampedArray): Float16Array;
89
+ static convertArrayToRec2100_hlg(data: Uint8ClampedArray): Float16Array;
90
+ pixelCallback(fn: HDRImagePixelCallback): void;
91
+ static fromImageData(imageData: HDRImageData): Float16Image;
92
+ static fromImageDataArray(width: number, height: number, imageDataArray: Uint8ClampedArray | Uint8ClampedArray<ArrayBufferLike>): Float16Image;
93
+ static fromURL(url: URL): Promise<Float16Image | undefined>;
94
+ setImageData(imageData: HDRImageData): void;
95
+ clone(): this;
48
96
  }
49
97
 
50
98
  declare function checkHDR(): boolean;
51
99
  declare function checkHDRCanvas(): boolean;
52
100
 
53
- declare function initHDRCanvas(canvas: HDRHTMLCanvasElement): RenderingContext | null;
101
+ declare function initHDRCanvas(canvas: HDRHTMLCanvasElement): CanvasRenderingContext2DHDR | null;
54
102
  declare function defaultGetContextHDR(): void;
55
103
  declare function resetGetContext(): void;
56
104
 
57
- export { Uint16Image, checkHDR, checkHDRCanvas, defaultGetContextHDR, initHDRCanvas, resetGetContext };
105
+ export { Float16Image, HDRImage, Uint16Image, checkHDR, checkHDRCanvas, defaultGetContextHDR, initHDRCanvas, resetGetContext };