Skip to content

Commit

Permalink
implement preview image, video and audio in combo list
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AlekPet committed Oct 13, 2024
1 parent 99eb7b1 commit d5814dd
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 3 deletions.
4 changes: 4 additions & 0 deletions ExtrasNode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
214 changes: 214 additions & 0 deletions ExtrasNode/js/extras_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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`,
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions PoseNode/js/pose_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -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]
Expand Down

0 comments on commit d5814dd

Please sign in to comment.