threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
220 lines • 9.62 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var CanvasSnapshotPlugin_1;
import { serialize, timeout } from 'ts-browser-helpers';
import { AViewerPluginSync } from '../../viewer';
import { uiButton, uiConfig, uiFolderContainer, uiInput } from 'uiconfig.js';
import { CanvasSnapshot } from '../../utils/canvas-snapshot';
import { ProgressivePlugin } from '../pipeline/ProgressivePlugin';
import { zipSync } from 'three/examples/jsm/libs/fflate.module.js';
let CanvasSnapshotPlugin = CanvasSnapshotPlugin_1 = class CanvasSnapshotPlugin extends AViewerPluginSync {
constructor() {
super();
this.enabled = true;
this.filename = 'snapshot';
// @uiInput('Frame Count')
// @serialize()
// progressiveFrames = 64
//
// @uiInput('Tile Rows')
// @serialize()
// tileRows = 1
//
// @uiInput('Tile Columns')
// @serialize()
// tileColumns = 1
//
// @uiVector('Crop Rect (x, y, w, h)', [0, 1], 0.001)
// @serialize()
// rect = new Vector4(0, 0, 1, 1)
this._downloading = false;
/**
* Only for {@link downloadSnapshot} and functions using that
*/
this.defaultOptions = {
waitForProgressive: true,
displayPixelRatio: window.devicePixelRatio,
scale: 1,
timeout: 0,
quality: 0.9,
tileRows: 1,
tileColumns: 1,
progressiveFrames: 64,
rect: {
x: 0,
y: 0,
width: 1,
height: 1,
normalized: true,
assumeClientRect: false,
},
};
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, options = { waitForProgressive: true }) {
return await this._getFile(filename || this.filename, { ...options, getDataUrl: false });
}
/**
* 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 = {}) {
return await this._getFile('', { ...options, getDataUrl: true }) ?? '';
}
async _getFile(filename, options = {}) {
await this._viewer?.doOnce('postFrame');
const viewer = this._viewer;
const canvas = this._viewer?.canvas;
if (!viewer || !canvas)
return undefined;
viewer.scene.mainCamera.setInteractions(false, CanvasSnapshotPlugin_1.PluginType);
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);
let waitForProgressive = options.waitForProgressive ?? !!progressive;
if (waitForProgressive && !progressive) {
viewer.console.warn('CanvasSnapshotPlugin: ProgressivePlugin required to wait for progressive rendering');
waitForProgressive = false;
}
if (options.progressiveFrames && !waitForProgressive) {
viewer.console.warn('CanvasSnapshotPlugin: waitForProgressive must be true to use progressiveFrames');
}
const lastMaxFrames = progressive?.maxFrameCount;
if (waitForProgressive && progressive) {
progressive.maxFrameCount = Math.max(options.progressiveFrames ?? 64, progressive.maxFrameCount);
viewer.setDirty();
await viewer.doOnce('postFrame');
while (!progressive.isConverged(true)) {
await viewer.doOnce('postFrame');
// console.log(`rendering ${ 100 * this._viewer!.renderer.frameCount / progressive.maxFrameCount }%`)
}
}
else {
viewer.setDirty();
await viewer.doOnce('postFrame');
}
delete options.displayPixelRatio;
// 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,
// }
// }
let file;
if (options.tileRows && options.tileRows > 1 || options.tileColumns && options.tileColumns > 1) {
const res = await CanvasSnapshot.GetTiledFiles(canvas, filename, Math.max(1, options.tileRows || 1), Math.max(1, options.tileColumns || 1), options);
if (Array.isArray(res)) {
if (res.length === 1)
file = res[0];
else if (res.length === 0)
file = undefined;
else if (!options.getDataUrl) {
const zippa = {};
for (const f of res) {
zippa[f.name] = new Uint8Array(await f.arrayBuffer());
}
const zipped = zipSync(zippa);
file = new File([zipped], filename + '.zip', { type: 'application/zip', lastModified: Date.now() });
}
else {
file = res;
}
}
else {
file = res;
}
}
else {
file = await CanvasSnapshot.GetFile(canvas, filename, options);
}
// const file = await CanvasSnapshot.GetFile(canvas, filename, options)
// options.rect = rect
options.displayPixelRatio = viewer.renderManager.renderScale;
if (progressive && lastMaxFrames !== undefined) {
progressive.maxFrameCount = lastMaxFrames;
}
viewer.scene.mainCamera.setInteractions(true, CanvasSnapshotPlugin_1.PluginType, false);
viewer.renderManager.renderScale = dpr;
return file;
}
// @uiButton('Download .png', {sendArgs: false})
async downloadSnapshot(filename, options = { waitForProgressive: true }) {
if (!this._viewer)
return;
while (this._downloading) {
console.warn('CanvasSnipperPlugin: Another rendering already in progress, waiting...');
await timeout(100);
}
this._downloading = true;
// if (!options.mimeType && !filename) this.filename = this.filename.split('.').slice(0, -1).join('.') + '.png'
const file = await this.getFile(filename, { ...this.defaultOptions, ...options }).catch(e => {
this._viewer?.console.error('CanvasSnapshotPlugin: Error exporting file', e);
return null;
});
if (file)
await this._viewer.exportBlob(file, file.name);
this._downloading = false;
}
async _downloadPng() {
// this.filename = this.filename.split('.').slice(0, -1).join('.') + '.png'
return this.downloadSnapshot(undefined, { mimeType: 'image/png' });
}
async _downloadJpeg() {
// this.filename = this.filename.split('.').slice(0, -1).join('.') + '.jpeg'
return this.downloadSnapshot(undefined, { mimeType: 'image/jpeg' });
}
async _downloadWebp() {
// this.filename = this.filename.split('.').slice(0, -1).join('.') + '.webp'
return this.downloadSnapshot(undefined, { mimeType: 'image/webp' });
}
};
CanvasSnapshotPlugin.PluginType = 'CanvasSnapshotPlugin';
__decorate([
uiInput('Filename'),
serialize()
], CanvasSnapshotPlugin.prototype, "filename", void 0);
__decorate([
uiConfig(undefined, { label: 'Options' }),
serialize()
], CanvasSnapshotPlugin.prototype, "defaultOptions", void 0);
__decorate([
uiButton('Download .png')
], CanvasSnapshotPlugin.prototype, "_downloadPng", null);
__decorate([
uiButton('Download .jpeg')
], CanvasSnapshotPlugin.prototype, "_downloadJpeg", null);
__decorate([
uiButton('Download .webp')
], CanvasSnapshotPlugin.prototype, "_downloadWebp", null);
CanvasSnapshotPlugin = CanvasSnapshotPlugin_1 = __decorate([
uiFolderContainer('Image Export (Canvas Snapshot)')
], CanvasSnapshotPlugin);
export { CanvasSnapshotPlugin };
/**
* @deprecated - use {@link CanvasSnapshotPlugin}
*/
export class CanvasSnipperPlugin extends CanvasSnapshotPlugin {
constructor() {
super();
console.warn('CanvasSnipperPlugin is deprecated, use CanvasSnapshotPlugin');
}
}
CanvasSnipperPlugin.PluginType = 'CanvasSnipper';
//# sourceMappingURL=CanvasSnapshotPlugin.js.map