screenshotTools.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import { Nullable } from "../types";
  2. import { Camera } from "../Cameras/camera";
  3. import { Texture } from "../Materials/Textures/texture";
  4. import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
  5. import { FxaaPostProcess } from "../PostProcesses/fxaaPostProcess";
  6. import { Constants } from "../Engines/constants";
  7. import { Logger } from "./logger";
  8. import { _TypeStore } from "./typeStore";
  9. import { Tools } from "./tools";
  10. declare type Engine = import("../Engines/engine").Engine;
  11. /**
  12. * This interface describe parameter that can be set to an object
  13. *
  14. * 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
  15. */
  16. export interface IScreenshotSize {
  17. /**
  18. * number in pixels for canvas height
  19. */
  20. height?: number;
  21. /**
  22. * multiplier allowing render at a higher or lower resolution
  23. * If value is defined then height and width will be ignored and taken from camera
  24. */
  25. precision?: number;
  26. /**
  27. * number in pixels for canvas width
  28. */
  29. width?: number;
  30. }
  31. /**
  32. * Class containing a set of static utilities functions for screenshots
  33. */
  34. export class ScreenshotTools {
  35. /**
  36. * Captures a screenshot of the current rendering
  37. * @see http://doc.babylonjs.com/how_to/render_scene_on_a_png
  38. * @param engine defines the rendering engine
  39. * @param camera defines the source camera
  40. * @param size This parameter can be set to a single number or to an object with the
  41. * following (optional) properties: precision, width, height. If a single number is passed,
  42. * it will be used for both width and height. If an object is passed, the screenshot size
  43. * will be derived from the parameters. The precision property is a multiplier allowing
  44. * rendering at a higher or lower resolution
  45. * @param successCallback defines the callback receives a single parameter which contains the
  46. * screenshot as a string of base64-encoded characters. This string can be assigned to the
  47. * src parameter of an <img> to display it
  48. * @param mimeType defines the MIME type of the screenshot image (default: image/png).
  49. * Check your browser for supported MIME types
  50. */
  51. public static CreateScreenshot(engine: Engine, camera: Camera, size: IScreenshotSize | number, successCallback?: (data: string) => void, mimeType: string = "image/png"): void {
  52. let width = 0;
  53. let height = 0;
  54. //If a size value defined as object
  55. if (typeof(size) === 'object') {
  56. // If a precision value is specified
  57. if (size.precision) {
  58. width = Math.round(engine.getRenderWidth() * size.precision);
  59. height = Math.round(width / engine.getAspectRatio(camera));
  60. }
  61. else if (size.width && size.height) {
  62. width = size.width;
  63. height = size.height;
  64. }
  65. //If passing only width, computing height to keep display canvas ratio.
  66. else if (size.width && !size.height) {
  67. width = size.width;
  68. height = Math.round(width / engine.getAspectRatio(camera));
  69. }
  70. //If passing only height, computing width to keep display canvas ratio.
  71. else if (size.height && !size.width) {
  72. height = size.height;
  73. width = Math.round(height * engine.getAspectRatio(camera));
  74. }
  75. else {
  76. width = Math.round(engine.getRenderWidth());
  77. height = Math.round(width / engine.getAspectRatio(camera));
  78. }
  79. }
  80. //Assuming here that "size" parameter is a number
  81. else if (!isNaN(size)) {
  82. height = size;
  83. width = size;
  84. }
  85. else {
  86. Logger.Error("Invalid 'size' parameter !");
  87. return;
  88. }
  89. if (!Tools._ScreenshotCanvas) {
  90. Tools._ScreenshotCanvas = document.createElement('canvas');
  91. }
  92. Tools._ScreenshotCanvas.width = width;
  93. Tools._ScreenshotCanvas.height = height;
  94. var renderContext = Tools._ScreenshotCanvas.getContext("2d");
  95. var ratio = engine.getRenderWidth() / engine.getRenderHeight();
  96. var newWidth = width;
  97. var newHeight = newWidth / ratio;
  98. if (newHeight > height) {
  99. newHeight = height;
  100. newWidth = newHeight * ratio;
  101. }
  102. var offsetX = Math.max(0, width - newWidth) / 2;
  103. var offsetY = Math.max(0, height - newHeight) / 2;
  104. var renderingCanvas = engine.getRenderingCanvas();
  105. if (renderContext && renderingCanvas) {
  106. renderContext.drawImage(renderingCanvas, offsetX, offsetY, newWidth, newHeight);
  107. }
  108. Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
  109. }
  110. /**
  111. * Generates an image screenshot from the specified camera.
  112. * @see http://doc.babylonjs.com/how_to/render_scene_on_a_png
  113. * @param engine The engine to use for rendering
  114. * @param camera The camera to use for rendering
  115. * @param size This parameter can be set to a single number or to an object with the
  116. * following (optional) properties: precision, width, height. If a single number is passed,
  117. * it will be used for both width and height. If an object is passed, the screenshot size
  118. * will be derived from the parameters. The precision property is a multiplier allowing
  119. * rendering at a higher or lower resolution
  120. * @param successCallback The callback receives a single parameter which contains the
  121. * screenshot as a string of base64-encoded characters. This string can be assigned to the
  122. * src parameter of an <img> to display it
  123. * @param mimeType The MIME type of the screenshot image (default: image/png).
  124. * Check your browser for supported MIME types
  125. * @param samples Texture samples (default: 1)
  126. * @param antialiasing Whether antialiasing should be turned on or not (default: false)
  127. * @param fileName A name for for the downloaded file.
  128. */
  129. 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): void {
  130. let width = 0;
  131. let height = 0;
  132. let targetTextureSize: number | { width: number, height: number } = 0;
  133. //If a size value defined as object
  134. if (typeof(size) === 'object') {
  135. //If a precision value is specified
  136. if (size.precision) {
  137. width = Math.round(engine.getRenderWidth() * size.precision);
  138. height = Math.round(width / engine.getAspectRatio(camera));
  139. size = { width: width, height: height };
  140. }
  141. else if (size.width && size.height) {
  142. width = size.width;
  143. height = size.height;
  144. }
  145. //If passing only width, computing height to keep display canvas ratio.
  146. else if (size.width && !size.height) {
  147. width = size.width;
  148. height = Math.round(width / engine.getAspectRatio(camera));
  149. size = { width: width, height: height };
  150. }
  151. //If passing only height, computing width to keep display canvas ratio.
  152. else if (size.height && !size.width) {
  153. height = size.height;
  154. width = Math.round(height * engine.getAspectRatio(camera));
  155. size = { width: width, height: height };
  156. }
  157. else {
  158. width = Math.round(engine.getRenderWidth());
  159. height = Math.round(width / engine.getAspectRatio(camera));
  160. }
  161. targetTextureSize = {width, height};
  162. }
  163. //Assuming here that "size" parameter is a number
  164. else if (!isNaN(size)) {
  165. height = size;
  166. width = size;
  167. targetTextureSize = size;
  168. }
  169. else {
  170. Logger.Error("Invalid 'size' parameter !");
  171. return;
  172. }
  173. var scene = camera.getScene();
  174. var previousCamera: Nullable<Camera> = null;
  175. if (scene.activeCamera !== camera) {
  176. previousCamera = scene.activeCamera;
  177. scene.activeCamera = camera;
  178. }
  179. var renderCanvas = engine.getRenderingCanvas();
  180. if (!renderCanvas) {
  181. Logger.Error("No rendering canvas found !");
  182. return;
  183. }
  184. var originalSize = { width: renderCanvas.width, height: renderCanvas.height };
  185. engine.setSize(width, height);
  186. scene.render();
  187. // At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
  188. var texture = new RenderTargetTexture("screenShot", targetTextureSize, scene, false, false, Constants.TEXTURETYPE_UNSIGNED_INT, false, Texture.NEAREST_SAMPLINGMODE);
  189. texture.renderList = null;
  190. texture.samples = samples;
  191. if (antialiasing) {
  192. texture.addPostProcess(new FxaaPostProcess('antialiasing', 1.0, scene.activeCamera));
  193. }
  194. texture.onAfterRenderObservable.add(() => {
  195. Tools.DumpFramebuffer(width, height, engine, successCallback, mimeType, fileName);
  196. });
  197. scene.incrementRenderId();
  198. scene.resetCachedMaterial();
  199. texture.render(true);
  200. texture.dispose();
  201. if (previousCamera) {
  202. scene.activeCamera = previousCamera;
  203. }
  204. engine.setSize(originalSize.width, originalSize.height);
  205. camera.getProjectionMatrix(true); // Force cache refresh;
  206. }
  207. }
  208. Tools.CreateScreenshot = ScreenshotTools.CreateScreenshot;
  209. Tools.CreateScreenshotUsingRenderTarget = ScreenshotTools.CreateScreenshotUsingRenderTarget;