niklasvh / html2canvas

Screenshots with JavaScript
https://html2canvas.hertzen.com/
MIT License
30.7k stars 4.82k forks source link

The captured video is rendered on the canvas, and the position is wrong. #3064

Open hailanglang opened 1 year ago

hailanglang commented 1 year ago

Bug reports:

The captured video is rendered on the canvas, and the position is wrong. Am I using it wrong? code segment:

<html lang="en">
<body>
    <button onclick="snapshot()">snapshot</button>
    <div id="snapshotTarget" style="width: 400px;height: 400px; background-color: pink; border: 1px solid black;">
        <video style="width: 300px; height: 200px; margin-top: 50px; margin-left: 50px;" controls
            crossorigin="anonymous"
            src="https://webrtc.github.io/samples/src/video/chrome.mp4"></video>
    </div>
    canvas:
    <div id="canvasContainer"></div>

    <script src="https://unpkg.com/html2canvas@1.4.1/dist/html2canvas.js"></script>
    <script>
        const snapshotTarget = document.querySelector("#snapshotTarget")
        const canvasContainer = document.querySelector("#canvasContainer")
        async function snapshot() {
            // setVideoBackImg(snapshotTarget);
            const canvas = await html2canvas(snapshotTarget, {
                width: 400,
                height: 400,
                useCORS: true
            })
            canvasContainer.appendChild(canvas)
        }
        console.log('html2canvas', html2canvas)
    </script>
</body>
</html>

image

Specifications:

daylanKifky commented 6 months ago

Something similar was happening to me, with a video created by AR.js. this library uses negative offsets to center the video and fill the container. This is a quick workaround:

 DocumentCloner.prototype.createVideoClone = function (video) {
            var canvas = video.ownerDocument.createElement('canvas');
            canvas.width = video.offsetWidth;
            canvas.height = video.offsetHeight;
            let left = parseInt(video.style.marginLeft);
            let top =  parseInt(video.style.marginTop);
            var ctx = canvas.getContext('2d');
            try {
                if (ctx) {
                    ctx.drawImage(video, left, top, canvas.width, canvas.height);
                    if (!this.options.allowTaint) {
                        ctx.getImageData(0, 0, canvas.width, canvas.height);
                    }
                }
                return canvas;
            }
            catch (e) {
                this.context.logger.info("Unable to clone video as it is tainted", video);
            }
            var blankCanvas = video.ownerDocument.createElement('canvas');
            blankCanvas.width = video.offsetWidth;
            blankCanvas.height = video.offsetHeight;
            return blankCanvas;
        };

In this mod just the left and top vars are obtained, and then passed to ctx.drawImage. This is a quick solution, some check should probably be made to make sure those properties make sense (for example transforming them to pixels if they are percentaje, etc)