diff --git a/README.md b/README.md index 15441f6..efe6ef7 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,13 @@ seed: 42 ### Architecture - **Python Backend**: Image loading and processing using PIL/Pillow - **JavaScript Frontend**: File picker with FileReader API for browser-based file access -- **Base64 Transfer**: Secure data transfer from browser to ComfyUI backend +- **Temp Upload**: Image uploaded to ComfyUI temp storage; widget stores a small reference string ### Browser Limitations Due to browser security restrictions, the file picker: - Cannot access full file system paths - Uses FileReader API to read files directly in browser -- Transfers image data as base64-encoded strings +- Uploads the image to ComfyUI temp storage and stores a small reference string (avoids workflow JSON bloat) - Works completely client-side until execution ### Output Format diff --git a/random_image_picker.py b/random_image_picker.py index 852f944..36be327 100644 --- a/random_image_picker.py +++ b/random_image_picker.py @@ -62,7 +62,7 @@ class RandomImagePicker(SaveImage): "image_data": ("STRING", { "default": "", "multiline": True, - "tooltip": "Base64 image data from file picker (auto-filled)" + "tooltip": "Image reference (temp) from file picker (auto-filled)" }), } } @@ -179,40 +179,45 @@ class RandomImagePicker(SaveImage): "Please use the 📁 Choose File button to select an image." ) - import base64 - import io - - try: - # Remove data URL prefix if present - if ',' in image_data: + if image_data.startswith("data:"): + # Backward compatibility: base64 data URL from older versions + import base64 + import io + + try: + # Remove data URL prefix if present image_data = image_data.split(',', 1)[1] - - # Decode base64 - img_bytes = base64.b64decode(image_data) - img = Image.open(io.BytesIO(img_bytes)) - - # 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 - img_tensor = torch.from_numpy(img_array)[None,] - - print(f"[Random Image Picker] Mode: Single (File Picker)") - print(f"[Random Image Picker] Resolution: {width}x{height}") - - # Save for preview and return with image tensor - preview = self.save_images(img_tensor, filename_prefix="RandomPicker") - return {"ui": preview["ui"], "result": (img_tensor,)} - - except Exception as e: - raise ValueError(f"Failed to load image from file picker: {str(e)}") + + # Decode base64 + img_bytes = base64.b64decode(image_data) + img = Image.open(io.BytesIO(img_bytes)) + + # 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 + img_tensor = torch.from_numpy(img_array)[None,] + + except Exception as e: + raise ValueError(f"Failed to load image from file picker: {str(e)}") + else: + # New path: resolve temp image reference (e.g. "name.png [temp]") + image_path = folder_paths.get_annotated_filepath(image_data) + img_tensor, width, height = self.load_image_file(image_path) + + print(f"[Random Image Picker] Mode: Single (File Picker)") + print(f"[Random Image Picker] Resolution: {width}x{height}") + + # Save for preview and return with image tensor + preview = self.save_images(img_tensor, filename_prefix="RandomPicker") + return {"ui": preview["ui"], "result": (img_tensor,)} # Node registration diff --git a/web/random_image_picker.js b/web/random_image_picker.js index 4fef985..5506d3a 100644 --- a/web/random_image_picker.js +++ b/web/random_image_picker.js @@ -28,7 +28,7 @@ app.registerExtension({ input.type = "file"; input.accept = "image/png,image/jpeg,image/jpg,image/webp,image/bmp,image/gif"; - input.onchange = (e) => { + input.onchange = async (e) => { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; @@ -38,28 +38,41 @@ app.registerExtension({ folderModeWidget.value = false; } - // Read file as base64 - const reader = new FileReader(); - reader.onload = (event) => { - const base64Data = event.target.result; + try { + // Upload image to ComfyUI temp storage + const body = new FormData(); + body.append('image', file); + body.append('type', 'temp'); - // Store image_data in widget - let imageDataWidget = node.widgets.find(w => w.name === "image_data"); - if (imageDataWidget) { - imageDataWidget.value = base64Data; + const api = app.api; + const fetchFn = api.apiFetch ? api.apiFetch.bind(api) : api.fetchApi.bind(api); + const resp = await fetchFn('/upload/image', { method: 'POST', body }); + if (resp.status !== 200) { + throw new Error(`Upload failed with status ${resp.status}`); } - // Show instant preview + const data = await resp.json(); + + // Store reference string in widget (not base64) + const path = data.subfolder ? `${data.subfolder}/${data.name}` : data.name; + const ref = `${path} [temp]`; + + let imageDataWidget = node.widgets.find(w => w.name === "image_data"); + if (imageDataWidget) { + imageDataWidget.value = ref; + } + + // Show instant preview from temp storage const img = new Image(); img.onload = () => { node.imgs = [img]; node.setSizeForImage?.(); app.graph.setDirtyCanvas(true); }; - img.src = base64Data; - }; - - reader.readAsDataURL(file); + img.src = api.apiURL('/view?filename=' + encodeURIComponent(data.name) + '&type=temp&subfolder=' + encodeURIComponent(data.subfolder || '')); + } catch (err) { + console.error("[Random Image Picker] Upload failed:", err); + } } };