@@ -11,6 +11,13 @@ import { VtkDataTypes } from 'vtk.js/Sources/Common/Core/DataArray/Constants';
1111
1212const { vtkDebugMacro, vtkErrorMacro } = macro ;
1313const IS_CHROME = navigator . userAgent . indexOf ( 'Chrome' ) !== - 1 ;
14+ const SCREENSHOT_PLACEHOLDER = {
15+ position : 'absolute' ,
16+ top : 0 ,
17+ left : 0 ,
18+ width : '100%' ,
19+ height : '100%' ,
20+ } ;
1421
1522function checkRenderTargetSupport ( gl , format , type ) {
1623 // create temporary frame buffer and texture
@@ -522,19 +529,102 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
522529 publicAPI . invokeImageReady ( screenshot ) ;
523530 }
524531
525- publicAPI . captureNextImage = ( format = 'image/png' ) => {
532+ publicAPI . captureNextImage = (
533+ format = 'image/png' ,
534+ { resetCamera = false , size = null , scale = 1 } = { }
535+ ) => {
526536 if ( model . deleted ) {
527537 return null ;
528538 }
529539 model . imageFormat = format ;
530540 const previous = model . notifyStartCaptureImage ;
531541 model . notifyStartCaptureImage = true ;
532542
543+ model . _screenshot = {
544+ size :
545+ ! ! size || scale !== 1
546+ ? size || model . size . map ( ( val ) => val * scale )
547+ : null ,
548+ } ;
549+
533550 return new Promise ( ( resolve , reject ) => {
534551 const subscription = publicAPI . onImageReady ( ( imageURL ) => {
535- model . notifyStartCaptureImage = previous ;
536- subscription . unsubscribe ( ) ;
537- resolve ( imageURL ) ;
552+ if ( model . _screenshot . size === null ) {
553+ model . notifyStartCaptureImage = previous ;
554+ subscription . unsubscribe ( ) ;
555+ if ( model . _screenshot . placeHolder ) {
556+ // resize the main canvas back to its original size and show it
557+ model . size = model . _screenshot . originalSize ;
558+
559+ // process the resize
560+ publicAPI . modified ( ) ;
561+
562+ // restore the saved camera parameters, if applicable
563+ if ( model . _screenshot . cameras ) {
564+ model . _screenshot . cameras . forEach ( ( { restoreParamsFn, arg } ) =>
565+ restoreParamsFn ( arg )
566+ ) ;
567+ }
568+
569+ // Trigger a render at the original size
570+ publicAPI . traverseAllPasses ( ) ;
571+
572+ // Remove and clean up the placeholder, revealing the original
573+ model . el . removeChild ( model . _screenshot . placeHolder ) ;
574+ model . _screenshot . placeHolder . remove ( ) ;
575+ model . _screenshot = null ;
576+ }
577+ resolve ( imageURL ) ;
578+ } else {
579+ // Create a placeholder image overlay while we resize and render
580+ const tmpImg = document . createElement ( 'img' ) ;
581+ tmpImg . style = SCREENSHOT_PLACEHOLDER ;
582+ tmpImg . src = imageURL ;
583+ model . _screenshot . placeHolder = model . el . appendChild ( tmpImg ) ;
584+
585+ // hide the main canvas
586+ model . canvas . style . display = 'none' ;
587+
588+ // remember the main canvas original size, then resize it
589+ model . _screenshot . originalSize = model . size ;
590+ model . size = model . _screenshot . size ;
591+ model . _screenshot . size = null ;
592+
593+ // process the resize
594+ publicAPI . modified ( ) ;
595+
596+ if ( resetCamera ) {
597+ // If resetCamera was requested, we first save camera parameters
598+ // from all the renderers, so we can restore them later
599+ model . _screenshot . cameras = model . renderable
600+ . getRenderers ( )
601+ . map ( ( renderer ) => {
602+ const camera = renderer . getActiveCamera ( ) ;
603+ const params = camera . get (
604+ 'focalPoint' ,
605+ 'position' ,
606+ 'parallelScale'
607+ ) ;
608+
609+ return {
610+ resetCameraFn : renderer . resetCamera ,
611+ restoreParamsFn : camera . set ,
612+ // "clone" the params so we don't keep refs to properties
613+ arg : JSON . parse ( JSON . stringify ( params ) ) ,
614+ } ;
615+ } ) ;
616+
617+ // Perform the resetCamera() on each renderer only after capturing
618+ // the params from all active cameras, in case there happen to be
619+ // linked cameras among the renderers.
620+ model . _screenshot . cameras . forEach ( ( { resetCameraFn } ) =>
621+ resetCameraFn ( )
622+ ) ;
623+ }
624+
625+ // Trigger a render at the custom size
626+ publicAPI . traverseAllPasses ( ) ;
627+ }
538628 } ) ;
539629 } ) ;
540630 } ;
0 commit comments