UNPKG

threepipe

Version:

A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.

96 lines 4.89 kB
import { now } from 'ts-browser-helpers'; export class CanvasSnapshot { static async GetClonedCanvas(canvas, { rect = { x: 0, y: 0, width: canvas.width, height: canvas.height, assumeClientRect: false }, displayPixelRatio = 1, scale = 1, }) { // return canvas.toDataURL(mimeType); // in Safari, images are flipped when premultipliedAlpha is true in canvas, so it works with 2d context, see: https://github.com/pixijs/pixi.js/blob/dev/packages/extract/src/Extract.ts and https://github.com/pixijs/pixi.js/issues/2951 const destCanvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas'); destCanvas.width = rect.width * scale * displayPixelRatio; destCanvas.height = rect.height * scale * displayPixelRatio; // const iRect = {...rect} if (rect.assumeClientRect) { rect.x *= canvas.width / (displayPixelRatio * canvas.clientWidth); rect.y *= canvas.height / (displayPixelRatio * canvas.clientHeight); rect.width *= canvas.width / (displayPixelRatio * canvas.clientWidth); rect.height *= canvas.height / (displayPixelRatio * canvas.clientHeight); } const destCtx = destCanvas.getContext('2d'); if (!destCtx) { console.error('snapshot: cannot create context'); return destCanvas; } // console.log(canvas.style.background) const background = canvas.style.background || canvas.parentElement?.style.background || ''; if (background.includes('url')) { const url = /url\("(.*)"\)/ig.exec(background)?.[1]; if (url) { const img = new Image(); img.src = url; await new Promise((resolve, reject) => { img.onload = () => resolve(); img.onerror = () => reject(); if (img.complete) resolve(); }); destCtx.drawImage(img, img.width * rect.x * displayPixelRatio / canvas.width, img.height * rect.y * displayPixelRatio / canvas.height, img.width * rect.width * displayPixelRatio / canvas.width, img.height * rect.height * displayPixelRatio / canvas.height, 0, 0, destCanvas.width, destCanvas.height); } } else { destCtx.fillStyle = canvas.style.background || canvas.parentElement?.style.backgroundColor || '#00000000'; destCtx.fillRect(0, 0, destCanvas.width, destCanvas.height); } destCtx?.drawImage(canvas, rect.x * displayPixelRatio, rect.y * displayPixelRatio, rect.width * displayPixelRatio, rect.height * displayPixelRatio, 0, 0, destCanvas.width, destCanvas.height); const debug = this.Debug; if (debug) { // console.log( // destCanvas, // ) document.body.appendChild(destCanvas); destCanvas.style.position = 'absolute'; destCanvas.style.top = '0'; destCanvas.style.left = '0'; destCanvas.style.borderWidth = '2px'; destCanvas.style.borderColor = '#ff00ff'; setTimeout(() => destCanvas.remove(), 5000); } return destCanvas; } static async GetDataUrl(canvas, { mimeType = 'image/png', quality, ...options }) { const clone = options.cloneCanvas === false ? canvas : await this.GetClonedCanvas(canvas, options); const url = clone.toDataURL(mimeType, quality); if (!this.Debug && clone !== canvas) clone.remove(); return url; } // set one of canvas or context to draw in. static async GetImage(canvas, options = {}) { const imgUrl = await this.GetDataUrl(canvas, options); return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = () => reject(); img.src = imgUrl; }); } static async GetBlob(canvas, options = {}) { const clone = options.cloneCanvas === false ? canvas : await this.GetClonedCanvas(canvas, options); const blob = await new Promise((resolve, reject) => { clone.toBlob((b) => { if (b) resolve(b); else reject(); }, options.mimeType ?? 'image/png', options.quality); }); if (!this.Debug && clone !== canvas) clone.remove(); return blob; } static async GetFile(canvas, filename = 'image.png', options = {}) { return options.getDataUrl ? await this.GetDataUrl(canvas, options) : new File([await this.GetBlob(canvas, options)], filename, { type: options.mimeType ?? 'image/png', lastModified: now(), }); } } CanvasSnapshot.Debug = false; //# sourceMappingURL=canvas-snapshot.js.map