JavaScript Canvas getImageData() function returning data with all the values as 0

479 views Asked by At

I am trying to make a Chrome extension. I am trying to take screenshots using the video method in JavaScript, and then drawing the video frame on canvas, then getting image Data using getImageData(), but it's still not working it is giving data with 0 values like this:

enter image description here

I tried all methods on stack Overflow like using the onload method and others but still nothing works for me.

I am sorry the code is over commented for better understanding because I always write messy code here is the code:

//A function to take screenshot
const takeSnip = async () => {
  try {
    //Creating stream to capture a single frame of the current tab video
    const stream = await navigator.mediaDevices.getDisplayMedia({ preferCurrentTab: true });
    
    //Creating video element
    const video = document.createElement('video');
    
    //Creating canvas element
    const canvas = document.createElement('canvas');
    
    //Some styling to the canvas
    canvas.style.position = 'absolute';
    canvas.style.margin = 'auto';
    
    //Creating context
    const CTX = canvas.getContext('2d');
    
    //Adding event listener to the video
    video.addEventListener('loadedmetadata', () => {
      
      //Defining the width height of the canvas
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      
      //Playing the video
      video.play()
      
      //Drawing the image on the canvas
      CTX.drawImage(video, 0, 0, canvas.width, canvas.height);
      
      //Stopping the video on first frame as a screenshot
      stream.getVideoTracks()[0].stop();
      
      //Adding the canvas to the body
      document.body.appendChild(canvas)
    })
    
    //Getting image data from the drawn image on canvas
    const imageData = CTX.getImageData(0, 0, canvas.width, canvas.height);
    video.srcObject = stream;
    
    //Printing the imagedata on the console
    console.log(imageData.data)  //It is getting all the data with 0 values as shown above
  } catch (error) {
    console.log(error);
  }
}
2

There are 2 answers

0
Priyanshu kuntal On BEST ANSWER

Just move the getImageData() inside the adddEventListener() that would work fine.

0
Mr. Polywhirl On

Your loadedmetadata event is being called asynchronously. There is no guarantee that the callback of the event will finish before you call getImageData.

You could wrap your event listeners in an async function that returns a Promise:

const onLoadMetadataAsync = async (video) =>
  new Promise((resolve) => {
    video.addEventListener('loadedmetadata', (event) => {
      resolve(event);
    });
  });

Now, you can await the event response:

const event = await onLoadMetadataAsync(video);

Modified script:

const onLoadMetadataAsync = async (video) =>
  new Promise((resolve) => {
    video.addEventListener('loadedmetadata', (event) => {
      resolve(event);
    });
  });

//A function to take screenshot
const takeSnip = async () => {
  try {
    //Creating stream to capture a single frame of the current tab video
    const stream = await navigator.mediaDevices.getDisplayMedia({ preferCurrentTab: true });
    
    //Creating video element
    const video = document.createElement('video');
    
    //Creating canvas element
    const canvas = document.createElement('canvas');
    
    //Some styling to the canvas
    canvas.style.position = 'absolute';
    canvas.style.margin = 'auto';
    
    //Creating context
    const CTX = canvas.getContext('2d');
    
    //Adding event listener to the video
    const event = await onLoadMetadataAsync(video);
      
    //Defining the width height of the canvas
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;

    //Playing the video
    video.play()

    //Drawing the image on the canvas
    CTX.drawImage(video, 0, 0, canvas.width, canvas.height);

    //Stopping the video on first frame as a screenshot
    stream.getVideoTracks()[0].stop();

    //Adding the canvas to the body
    document.body.appendChild(canvas)

    
    //Getting image data from the drawn image on canvas
    const imageData = CTX.getImageData(0, 0, canvas.width, canvas.height);
    video.srcObject = stream;
    
    //Printing the imagedata on the console
    console.log(imageData.data)  //It is getting all the data with 0 values as shown above
  } catch (error) {
    console.log(error);
  }
}