function imageDataFromCanvas(image : CanvasImageSource, width : number, height : number) : ImageData { const canvas = document.createElement("canvas"); const canvasCtx = canvas.getContext("2d"); canvas.width = width; canvas.height = height; canvasCtx.drawImage(image, 0, 0, width, height); return canvasCtx.getImageData(0, 0, width, height); } async function imageDataFromBlob(blob : Blob) : Promise { // turn blob into an img element and pass back to imageDataFrom const url = URL.createObjectURL(blob) const image = new Image() image.src = url await new Promise((resolve, reject) => { image.onload = resolve image.onerror = reject }) URL.revokeObjectURL(url) return imageDataFrom(image) } export async function imageDataFrom(image : ImageBitmapSource) : Promise { // spec quoted from: // https://wicg.github.io/shape-detection-api/#image-sources-for-detection // [TODO] // If any ImageBitmapSource have an effective script origin (origin) which is // not the same as the Document’s effective script origin, then reject the // Promise with a new DOMException whose name is SecurityError. if (image instanceof HTMLImageElement) { // [TODO] // When an ImageBitmapSource object represents an HTMLImageElement, the // element’s image must be used as the source image. Specifically, when an // ImageBitmapSource object represents an animated image in an // HTMLImageElement, the user agent must use the default image of the // animation (the one that the format defines is to be used when animation // is not supported or is disabled), or, if there is no such image, the // first frame of the animation. // [SPEC] // If the ImageBitmapSource is an HTMLImageElement object that is in the // Broken (HTML Standard §img-error) state, then reject the Promise with a // new DOMException whose name is InvalidStateError, and abort any further // steps. // [SPEC] // If the ImageBitmapSource is an HTMLImageElement object that is not fully // decodable then reject the Promise with a new DOMException whose name is // InvalidStateError, and abort any further steps try { image.decode() } catch (_) { throw new DOMException("HTMLImageElement is not decodable", "InvalidStateError") } return imageDataFromCanvas(image, image.naturalWidth, image.naturalHeight) } else if (image instanceof SVGImageElement) { // TODO width/height is a little bit arbitrary return imageDataFromCanvas(image, 640, 480) } else if (image instanceof HTMLVideoElement) { // [SPEC] // If the ImageBitmapSource is an HTMLVideoElement object whose readyState // attribute is either HAVE_NOTHING or HAVE_METADATA then reject the Promise // with a new DOMException whose name is InvalidStateError, and abort any // further steps. const HAVE_NOTHING = 0, HAVE_METADATA = 1; if (image.readyState === HAVE_NOTHING || image.readyState === HAVE_METADATA) { throw new DOMException("", "InvalidStateError") } // [SPEC] // When an ImageBitmapSource object represents an HTMLVideoElement, then // the frame at the current playback position when the method with the // argument is invoked must be used as the source image when processing the // image, and the source image’s dimensions must be the intrinsic dimensions // of the media resource (i.e. after any aspect-ratio correction has been applied). return imageDataFromCanvas(image, image.videoWidth, image.videoHeight) } else if (image instanceof HTMLCanvasElement) { // [TODO] // When an ImageBitmapSource object represents an HTMLCanvasElement, the // element’s bitmap must be used as the source image. // [TODO] // If the ImageBitmapSource argument is an HTMLCanvasElement whose bitmap’s // origin-clean (HTML Standard §concept-canvas-origin-clean) flag is false, // then reject the Promise with a new DOMException whose name is // SecurityError, and abort any further steps. const canvasCtx = image.getContext("2d") return canvasCtx.getImageData(0, 0, image.width, image.height) } else if (image instanceof ImageBitmap) { return imageDataFromCanvas(image, image.width, image.height) } else if (image instanceof OffscreenCanvas) { const canvasCtx = image.getContext("2d") return canvasCtx.getImageData(0, 0, image.width, image.height) } else if (image instanceof Blob) { return imageDataFromBlob(image) } else if (image instanceof ImageData) { return image } else { // TODO TypeError? } }