hdr-canvas 0.0.8 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -4,6 +4,8 @@ This module contains a collection of functions and classes to work with the HDR
4
4
 
5
5
  **This should only be considered as proof of concept or alpha code, don't use it in production environments!**
6
6
 
7
+ **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.**
8
+
7
9
  **Especially operations on the `ImageData` arrays are not optimized, e.g. quite slow.**
8
10
 
9
11
  # Feature detection
@@ -44,6 +46,8 @@ if (checkHDRCanvas()) {
44
46
 
45
47
  # Canvas
46
48
 
49
+ **Note: Currently the Chrome flag `enable-experimental-web-platform-features` needs to be enabled to have HDR support for the `canvas` element. You need to tell your visitors about that.**
50
+
47
51
  The HDR `canvas` support is activated by initializing a canvas context using the following snippet:
48
52
 
49
53
  ```javascript
@@ -51,7 +55,7 @@ const colorSpace = "rec2100-hlg";
51
55
  canvas.configureHighDynamicRange({ mode: "extended" });
52
56
  const ctx = canvas.getContext("2d", {
53
57
  colorSpace: colorSpace,
54
- pixelFormat: "float16",
58
+ pixelFormat: "float16"
55
59
  });
56
60
  ```
57
61
 
@@ -63,6 +67,31 @@ The snippet above is also available as function:
63
67
  import { initHDRCanvas } from "hdr-canvas";
64
68
  ```
65
69
 
70
+ ## Implicit Canvas setup
71
+
72
+ It's now also possible to use a HDR enabled Canvas by wrapping the browser internal `getContext()` function, by calling `defaultGetContextHDR()`.
73
+
74
+ ```
75
+ import {defaultGetContextHDR, checkHDR, checkHDRCanvas} from 'hdr-canvas';
76
+
77
+ if (checkHDR() && checkHDRCanvas()) {
78
+ defaultGetContextHDR();
79
+ console.log('Enabled HDR Canvas');
80
+ }
81
+ ```
82
+
83
+ **Note:** This example wraps the call to `defaultGetContextHDR()` into a check (`checkHDR() && checkHDRCanvas()`), because calling the function in a browser that isn't HDR-capable will break every subsequent call to `getContext()`.
84
+
85
+ ## Resetting default HDR canvas
86
+
87
+ Use the method `resetGetContext()` to undo the changes by `defaultGetContextHDR()`.
88
+
89
+ ```
90
+ import {resetGetContext} from 'hdr-canvas';
91
+
92
+ resetGetContext();
93
+ ```
94
+
66
95
  ## Importing `Uint16Image`
67
96
 
68
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:
@@ -73,7 +102,7 @@ import { Uint16Image } from "hdr-canvas";
73
102
 
74
103
  ## Example: Loading an image
75
104
 
76
- Thisexample assumes `image` to be a [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement) including an existing image.
105
+ This example assumes `image` to be a [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement) including an existing image.
77
106
 
78
107
  ```javascript
79
108
  const offscreen = new OffscreenCanvas(image.width, image.height);
@@ -96,21 +125,66 @@ ctx.putImageData(rec210hglImage.getImageData(), 0, 0);
96
125
 
97
126
  **Note**: Make sure to have Three.js added as a dependency.
98
127
 
99
- This is just a drop in replacement for the regular `WebGPURenderer` of Three.js.
128
+ This is just a drop-in-replacement for the regular `WebGPURenderer` of Three.js.
100
129
 
101
130
  ```javascript
102
131
  import HDRWebGPURenderer from "hdr-canvas/three/HDRWebGPURenderer.js";
103
132
  ```
104
133
 
134
+ **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
+
136
+ ```
137
+ import * as THREE from 'three/src/Three.js';
138
+ ```
139
+
105
140
  Use it as you'll do with a `WebGPURenderer`.
106
141
 
107
142
  ```javascript
108
143
  renderer = new HDRWebGPURenderer({ canvas: canvas, antialias: true });
109
144
  ```
110
145
 
111
- # Example
146
+ ## Updating textures
147
+
148
+ Starting from Three.js version 167 you need to fix imported UHDR Textures, otherwise they will appear black:
149
+
150
+ ```
151
+ model = gltf.scene;
152
+ model.traverse((element) => {
153
+ if (element?.material?.type != undefined) {
154
+ let targetMaterial = new THREE.MeshBasicMaterial();
155
+ THREE.MeshBasicMaterial.prototype.copy.call(targetMaterial, element.material);
156
+ element.material = targetMaterial;
157
+ }
158
+ });
159
+ scene.add(model);
160
+ ```
161
+
162
+ ## Compatibility
163
+
164
+ This currently doesn't work with Firefox, due to missing support for HDR and only partial WebGPU support.
165
+ One can import `WebGPU` and use also a HDR check to guard from errors:
166
+
167
+ ```
168
+ import WebGPU from 'hdr-canvas/three/WebGPU.js';
169
+ ```
170
+
171
+ Only use the provided renderer if the browser supports WebGPU and HDR:
172
+
173
+ ```
174
+ if (WebGPU.isAvailable() && checkHDRCanvas()) {
175
+ renderer = new HDRWebGPURenderer({canvas: canvas, antialias: true});
176
+ } else {
177
+ renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
178
+ }
179
+ ```
180
+
181
+ # Examples
182
+
183
+ All examples requires a Chromium based browser (like Chrome, Edge, Opera and Brave) and a HDR-enable monitor.
112
184
 
113
- See [this](https://christianmahnke.de/en/post/hdr-image-analysis/) blog post for an example in action, requires a Chromium based browser (like Chrome, Edge, Opera and Brave) and a HDR-enable monitor.
185
+ - [Contrast enhancement for UV images using HDR](https://christianmahnke.de/en/post/hdr-image-analysis/)
186
+ - [HDR IIIF](https://christianmahnke.de/en/post/hdr-iiif/)
187
+ - [Ultraviolet Photogrammetry](https://christianmahnke.de/en/post/uv-photogrammetry/)
114
188
 
115
189
  ---
116
190
 
@@ -5752,6 +5752,18 @@ Color.extend(interpolation);
5752
5752
  Color.extend(contrastMethods);
5753
5753
 
5754
5754
  class Uint16Image {
5755
+ height;
5756
+ width;
5757
+ data;
5758
+ static DEFAULT_COLORSPACE = "rec2100-hlg";
5759
+ static SDR_MULTIPLIER = 2 ** 16 - 1;
5760
+ static COLORSPACES = {
5761
+ "rec2100-hlg": "rec2100hlg",
5762
+ "display-p3": "p3",
5763
+ srgb: "sRGB",
5764
+ "rec2100-pq": "rec2100pq"
5765
+ };
5766
+ colorSpace;
5755
5767
  constructor(width, height, colorspace) {
5756
5768
  if (colorspace === undefined || colorspace === null) {
5757
5769
  this.colorSpace = Uint16Image.DEFAULT_COLORSPACE;
@@ -5793,10 +5805,12 @@ class Uint16Image {
5793
5805
  if (this.data === undefined || this.data === null) {
5794
5806
  return null;
5795
5807
  }
5796
- return new ImageData(this.data, this.width, this.height, { colorSpace: this.colorSpace });
5808
+ return new ImageData(this.data, this.width, this.height, {
5809
+ colorSpace: this.colorSpace
5810
+ });
5797
5811
  }
5798
5812
  static convertPixelToRec2100_hlg(pixel) {
5799
- const colorJScolorSpace = (Uint16Image.COLORSPACES["rec2100-hlg"]);
5813
+ const colorJScolorSpace = Uint16Image.COLORSPACES["rec2100-hlg"];
5800
5814
  const srgbColor = new Color("srgb", Array.from(pixel.slice(0, 3)).map((band) => {
5801
5815
  return band / 255;
5802
5816
  }), pixel[3] / 255);
@@ -5831,11 +5845,11 @@ class Uint16Image {
5831
5845
  const { width, height } = bitmap;
5832
5846
  const offscreen = new OffscreenCanvas(width, height);
5833
5847
  const ctx = offscreen.getContext("2d");
5834
- ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(bitmap, 0, 0);
5848
+ ctx?.drawImage(bitmap, 0, 0);
5835
5849
  return ctx;
5836
5850
  })
5837
5851
  .then((ctx) => {
5838
- return ctx === null || ctx === void 0 ? void 0 : ctx.getImageData(0, 0, ctx === null || ctx === void 0 ? void 0 : ctx.canvas.width, ctx === null || ctx === void 0 ? void 0 : ctx.canvas.height);
5852
+ return ctx?.getImageData(0, 0, ctx?.canvas.width, ctx?.canvas.height);
5839
5853
  });
5840
5854
  }
5841
5855
  static fromImageData(imageData) {
@@ -5878,22 +5892,13 @@ class Uint16Image {
5878
5892
  return i;
5879
5893
  }
5880
5894
  }
5881
- Uint16Image.DEFAULT_COLORSPACE = "rec2100-hlg";
5882
- Uint16Image.SDR_MULTIPLIER = 2 ** 16 - 1;
5883
- Uint16Image.COLORSPACES = {
5884
- "rec2100-hlg": "rec2100hlg",
5885
- "display-p3": "p3",
5886
- srgb: "sRGB",
5887
- "rec2100-pq": "rec2100pq",
5888
- };
5889
5895
 
5890
5896
  function checkHDR() {
5891
5897
  try {
5892
5898
  const bitsPerChannel = screen.colorDepth / 3;
5893
5899
  const hdrSupported = bitsPerChannel > 8;
5894
5900
  const dynamicRangeHighMQ = window.matchMedia("(dynamic-range: high)").matches;
5895
- const colorGamutMQ = window.matchMedia("(color-gamut: rec2020)").matches ||
5896
- window.matchMedia("(color-gamut: p3)").matches;
5901
+ const colorGamutMQ = window.matchMedia("(color-gamut: rec2020)").matches || window.matchMedia("(color-gamut: p3)").matches;
5897
5902
  if (colorGamutMQ && dynamicRangeHighMQ) {
5898
5903
  if (bitsPerChannel !== Math.round(bitsPerChannel)) {
5899
5904
  return false;
@@ -5919,17 +5924,17 @@ function checkHDRCanvas() {
5919
5924
  if (!canvas.getContext) {
5920
5925
  return false;
5921
5926
  }
5922
- const ctx = (canvas.getContext("2d", {
5927
+ const ctx = canvas.getContext("2d", {
5923
5928
  colorSpace: colorSpace,
5924
- pixelFormat: "float16",
5925
- }));
5929
+ pixelFormat: "float16"
5930
+ });
5926
5931
  if (ctx === null) {
5927
5932
  return false;
5928
5933
  }
5929
5934
  return true;
5930
5935
  }
5931
5936
  catch (e) {
5932
- console.error("Bad canvas ColorSpace test", e);
5937
+ console.error("Bad canvas ColorSpace test - make sure that the Chromium browser flag 'enable-experimental-web-platform-features' has been enabled");
5933
5938
  return false;
5934
5939
  }
5935
5940
  }