0

I have a simple function which draws a video image on a canvas, like this:

setInterval(function() {
    localCanvas.getContext('2d').drawImage(localVideo, 0, 0, 250, 150);
}, 0);

However, the images on the canvas, while streaming smoothly, appears slightly blurry. It's even more blurry if the canvas goes to fullscreen. The dimensions are correct, so I know that the dimensions are not the problem (I've tried many different dimensions - all blurry). I've also tried:

localCanvas.getContext('2d').imageSmoothingEnabled = false;

But that give a weird pixelated result. Is there any way to get images on the canvas that look as good as the original video?

Here's the HTML for the objects:

<div id="container" style="box-sizing:border-box;display:flex;flex-direction:row;">
    <div style="width:400px;height:300px;">
        <video id="localVideo" style="width:90%;height:90%;" autoplay playsinline muted controls></video>
    </div>
    <div id="canvasContainer" style="position:relative;width:400px;height:300px;">
        <canvas id="localCanvas" style="width:100%;height:100%;"></canvas>
        <div id="myDiv" style="position:absolute;top:0;left:0;width:100%;height:100%;background:transparent;border:2px solid purple;">
            <div style="width:100%;height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;">
                <div style="color:yellow;">test</div>
            </div>
        </div>
        <div style="box-sizing:border-box;display:flex;flex-direction:row;justify-content:space-around;align-items:center;">
            <button id="fullscreenButton" onclick="var cvs = document.getElementById('localCanvas'); if(cvs.webkitRequestFullScreen) {cvs.webkitRequestFullScreen();} else {cvs.mozRequestFullScreen();}; return;">Fullscreen</button>
        </div>
    </div>
</div>
swabygw
  • 813
  • 1
  • 10
  • 22
  • **Unrelated to your issue:** Remove immediately that `setInteval(fn, 0)`: your monitor can't render that fast, so at least stick to its refresh rate by using a requestAnimationFrame loop, and your video will probably gets painted at even lower frame rate... **Related to your issue:** Please provide the code that defines this canvas and related CSS code if any, your description really fits the usual [canvas is stretched by CSS issue](https://stackoverflow.com/questions/2588181/canvas-is-stretched-when-using-css-but-normal-with-width-height-properties?noredirect=1&lq=1). – Kaiido Mar 18 '20 at 06:12
  • Regarding the first point, thanks for that - never used it before but it works fine (but doesn't solve the blurry issue) - the blurriness shows up even in just a still image, so it doesn't have anything to do with frame rate. Regarding the second issue, the video and canvas are exactly the same size, but I'll post the code anyway...see edit. – swabygw Mar 18 '20 at 07:13
  • Nope, your bitmap is still at its default size 300x150px. You are stretching it by CSS. Set its `width` and `height` attributes in the video.onloadedmetadata handler: `video.onloadedmetadata = e => { canvas.width = video.videoWidth; canvas.height = video.videoHeight; }` – Kaiido Mar 18 '20 at 07:23
  • Son-of-a-gun, you're right and the image is sharp now. But the canvas is now quite small. What's the best way to get larger dimensions, if not by CSS? – swabygw Mar 18 '20 at 07:41
  • I tried adding: localCanvas.getContext('2d').scale(2.5, 4); and the results came out very well. But I used trial-and-error to guess the 2.5 and the 4. I'm guessing that there's a better way to scale it correctly and maintain the aspect ratio. Right? – swabygw Mar 18 '20 at 07:50
  • Yes sure. But if your source video really is that small, you will not win much by scaling on the canvas vs scaling the canvas through CSS. The most important thing is to draw at pixel size, and scale uniformly (so that a pixel still is a square when stretched). You can use the CSS `object-fit` on your canvas to keep the correct aspect-ratio when stretching it with CSS after you set your canvas `width` and `height`. https://jsfiddle.net/gqdxmo06/ – Kaiido Mar 18 '20 at 07:58
  • Hmm, I changed the Canvas tag to this: . But it came out weird - the image is still the same small size, and there is now a tall gray background. Also tried: localCanvas.style.objectFit = "contain"; after setting the height & width in javascript. – swabygw Mar 18 '20 at 08:11
  • 1
    Eureka - I found the issue. I had, accidentally, plugged in static values in this line: localCanvas.getContext('2d').drawImage(localVideo, 0, 0, 270, 135);. I changed it to: localCanvas.getContext('2d').drawImage(localVideo, 0, 0, localCanvas.width, localCanvas.height); and it came out perfectly. – swabygw Mar 18 '20 at 08:48

0 Answers0