Three.js: How can I make a 2D SnapShot of a Scene as a JPG Image?

There are a couple of things you will have to do to save the frame as a jpg image.

Firstly initialize the WebGL context like this

renderer = new THREE.WebGLRenderer({
    preserveDrawingBuffer: true
});

preserveDrawingBuffer flag will help you to get the base64 encoding of the current frame
The code for that will be something like this

var strMime = "image/jpeg";
imgData = renderer.domElement.toDataURL(strMime);

Now secondly you might want to save the file using a .jpg extension, but not all browsers allow you to specify the file name.
The best solution I found was in this SO thread.

So our script will check if the browser allows it will create a new anchor element and set its download and click it(which will save the file in a specified filename) else it will just download the file but the user will have to rename it with a .jpg extension to open it.

Codepen Link

var camera, scene, renderer;
var mesh;
var strDownloadMime = "image/octet-stream";

init();
animate();

function init() {

    var saveLink = document.createElement('div');
    saveLink.style.position = 'absolute';
    saveLink.style.top = '10px';
    saveLink.style.width="100%";
    saveLink.style.background = '#FFFFFF';
    saveLink.style.textAlign = 'center';
    saveLink.innerHTML =
        '<a href="#" id="saveLink">Save Frame</a>';
    document.body.appendChild(saveLink);
    document.getElementById("saveLink").addEventListener('click', saveAsImage);
    renderer = new THREE.WebGLRenderer({
        preserveDrawingBuffer: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 400;

    scene = new THREE.Scene();

    var geometry = new THREE.BoxGeometry(200, 200, 200);


    var material = new THREE.MeshBasicMaterial({
        color: 0x00ff00
    });

    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
    requestAnimationFrame(animate);

    mesh.rotation.x += 0.005;
    mesh.rotation.y += 0.01;

    renderer.render(scene, camera);
}

function saveAsImage() {
    var imgData, imgNode;

    try {
        var strMime = "image/jpeg";
        var strDownloadMime = "image/octet-stream";

        imgData = renderer.domElement.toDataURL(strMime);

        saveFile(imgData.replace(strMime, strDownloadMime), "test.jpg");

    } catch (e) {
        console.log(e);
        return;
    }

}

var saveFile = function (strData, filename) {
    var link = document.createElement('a');
    if (typeof link.download === 'string') {
        document.body.appendChild(link); //Firefox requires the link to be in the body
        link.download = filename;
        link.href = strData;
        link.click();
        document.body.removeChild(link); //remove the link when done
    } else {
        location.replace(uri);
    }
}
html, body {
    padding:0px;
    margin:0px;
}
canvas {
    width: 100%;
    height: 100%
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/three.js/r69/three.min.js"></script>
<script src="http://threejs.org/examples/js/libs/stats.min.js"></script>

Edit Dec 2022

As Mohammad Tbeishat pointed out in a comment this is a more preformat API available now canvas.toBlob you can refer to at

https://r105.threejsfundamentals.org/threejs/lessons/threejs-tips.html

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)