implement preview image, video and audio in combo list

Add option in settings show preview content in combo list
Change path to save pose image to input
update readme extras_nodes and pyprojects version.
This commit is contained in:
AlekPet
2024-10-13 12:41:14 +03:00
parent 99eb7b1b33
commit d5814dd0d3
5 changed files with 221 additions and 3 deletions
+4
View File
@@ -20,4 +20,8 @@
- Speech & Recognition speech
- Preview image, video and sound select list combo
![Preview image, video and audio select list combo](https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet/raw/master/ExtrasNode/extras_node_preview_img_vid_audio_combo.gif)
**Note** (Speech & Recognition speech): If your browser Firefox: go to `about:config`, find `media.webspeech.recognition.enable`, `media.webspeech.recognition.force_enable` set values ​​to `true`
Binary file not shown.

After

Width:  |  Height:  |  Size: 820 KiB

+214
View File
@@ -39,6 +39,11 @@ const SpeechAndRecognationSpeechLS = localStorage.getItem(
);
// end - Recognation & speech
// Preview image, video and audio select list combo
const PreviewImageVideoComboLS = localStorage.getItem(
`Comfy.Settings.${idExt}.PreviewImageVideoCombo`
);
// Settings set values from LS or default
let PreviewImageSize = PreviewImageSizeLS
? JSON.parse(PreviewImageSizeLS)
@@ -52,14 +57,212 @@ let PreviewImageSize = PreviewImageSizeLS
// Speech & Recognition widget settings
SpeechAndRecognationSpeech = SpeechAndRecognationSpeechLS
? JSON.parse(SpeechAndRecognationSpeechLS)
: true,
// Preview image, video and audio select list combo
PreviewImageVideoCombo = PreviewImageVideoComboLS
? JSON.parse(PreviewImageVideoComboLS)
: true;
// Preview image, video and audio content loading function
const SUPPORTS_FORMAT = {
image: ["jpg", "jpeg", "bmp", "png", "gif", "tiff", "avif"],
video: ["mp4", "webm"],
audio: ["ogg", "wav", "mp3"],
};
const loadingContent = (src) => {
return new Promise((res, rej) => {
let ext = src.slice(src.lastIndexOf(".") + 1).toLowerCase();
ext = /\w+/.exec(ext)[0];
if (SUPPORTS_FORMAT.image.includes(ext)) {
const img = new Image();
img.crossOrigin = "";
img.onload = (e) => res({ raw: img, type: "image", src });
img.onerror = (err) => rej(err);
img.src = src;
} else if (SUPPORTS_FORMAT.video.includes(ext)) {
const video = document.querySelector(".preview_vid");
video.onerror = (err) => rej(err);
video.addEventListener("canplay", (e) => {
res({ raw: video, type: "video", src });
});
video.src = src;
} else if (SUPPORTS_FORMAT.audio.includes(ext)) {
const audio = document.querySelector(".preview_audio");
audio.onerror = (err) => rej(err);
audio.addEventListener("canplaythrough", (e) => {
res({ raw: audio, type: "audio", src });
});
audio.src = src;
}
});
};
function drawVid(raw, canvas, ctx, type) {
ctx.drawImage(raw, 0, 0, canvas.width, canvas.height);
canvas.requanim = requestAnimationFrame(
drawVid.bind(this, raw, canvas, ctx, type)
);
}
//
// Register Extension
app.registerExtension({
name: idExt,
init() {
addStylesheet("css/extrasnode/extras_node_styles.css", import.meta.url);
// Preview image, video and audio select list combo
const addItem = LiteGraph.ContextMenu.prototype.addItem;
LiteGraph.ContextMenu.prototype.addItem = function () {
const element = addItem?.apply(this, arguments);
if (!PreviewImageVideoCombo) return;
const [name, value, options] = arguments;
if (value instanceof Object) return;
if (!this.root?.preview_content_combo) {
const preview_content_combo = $el(
"div.preview_content_combo",
{
style: {
position: "absolute",
maxWidth: "160px",
right: "calc(-1% - 160px)",
},
parent: this.root,
},
[
$el("canvas.preview_img", {
style: { width: "100%" },
}),
$el("video.preview_vid", {
style: { opacity: 0, width: 0, height: 0 },
crossOrigin: "anonymous",
autoplay: false,
muted: false,
preload: "auto",
}),
$el("audio.preview_audio", {
style: { opacity: 0, position: "absolute", left: 0 },
crossOrigin: "anonymous",
autoplay: false,
muted: false,
preload: "auto",
controls: true,
}),
]
);
this.root.preview_content_combo = preview_content_combo;
}
LiteGraph.pointerListenerAdd(element, "enter", (e) => {
if (element?.dataset?.value) {
const body_rect = document.body.getBoundingClientRect();
const root_rect = this.root.getBoundingClientRect();
const { x, y } = element.getBoundingClientRect();
const scale = app.graph.extra.ds.scale;
const canvas = this.root.preview_content_combo.children[0];
const ctx = canvas.getContext("2d");
loadingContent(
api.apiURL(
`/view?filename=${encodeURIComponent(
element.dataset.value
)}&type=input`
)
).then(({ raw, type, src }) => {
this.root.preview_content_combo.style.maxWidth =
type === "audio" ? "300px" : "160px";
const previewWidth = parseInt(
this.root.preview_content_combo.style.maxWidth
);
if (scale >= 1) {
this.root.preview_content_combo.style.top = `${
(y - root_rect.top) / scale
}px`;
} else {
this.root.preview_content_combo.style.top = `${
y - root_rect.top
}px`;
}
if (
body_rect.width &&
root_rect.right + previewWidth > body_rect.width
) {
this.root.preview_content_combo.style.left = `${
-previewWidth - 10
}px`;
this.root.preview_content_combo.style.right = "auto";
} else {
this.root.preview_content_combo.style.left = "auto";
this.root.preview_content_combo.style.right = `calc(-1% - ${this.root.preview_content_combo.style.maxWidth})`;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
const video = document.querySelector(".preview_vid");
const audio = document.querySelector(".preview_audio");
if (type === "image") {
canvas.width = raw.naturalWidth;
canvas.height = raw.naturalHeight;
if (!video.paused) {
video.pause();
video.currentTime = 0;
}
cancelAnimationFrame(canvas.requanim);
} else if (type === "video") {
canvas.width = raw.videoWidth;
canvas.height = raw.videoHeight;
video.play();
} else if (type === "audio") {
Object.assign(audio.style, {
opacity: 1,
});
audio.play();
}
if (type === "video" || type === "image") {
Object.assign(audio.style, {
opacity: 0,
});
!audio.paused && audio.pause();
ctx.drawImage(raw, 0, 0, canvas.width, canvas.height);
}
if (type === "video")
canvas.requanim = requestAnimationFrame(
drawVid.bind(this, raw, canvas, ctx, type)
);
});
}
});
LiteGraph.pointerListenerAdd(element, "leave", (e) => {
if (element?.dataset?.value) {
const canvas = this.root.preview_content_combo.children[0];
const video = document.querySelector(".preview_vid");
if (!video.paused) {
video.pause();
video.currentTime = 0;
}
cancelAnimationFrame(canvas.requanim);
}
});
};
// PreviewImage settings ui
app.ui.settings.addSetting({
id: `${idExt}.PreviewImage`,
@@ -242,6 +445,17 @@ app.registerExtension({
]);
},
});
// Preview image, video and audio settings ui
app.ui.settings.addSetting({
id: `${idExt}.PreviewImageVideoCombo`,
name: "🔸 Preview images and videos in the list",
defaultValue: true,
type: "boolean",
onChange(value) {
PreviewImageVideoCombo = value;
},
});
},
async beforeRegisterNodeDef(nodeType, nodeData, app) {
// --- Preview Text Node
+2 -2
View File
@@ -2,7 +2,7 @@
* Title: Set Poses in ComflyUI from ControlNet
* Author: AlekPet
* Description: I rewrote the main.js file as a class, from fkunn1326's openpose-editor (https://github.com/fkunn1326/openpose-editor/blob/master/javascript/main.js)
* Version: 2024.07.21
* Version: 2024.10.13
* Github: https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet
*/
@@ -492,7 +492,7 @@ class OpenPose {
let formData = new FormData();
formData.append("image", blob, fileName);
formData.append("overwrite", "true");
formData.append("type", "temp");
formData.append("type", "input");
uploadFile(formData);
}, "image/png");
// - end
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_custom_nodes_alekpet"
description = "Nodes: PoseNode, PainterNode, TranslateTextNode, TranslateCLIPTextEncodeNode, DeepTranslatorTextNode, DeepTranslatorCLIPTextEncodeNode, ArgosTranslateTextNode, ArgosTranslateCLIPTextEncodeNode, PreviewTextNode, HexToHueNode, ColorsCorrectNode, IDENode."
version = "1.0.29.1"
version = "1.0.29.3"
license = { file = "LICENSE" }
[project.urls]