What is the alternative to take high resolution picture rather than take canvas screenshot

We know the way to take screenshot from canvas, but the resolution and quality is not good.

Is it way to take picture using webgl renderer or something else, with ability to config resolution and quality of screenshot.

Best Regards
Anthony Vinnik

3 Likes

I’ll give my opinion from what I currently know.
For higher resolution snapshot (meaning just getting a bigger resolution screen shot) you can just increase the canvas size (width x height).

As for quality, that term can be quite board: softer shadows, crispier lines, etc.

But ultimately, from what I know, the quality you see displayed in the canvas is the best quality you can get with a snapshot (if that makes sense).
So what you’ll want to do if you want higher quality is, modify the scene itself, such as correct lighting, add more lights, increase shadows resolution, increase polygon model resolutions, create custom rendering shaders, etc. then take a snap shot. These are what I may consider when I think of webGL confiurations for rendering.

5 Likes

Thanks you very much for your response!
Now we will try to achieve bigger quality and resolution

I’m not sure if you knew it, but you can pass the format and quality parameter in toDataURL.

Other than that, you could also render to a framebuffer and download it’s plain memory block. But you would have to deal with anitaliasing yourself, as well as compression / encoding it to various formats what wouldn’t make much sense except for libraries which require single frames maybe.

2 Likes

Many many thanks for your help!

I have worked a lot with models but a few with framebuffers, memory blocks and antialiasing
I will be very appreciate for materials for reading, examples and libraries on this topic.
Please help, I really want to understand this topic.

You can set the canvas size to whatever you like, render a frame, take a screenshot, then reset the size back to the original like this

function takeScreenshot( width, height ) {
    
    // set camera and renderer to desired screenshot dimension
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize(  width, height );
  
    renderer.render( scene, camera, null, false );

    const dataURL = renderer.domElement.toDataURL( 'image/png' );

    const iframe = `
      <iframe
        src="${dataURL}"
        frameborder="0"
        style="border:0; top:0px; left:0px; bottom:0px; right:0px; width:100%; height:100%;"
        allowfullscreen>
      </iframe>`

    const win = window.open();
    win.document.open();
    win.document.write( iframe );
    win.document.close();

    // reset to old dimensions (cheat version)
    onWindowResize();
  
 }

See below for updated pen.

4 Likes

I found that with this method, there are problems downloading the image on Chrome (it’s difficult to save the image using right click or CTRL+S). I haven’t sound a good workaround, so instead I’ve switched to directly downloading the image which should work on all browsers. I’ve updated the pen, here are the new functions, mainly taken from mattdesl/threejs-app:

function dataURIToBlob( dataURI ) {
  const binStr = window.atob( dataURI.split( ',' )[1] );
  const len = binStr.length;
  const arr = new Uint8Array( len );
  for ( let i = 0; i < len; i++ ) {
    arr[i] = binStr.charCodeAt( i );
  }
  return new window.Blob( [arr] );
}

function saveDataURI( name, dataURI ) {
  const blob = dataURIToBlob( dataURI );

  // force download
  const link = document.createElement( 'a' );
  link.download = name;
  link.href = window.URL.createObjectURL( blob );
  link.onclick = () => {
    window.setTimeout( () => {
      window.URL.revokeObjectURL( blob );
      link.removeAttribute( 'href' );
    }, 500 );

  };
  link.click();
}

function defaultFileName (ext) {
  const str = `${new Date().toLocaleDateString()} at ${new Date().toLocaleTimeString()}${ext}`;
  return str.replace(/\//g, '-').replace(/:/g, '.');
}

function takeScreenshot( width, height ) {
  
    // set camera and renderer to desired screenshot dimension
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize(  width, height );
  
    renderer.render( scene, camera, null, false );

    const DataURI = renderer.domElement.toDataURL( 'image/png' );

    // save
    saveDataURI(defaultFileName( '.png' ), DataURI);

    // reset to old dimensions by invoking the on window resize function
    onWindowResize();
  
 }

8 Likes

This is the simplest way to save custom resolution screenshot,
However it seems like it does not work anymore on “Firefox” (in Windows at least)
Is there anyway to fix the above pen to make it work in Firefox!?

Thank you

Note that forcing a download may in some browsers have to be triggered by a user action. What this means in practice is that the code flow must originate in an event handler for clicks, keyboard presses etc…

Thanks for the reply,
I did try it with “keyboard press” handler, And the same issue exists!
I might have to just use Chrome then!

Maybe. At least the problem must be something else. But do you know what browsers your users will be using?

We use Chrome

I use the same kind of approach to generate exports. It works great for exports up to around 2 times the size of the original but after that fails as especially Chrome tends to cut off certain parts.

If I use your sketch and export at base values, it looks great:

But when I bump that up to a higher ratio of export (in this case 6 times the base resolution) Chrome (and other browsers) cut off certain parts:

This varies on the aspect ratio / resolution but I have found that to be true for all of my sketches and projects where I tried to implement this.

While trying to debug this I tried to use promises and timeouts for the actual rendering to make sure the frame is ready when exporting, using various options for the renderer (like setting “preserveDrawingBuffer” to true) and stopping requestAnimationFrame to make sure nothing overlaps but nothing seems to solve that.

If someone has any idea how to create “real” high resolution exports that would be a tremendous help!

2 Likes

how i can change the background of the screenshot only please any one can help

Did you try scene.background = new THREE.Color( yourHexColor ); ?

@felixmariotto thanks for attention
yes i did and also i tried to set the renderer color but in screenshot i am getting black background

Any updates to turn the screen shot backgroung into white

thanks this solve my problem

I just wanted to echo and say that I’m also having this problem, even with the current three.js version :confused:

It’s very useful, but I have more quesiont.
I use two renders in my project, one for 3D objects, the other for 2D-CSS-label. How can I render all these 2 renders sequentially into the picture?