Files
CraftopiaStudio-ComfyUI-Cra…/js/smart_resize.js
T
rubz c0609cfc85 add Smart Profile Switch, fix folder picker, README overhaul, v1.0.2
- rename Smart Category Config → Smart Profile Switch 🧩 (code, JS, locales, demo workflow)
- add banner.svg and embed it at the top of README
- replace fragile OpenFileDialog folder-browse hack with native IFileDialog/FOS_PICKFOLDERS picker — fixes wrong-folder bug on single-click select
- flip Smart Resize's upscale_if_smaller default to true — node now resizes to target by default, as the name implies
- add width/height source tooltip to Smart Resolution Multiplier's image input
- fix stale widgets_values in smart_batch_resize_demo.json (10 fields → 13 after prefix/counter fields were added)
- full README rewrite: correct inputs/defaults/outputs for all 5 nodes, new Smart Profile Switch section, Example workflows section, expanded "Why these nodes?"
- add new example workflow (seedvr2_smartresize_demo.json), updated screenshots
- add assets/*.ai to .gitignore
- bump version to 1.0.2
2026-07-01 12:33:32 +02:00

90 lines
3.4 KiB
JavaScript

import { app } from "../../scripts/app.js";
app.registerExtension({
name: "Craftopia.SmartResize",
async nodeCreated(node) {
if (node.comfyClass !== "SmartResize") return;
const longestSideWidget = node.widgets?.find(w => w.name === "longest_side");
if (!longestSideWidget) return;
const PRESETS = [512, 768, 1024, 1536];
const presetWidget = node.addWidget("button", "size_presets", null, (value, canvas, node) => {
const gm = (canvas || app.canvas)?.graph_mouse;
if (!gm) return;
const lx = gm[0] - node.pos[0];
const ly = gm[1] - node.pos[1];
for (const r of presetWidget._rects) {
if (lx >= r.x1 && lx <= r.x2 && ly >= r.y1 && ly <= r.y2) {
longestSideWidget.value = r.size;
longestSideWidget.callback?.(r.size, app.canvas, node);
node.setDirtyCanvas(true);
return;
}
}
}, { serialize: false });
presetWidget.serialize = false;
presetWidget._rects = [];
presetWidget.draw = function (ctx, node, widgetWidth, y, height) {
const margin = 14;
const gap = 5;
const innerW = Math.max(40, widgetWidth - margin * 2);
const n = PRESETS.length;
const cellW = Math.max(10, (innerW - gap * (n - 1)) / n);
const h = Math.min(height - 2, 18);
const top = y + (height - h) / 2;
const current = longestSideWidget.value;
this._rects = [];
ctx.save();
ctx.font = "11px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
for (let i = 0; i < n; i++) {
const x = margin + i * (cellW + gap);
const active = Number(current) === PRESETS[i];
ctx.beginPath();
if (ctx.roundRect) ctx.roundRect(x, top, cellW, h, 4);
else ctx.rect(x, top, cellW, h);
ctx.fillStyle = active ? "#f28f41" : "#2a2a2a";
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = active ? "#f28f41" : "#555";
ctx.stroke();
ctx.fillStyle = active ? "#111" : "#ccc";
ctx.fillText(String(PRESETS[i]), x + cellW / 2, top + h / 2 + 0.5);
this._rects.push({ x1: x, x2: x + cellW, y1: top, y2: top + h, size: PRESETS[i] });
}
ctx.restore();
};
// Override serialize to exclude the non-serializable preset widget from
// widgets_values — same drift fix as SmartBatchResize (see that file for details).
const origSerialize = node.serialize;
node.serialize = function () {
const data = origSerialize.call(this);
if (data.widgets_values) {
data.widgets_values = this.widgets
.filter(w => w.serialize !== false && w.options?.serialize !== false)
.map(w => w.value);
}
return data;
};
// Move preset row to right after longest_side
const lsIdx = node.widgets.indexOf(longestSideWidget);
const pwIdx = node.widgets.indexOf(presetWidget);
if (pwIdx !== lsIdx + 1) {
node.widgets.splice(pwIdx, 1);
node.widgets.splice(lsIdx + 1, 0, presetWidget);
}
},
});