Search code examples
javascriptelectronscreenshot

Javascript Electron how to take screenshots from a video source


I'm using Electron Desktop Capturer https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md to capture a screenshot of this stream at regular intervals. I'm using this code but for some reason I get an error:

function takeScr(stream) {
  const video = localStream.getVideoTracks()[0];
  console.log(video)
  const canvas = document.createElement('canvas');
  canvas.getContext("2d").drawImage(video, 0, 0, 300, 300, 0, 0, 300, 300);
}

At the moment I'm simply pressing a button to activate this take screenshot function after the stream has started playing. The console log shows the video track no problem with output:

MediaStreamTrack {kind: "video", id: "7a19a94f-6077-4e3d-b534-03d138b3f300", label: "Screen", enabled: true, muted: false, …}

but the canvas.getContext function throws the error:

Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'

There are many questions on here about this error but none seem to solve my problem and none are regarding video streams. Some solutions were that the image was not loaded when trying to draw to canvas but since I'm pressing a button several seconds after the stream has started I'm sure it must be loaded?

Maybe I'm doing this the wrong way and there is a better way to take screenshots of the video source from Desktop Capturer?


Solution

  • I found an example in the following question regarding taking snapshots from a video.

    You could do something like this:

    document.getElementById("snap").addEventListener("click", function() {
      snap();
    });
    
    // Get handles on the video and canvas elements
    var video = document.querySelector('video');
    var canvas = document.querySelector('canvas');
    // Get a handle on the 2d context of the canvas element
    var context = canvas.getContext('2d');
    // Define some vars required later
    var w, h, ratio;
    
    // Add a listener to wait for the 'loadedmetadata' state so the video's dimensions can be read
    video.addEventListener('loadedmetadata', function() {
      // Calculate the ratio of the video's width to height
      ratio = video.videoWidth / video.videoHeight;
      // Define the required width as 100 pixels smaller than the actual video's width
      w = video.videoWidth - 100;
      // Calculate the height based on the video's width and the ratio
      h = parseInt(w / ratio, 10);
      // Set the canvas width and height to the values just calculated
      canvas.width = w;
      canvas.height = h;
    }, false);
    
    // Takes a snapshot of the video
    function snap() {
      // Define the size of the rectangle that will be filled (basically the entire element)
      context.fillRect(0, 0, w, h);
      // Grab the image from the video
      context.drawImage(video, 0, 0, w, h);
    }
    <video width="400" controls>
      <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
      <source src="https://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg">
      Your browser does not support HTML5 video.
    </video>
    
    <canvas width="364" height="204"></canvas>
    
    <button id="snap">Take screenshot</button>

    JSFiddle