Skip to content

Instantly share code, notes, and snippets.

@pseudosavant
Forked from MonsieurV/createImageBitmap.js
Last active March 20, 2022 12:30
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pseudosavant/a6d970b945ae85ef4dbc43200da94faf to your computer and use it in GitHub Desktop.
Save pseudosavant/a6d970b945ae85ef4dbc43200da94faf to your computer and use it in GitHub Desktop.
createImageBitmap polyfill with support for CanvasImageSource (img, video, canvas) sources, Blobs, and ImageData. https://createimagebitmap-polyfill.glitch.me/
/*
* Polyfill for createImageBitmap
* https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
*
* Supports CanvasImageSource (img, video, canvas) sources, Blobs, and ImageData.
*
* From:
* - https://dev.to/nektro/createimagebitmap-polyfill-for-safari-and-edge-228
* - https://gist.github.com/MonsieurV/fb640c29084c171b4444184858a91bc7
* Updated by:
* - Yoan Tournade <yoan@ytotech.com>
* - diachedelic, https://gist.github.com/diachedelic
* - Paul Ellis, https://pseudosavant.com
*/
(function createImageBitmapIIFE(global){
function isCanvasImageSource(el) {
const validElements = ['img', 'video', 'canvas'];
return (el && el.tagName && validElements.includes(el.tagName.toLowerCase()));
}
function idealSize(currentValue, newValue, numerator, denominator){
if (typeof newValue === 'number') return newValue;
if (typeof numerator !== 'number' || typeof denominator !== 'number') return currentValue;
return (numerator / denominator) * currentValue;
}
if (!('createImageBitmap' in global) || test) {
global.createImageBitmap = async function polyfillCreateImageBitmap(data, opts) {
return new Promise((resolve, reject) => {
opts = opts || {};
let dataURL;
const canvas = document.createElement('canvas');
try {
const ctx = canvas.getContext('2d');
if (data instanceof Blob) {
dataURL = URL.createObjectURL(data);
} else if (isCanvasImageSource(data)) {
const width = data.naturalWidth || data.videoWidth || data.clientWidth || data.width
const height = data.naturalHeight || data.videoHeight || data.clientHeight || data.height
canvas.width = idealSize(width, opts.resizeWidth, opts.resizeHeight, height);
canvas.height = idealSize(height, opts.resizeHeight, opts.resizeWidth, width);
ctx.drawImage(data, 0, 0, canvas.width, canvas.height);
dataURL = canvas.toDataURL();
} else if (data instanceof ImageData) {
canvas.width = idealSize(data.width, opts.resizeWidth, opts.resizeHeight, data.height);;
canvas.height = idealSize(data.height, opts.resizeHeight, opts.resizeWidth, data.width);
ctx.putImageData(data,0,0);
dataURL = canvas.toDataURL();
} else {
reject('createImageBitmap does not handle the provided image source type');
}
const img = new Image();
img.onerror = reject;
img.onload = () => resolve(img);
img.src = dataURL;
} finally {
// avoid memory leaks on iOS Safari, see https://stackoverflow.com/a/52586606
canvas.width = 0;
canvas.height = 0;
}
});
};
}
})(this);
@ahmetozalp
Copy link

how do we use it exactly?

@pseudosavant
Copy link
Author

Drop this into any page inline or put it in a separate script file. You can even use a service like Statically.io to use the gist as the script file (like this link). Then try to use window.createImageBitmap as you normally would. createImageBitmap is supported by every major browser but Safari now so it is really only useful there.

@diachedelic
Copy link

diachedelic commented Aug 20, 2020

iOS Safari 12+ has a memory leak where, unless you set the width and height of a canvas to zero, it does not release the resources, fairly quickly crashing your page/webview if you are working with photos. I added that in a finally clause:

...
      const canvas = document.createElement("canvas");

      try {
        const ctx = canvas.getContext("2d");
...
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.src = dataURL;
      } finally {
        // avoid memory leaks on iOS Safari, see https://stackoverflow.com/a/52586606
        canvas.width = 0;
        canvas.height = 0;
      }

Source: openlayers/openlayers#9291

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment