Initial implementation of Random Image Picker node

- Single image and folder random selection modes
- Subfolder scanning support
- Resolution output (width/height)
- Seed control for reproducible random selection
- Support for PNG, JPEG, WebP, BMP, GIF formats
This commit is contained in:
solidlime
2026-01-07 20:09:11 +09:00
commit 1f3bfe02ef
12 changed files with 507 additions and 0 deletions
View File
+1
View File
@@ -0,0 +1 @@
/cache
@@ -0,0 +1,35 @@
# Code Style and Conventions
## Naming Conventions
- **Classes**: PascalCase (例: `RandomImagePicker`)
- **Functions/Methods**: snake_case (例: `load_image`, `get_image_files`)
- **Constants**: UPPER_SNAKE_CASE (例: `NODE_CLASS_MAPPINGS`)
- **Private methods**: アンダースコアなし(staticmethodを活用)
## Type Hints
- **使用**: 全ての関数/メソッドパラメータと戻り値に型ヒントを使用
- **例**: `def load_image_file(image_path: str) -> Tuple[torch.Tensor, int, int]:`
## Docstrings
- **スタイル**: Google style docstrings
- **必須箇所**:
- すべてのクラス
- すべてのpublicメソッド/関数
- staticmethod
- **内容**:
- 簡潔な説明
- Args: 引数の説明
- Returns: 戻り値の説明
## Import Order
1. 標準ライブラリ
2. サードパーティライブラリ
3. ComfyUI関連
4. ローカルモジュール
## ComfyUI Specific
- **INPUT_TYPES**: classmethodで定義、辞書形式で入力パラメータを定義
- **RETURN_TYPES**: タプル形式で出力型を定義
- **RETURN_NAMES**: タプル形式で出力名を定義
- **FUNCTION**: 実行される関数名を文字列で指定
- **CATEGORY**: ノードのカテゴリを文字列で指定
+32
View File
@@ -0,0 +1,32 @@
# Codebase Structure
## Directory Layout
```
Comfyui-Random_Image_Picker/
├── .github/
│ └── copilot-instructions.md # AI assistant instructions
├── .serena/ # Serena project config
├── __init__.py # Package entry point
└── random_image_picker.py # Main node implementation
```
## File Descriptions
### `__init__.py`
- パッケージのエントリーポイント
- `NODE_CLASS_MAPPINGS`と`NODE_DISPLAY_NAME_MAPPINGS`をインポートしてエクスポート
- ComfyUIがカスタムノードを認識するために必要
### `random_image_picker.py`
- メインの実装ファイル
- `RandomImagePicker`クラス: ノードの本体
- `INPUT_TYPES()`: 入力パラメータの定義
- `get_image_files()`: 画像ファイルのリスト取得
- `load_image_file()`: 画像ファイルの読み込みとテンソル変換
- `load_image()`: メイン処理(モードに応じた画像読み込み)
- ノード登録用の定数
## Future Extensions
- 追加の画像処理機能
- フィルタリングオプション
- プレビュー機能
+22
View File
@@ -0,0 +1,22 @@
# Project Purpose
**Project Name**: Comfyui-Random_Image_Picker
## Overview
ComfyUIカスタムノード - ランダム画像選択機能
## Core Features
1. **単一画像ロード**: 指定された画像ファイルを読み込み
2. **フォルダランダムロード**: フォルダ内からランダムに画像を選択
3. **モード切り替え**: ボタンで単一/フォルダモードを切り替え
4. **サブフォルダスキャン**: オプションでサブフォルダも検索対象に
5. **解像度情報出力**: 画像と共にwidth, heightを出力
## Output
- IMAGE: ComfyUI形式の画像テンソル
- width: 画像の幅(整数)
- height: 画像の高さ(整数)
## Target System
- ComfyUI custom node
- Python-based implementation
+28
View File
@@ -0,0 +1,28 @@
# Suggested Commands
## Windows System Commands
- `ls` または `dir`: ディレクトリ内容の表示
- `cd <path>`: ディレクトリ移動
- `Get-Content <file>`: ファイル内容の表示
- `Select-String -Path <file> -Pattern <pattern>`: ファイル内検索
## Git Commands
- `git status`: 変更状況の確認
- `git add .`: 変更をステージング
- `git commit -m "message"`: コミット
- `git push`: リモートへプッシュ
## Python Development
- `python -m py_compile <file>`: Pythonファイルの構文チェック
- `python <file>`: Pythonスクリプトの実行
## ComfyUI Testing
- ComfyUIを起動してカスタムノードをテスト
- カスタムノードは `custom_nodes/Comfyui-Random_Image_Picker/` に配置
## Code Quality (推奨)
- **Black**: `python -m black <file>` - コードフォーマット
- **Flake8**: `python -m flake8 <file>` - リンティング
- **MyPy**: `python -m mypy <file>` - 型チェック
Note: これらのツールは必要に応じてインストール
@@ -0,0 +1,34 @@
# Task Completion Checklist
## タスク完了時の必須作業
### 1. コード品質チェック
- [ ] 構文エラーがないことを確認
- [ ] 型ヒントが正しく付与されているか
- [ ] Docstringsが適切に書かれているか
### 2. ComfyUI互換性
- [ ] `INPUT_TYPES`が正しく定義されているか
- [ ] `RETURN_TYPES`と`RETURN_NAMES`が一致しているか
- [ ] ノードの登録(`NODE_CLASS_MAPPINGS`)が正しいか
### 3. ドキュメント
- [ ] README.mdが最新の情報か
- [ ] 使用方法が明確に記載されているか
- [ ] 公開情報に個人情報が含まれていないか
### 4. Git管理
- [ ] 変更をコミット: `git add . && git commit -m "descriptive message"`
- [ ] 適切なタイミングでプッシュ: `git push`
### 5. テスト
- [ ] ComfyUIでノードが正しく読み込まれるか
- [ ] 単一画像モードが動作するか
- [ ] フォルダモードが動作するか
- [ ] サブフォルダスキャンが動作するか
- [ ] 出力(IMAGE, width, height)が正しいか
## 区切りのいいタイミング
- 機能追加完了時
- バグ修正完了時
- リファクタリング完了時
+23
View File
@@ -0,0 +1,23 @@
# Tech Stack
## Programming Language
- **Python 3.x**
## Dependencies
- **ComfyUI**: カスタムノードのベースシステム
- **PyTorch**: 画像テンソル処理
- **PIL (Pillow)**: 画像ファイル読み込み
- **NumPy**: 配列処理
- **folder_paths**: ComfyUI標準パス管理
## Supported Image Formats
- PNG (.png)
- JPEG (.jpg, .jpeg)
- WebP (.webp)
- BMP (.bmp)
- GIF (.gif)
## ComfyUI Node Structure
- `NODE_CLASS_MAPPINGS`: ノードクラスの登録辞書
- `NODE_DISPLAY_NAME_MAPPINGS`: 表示名の登録辞書
- `__init__.py`: エントリーポイント
+84
View File
@@ -0,0 +1,84 @@
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp csharp_omnisharp
# dart elixir elm erlang fortran go
# haskell java julia kotlin lua markdown
# nix perl php python python_jedi r
# rego ruby ruby_solargraph rust scala swift
# terraform typescript typescript_vts yaml zig
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# Special requirements:
# - csharp: Requires the presence of a .sln file in the project folder.
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- python
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# whether to use the project's gitignore file to ignore files
# Added on 2025-04-07
ignore_all_files_in_gitignore: true
# list of additional paths to ignore
# same syntax as gitignore, so you can use * and **
# Was previously called `ignored_dirs`, please update your config if you are using that.
# Added (renamed) on 2025-04-07
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
project_name: "Comfyui-Random_Image_Picker"
included_optional_tools: []
+99
View File
@@ -0,0 +1,99 @@
# Random Image Picker - ComfyUI Custom Node
A ComfyUI custom node that provides flexible image loading with support for both single file and random folder selection.
## Features
- **Single Image Mode**: Load a specific image file
- **Folder Mode**: Randomly select an image from a folder
- **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
## Installation
1. Clone or download this repository to your ComfyUI custom nodes directory:
```bash
cd ComfyUI/custom_nodes
git clone <repository-url> Comfyui-Random_Image_Picker
```
2. Restart ComfyUI
## Usage
### Node Inputs
- **path** (STRING):
- In Single mode: Full path to an image file
- In Folder mode: Full path to a folder containing images
- **folder_mode** (BOOLEAN):
- `OFF` (Single): Load the specified image file
- `ON` (Folder): Randomly select an image from the folder
- **include_subfolders** (BOOLEAN):
- `OFF`: Only scan the specified folder
- `ON`: Include all subfolders in the search
- **seed** (INT):
- Random seed for reproducible image selection in Folder mode
- Range: 0 to 18446744073709551615
### Node Outputs
- **IMAGE**: The loaded image in ComfyUI tensor format
- **width** (INT): Image width in pixels
- **height** (INT): Image height in pixels
### Supported Image Formats
- PNG (.png)
- JPEG (.jpg, .jpeg)
- WebP (.webp)
- BMP (.bmp)
- GIF (.gif)
## Examples
### Single Image Mode
```
path: D:/images/photo.png
folder_mode: OFF
include_subfolders: OFF
seed: 0
```
Loads the specific image at `D:/images/photo.png`
### Random Folder Mode
```
path: D:/images/
folder_mode: ON
include_subfolders: OFF
seed: 42
```
Randomly selects one image from `D:/images/` (excluding subfolders)
### Random with Subfolders
```
path: D:/images/
folder_mode: ON
include_subfolders: ON
seed: 42
```
Randomly selects one image from `D:/images/` and all its subfolders
## Technical Details
- Images are converted to RGB format
- Output tensor format: `[batch, height, width, channels]`
- Pixel values normalized to 0.0-1.0 range
- Uses PyTorch tensors for ComfyUI compatibility
## License
MIT License
## Author
Created for ComfyUI
+8
View File
@@ -0,0 +1,8 @@
"""
Random Image Picker Node for ComfyUI
Loads single images or random images from folders
"""
from .random_image_picker import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
+141
View File
@@ -0,0 +1,141 @@
"""
Random Image Picker Node Implementation
"""
import os
import random
from pathlib import Path
from typing import Tuple, List
import folder_paths
from PIL import Image
import numpy as np
import torch
class RandomImagePicker:
"""
ComfyUI node that loads either a single image or a random image from a folder.
Supports subfolder scanning and outputs image with resolution information.
"""
@classmethod
def INPUT_TYPES(cls):
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}),
},
}
RETURN_TYPES = ("IMAGE", "INT", "INT")
RETURN_NAMES = ("IMAGE", "width", "height")
FUNCTION = "load_image"
CATEGORY = "image"
@staticmethod
def get_image_files(directory: str, include_subfolders: bool = False) -> List[str]:
"""
Get all image files from a directory.
Args:
directory: Directory path to scan
include_subfolders: Whether to include subfolders in the scan
Returns:
List of image file paths
"""
supported_formats = {'.png', '.jpg', '.jpeg', '.webp', '.bmp', '.gif'}
image_files = []
if include_subfolders:
for root, _, files in os.walk(directory):
for file in files:
if Path(file).suffix.lower() in supported_formats:
image_files.append(os.path.join(root, file))
else:
for file in os.listdir(directory):
file_path = os.path.join(directory, file)
if os.path.isfile(file_path) and Path(file).suffix.lower() in supported_formats:
image_files.append(file_path)
return image_files
@staticmethod
def load_image_file(image_path: str) -> Tuple[torch.Tensor, int, int]:
"""
Load an image file and convert to ComfyUI format.
Args:
image_path: Path to the image file
Returns:
Tuple of (image_tensor, width, height)
"""
img = Image.open(image_path)
# Convert to RGB if needed
if img.mode != 'RGB':
img = img.convert('RGB')
# Get dimensions
width, height = img.size
# Convert to numpy array
img_array = np.array(img).astype(np.float32) / 255.0
# Convert to torch tensor and add batch dimension
# ComfyUI expects [batch, height, width, channels]
img_tensor = torch.from_numpy(img_array)[None,]
return img_tensor, width, height
def load_image(self, path: str, folder_mode: bool, include_subfolders: bool, seed: int):
"""
Load image based on mode settings.
Args:
path: File or folder path
folder_mode: True for folder mode, False for single file mode
include_subfolders: Whether to scan subfolders
seed: Random seed for folder mode
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 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}")
image_files = self.get_image_files(path, include_subfolders)
if not image_files:
raise ValueError(f"No image files found in directory: {path}")
# Use seed for reproducible random selection
random.seed(seed)
selected_image = random.choice(image_files)
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}")
return self.load_image_file(path)
# Node registration
NODE_CLASS_MAPPINGS = {
"RandomImagePicker": RandomImagePicker
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RandomImagePicker": "Random Image Picker"
}