我正在使用 媒体捕获和流 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 和尚未保存在任何地方的图像设置画布背景的方法。
我目前无法使用相机,但我在 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);
}
但我不建议这样做