123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- import { Nullable } from "../types";
- import { Camera } from "../Cameras/camera";
- import { Texture } from "../Materials/Textures/texture";
- import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
- import { FxaaPostProcess } from "../PostProcesses/fxaaPostProcess";
- import { Constants } from "../Engines/constants";
- import { Logger } from "./logger";
- import { _TypeStore } from "./typeStore";
- import { Tools } from "./tools";
- import { IScreenshotSize } from './interfaces/screenshotSize';
- declare type Engine = import("../Engines/engine").Engine;
- /**
- * Class containing a set of static utilities functions for screenshots
- */
- export class ScreenshotTools {
- /**
- * Captures a screenshot of the current rendering
- * @see https://doc.babylonjs.com/how_to/render_scene_on_a_png
- * @param engine defines the rendering engine
- * @param camera defines the source camera
- * @param size This parameter can be set to a single number or to an object with the
- * following (optional) properties: precision, width, height. If a single number is passed,
- * it will be used for both width and height. If an object is passed, the screenshot size
- * will be derived from the parameters. The precision property is a multiplier allowing
- * rendering at a higher or lower resolution
- * @param successCallback defines the callback receives a single parameter which contains the
- * screenshot as a string of base64-encoded characters. This string can be assigned to the
- * src parameter of an <img> to display it
- * @param mimeType defines the MIME type of the screenshot image (default: image/png).
- * Check your browser for supported MIME types
- */
- public static CreateScreenshot(engine: Engine, camera: Camera, size: IScreenshotSize | number, successCallback?: (data: string) => void, mimeType: string = "image/png"): void {
- const { height, width } = ScreenshotTools._getScreenshotSize(engine, camera, size);
- if (!(height && width)) {
- Logger.Error("Invalid 'size' parameter !");
- return;
- }
- if (!Tools._ScreenshotCanvas) {
- Tools._ScreenshotCanvas = document.createElement('canvas');
- }
- Tools._ScreenshotCanvas.width = width;
- Tools._ScreenshotCanvas.height = height;
- var renderContext = Tools._ScreenshotCanvas.getContext("2d");
- var ratio = engine.getRenderWidth() / engine.getRenderHeight();
- var newWidth = width;
- var newHeight = newWidth / ratio;
- if (newHeight > height) {
- newHeight = height;
- newWidth = newHeight * ratio;
- }
- var offsetX = Math.max(0, width - newWidth) / 2;
- var offsetY = Math.max(0, height - newHeight) / 2;
- engine.onEndFrameObservable.addOnce(() => {
- var renderingCanvas = engine.getRenderingCanvas();
- if (renderContext && renderingCanvas) {
- renderContext.drawImage(renderingCanvas, offsetX, offsetY, newWidth, newHeight);
- }
- Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
- });
- }
- /**
- * Captures a screenshot of the current rendering
- * @see https://doc.babylonjs.com/how_to/render_scene_on_a_png
- * @param engine defines the rendering engine
- * @param camera defines the source camera
- * @param size This parameter can be set to a single number or to an object with the
- * following (optional) properties: precision, width, height. If a single number is passed,
- * it will be used for both width and height. If an object is passed, the screenshot size
- * will be derived from the parameters. The precision property is a multiplier allowing
- * rendering at a higher or lower resolution
- * @param mimeType defines the MIME type of the screenshot image (default: image/png).
- * Check your browser for supported MIME types
- * @returns screenshot as a string of base64-encoded characters. This string can be assigned
- * to the src parameter of an <img> to display it
- */
- public static CreateScreenshotAsync(engine: Engine, camera: Camera, size: any, mimeType: string = "image/png"): Promise<string> {
- return new Promise((resolve, reject) => {
- ScreenshotTools.CreateScreenshot(engine, camera, size, (data) => {
- if (typeof(data) !== "undefined") {
- resolve(data);
- } else {
- reject(new Error("Data is undefined"));
- }
- }, mimeType);
- });
- }
- /**
- * Generates an image screenshot from the specified camera.
- * @see https://doc.babylonjs.com/how_to/render_scene_on_a_png
- * @param engine The engine to use for rendering
- * @param camera The camera to use for rendering
- * @param size This parameter can be set to a single number or to an object with the
- * following (optional) properties: precision, width, height. If a single number is passed,
- * it will be used for both width and height. If an object is passed, the screenshot size
- * will be derived from the parameters. The precision property is a multiplier allowing
- * rendering at a higher or lower resolution
- * @param successCallback The callback receives a single parameter which contains the
- * screenshot as a string of base64-encoded characters. This string can be assigned to the
- * src parameter of an <img> to display it
- * @param mimeType The MIME type of the screenshot image (default: image/png).
- * Check your browser for supported MIME types
- * @param samples Texture samples (default: 1)
- * @param antialiasing Whether antialiasing should be turned on or not (default: false)
- * @param fileName A name for for the downloaded file.
- * @param renderSprites Whether the sprites should be rendered or not (default: false)
- * @param enableStencilBuffer Whether the stencil buffer should be enabled or not (default: false)
- */
- public static CreateScreenshotUsingRenderTarget(engine: Engine, camera: Camera, size: IScreenshotSize | number, successCallback?: (data: string) => void, mimeType: string = "image/png", samples: number = 1, antialiasing: boolean = false, fileName?: string, renderSprites: boolean = false, enableStencilBuffer: boolean = false): void {
- const { height, width } = ScreenshotTools._getScreenshotSize(engine, camera, size);
- let targetTextureSize = { width, height };
- if (!(height && width)) {
- Logger.Error("Invalid 'size' parameter !");
- return;
- }
- var scene = camera.getScene();
- var previousCamera: Nullable<Camera> = null;
- if (scene.activeCamera !== camera) {
- previousCamera = scene.activeCamera;
- scene.activeCamera = camera;
- }
- // At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
- var texture = new RenderTargetTexture("screenShot", targetTextureSize, scene, false, false, Constants.TEXTURETYPE_UNSIGNED_INT, false, Texture.NEAREST_SAMPLINGMODE, undefined, enableStencilBuffer, undefined, undefined, undefined, samples);
- texture.renderList = null;
- texture.samples = samples;
- texture.renderSprites = renderSprites;
- engine.onEndFrameObservable.addOnce(() => {
- texture.readPixels()!.then((data) => {
- Tools.DumpData(width, height, data, successCallback, mimeType, fileName, true);
- texture.dispose();
- if (previousCamera) {
- scene.activeCamera = previousCamera;
- }
- camera.getProjectionMatrix(true); // Force cache refresh;
- });
- });
- const renderToTexture = () => {
- scene.incrementRenderId();
- scene.resetCachedMaterial();
- texture.render(true);
- };
- if (antialiasing) {
- const fxaaPostProcess = new FxaaPostProcess('antialiasing', 1.0, scene.activeCamera);
- texture.addPostProcess(fxaaPostProcess);
- // Async Shader Compilation can lead to none ready effects in synchronous code
- if (!fxaaPostProcess.getEffect().isReady()) {
- fxaaPostProcess.getEffect().onCompiled = () => {
- renderToTexture();
- };
- }
- // The effect is ready we can render
- else {
- renderToTexture();
- }
- }
- else {
- // No need to wait for extra resources to be ready
- renderToTexture();
- }
- }
- /**
- * Generates an image screenshot from the specified camera.
- * @see https://doc.babylonjs.com/how_to/render_scene_on_a_png
- * @param engine The engine to use for rendering
- * @param camera The camera to use for rendering
- * @param size This parameter can be set to a single number or to an object with the
- * following (optional) properties: precision, width, height. If a single number is passed,
- * it will be used for both width and height. If an object is passed, the screenshot size
- * will be derived from the parameters. The precision property is a multiplier allowing
- * rendering at a higher or lower resolution
- * @param mimeType The MIME type of the screenshot image (default: image/png).
- * Check your browser for supported MIME types
- * @param samples Texture samples (default: 1)
- * @param antialiasing Whether antialiasing should be turned on or not (default: false)
- * @param fileName A name for for the downloaded file.
- * @param renderSprites Whether the sprites should be rendered or not (default: false)
- * @returns screenshot as a string of base64-encoded characters. This string can be assigned
- * to the src parameter of an <img> to display it
- */
- public static CreateScreenshotUsingRenderTargetAsync(engine: Engine, camera: Camera, size: any, mimeType: string = "image/png", samples: number = 1, antialiasing: boolean = false, fileName?: string, renderSprites: boolean = false): Promise<string> {
- return new Promise((resolve, reject) => {
- ScreenshotTools.CreateScreenshotUsingRenderTarget(engine, camera, size, (data) => {
- if (typeof(data) !== "undefined") {
- resolve(data);
- } else {
- reject(new Error("Data is undefined"));
- }
- }, mimeType, samples, antialiasing, fileName, renderSprites);
- });
- }
- /**
- * Gets height and width for screenshot size
- * @private
- */
- private static _getScreenshotSize(engine: Engine, camera: Camera, size: IScreenshotSize | number): {height: number, width: number} {
- let height = 0;
- let width = 0;
- //If a size value defined as object
- if (typeof(size) === 'object') {
- const precision = size.precision
- ? Math.abs(size.precision) // prevent GL_INVALID_VALUE : glViewport: negative width/height
- : 1;
- //If a width and height values is specified
- if (size.width && size.height) {
- height = size.height * precision;
- width = size.width * precision;
- }
- //If passing only width, computing height to keep display canvas ratio.
- else if (size.width && !size.height) {
- width = size.width * precision;
- height = Math.round(width / engine.getAspectRatio(camera));
- }
- //If passing only height, computing width to keep display canvas ratio.
- else if (size.height && !size.width) {
- height = size.height * precision;
- width = Math.round(height * engine.getAspectRatio(camera));
- }
- else {
- width = Math.round(engine.getRenderWidth() * precision);
- height = Math.round(width / engine.getAspectRatio(camera));
- }
- }
- //Assuming here that "size" parameter is a number
- else if (!isNaN(size)) {
- height = size;
- width = size;
- }
- // When creating the image data from the CanvasRenderingContext2D, the width and height is clamped to the size of the _gl context
- // On certain GPUs, it seems as if the _gl context truncates to an integer automatically. Therefore, if a user tries to pass the width of their canvas element
- // and it happens to be a float (1000.5 x 600.5 px), the engine.readPixels will return a different size array than context.createImageData
- // to resolve this, we truncate the floats here to ensure the same size
- if (width) {
- width = Math.floor(width);
- }
- if (height) {
- height = Math.floor(height);
- }
- return { height: height | 0, width: width | 0 };
- }
- }
- Tools.CreateScreenshot = ScreenshotTools.CreateScreenshot;
- Tools.CreateScreenshotAsync = ScreenshotTools.CreateScreenshotAsync;
- Tools.CreateScreenshotUsingRenderTarget = ScreenshotTools.CreateScreenshotUsingRenderTarget;
- Tools.CreateScreenshotUsingRenderTargetAsync = ScreenshotTools.CreateScreenshotUsingRenderTargetAsync;
|