1

I'm trying to generate a screenshot of a video. The goal is to generate an image that is identical to the first frame of the video. However, I'm facing an issue with the resulting image being stretched.

This image displays the video on the left, paused at the very beginning - and the generated image on the right:

enter image description here

Notice the grey area at the bottom? It has been stretched to a taller height than that of the video.

I am using the following code the generate the screenshot:

Example Markup:

<video id="video" height="300" width="320" preload="auto">
    <source src="http://domain.com/video.mp4">
</video>
<canvas id="canvas" height="300" width="320"></canvas>

Script:

// Grab an existing video element, 300px tall, 320px wide.
var video = document.getElementById('video');
// Grab existing canvas, 300px tall, 320px wide.
var canvas = document.getElementById('canvas');
// Wait until video has loaded
video.addEventListener('loadeddata', function() {
    var context = canvas.getContext('2d');
    // Render using same dimensions.
    context.drawImage(video, 0, 0, 320, 300);
}, false);

Could someone please advise me on how to avoid this stretching?

  • The `canvas.style.width` and `canvas.style.height` attributes are only the page display properties and are not related to the canvas pixel resolution. You need to set the `canvas.width` and `canvas.height` to the correct resolution – Blindman67 Jun 29 '16 at 20:32
  • I am setting the width and height directly on the element. I've added the markup I used to create my example screenshot into the question example code. –  Jun 29 '16 at 22:59
  • No you have to set it to the media's width and height, video element's size attributes are only displaying sizes too. You can retrieve it by js with `video.videoWidth` and `video.videoHeight`. – Kaiido Jun 29 '16 at 23:07

1 Answers1

0

Just like for <img> elements, <video> element's width and height attributes resize the container. drawImagemethod in other hand do use the content.

You then have to use the videoElement.videoWidth and videoElement.videoHeight attributes to retrieve the media's width and height (or img.naturalWidth and img.naturalHeight for image elements).

So you've got two possibilities :

Either you want to make a capture of the video, in its real size :

var ctx = canvas.getContext('2d');
btn.onclick = function(){
  // set your canvas width and height to the media's ones
  canvas.width = vid.videoWidth;
  canvas.height = vid.videoHeight;
  ctx.drawImage(vid, 0,0);
  };
<video src="http://vjs.zencdn.net/v/oceans.mp4" width="200" height="100" autoplay controls muted loop id="vid"></video><button id="btn">take a screenshot</button>
<canvas id="canvas"></canvas>

Or if you want to take a screenshot of your video element, you'll face more complexity since you'll have to fake the default object-fit: contain; CSS property. This can be done thanks to the ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); properties.

You can find one way here, and a more complete one here so I won't include it in this answer, just remember to use the video.videoWidth and video.videoHeight attributes as sourceWidth and sourceHeight.

Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Are you thinking that the natural size of the video is not the same as what I'm setting it to? I'm not resizing the video - the frame width is 320px and frame height is 300px on the mp4 file. As in your example, I'm simply trying to take a screenshot of the video with it's natural size. Yet the resulting screenshot seems to have its contents stretched. –  Jun 30 '16 at 01:55
  • @Tyler Well yes, that's what I'm thinking given your explanations. It's the only possibility I can think of. Can you check that `video.videoHeight === 300` on your side? – Kaiido Jun 30 '16 at 02:08
  • Yes, `video.videoHeight` is showing as 300. I made a fiddle with a basic version of what I'm trying to do so you can see the actual video I'm working with: https://jsfiddle.net/owLgg94b/ –  Jun 30 '16 at 02:17
  • Ok, I'm able to [reproduce it](http://jsfiddle.net/owLgg94b/2/) but only on chrome... and [only with **your** video](http://jsfiddle.net/owLgg94b/3/). you may raise a bug to there bugzilla..., and I'll try to find some more time to investigate it. But right now, I'll let this general answer since you seem to be in a very particular case. – Kaiido Jun 30 '16 at 02:42
  • Are you using Windows? I just tested the fiddle again this morning and the bug is showing up on my PC but not my Mac - using the exact same version of Chrome. –  Jun 30 '16 at 15:51
  • @Tyler, no I'm on a mac. Didn't had time yet to analyse your video file (seems legit at first glance). Are you saying that the bug occurs also with the other example video on your windows? – Kaiido Jun 30 '16 at 23:02
  • The other example video seems fine - but I am only able to reproduce the stretching on my Windows Desktop + Chrome. Chrome on Mac is displaying correctly. –  Jul 01 '16 at 15:59