Refactor: Simplify file picker and auto-extract folder path

Major changes:
- Changed input parameter from 'path' to 'image' for clarity
- Auto-extract folder path from file selection in folder mode
- Simplified JavaScript widget implementation
- Added OUTPUT_IS_LIST flag for proper output handling
- Improved file selection UI with emoji icons
- Added helpful info widget explaining the modes

Features:
- Single mode: Load selected file directly
- Folder mode: Extract folder from selected file, then pick random image
- Better user feedback with console logging
- More robust path handling (file or directory input)
This commit is contained in:
solidlime
2026-01-07 20:59:15 +09:00
parent a990101377
commit aef43bd2f8
2 changed files with 68 additions and 68 deletions
+22 -14
View File
@@ -28,10 +28,9 @@ class RandomImagePicker:
return {
"required": {
"path": ("STRING", {
"image": ("STRING", {
"default": default_path,
"multiline": False,
"placeholder": "Path to image file or folder"
}),
"folder_mode": ("BOOLEAN", {
"default": False,
@@ -56,6 +55,7 @@ class RandomImagePicker:
FUNCTION = "load_image"
CATEGORY = "image"
OUTPUT_NODE = True
OUTPUT_IS_LIST = (False, False, False)
@staticmethod
def get_image_files(directory: str, include_subfolders: bool = False) -> List[str]:
@@ -114,12 +114,12 @@ class RandomImagePicker:
return img_tensor, width, height
def load_image(self, path: str, folder_mode: bool, include_subfolders: bool, seed: int):
def load_image(self, image: str, folder_mode: bool, include_subfolders: bool, seed: int):
"""
Load image based on mode settings.
Args:
path: File or folder path
image: File path (single mode) or file path to extract folder from (folder mode)
folder_mode: True for folder mode, False for single file mode
include_subfolders: Whether to scan subfolders
seed: Random seed for folder mode
@@ -127,31 +127,39 @@ class RandomImagePicker:
Returns:
Tuple of (image_tensor, width, height)
"""
if not path or not os.path.exists(path):
raise ValueError(f"Path does not exist: {path}")
if not image or not os.path.exists(image):
raise ValueError(f"Path does not exist: {image}")
if folder_mode:
# Folder mode: pick random image
if not os.path.isdir(path):
raise ValueError(f"Folder mode enabled but path is not a directory: {path}")
# Folder mode: extract folder from file path and pick random image
if os.path.isfile(image):
# Extract folder path from file path
folder_path = os.path.dirname(image)
elif os.path.isdir(image):
# Direct folder path
folder_path = image
else:
raise ValueError(f"Invalid path: {image}")
image_files = self.get_image_files(path, include_subfolders)
image_files = self.get_image_files(folder_path, include_subfolders)
if not image_files:
raise ValueError(f"No image files found in directory: {path}")
raise ValueError(f"No image files found in directory: {folder_path}")
# Use seed for reproducible random selection
random.seed(seed)
selected_image = random.choice(image_files)
print(f"[Random Image Picker] Folder: {folder_path}")
print(f"[Random Image Picker] Selected: {selected_image}")
return self.load_image_file(selected_image)
else:
# Single file mode
if not os.path.isfile(path):
raise ValueError(f"Single file mode enabled but path is not a file: {path}")
if not os.path.isfile(image):
raise ValueError(f"Single file mode enabled but path is not a file: {image}")
return self.load_image_file(path)
print(f"[Random Image Picker] Loading: {image}")
return self.load_image_file(image)
# Node registration
+46 -54
View File
@@ -1,4 +1,5 @@
import { app } from "../../scripts/app.js";
import { ComfyWidgets } from "../../scripts/widgets.js";
app.registerExtension({
name: "Comfy.RandomImagePicker",
@@ -8,63 +9,54 @@ app.registerExtension({
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const result = onNodeCreated?.apply(this, arguments);
const ret = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
// Add file browser button
const pathWidget = this.widgets.find(w => w.name === "path");
if (pathWidget) {
// Add button to open file dialog
const button = this.addWidget("button", "Browse...", null, () => {
// Create file input element
const input = document.createElement("input");
// Get folder_mode widget value
const folderModeWidget = this.widgets.find(w => w.name === "folder_mode");
const isFolderMode = folderModeWidget?.value || false;
if (isFolderMode) {
// Folder selection
input.type = "file";
input.webkitdirectory = true;
input.directory = true;
} else {
// File selection
input.type = "file";
input.accept = "image/png, image/jpeg, image/webp, image/bmp, image/gif";
}
input.onchange = (e) => {
if (e.target.files && e.target.files[0]) {
if (isFolderMode) {
// Get folder path from first file
const firstFile = e.target.files[0];
const fullPath = firstFile.webkitRelativePath || firstFile.name;
const folderPath = fullPath.split('/')[0];
pathWidget.value = folderPath;
} else {
// Get file path
const file = e.target.files[0];
// Note: For security reasons, browsers don't expose full file paths
// We can only get the file name, not the full path
// Users will need to manually enter the full path or use relative paths
pathWidget.value = file.name;
// Show info message
console.log("Note: Due to browser security, full path is not available. Please enter the complete path manually.");
}
}
};
input.click();
});
// Find the image widget
const imageWidget = this.widgets.find(w => w.name === "image");
if (!imageWidget) return ret;
// Create file input button widget
const fileWidget = this.addWidget("button", "📁 Choose File", "file", () => {
const input = document.createElement("input");
input.type = "file";
input.accept = "image/png,image/jpeg,image/jpg,image/webp,image/bmp,image/gif";
// Add helper text
this.addWidget("text", "helper", "Tip: Enter full path or use ComfyUI input folder", () => {}, {
serialize: false
});
}
input.onchange = (e) => {
if (e.target.files && e.target.files[0]) {
const file = e.target.files[0];
// Create a URL for the file
const reader = new FileReader();
reader.onload = (event) => {
// Get file path (name only, browser security limitation)
const fileName = file.name;
// Try to use the webkitRelativePath or fall back to name
const filePath = file.webkitRelativePath || file.path || fileName;
// Update the image widget value
imageWidget.value = filePath;
console.log("Selected file:", filePath);
// Show notification
app.ui.dialog.show(`File selected: ${fileName}\n\nNote: You may need to enter the full path manually due to browser security restrictions.`);
};
reader.readAsDataURL(file);
}
};
input.click();
});
return result;
// Add info widget
const infoWidget = this.addWidget("text", "ℹ️ Info",
"Single mode: Select any image file\nFolder mode: File's folder will be used",
() => {},
{ serialize: false }
);
return ret;
};
}
}