CesiumGS / cesium

An open-source JavaScript library for world-class 3D globes and maps :earth_americas:
https://cesium.com/cesiumjs/
Apache License 2.0
12.72k stars 3.44k forks source link

Create one liner to render canvas to image #5938

Open ggetz opened 6 years ago

ggetz commented 6 years ago

Create a one liner to render the current canvas to an image.

Requested on the forum here: https://groups.google.com/forum/#!searchin/cesium-dev/webgl%7Csort:date/cesium-dev/FdQk03zgOMI/KAZp4QiPBwAJ

gabriellagal commented 6 years ago

Hello! We will try and complete this as part of 24 Pull Requests London with Codebar.

hpinkos commented 6 years ago

Thanks @gabriellagal! Let us know if you have any questions =)

gabriellagal commented 6 years ago

Sorry @hpinkos we ended up shifting our focus from it. It was a more advanced problem than we thought - a little above our level at the moment!

hpinkos commented 6 years ago

No problem =)

sg-gily commented 5 years ago

Hi, any update about the progress of the issue?

OmarShehata commented 5 years ago

TerriaJS actually builds this right into their Cesium viewer, see the snippet linked to from this forum post:

https://groups.google.com/d/msg/cesium-dev/I-SN1jx0bvg/Vi0h24vFBgAJ

srothst1 commented 2 years ago

Hi @ggetz! I am happy to take this on. However, it would be very helpful if you could provide some more context for this issue. What specifically is needed to implement a fix?

sanjeetsuhag commented 2 years ago

Bumping this issue since taking screenshots is an important part of the dev process and this seems like it could be useful feature for end users too.

Currently, I am using this snippet; and based on offline discussion, a lot of other CesiumJS developers use a similar approach:

Sandcastle.addToolbarButton("Capture", function() {
  const scene = viewer.scene;
  const screenshot = function (scene) {

    const canvas = scene.canvas;
    const fileName = "screenshot";
    const link = document.createElement('a');
    link.download = fileName + '.png';
    canvas.toBlob(function(blob) {
        link.href = URL.createObjectURL(blob);
        link.click();
    });
    link.remove();
    scene.postRender.removeEventListener(screenshot);
  };
  scene.postRender.addEventListener(screenshot);
});

This has come up several times on the community forum:

I think adding this to the public API, and potentially integrating it into Sandcastle should be looked into (by way of a keyboard shortcut, for example).

Additionally, this function to take a screenshot could take in parameters to do things like increasing resolution scale, improving shadow quality, screen space error to take high quality screenshots.

From a quick look, it seems like ThreeJS doesn't have an API for this, but Babylon.js has tools to help with screenshots.

javagl commented 8 months ago

This has also been requested in https://community.cesium.com/t/question-about-screenshot-and-model/28940

The basic functionality of registering a postRender listener and saving the canvas as a blob/URL seems to work. However, at a certain size, the screenshot function just generates a black image. To reproduce this, the sandcastle that was also posted at https://community.cesium.com/t/question-about-screenshot-and-model/28940/18 is replicated here:

https://sandcastle.cesium.com/index.html#c=lVRta9swEP4rwl9qr0FeKIOOvDASChsECs1evhiGIl1sJbIUJNlpN/Lfe7Id8tJkdF8s393zPDrdncSNdp7UErZgyYho2JIpOFmV9Gfji7OIN/bUaM+kBptFySDTmV5WmntpNHGcKRBTtvGVhThYUucJ+Ztp0glTC86oKqDnAYwbdbBBAPEmB8dBh0hHacyTsAXQrjAeMXETTcho3G6zB3Gma+YaeYzT1hx0iMag3kyUWcTxAr/HAoTs1zT9kB7+BSyqPAc72LvanbZnmVJ0e3j29HeuqLBsi4ebVMsl2F9S+OKMXbyb/RVkXvgTulFAlcmxM3P5B4h0JItut7dZFNYiGVw6x+n2WPk1ZiAMr0rQnmJpmYcHBcGKb9jNQSRAqTBbrQwTyMmibyXLga42eRadogoLS0T8eJp1go+LFXCPdlvsUzRXkq/jM6eF0tRw5A1iFmqzvip2dcL6HWTXw6RlSDpdbQCz7pGP9POnvUJb/41x/gm0aJRCDg81lmImnceojQ/D19J2zfcNlQnxL94uXJs504Iz57GJCP9ujFowO6m8Nxo72t0i8twPecbNgJ7er34SpN6pcndN5e5/VO6vqdwn7VMQ9aKh8y8KxvuufJHlxlhPKqtiSlMP5UbhRLh0UfE14MQ5t2/AMD2mDoWsiRSjC88O4Yo5h5FlpVQY/SwaD1PEv6GGWcUb9FiDVewlwIr+eNY6KaXDFM3LTN/W4Ez5FQ

I did spend some time (too much - a few hours, to be honest) trying to figure out why that happens. For the "standalone HTML test" posted at https://community.cesium.com/t/question-about-screenshot-and-model/28940/20 , it is possible to create screenshots that are waaaay larger than the ones that are possible from within CesiumJS. I've been reading about GL context, WebGL, drawing buffers, device limits, but no avail. In other (WebGL) tests, it also seems to bail out at a certain size, but without any error messages or clues about the reasons.

(While diving into some details, the GL context and toBlob function exposed completely erratic behavior. For example: I could save a ~13000x8000 pixel screenshot. but whether or not that was possible depended on the CSS styling that was used for the cesiumViewer div. Yes. Seriously.)

The point is: If the "one-liner" screenshot functionality is added, it should be checked whether this also works when the resolutionScale is set to a "high" value (like 8 or 10, to create a screenshot in the >10k x 10k size range).