187 lines
6.1 KiB
JavaScript
187 lines
6.1 KiB
JavaScript
import { app } from "../../../scripts/app.js";
|
|
import { api } from "../../../scripts/api.js";
|
|
import { $el } from "../../../scripts/ui.js";
|
|
|
|
function get_position_style(ctx, widget_width, y, node_height) {
|
|
const MARGIN = 4; // the margin around the html element
|
|
|
|
/* Create a transform that deals with all the scrolling and zooming */
|
|
const elRect = ctx.canvas.getBoundingClientRect();
|
|
const transform = new DOMMatrix()
|
|
.scaleSelf(
|
|
elRect.width / ctx.canvas.width,
|
|
elRect.height / ctx.canvas.height
|
|
)
|
|
.multiplySelf(ctx.getTransform())
|
|
.translateSelf(MARGIN, MARGIN + y);
|
|
|
|
return {
|
|
transformOrigin: "0 0",
|
|
transform: transform,
|
|
left: `0px`,
|
|
top: `0px`,
|
|
position: "absolute",
|
|
maxWidth: `${widget_width - MARGIN * 2}px`,
|
|
maxHeight: `${node_height - MARGIN * 2}px`,
|
|
width: `auto`,
|
|
height: `auto`,
|
|
};
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "webcam.capture.extension",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
if (nodeType.comfyClass == "webcam_capture_node") {
|
|
console.log("Starting webcam capture extension");
|
|
const orig_nodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
console.log("webcam node created");
|
|
|
|
const widget0 = {
|
|
name: "webcam_selector",
|
|
draw(ctx, node, widget_width, y) {
|
|
Object.assign(
|
|
this.inputEl.style,
|
|
get_position_style(ctx, widget_width, y, node.size[1])
|
|
);
|
|
},
|
|
inputEl: document.createElement("select"),
|
|
};
|
|
|
|
const widget = {
|
|
name: "webcam",
|
|
draw(ctx, node, widget_width, y) {
|
|
Object.assign(
|
|
this.inputEl.style,
|
|
get_position_style(ctx, widget_width, y, node.size[1])
|
|
);
|
|
},
|
|
inputEl: document.createElement("button"),
|
|
};
|
|
|
|
const widget2 = {
|
|
name: "webcam_image",
|
|
draw(ctx, node, widget_width, y) {
|
|
Object.assign(
|
|
this.inputEl.style,
|
|
get_position_style(ctx, widget_width, y + 50, node.size[1])
|
|
);
|
|
},
|
|
inputEl: document.createElement("img"),
|
|
};
|
|
|
|
const widget3 = {
|
|
name: "webcam_stop",
|
|
draw(ctx, node, widget_width, y) {
|
|
Object.assign(
|
|
this.inputEl.style,
|
|
get_position_style(ctx, widget_width, y, node.size[1])
|
|
);
|
|
},
|
|
inputEl: document.createElement("button"),
|
|
};
|
|
|
|
widget.inputEl.textContent = "Start Capture";
|
|
widget.inputEl.className = "start-capture";
|
|
|
|
widget3.inputEl.textContent = "Stop Capture";
|
|
widget3.inputEl.className = "stop-capture";
|
|
|
|
let captureInterval;
|
|
|
|
widget0.inputEl.onchange = async () => {
|
|
if (captureInterval) {
|
|
console.warn("Switching cameras while capturing is not supported.");
|
|
return;
|
|
}
|
|
// Change camera based on selected option
|
|
const videoConstraints = {
|
|
deviceId: { exact: widget0.inputEl.value }
|
|
};
|
|
console.log("Camera switched to:", videoConstraints.deviceId.exact);
|
|
};
|
|
|
|
// Fetch all video input devices
|
|
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
|
devices.forEach((device) => {
|
|
if (device.kind === "videoinput") {
|
|
const option = document.createElement("option");
|
|
option.value = device.deviceId;
|
|
option.text = device.label || `Camera ${widget0.inputEl.length + 1}`;
|
|
widget0.inputEl.appendChild(option);
|
|
}
|
|
});
|
|
});
|
|
|
|
widget.inputEl.onclick = async () => {
|
|
try {
|
|
const selectedDeviceId = widget0.inputEl.value;
|
|
const constraints = {
|
|
video: { deviceId: selectedDeviceId ? { exact: selectedDeviceId } : undefined },
|
|
audio: false
|
|
};
|
|
captureInterval = setInterval(async () => {
|
|
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
console.log(stream);
|
|
const video = document.createElement("video");
|
|
video.srcObject = stream;
|
|
video.play();
|
|
|
|
await new Promise((resolve) => (video.onplaying = resolve));
|
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
|
|
stream.getTracks().forEach((track) => track.stop());
|
|
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = video.videoWidth;
|
|
canvas.height = video.videoHeight;
|
|
const ctx = canvas.getContext("2d");
|
|
ctx.drawImage(video, 0, 0);
|
|
|
|
widget2.inputEl.src = canvas.toDataURL("image/png");
|
|
|
|
canvas.toBlob((blob) => {
|
|
api.fetchApi("/webcam_capture", {
|
|
method: "POST",
|
|
body: blob,
|
|
}).then((response) => response.json())
|
|
.then((data) => console.log(data))
|
|
.catch((error) => console.error("Error uploading image:", error));
|
|
});
|
|
}, 1000);
|
|
} catch (error) {
|
|
console.error("Error capturing image:", error);
|
|
}
|
|
};
|
|
|
|
widget3.inputEl.onclick = () => {
|
|
if (captureInterval) {
|
|
clearInterval(captureInterval);
|
|
captureInterval = null;
|
|
console.log("Capture stopped.");
|
|
}
|
|
};
|
|
|
|
document.body.appendChild(widget0.inputEl);
|
|
document.body.appendChild(widget.inputEl);
|
|
document.body.appendChild(widget2.inputEl);
|
|
document.body.appendChild(widget3.inputEl);
|
|
|
|
this.addCustomWidget(widget0);
|
|
this.addCustomWidget(widget);
|
|
this.addCustomWidget(widget2);
|
|
this.addCustomWidget(widget3);
|
|
this.onRemoved = function () {
|
|
widget0.inputEl.remove();
|
|
widget.inputEl.remove();
|
|
widget2.inputEl.remove();
|
|
widget3.inputEl.remove();
|
|
};
|
|
this.serialize_widgets = false;
|
|
|
|
orig_nodeCreated?.apply(this, arguments);
|
|
};
|
|
}
|
|
},
|
|
});
|