UNPKG

threepipe

Version:

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

128 lines (116 loc) 5.46 kB
import {serialize, timeout} from 'ts-browser-helpers' import {AViewerPluginSync} from '../../viewer' import {uiButton, uiConfig, uiFolderContainer, uiInput} from 'uiconfig.js' import {CanvasSnapshot, CanvasSnapshotOptions} from '../../utils/canvas-snapshot' import {ProgressivePlugin} from '../pipeline/ProgressivePlugin' @uiFolderContainer('Canvas Snapshot (Image Export)') export class CanvasSnapshotPlugin extends AViewerPluginSync<''> { static readonly PluginType = 'CanvasSnapshotPlugin' enabled = true constructor() { super() this.downloadSnapshot = this.downloadSnapshot.bind(this) } /** * Returns a File object with screenshot of the viewer canvas * @param filename default is {@link CanvasSnapshotPlugin.filename} * @param options waitForProgressive: wait for progressive rendering to finish, default: true */ async getFile(filename?: string, options: CanvasSnapshotOptions&{waitForProgressive?: boolean} = {waitForProgressive: true}): Promise<File|undefined> { options.getDataUrl = false return await this._getFile(filename || this.filename, options) as File } /** * Returns a data url of the screenshot of the viewer canvas * @param options waitForProgressive: wait for progressive rendering to finish, default: true */ async getDataUrl(options: CanvasSnapshotOptions&{waitForProgressive?: boolean} = {}): Promise<string> { options.getDataUrl = true return await this._getFile('', options) as string ?? '' } private async _getFile(filename: string, options: CanvasSnapshotOptions&{waitForProgressive?: boolean} = {}): Promise<File|string|undefined> { const viewer = this._viewer const canvas = this._viewer?.canvas if (!viewer || !canvas) return undefined const dpr = viewer.renderManager.renderScale if (options.displayPixelRatio !== undefined && options.displayPixelRatio !== dpr) { viewer.renderManager.renderScale = options.displayPixelRatio } if (options.timeout) await timeout(options.timeout) const progressive = viewer.getPlugin(ProgressivePlugin) if (options.waitForProgressive !== false && progressive) { // todo: disable interactions and all so that frameCount is not affected await new Promise<void>((res)=>{ const listener = () => { if (!progressive.isConverged(true)) return viewer.removeEventListener('postFrame', listener) res() } viewer.addEventListener('postFrame', listener) }) } else await viewer.doOnce('postFrame') options.displayPixelRatio = 1 const rect = options.rect if (rect && viewer.renderManager.renderScale !== 1) { options.rect = { ...rect, x: rect.x * viewer.renderManager.renderScale, y: rect.y * viewer.renderManager.renderScale, width: rect.width * viewer.renderManager.renderScale, height: rect.height * viewer.renderManager.renderScale, } } const file = await CanvasSnapshot.GetFile(canvas, filename, options) options.rect = rect options.displayPixelRatio = viewer.renderManager.renderScale viewer.renderManager.renderScale = dpr return file } @uiInput('Filename') @serialize() filename = 'snapshot.png' /** * Only for {@link downloadSnapshot} and functions using that */ @uiConfig() @serialize() defaultOptions: CanvasSnapshotOptions&{waitForProgressive?: boolean} = { waitForProgressive: true, displayPixelRatio: window.devicePixelRatio, scale: 1, timeout: 0, quality: 0.9, } // @uiButton('Download .png', {sendArgs: false}) async downloadSnapshot(filename?: string, options: CanvasSnapshotOptions&{waitForProgressive?: boolean} = {waitForProgressive: true}): Promise<void> { if (!this._viewer) return if (!options.mimeType && !filename) this.filename = this.filename.split('.').slice(0, -1).join('.') + '.png' const file = await this.getFile(filename, {...this.defaultOptions, ...options}) if (file) await this._viewer.exportBlob(file, file.name) } @uiButton('Download .png') protected async _downloadPng(): Promise<void> { this.filename = this.filename.split('.').slice(0, -1).join('.') + '.png' return this.downloadSnapshot(undefined, {mimeType: 'image/png'}) } @uiButton('Download .jpeg') protected async _downloadJpeg(): Promise<void> { this.filename = this.filename.split('.').slice(0, -1).join('.') + '.jpeg' return this.downloadSnapshot(undefined, {mimeType: 'image/jpeg'}) } @uiButton('Download .webp') protected async _downloadWebp(): Promise<void> { this.filename = this.filename.split('.').slice(0, -1).join('.') + '.webp' return this.downloadSnapshot(undefined, {mimeType: 'image/webp'}) } } /** * @deprecated - use {@link CanvasSnapshotPlugin} */ export class CanvasSnipperPlugin extends CanvasSnapshotPlugin { static readonly PluginType: any = 'CanvasSnipper' constructor() { super() console.warn('CanvasSnipperPlugin is deprecated, use CanvasSnapshotPlugin') } }