Add preview and file browser features

Features:
- Added OUTPUT_NODE for real-time image preview
- Implemented Browse button with JavaScript widget
- Enhanced path input with placeholder and default value
- Updated README with new feature documentation

Changes:
- random_image_picker.py: Added OUTPUT_NODE, improved INPUT_TYPES
- web/random_image_picker.js: New custom widget for file/folder selection
- README.md: Updated documentation with new features
- .gitignore: Added web directory ignore patterns
This commit is contained in:
solidlime
2026-01-07 20:49:47 +09:00
parent 1f3bfe02ef
commit a990101377
4 changed files with 140 additions and 5 deletions
+24
View File
@@ -0,0 +1,24 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# Virtual environments
venv/
env/
ENV/
# IDEs
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Project specific
*.log
+18 -1
View File
@@ -9,6 +9,8 @@ A ComfyUI custom node that provides flexible image loading with support for both
- **Subfolder Support**: Option to include subfolders in the search
- **Resolution Output**: Automatically outputs image width and height
- **Reproducible Random**: Seed control for consistent random selection
- **🆕 Image Preview**: Real-time preview of loaded images in the UI
- **🆕 File Browser**: Convenient "Browse..." button for file/folder selection
## Installation
@@ -20,6 +22,16 @@ A ComfyUI custom node that provides flexible image loading with support for both
2. Restart ComfyUI
3. The node will appear in the "image" category as "Random Image Picker"
## Usage Tips
- **Using the Browse Button**: Click "Browse..." to open your system's file/folder selector
- Note: Due to browser security limitations, you may need to manually enter the full path
- **Default Path**: The input field defaults to your ComfyUI input directory
- **Path Format**: Use forward slashes `/` or double backslashes `\\` on Windows
- **Preview**: The loaded image automatically appears in the node's preview area
## Usage
### Node Inputs
@@ -27,10 +39,13 @@ A ComfyUI custom node that provides flexible image loading with support for both
- **path** (STRING):
- In Single mode: Full path to an image file
- In Folder mode: Full path to a folder containing images
- 🆕 **Browse Button**: Click "Browse..." to select files/folders using your file explorer
- Default: ComfyUI input directory
- **folder_mode** (BOOLEAN):
- `OFF` (Single): Load the specified image file
- `ON` (Folder): Randomly select an image from the folder
- Note: The browse dialog changes based on this setting
- **include_subfolders** (BOOLEAN):
- `OFF`: Only scan the specified folder
@@ -42,7 +57,7 @@ A ComfyUI custom node that provides flexible image loading with support for both
### Node Outputs
- **IMAGE**: The loaded image in ComfyUI tensor format
- **IMAGE**: The loaded image in ComfyUI tensor format (with real-time preview)
- **width** (INT): Image width in pixels
- **height** (INT): Image height in pixels
@@ -89,6 +104,8 @@ Randomly selects one image from `D:/images/` and all its subfolders
- Output tensor format: `[batch, height, width, channels]`
- Pixel values normalized to 0.0-1.0 range
- Uses PyTorch tensors for ComfyUI compatibility
- Real-time preview in ComfyUI UI (OUTPUT_NODE enabled)
- Custom JavaScript widget for enhanced file selection
## License
+27 -4
View File
@@ -20,12 +20,34 @@ class RandomImagePicker:
@classmethod
def INPUT_TYPES(cls):
# Get default input directory from ComfyUI
try:
default_path = folder_paths.get_input_directory()
except:
default_path = ""
return {
"required": {
"path": ("STRING", {"default": "", "multiline": False}),
"folder_mode": ("BOOLEAN", {"default": False, "label_on": "Folder", "label_off": "Single"}),
"include_subfolders": ("BOOLEAN", {"default": False, "label_on": "ON", "label_off": "OFF"}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"path": ("STRING", {
"default": default_path,
"multiline": False,
"placeholder": "Path to image file or folder"
}),
"folder_mode": ("BOOLEAN", {
"default": False,
"label_on": "Folder",
"label_off": "Single"
}),
"include_subfolders": ("BOOLEAN", {
"default": False,
"label_on": "ON",
"label_off": "OFF"
}),
"seed": ("INT", {
"default": 0,
"min": 0,
"max": 0xffffffffffffffff
}),
},
}
@@ -33,6 +55,7 @@ class RandomImagePicker:
RETURN_NAMES = ("IMAGE", "width", "height")
FUNCTION = "load_image"
CATEGORY = "image"
OUTPUT_NODE = True
@staticmethod
def get_image_files(directory: str, include_subfolders: bool = False) -> List[str]:
+71
View File
@@ -0,0 +1,71 @@
import { app } from "../../scripts/app.js";
app.registerExtension({
name: "Comfy.RandomImagePicker",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "RandomImagePicker") {
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const result = onNodeCreated?.apply(this, arguments);
// 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();
});
// Add helper text
this.addWidget("text", "helper", "Tip: Enter full path or use ComfyUI input folder", () => {}, {
serialize: false
});
}
return result;
};
}
}
});