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
JavaScript
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