import { HDRImage } from "./HDRImage";
import { isSafari } from "./browser";
import type { HDRHTMLCanvasElement, CanvasRenderingContext2DHDRSettings, CanvasRenderingContext2DHDR } from "./types/HDRCanvas.d.ts";
/**
* Gets a `CanvasRenderingContext2DSettings` object configured for HDR.
* This function detects the browser version to determine the appropriate `colorType` for HDR support.
*
* @returns {CanvasRenderingContext2DHDRSettings} An options object for creating an HDR canvas context.
*/
export function getHdrOptions(): CanvasRenderingContext2DHDRSettings {
const hdrOptions: CanvasRenderingContext2DHDRSettings = {
colorSpace: HDRImage.DEFAULT_COLORSPACE,
colorType: "float16",
toneMapping: { mode: "extended" }
};
if (isSafari()) {
hdrOptions["colorSpace"] = "display-p3";
}
return hdrOptions;
}
/**
* Initializes a given `HTMLCanvasElement` for HDR and returns its 2D rendering context.
* It first configures the canvas for high dynamic range and then gets the 2D context with HDR options.
*
* @param {HDRHTMLCanvasElement} canvas - The canvas element to initialize.
* @returns {CanvasRenderingContext2DHDR | null} The 2D rendering context, or `null` if the context cannot be created. Can be cast down to `CanvasRenderingContext2D` or `RenderingContext`
*/
export function initHDRCanvas(canvas: HDRHTMLCanvasElement): CanvasRenderingContext2DHDR | null {
const ctx = canvas.getContext("2d", getHdrOptions());
return ctx as CanvasRenderingContext2DHDR;
}
/**
* Patches the `getContext` method of `HTMLCanvasElement` to default to HDR settings.
* This allows all subsequent calls to `getContext('2d')` to be HDR-enabled without
* explicitly passing the HDR options.
*
* @remarks
* This function modifies the global `HTMLCanvasElement.prototype` and should be used with caution.
* Calling it multiple times has no additional effect. Contexts other than `2d` are passed
* through unmodified.
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
export function defaultGetContextHDR() {
const prototype = HTMLCanvasElement.prototype as HDRHTMLCanvasElement;
if (typeof prototype._getContext === "function") {
return;
}
prototype._getContext = HTMLCanvasElement.prototype.getContext;
(HTMLCanvasElement.prototype as any).getContext = function (type: string, options?: object) {
if (type === "2d") {
if (options !== undefined) {
options = Object.assign({}, options, getHdrOptions());
} else {
options = getHdrOptions();
}
}
return (this as HDRHTMLCanvasElement)._getContext(type, options);
};
}
/**
* Resets the `getContext` method of `HTMLCanvasElement` to its original behavior.
* This reverses the changes made by `defaultGetContextHDR`.
*
* @remarks
* This function only works if `defaultGetContextHDR` has been previously called.
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
export function resetGetContext() {
const prototype = HTMLCanvasElement.prototype as HDRHTMLCanvasElement;
if (typeof prototype._getContext === "function") {
HTMLCanvasElement.prototype.getContext = prototype._getContext as typeof HTMLCanvasElement.prototype.getContext;
delete (prototype as any)._getContext;
}
}
Source