使用未保存的网络摄像头图像设置 Fabric.js 画布背景

问题描述 投票:0回答:1

我正在使用 媒体捕获和流 API 来初始化网络摄像头并允许用户从网络摄像头流中捕获照片。我还在尝试使用 Fabric.js 来允许用户编辑/标记照片。我的 HTML 有一个画布元素和一个视频元素,如下所示:

<canvas id="img-canvas"> </canvas>
<video id="img-stream" autoplay></video>

我像这样启动网络摄像头:

navigator.mediaDevices
    .getUserMedia(constraints)
    .then((stream) => {
        const videoTracks = stream.getVideoTracks();
        video.srcObject = stream;
    })
    .catch((error) => {
       // error
    });

并从实时动态中捕获照片,如下所示:

const context = canvas.getContext("2d");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
return canvas.toDataURL("image/png"); // returns a base64 string that can be used to set <img> src

并像这样初始化织物画布:

canvas = new fabric.Canvas("img-canvas");

我遇到的问题是使用 Fabric.js 将形状和其他织物对象添加到画布上。一旦我添加一些东西,我的形象就会消失。例如尝试添加一个圆圈:

canvas.add(new fabric.Circle({
    id: "circle1",
    left: canvas.width / 2,
    top: canvas.height / 2,
    fill: 'rgba(0,0,0,0)',
    stroke: 'red',
    width: 50,
    height: 50,
    originX: 'center',
    originY: 'center',
    strokeWidth: 3,
    radius: 20
}));

我也尝试过使用 Fabric.js 将画布的背景设置为图像,但似乎需要一个有效的 URL:

canvas.setBackgroundImage(imageData, canvas.renderAll.bind(canvas));

他们列出了设置添加采用实际

<img>
元素的图像的其他方法,因此我将
<img>
标签的源设置为
canvas.toDataURL("image/png")
结果(适用于
<img>
元素),但我仍然得到将图像添加到我的画布中:

var cvsimg = document.getElementById("captured-img");
var image = new fabric.Image(cvsimg, {
    opacity: 1,
    left: 0,
    top: 0,
});
canvas.add(image);

总之,我需要一种方法将 Fabric.js 对象添加到现有的

<canvas>
且图像不会消失,或者一种使用 Fabric.js 和尚未保存在任何地方的图像设置画布背景的方法。

javascript html canvas fabricjs
1个回答
0
投票

我目前无法使用相机,但我在 mp4 视频上测试了我的代码,并且视频显示在背景中,我还可以在视频运行时移动红色方块,一切都很好。

我编写了一个类并在渲染方法中编写 - drawImage 并将第一个对象添加到画布中

这是生成的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body, html {
            padding: 0;
            margin: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }

        canvas {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <video id="img-stream" src="video.mp4" controls autoplay></video>
    <canvas id="img-canvas"></canvas>

    <script src="fabric.min.js"></script>

    <script>
        var canvas = new fabric.Canvas('img-canvas', {
            backgroundColor: 'rgb(0,0,0)',
            selectionColor: 'rgba(100,100,100,0.3)', // selection with opacity 0.3
            selectionLineWidth: 2,
            width: window.outerWidth,
            height: window.outerHeight,
            viewportTransform: [1, 0, 0, 1, -window.outerWidth/2, -window.outerHeight/2],
            //stopContextMenu: true, // prevent the right-click context menu from appearing
            fireRightClick: true, // enable firing of right click events
            fireMiddleClick: true, // enable firing of middle click events

        });

        const video = document.getElementById("img-stream");

        var fabricBGStream = fabric.util.createClass(fabric.Object, {
            type: 'fabricBGStream',
    
            initialize: function () {
        
            },
    
            render: function (ctx) {
                ctx.save();
                //ctx.drawImage(video, -canvas.viewportTransform[4], -canvas.viewportTransform[5], canvas.width, canvas.height);
                ctx.drawImage(video, -canvas.viewportTransform[4], -canvas.viewportTransform[5], video.videoWidth, video.videoHeight);
                ctx.restore();
            }
        });

        var bg = new fabricBGStream();

        canvas.add(bg);

        var rec = new fabric.Rect({
            left: -canvas.viewportTransform[4],
            top: -canvas.viewportTransform[5],
            width: 100,
            height: 100,
            fill: 'red',
            stroke: 'red',
            strokeWidth: 2,
            selectable: true,
            evented: true,
            draggable: true,
            angle: 0
        });

        canvas.add(rec);

        canvas.renderAll();

        var requestVideo = null;

        function captureFrame() { 
            canvas.renderAll();
            requestVideo = requestAnimationFrame(captureFrame);
        }

        video.onplaying = function(e) {
            captureFrame();
        }

        video.addEventListener("play", function() {    
            //captureFrame();
        });

        video.addEventListener("pause", function() {
            window.cancelAnimationFrame(requestVideo);
        });

        
        if (navigator.mediaDevices.getUserMedia) {
            navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
                const videoTracks = stream.getVideoTracks();
                video.srcObject = stream;
                video.play();
            })
            .catch((error) => {
                // error
            });
        }
    </script>
</body>
</html>

您还可以重写内置的私有方法,而不是创建单独的类,如下所示:

canvas._renderBackground = function(ctx) {
    if (!this.backgroundColor) {
        return;
    }
    ctx.fillStyle = this.backgroundColor;
    ctx.fillRect(
        0,
        0,
        canvas.width,
        canvas.height
    );
    ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
    //ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
}

但我不建议这样做

© www.soinside.com 2019 - 2024. All rights reserved.