Files
rgthree-rgthree-comfy/web/image_comparer.js
T

191 lines
7.6 KiB
JavaScript

import { app } from "/scripts/app.js";
import { api } from "/scripts/api.js";
import { RgthreeBaseServerNode } from "./base_node.js";
import { NodeTypesString } from "./constants.js";
import { addConnectionLayoutSupport } from "./utils.js";
export class RgthreeImageComparer extends RgthreeBaseServerNode {
constructor(title = RgthreeImageComparer.title) {
super(title);
this.imageIndex = 0;
this.imgs = [];
this.serialize_widgets = true;
this.isPointerDown = false;
this.isPointerOver = false;
this.pointerOverPos = [0, 0];
this.canvasWidget = null;
this.properties['comparer_mode'] = 'Slide';
}
onExecuted(output) {
var _a;
(_a = super.onExecuted) === null || _a === void 0 ? void 0 : _a.call(this, output);
this.canvasWidget.value = (output.images || []).map((d) => api.apiURL(`/view?filename=${encodeURIComponent(d.filename)}&type=${d.type}&subfolder=${d.subfolder}${app.getPreviewFormatParam()}${app.getRandParam()}`));
}
drawWidgetImage(ctx, image, y, cropX) {
if (!(image === null || image === void 0 ? void 0 : image.naturalWidth) || !(image === null || image === void 0 ? void 0 : image.naturalHeight)) {
return;
}
let [nodeWidth, nodeHeight] = this.size;
const imageAspect = image.naturalWidth / image.naturalHeight;
let height = nodeHeight - y;
const widgetAspect = nodeWidth / height;
let targetWidth, targetHeight;
let offsetX = 0;
if (imageAspect > widgetAspect) {
targetWidth = nodeWidth;
targetHeight = nodeWidth / imageAspect;
}
else {
targetHeight = height;
targetWidth = height * imageAspect;
offsetX = (nodeWidth - targetWidth) / 2;
}
const widthMultiplier = image.naturalWidth / targetWidth;
const sourceX = 0;
const sourceY = 0;
const sourceWidth = cropX != null ? (cropX - offsetX) * widthMultiplier : image.naturalWidth;
const sourceHeight = image.naturalHeight;
const destX = (nodeWidth - targetWidth) / 2;
const destY = y + (height - targetHeight) / 2;
const destWidth = cropX != null ? (cropX - offsetX) : targetWidth;
const destHeight = targetHeight;
ctx.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
if (cropX != null
&& cropX >= (nodeWidth - targetWidth) / 2
&& cropX <= targetWidth + offsetX) {
let globalCompositeOperation = ctx.globalCompositeOperation;
ctx.globalCompositeOperation = "difference";
ctx.moveTo(cropX, destY);
ctx.lineTo(cropX, destY + destHeight);
ctx.strokeStyle = 'rgba(255,255,255, 1)';
ctx.stroke();
ctx.globalCompositeOperation = globalCompositeOperation;
}
}
onNodeCreated() {
const node = this;
const widget = {
type: "RGTHREE_CANVAS_COMPARER",
name: "CANVAS_COMPARER",
options: { serialize: false },
_value: [],
set value(v) {
this._value = v;
node.imgs = [];
if (v && v.length) {
for (let i = 0; i < 2; i++) {
let img = new Image();
img.src = v[i];
node.imgs.push(img);
}
}
},
get value() {
return this._value;
},
draw(ctx, node, width, y) {
var _a;
let [nodeWidth, nodeHeight] = node.size;
if (((_a = node.properties) === null || _a === void 0 ? void 0 : _a['comparer_mode']) === 'Click') {
const image = node.isPointerDown ? node.imgs[1] : node.imgs[0];
node.drawWidgetImage(ctx, image, y);
}
else {
node.drawWidgetImage(ctx, node.imgs[0], y);
if (node.isPointerOver) {
node.drawWidgetImage(ctx, node.imgs[1], y, node.pointerOverPos[0]);
}
}
},
computeSize(...args) {
return [128, 128];
},
};
this.canvasWidget = this.addCustomWidget(widget);
}
setIsPointerDown(down = this.isPointerDown) {
const newIsDown = down && !!app.canvas.pointer_is_down;
if (this.isPointerDown !== newIsDown) {
this.isPointerDown = newIsDown;
this.setDirtyCanvas(true, false);
}
this.imageIndex = this.isPointerDown ? 1 : 0;
if (this.isPointerDown) {
requestAnimationFrame(() => {
this.setIsPointerDown();
});
}
}
onMouseDown(event, pos, graphCanvas) {
var _a;
(_a = super.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(this, event, pos, graphCanvas);
this.setIsPointerDown(true);
}
onMouseEnter(event, pos, graphCanvas) {
var _a;
(_a = super.onMouseEnter) === null || _a === void 0 ? void 0 : _a.call(this, event, pos, graphCanvas);
this.setIsPointerDown(!!app.canvas.pointer_is_down);
this.isPointerOver = true;
}
onMouseLeave(event, pos, graphCanvas) {
var _a;
(_a = super.onMouseLeave) === null || _a === void 0 ? void 0 : _a.call(this, event, pos, graphCanvas);
this.setIsPointerDown(false);
this.isPointerOver = false;
}
onMouseMove(event, pos, graphCanvas) {
var _a;
(_a = super.onMouseMove) === null || _a === void 0 ? void 0 : _a.call(this, event, pos, graphCanvas);
this.pointerOverPos = [...pos];
}
getHelp() {
return `
<p>
The ${this.type.replace("(rgthree)", "")} node compares two images on top of each other.
Two images must be provided, either using both the <code>image_a</code> and
<code>image_b</code> inputs, or using the first two images in a <code>image_a</code> batch.
Note, only two images can be compared; if the inputs contain multiple batches, only the
first image of each batch will be shown.
</p>
<ul>
<li>
<p>
<strong>Properties.</strong> You can change the following properties (by right-clicking
on the node, and select "Properties" or "Properties Panel" from the menu):
</p>
<ul>
<li><p>
<code>comparer_mode</code> - Choose between "Slide" and "Click". Defaults to "Slide".
</p></li>
</ul>
</li>
</ul>`;
}
static setUp(comfyClass) {
RgthreeBaseServerNode.registerForOverride(comfyClass, RgthreeImageComparer);
addConnectionLayoutSupport(RgthreeBaseServerNode, app, [
["Left", "Right"],
["Right", "Left"],
]);
setTimeout(() => {
RgthreeImageComparer.category = comfyClass.category;
});
}
}
RgthreeImageComparer.title = NodeTypesString.IMAGE_COMPARER;
RgthreeImageComparer.type = NodeTypesString.IMAGE_COMPARER;
RgthreeImageComparer.comfyClass = NodeTypesString.IMAGE_COMPARER;
RgthreeImageComparer["@comparer_mode"] = {
type: "combo",
values: ["Slide", "Click"],
};
app.registerExtension({
name: "rgthree.ImageComparer",
async beforeRegisterNodeDef(nodeType, nodeData) {
if (nodeData.name === RgthreeImageComparer.type) {
RgthreeImageComparer.nodeType = nodeType;
RgthreeImageComparer.nodeData = nodeData;
RgthreeImageComparer.setUp(nodeType);
}
},
});