How to take a screenshot of a webpage using html5, without rendering it on a canvas via JS
Asked Answered
C

2

7

The important part is to take the screenshot

  • exactly as the user sees the browser window. This rules out canvas-based questions and answers, which emulate the browser but cannot exactly replicate how it renders html and css
  • without any non-standard plugins outside of plain, standards-compliant html5 and JS. This rules out Java applets, Flash, ActiveX, and kindly asking the user to press the "print-screen" button to then paste the image into a form.

I came across several questions on stackoverflow addressing this (see above), but did not find any answer that fulfilled both conditions. Instead of trying to add a partial answer for existing questions with slightly different requirements, I am asking this in a separate question instead.

I have so-far found a great explanation on how to acquire and stream pixels from a any window into a video element, using the Screen Capture API. However, I am missing the next step, where those pixels that are being displayed in a video element are converted into a jpg or png file that can be uploaded to a server.

Colmar answered 2/4, 2019 at 11:55 Comment(0)
C
9

This is simpler than it seemed. The missing part, saving a still shot of the video to png, can be achieved with code from this answer. The complete code would be as follows:

const v = document.getElementById("v");
const b = document.getElementById("b");
const i = document.getElementById("i");

navigator.mediaDevices.getDisplayMedia({
  audio: false
}).then((r) => {
  console.log(r);
  v.srcObject = r;
}).catch((e) => {
  console.log("this must be run in a secure context. Stack snippets (rightfully) refuse to run this.");
});

b.onclick = () => {
  // take screenshot
  // from https://mcmap.net/q/717208/-get-an-image-from-the-video
  let scale = 1;

  const canvas = document.createElement("canvas");
  canvas.width = v.clientWidth * scale;
  canvas.height = v.clientHeight * scale;
  canvas.getContext('2d').drawImage(v, 0, 0,
    canvas.width, canvas.height);

  i.src = canvas.toDataURL();
  // you can send i.src here to a server

  // stop video
  let tracks = v.srcObject.getTracks();
  tracks.forEach(track => track.stop());
  v.srcObject = null;
}
#v,
#i {
  width: 400;
  height: 300;
}

#v {
  border: 1px solid blue;
}

#i {
  border: 1px solid green;
}
<div>
  <video id="v" autoplay></video>
  <button id="b">take screenshot</button>
  <img id="i" src="//:0" />
</div>

Note that StackOverflow does not allow asking for screen-grabbing permissions, and therefore this code does not run here.

Colmar answered 2/4, 2019 at 15:33 Comment(5)
Creating a demo on a GH-Pages (i.e. https) domain would be nice, and explaining exactly how and why taking a snapshot works would help too. Atm this answer is just a bunch of code showing your solution, and the bulk of what matters is copied from another SO answer (that you linked). If there was anything else you needed to change to make capturing a snapshot work, it'd be worth noting that in this answer, too.Gametocyte
To the down-voter, I would appreciate feedback on what is wrong in the answer. @Florrie, if that is you, then I would argue that the lack of a GH demonstration is not, in itself, grounds for down-voting. Linking to sources is good attribution. Both were not previously readily connected (to the best of my googling), and this answer allows in-browser, standards-compliant screenshots to be generated.Colmar
...Agreed.. I suppose I was trying to rationalize why the down-voter did so, but I wasn't actually the one who did.Gametocyte
One thing though, in the question title you mention you don't want to render it to a canvas, but you actually do in your answer.Frae
@Cristy the rendering is done by the video stream, I am only using the canvas to convert the pixels into a PNG. "Render on to" was meant in the sense of actually drawing the document, element by element, as done by html2canvas and other js libraries.Colmar
P
1

I used tucuxi's answer but it not simple. So I wrote new JS library: screenshot.js.

It's enable to take real screenshot simply.

You load the script:

<script src="https://raw.githubusercontent.com/amiad/screenshot.js/master/screenshot.js"></script>

and take screenshot:

new Screenshot({success: img => {
        // callback function
        myimage = img;
    }});

You can read more options in project page.

Propraetor answered 24/2, 2022 at 9:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.