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 +126 -29
- package/dist/@types/hdr-canvas.d.ts +63 -15
- package/dist/hdr-canvas.js +252 -102
- package/dist/hdr-canvas.js.map +1 -1
- package/dist/hdr-canvas.min.js +1 -1
- package/dist/hdr-canvas.min.js.map +1 -1
- package/dist/hdr-canvas.umd.js +6124 -5972
- package/dist/hdr-canvas.umd.js.map +1 -1
- package/dist/index.d.ts +63 -15
- package/docs/release-notes-0.1.0.md +47 -0
- package/package.json +51 -16
- package/patches/@typescript+dom-lib-generator+0.0.1.patch +46 -0
- package/scripts/check.sh +12 -0
- package/scripts/git-submodules.js +175 -0
- package/src/Float16Image.ts +238 -0
- package/src/HDRImage.ts +130 -0
- package/src/Uint16Image.ts +86 -68
- package/src/browser-util.ts +9 -0
- package/src/hdr-canvas.ts +52 -8
- package/src/hdr-check.ts +31 -13
- package/src/index.ts +2 -0
- package/src/types/HDRCanvas.d.ts +34 -3
- package/src/types/ImageData.d.ts +17 -0
- package/three/HDRWebGPUBackend.js +22 -0
- package/three/HDRWebGPURenderer.js +19 -0
- package/tsconfig.json +12 -6
- package/dist/hdr-canvas.d.ts +0 -4
package/src/hdr-canvas.ts
CHANGED
|
@@ -1,28 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HDRImage } from "./HDRImage";
|
|
2
|
+
import { getBrowserVersion } from "./browser-util";
|
|
2
3
|
|
|
3
|
-
import type { HDRHTMLCanvasElement } from "./types/HDRCanvas.d.ts";
|
|
4
|
+
import type { HDRHTMLCanvasElement, CanvasRenderingContext2DHDRSettings, CanvasRenderingContext2DHDR } from "./types/HDRCanvas.d.ts";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Gets a `CanvasRenderingContext2DSettings` object configured for HDR.
|
|
8
|
+
* This function detects the browser version to determine the appropriate `colorType` for HDR support.
|
|
9
|
+
*
|
|
10
|
+
* @returns {CanvasRenderingContext2DHDRSettings} An options object for creating an HDR canvas context.
|
|
11
|
+
*/
|
|
12
|
+
export function getHdrOptions(): CanvasRenderingContext2DHDRSettings {
|
|
13
|
+
const hdrOptions: CanvasRenderingContext2DHDRSettings = { colorSpace: HDRImage.DEFAULT_COLORSPACE };
|
|
14
|
+
const browserMajorVersion = getBrowserVersion();
|
|
15
|
+
if (browserMajorVersion == null) {
|
|
16
|
+
console.warn(`Unsupported / untested browser (${navigator.userAgent}) detected - using more modern defaults`);
|
|
17
|
+
hdrOptions["colorType"] = "float16";
|
|
18
|
+
} else {
|
|
19
|
+
if (browserMajorVersion < 134) {
|
|
20
|
+
console.warn("Older Chrome / chromium based browser detected, using older `pixelFormat`");
|
|
21
|
+
} else {
|
|
22
|
+
hdrOptions["pixelFormat"] = "float16";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return hdrOptions;
|
|
27
|
+
}
|
|
6
28
|
|
|
7
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Initializes a given `HTMLCanvasElement` for HDR and returns its 2D rendering context.
|
|
31
|
+
* It first configures the canvas for high dynamic range and then gets the 2D context with HDR options.
|
|
32
|
+
*
|
|
33
|
+
* @param {HDRHTMLCanvasElement} canvas - The canvas element to initialize.
|
|
34
|
+
* @returns {CanvasRenderingContext2DHDR | null} The 2D rendering context, or `null` if the context cannot be created. Can be cast down to `CanvasRenderingContext2D` or `RenderingContext`
|
|
35
|
+
*/
|
|
36
|
+
export function initHDRCanvas(canvas: HDRHTMLCanvasElement): CanvasRenderingContext2DHDR | null {
|
|
8
37
|
canvas.configureHighDynamicRange({ mode: "extended" });
|
|
9
|
-
const ctx = canvas.getContext("2d",
|
|
10
|
-
return ctx;
|
|
38
|
+
const ctx = canvas.getContext("2d", getHdrOptions());
|
|
39
|
+
return ctx as CanvasRenderingContext2DHDR;
|
|
11
40
|
}
|
|
12
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Patches the `getContext` method of `HTMLCanvasElement` to default to HDR settings.
|
|
44
|
+
* This allows all subsequent calls to `getContext('2d')` to be HDR-enabled without
|
|
45
|
+
* explicitly passing the HDR options.
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* This function modifies the global `HTMLCanvasElement.prototype` and should be used with caution.
|
|
49
|
+
*/
|
|
13
50
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
14
51
|
export function defaultGetContextHDR() {
|
|
15
52
|
(HTMLCanvasElement.prototype as HDRHTMLCanvasElement)._getContext = HTMLCanvasElement.prototype.getContext;
|
|
16
53
|
(HTMLCanvasElement.prototype as any).getContext = function (type: string, options: object) {
|
|
17
54
|
if (options !== undefined) {
|
|
18
|
-
options = Object.assign({}, options,
|
|
55
|
+
options = Object.assign({}, options, getHdrOptions());
|
|
19
56
|
} else {
|
|
20
|
-
options =
|
|
57
|
+
options = getHdrOptions();
|
|
21
58
|
}
|
|
22
59
|
return (this as HDRHTMLCanvasElement)._getContext(type, options);
|
|
23
60
|
};
|
|
24
61
|
}
|
|
25
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Resets the `getContext` method of `HTMLCanvasElement` to its original behavior.
|
|
65
|
+
* This reverses the changes made by `defaultGetContextHDR`.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* This function only works if `defaultGetContextHDR` has been previously called.
|
|
69
|
+
*/
|
|
26
70
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
27
71
|
export function resetGetContext() {
|
|
28
72
|
if (typeof (HTMLCanvasElement.prototype as HDRHTMLCanvasElement)._getContext === "function") {
|
package/src/hdr-check.ts
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
import { getHdrOptions } from "./hdr-canvas";
|
|
2
|
+
|
|
3
|
+
// See https://developer.mozilla.org/en-US/docs/Web/CSS/@media/video-dynamic-range
|
|
4
|
+
|
|
5
|
+
/** Check if HDR video is supported using a CSS Media Query.
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
export function checkHDRVideo(): boolean {
|
|
9
|
+
try {
|
|
10
|
+
const dynamicRangeVideoHighMQ: boolean = window.matchMedia("(video-dynamic-range: high)").matches;
|
|
11
|
+
if (dynamicRangeVideoHighMQ) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Check if HDR content (like images) are supported using two CSS Media Queries:
|
|
21
|
+
* One for HDR content itself and another one for the rec2020 colorspace
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
1
24
|
export function checkHDR(): boolean {
|
|
2
25
|
try {
|
|
3
26
|
const bitsPerChannel: number = screen.colorDepth / 3;
|
|
@@ -18,39 +41,34 @@ export function checkHDR(): boolean {
|
|
|
18
41
|
}
|
|
19
42
|
return false;
|
|
20
43
|
} catch (e) {
|
|
21
|
-
|
|
22
|
-
console.error("Bad window.screen test", e);
|
|
23
|
-
/* eslint-enable */
|
|
44
|
+
console.error("Exception during check for HDR", e);
|
|
24
45
|
return false;
|
|
25
46
|
}
|
|
26
47
|
}
|
|
27
48
|
|
|
49
|
+
/** Check if HDR content is supported in a {HTMLCanvasElement} by tying to get a HDR enabled {CanvasRenderingContext2D}
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
28
52
|
export function checkHDRCanvas(): boolean {
|
|
29
|
-
const colorSpace: string = "rec2100-pq";
|
|
30
|
-
|
|
31
53
|
try {
|
|
32
54
|
const canvas: HTMLCanvasElement = document.createElement("canvas");
|
|
33
55
|
if (!canvas.getContext) {
|
|
34
56
|
return false;
|
|
35
57
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
58
|
+
|
|
59
|
+
const options = getHdrOptions();
|
|
60
|
+
const ctx: CanvasRenderingContext2D | null = <CanvasRenderingContext2D>canvas.getContext("2d", options);
|
|
40
61
|
//canvas.drawingBufferColorSpace = colorSpace;
|
|
41
62
|
//canvas.unpackColorSpace = colorSpace;
|
|
42
63
|
if (ctx === null) {
|
|
43
64
|
return false;
|
|
44
65
|
}
|
|
45
66
|
return true;
|
|
46
|
-
|
|
47
|
-
} catch (e) {
|
|
48
|
-
//console.error("Bad canvas ColorSpace test", e);
|
|
67
|
+
} catch {
|
|
49
68
|
console.error(
|
|
50
69
|
"Bad canvas ColorSpace test - make sure that the Chromium browser flag 'enable-experimental-web-platform-features' has been enabled"
|
|
51
70
|
);
|
|
52
71
|
|
|
53
72
|
return false;
|
|
54
73
|
}
|
|
55
|
-
/* eslint-enable */
|
|
56
74
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { Uint16Image } from "./Uint16Image";
|
|
2
|
+
export { Float16Image } from "./Float16Image";
|
|
3
|
+
export { HDRImage } from "./HDRImage";
|
|
2
4
|
export { checkHDR, checkHDRCanvas } from "./hdr-check";
|
|
3
5
|
export { initHDRCanvas, defaultGetContextHDR, resetGetContext } from "./hdr-canvas";
|
package/src/types/HDRCanvas.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
type HDRHTMLCanvasOptionsType = "mode";
|
|
5
5
|
type HDRHTMLCanvasOptions = { [key in HDRHTMLCanvasOptionsType]?: string };
|
|
6
6
|
|
|
7
|
+
type HDRImageDataArray = ImageDataArray | Float16Array | Uint16Array;
|
|
8
|
+
|
|
7
9
|
interface HDRHTMLCanvasElement extends HTMLCanvasElement {
|
|
8
10
|
configureHighDynamicRange(options: HDRHTMLCanvasOptions): void;
|
|
9
11
|
_getContext(contextId: string, options?: object): RenderingContext | null;
|
|
@@ -11,15 +13,44 @@ interface HDRHTMLCanvasElement extends HTMLCanvasElement {
|
|
|
11
13
|
|
|
12
14
|
interface HDRImageData {
|
|
13
15
|
readonly colorSpace: PredefinedColorSpace;
|
|
14
|
-
readonly data:
|
|
16
|
+
readonly data: HDRImageDataArray | Uint16Array;
|
|
15
17
|
readonly height: number;
|
|
16
18
|
readonly width: number;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
// See https://github.com/w3c/ColorWeb-CG/blob/main/hdr_html_canvas_element.md
|
|
20
|
-
// "rec2100-display-linear" is left out
|
|
22
|
+
// "rec2100-display-linear" is left out because of mapping issues
|
|
21
23
|
type HDRPredefinedColorSpace = "display-p3" | "srgb" | "rec2100-hlg" | "rec2100-pq";
|
|
22
24
|
|
|
23
25
|
//enum HDRPredefinedColorSpace {"display-p3", "srgb", "rec2100-hlg", "rec2100-pq", "rec2100-display-linear"};
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
/**
|
|
28
|
+
* A callback function that receives the red, green, blue, and alpha values of a pixel
|
|
29
|
+
* and returns a new `Float16Array` with the modified values.
|
|
30
|
+
*
|
|
31
|
+
* @callback HDRImagePixelCallback
|
|
32
|
+
* @param {number} red - The red channel value (0-65535).
|
|
33
|
+
* @param {number} green - The green channel value (0-65535).
|
|
34
|
+
* @param {number} blue - The blue channel value (0-65535).
|
|
35
|
+
* @param {number} alpha - The alpha channel value (0-65535).
|
|
36
|
+
* @returns {ImageDataArray} A new `Float16Array` containing the four channel values.
|
|
37
|
+
*/
|
|
38
|
+
type HDRImagePixelCallback = (red: number, green: number, blue: number, alpha: number) => HDRImageDataArray;
|
|
39
|
+
|
|
40
|
+
interface CanvasRenderingContext2DHDR extends CanvasRenderingContext2D {}
|
|
41
|
+
|
|
42
|
+
interface CanvasRenderingContext2DHDRSettings {
|
|
43
|
+
colorSpace: HDRPredefinedColorSpace;
|
|
44
|
+
pixelFormat?: "uint8" | "float16";
|
|
45
|
+
colorType?: "unorm8" | "float16";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
HDRHTMLCanvasElement,
|
|
50
|
+
HDRPredefinedColorSpace,
|
|
51
|
+
HDRImageDataArray,
|
|
52
|
+
HDRImageData,
|
|
53
|
+
HDRImagePixelCallback,
|
|
54
|
+
CanvasRenderingContext2DHDR,
|
|
55
|
+
CanvasRenderingContext2DHDRSettings
|
|
56
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
var ImageDataSettings: {
|
|
5
|
+
prototype: ImageDataSettings;
|
|
6
|
+
pixelFormat?: ImageDataPixelFormat;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
var ImageData: {
|
|
10
|
+
prototype: ImageData;
|
|
11
|
+
pixelFormat: ImageDataPixelFormat;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type ImageDataArray = Uint8ClampedArray | Float16Array;
|
|
15
|
+
|
|
16
|
+
type ImageDataPixelFormat = "rgba-unorm8" | "rgba-float16";
|
|
17
|
+
}
|
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
import WebGPUBackend from 'three/src/renderers/webgpu/WebGPUBackend.js';
|
|
2
2
|
import { GPUFeatureName, GPUTextureFormat } from 'three/src/renderers/webgpu/utils/WebGPUConstants.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* An HDR-enabled WebGPU backend for three.js, extending the standard `WebGPUBackend`.
|
|
6
|
+
* This class configures the WebGPU context to support High Dynamic Range rendering
|
|
7
|
+
* by setting the output color space to "rec2100-hlg".
|
|
8
|
+
* **You should never have the need to use this!**
|
|
9
|
+
*
|
|
10
|
+
* @class
|
|
11
|
+
* @augments {WebGPUBackend}
|
|
12
|
+
*/
|
|
13
|
+
|
|
4
14
|
class HDRWebGPUBackend extends WebGPUBackend {
|
|
5
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Initializes the backend, including requesting a WebGPU device and configuring the context.
|
|
18
|
+
* This method overrides the parent `init` to set a specific HDR color space.
|
|
19
|
+
*
|
|
20
|
+
* @param {WebGLRenderer} renderer - The three.js renderer instance.
|
|
21
|
+
* @returns {Promise<void>} A promise that resolves when the initialization is complete.
|
|
22
|
+
*/
|
|
6
23
|
// See https://github.com/mrdoob/three.js/blob/master/examples/jsm/renderers/webgpu/WebGPUBackend.js#L123
|
|
7
24
|
async init( renderer ) {
|
|
8
25
|
|
|
@@ -67,6 +84,11 @@ class HDRWebGPUBackend extends WebGPUBackend {
|
|
|
67
84
|
const alphaMode = parameters.alpha ? 'premultiplied' : 'opaque';
|
|
68
85
|
|
|
69
86
|
// See https://github.com/ccameron-chromium/webgpu-hdr/blob/main/EXPLAINER.md#example-use
|
|
87
|
+
/**
|
|
88
|
+
* Configures the WebGPU context with HDR settings.
|
|
89
|
+
* The `colorSpace` is set to `rec2100-hlg` for High Dynamic Range support.
|
|
90
|
+
* @see {@link https://github.com/ccameron-chromium/webgpu-hdr/blob/main/EXPLAINER.md#example-use | WebGPU HDR Explainer}
|
|
91
|
+
*/
|
|
70
92
|
this.context.configure( {
|
|
71
93
|
device: this.device,
|
|
72
94
|
format: GPUTextureFormat.BGRA8Unorm,
|
|
@@ -4,7 +4,22 @@ import Renderer from 'three/src/renderers/common/Renderer.js';
|
|
|
4
4
|
import WebGLBackend from 'three/src/renderers/webgl-fallback/WebGLBackend.js';
|
|
5
5
|
import HDRWebGPUBackend from './HDRWebGPUBackend.js';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* HDR enabled WebGPURenderer.
|
|
9
|
+
*
|
|
10
|
+
* @class
|
|
11
|
+
* @augments {Renderer}
|
|
12
|
+
* @fires contextrestored
|
|
13
|
+
* @fires contextlost
|
|
14
|
+
* @see {@link https://threejs.org/docs/#api/en/renderers/WebGLRenderer | WebGLRenderer}
|
|
15
|
+
*/
|
|
7
16
|
class HDRWebGPURenderer extends Renderer {
|
|
17
|
+
/**
|
|
18
|
+
* Creates an instance of HDRWebGPURenderer.
|
|
19
|
+
*
|
|
20
|
+
* @constructor
|
|
21
|
+
* @param {object} [parameters={}] - The parameters for the renderer.
|
|
22
|
+
*/
|
|
8
23
|
constructor( parameters = {} ) {
|
|
9
24
|
|
|
10
25
|
let BackendClass;
|
|
@@ -31,6 +46,10 @@ class HDRWebGPURenderer extends Renderer {
|
|
|
31
46
|
|
|
32
47
|
super( backend, parameters );
|
|
33
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @type {boolean}
|
|
51
|
+
* @default true
|
|
52
|
+
*/
|
|
34
53
|
this.isWebGPURenderer = true;
|
|
35
54
|
|
|
36
55
|
}
|
package/tsconfig.json
CHANGED
|
@@ -5,21 +5,27 @@
|
|
|
5
5
|
"removeComments": true,
|
|
6
6
|
"preserveConstEnums": true,
|
|
7
7
|
"sourceMap": true,
|
|
8
|
-
"moduleResolution": "
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
9
|
"noEmit": false,
|
|
10
10
|
"noEmitOnError": true,
|
|
11
11
|
"esModuleInterop": true,
|
|
12
12
|
"strict": true,
|
|
13
13
|
"strictNullChecks": true,
|
|
14
|
+
"strictPropertyInitialization": false,
|
|
14
15
|
"declaration": true,
|
|
15
|
-
"allowJs":
|
|
16
|
-
"skipLibCheck":
|
|
17
|
-
"target": "
|
|
16
|
+
"allowJs": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"target": "es2024",
|
|
18
19
|
"outDir": "dist",
|
|
19
20
|
"declarationDir": "dist",
|
|
20
21
|
"typeRoots": ["./node_modules/@types"],
|
|
21
|
-
"lib": ["
|
|
22
|
+
"lib": ["es2024"],
|
|
23
|
+
"paths": {
|
|
24
|
+
"~/hdr-canvas/three/*": ["./three/*"],
|
|
25
|
+
"~/hdr-canvas/*": ["./src/*"],
|
|
26
|
+
"three": ["./node_modules/@types/three"]
|
|
27
|
+
}
|
|
22
28
|
},
|
|
23
|
-
"include": ["src/**/*"],
|
|
29
|
+
"include": ["src/**/*", "tests/site/**/*", "tests/*"],
|
|
24
30
|
"exclude": ["node_modules", "**/*.spec.ts", "three/**/*"]
|
|
25
31
|
}
|
package/dist/hdr-canvas.d.ts
DELETED