提问人:Smitty-Werben-Jager-Manjenson 提问时间:10/31/2023 更新时间:11/1/2023 访问量:46
使用未保存的网络摄像头图像设置 Fabric.js 画布背景
Setting Fabric.js canvas background with unsaved webcam image
问:
我正在使用 Media Capture and Streams API 初始化网络摄像头,并允许用户从网络摄像头流中捕获照片。我也在尝试使用Fabric.js,允许用户编辑/标记照片。我的 HTML 有一个 canvas 元素和一个 video 元素,如下所示:
<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 对象添加到我的现有对象而不会使图像消失,或者需要一种使用 Fabric.js 和尚未保存在任何地方的图像设置画布背景的方法。<canvas>
答:
0赞
waffentrager
11/1/2023
#1
我目前无法使用相机,但我在 mp4 视频上测试了我的代码,并在后台显示视频,我还可以在视频运行时移动红色方块,一切正常。
我编写了一个类并在 render 方法 - 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);
}
但我不建议这样做
评论