refactor of some nodes
This commit is contained in:
+26
-23
@@ -1,6 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## v1.2 (December 28, 2024)
|
||||
## v1.3
|
||||
|
||||
### Added
|
||||
- Resize modes for `QwenMultiReferenceHandler` to prevent image distortion
|
||||
- `match_first`: resize all to image1 dimensions (original behavior)
|
||||
- `common_height`: same height, preserve aspect ratios (recommended for concat)
|
||||
- `common_width`: same width, preserve aspect ratios
|
||||
- `largest_dims`: use largest dimensions found across images
|
||||
|
||||
### Changed
|
||||
- Simplified `QwenVLTextEncoder` by removing unnecessary resolution interface
|
||||
- Removed confusing resolution controls that didn't affect generation
|
||||
- Node now focuses on text encoding and vision processing
|
||||
- Returns clean `(conditioning,)` output like standard ComfyUI text encoders
|
||||
- Resolution controlled by proper nodes (Empty Latent, Multi-Reference Handler)
|
||||
|
||||
### Fixed
|
||||
- Multi-reference concat mode squishing images with different aspect ratios
|
||||
- Added smart resize logic before concatenation
|
||||
- Aspect ratio preservation prevents distortion
|
||||
- Maintains backward compatibility with existing workflows
|
||||
- Grid mode tensor size mismatch when using aspect-preserving resize modes
|
||||
- Grid now uses uniform dimensions to prevent concatenation errors
|
||||
- Calculates average aspect ratio for balanced proportions
|
||||
|
||||
## v1.2
|
||||
|
||||
### Added
|
||||
- Documentation for multi-reference spatial ordering (MULTI_REFERENCE_SPATIAL_ORDERING.md)
|
||||
@@ -60,25 +85,3 @@
|
||||
- Improved parameter tooltips with plain English descriptions
|
||||
- Reference method tooltips now explain each option clearly
|
||||
- Removed redundant Scale Image node from workflows (optimizer handles this internally)
|
||||
|
||||
### Fixed
|
||||
- RoPE (Rotary Position Embeddings) batch processing bug
|
||||
- Applied monkey patch from DiffSynth-Studio
|
||||
- Fixes issues with different image sizes in batch
|
||||
- Resolution optimizer selecting wrong aspect ratios
|
||||
- Now considers both pixel count and aspect ratio
|
||||
- Parameter order breaking backward compatibility
|
||||
- Moved new parameters to end of function signature
|
||||
- Double image scaling causing quality degradation
|
||||
- Removed redundant scaling in workflows
|
||||
|
||||
### Technical Details
|
||||
- Integrated fixes from DiffSynth-Studio and DiffSynth-Engine
|
||||
- Maintained compatibility with ComfyUI's CLIP infrastructure
|
||||
- Reference latents passed through conditioning metadata
|
||||
- Support for 36 official Qwen resolutions
|
||||
- 16-channel VAE latent support throughout
|
||||
|
||||
### Documentation
|
||||
- Created REFERENCE_METHODS_EXPLAINED.md for multi-reference usage
|
||||
- Added decision guides for common use cases
|
||||
|
||||
@@ -65,16 +65,18 @@ ComfyUI nodes for the Qwen Image Edit model and Qwen2.5-VL text encoder. Does *N
|
||||
- `QwenVLCLIPLoader` - Loads Qwen2.5-VL model with RoPE fix applied
|
||||
- `QwenVLTextEncoder` - Text encoder with:
|
||||
- Default Qwen formatting or custom Template Builder input
|
||||
- Resolution optimization with aspect ratio preservation (36 Qwen resolutions)
|
||||
- Optional multi-reference input accepts `QwenMultiReferenceHandler` output
|
||||
- Context image support for ControlNet-style conditioning
|
||||
- Resolution control: dropdown (36 Qwen resolutions), custom (exact dimensions)
|
||||
- Optional edit_image input for vision-based editing
|
||||
- Optional context_image input for ControlNet-style conditioning (separate from vision processing)
|
||||
- Width/height outputs for downstream workflow integration
|
||||
- Debug mode for troubleshooting
|
||||
- `QwenLowresFixNode` - Two-stage generation for quality improvement
|
||||
- `QwenMultiReferenceHandler` - Combines up to 4 images with:
|
||||
- Six resize modes: keep_proportion, stretch, resize, pad, pad_edge, crop
|
||||
- `QwenMultiReferenceHandler` - Combines up to 4 images with aspect ratio preservation:
|
||||
- Four resize modes: match_first, common_height, common_width, largest_dims
|
||||
- Five upscale methods: nearest-exact, bilinear, area, bicubic, lanczos
|
||||
- Four combination methods: index, offset, concat, grid
|
||||
- Weighted blending for offset method
|
||||
- Smart resizing prevents distortion in concat mode
|
||||
|
||||
**Helper Nodes:**
|
||||
- `QwenVLEmptyLatent` - Creates empty 16-channel latents
|
||||
@@ -119,17 +121,24 @@ ComfyUI nodes for the Qwen Image Edit model and Qwen2.5-VL text encoder. Does *N
|
||||
- Vision processing duplication bug (2x speedup via patch)
|
||||
- Template token dropping standardized (consistency with DiffSynth)
|
||||
- Template Builder for custom system prompts (removed duplicate from encoder)
|
||||
- Resolution optimization with aspect ratio preservation
|
||||
- Resolution optimization with improved aspect ratio matching
|
||||
- Two-stage refinement (Lowres Fix)
|
||||
- Debug mode for troubleshooting
|
||||
- Multi-reference image support (up to 4 images) with spatial positioning clarity
|
||||
- Context image support for ControlNet-style conditioning
|
||||
- Multi-reference image support with aspect ratio preservation
|
||||
- Context image support for ControlNet-style conditioning (separate from vision processing)
|
||||
- Width/height outputs from QwenVLTextEncoder for workflow integration
|
||||
- Simplified resolution interface (removed buggy auto mode, dropdown + custom only)
|
||||
- Fixed grid mode tensor mismatch in multi-reference handler
|
||||
|
||||
### Phase 1 Complete (December 2024)
|
||||
### Phase 1 Complete (January 2025)
|
||||
- Fixed vision processing duplication (2x performance improvement)
|
||||
- Standardized template token dropping for consistency with DiffSynth
|
||||
- Added context_image support for ControlNet-style workflows
|
||||
- Clarified multi-reference spatial behavior vs temporal frames
|
||||
- Added width/height outputs to QwenVLTextEncoder
|
||||
- Simplified resolution interface (removed confusing auto mode, dropdown/custom only)
|
||||
- Fixed multi-reference concat distortion with aspect ratio preservation
|
||||
- Fixed grid mode tensor mismatch when using aspect-preserving resize modes
|
||||
|
||||
### Remaining Implementation Plan
|
||||
|
||||
|
||||
@@ -1,28 +1,159 @@
|
||||
*Despite the name, this is becoming more of a Qwen Image Edit repo.*
|
||||
|
||||
# Overview
|
||||
ComfyUI nodes for Qwen2.5-VL and Qwen Image Edit models with enhanced template control.
|
||||
# ComfyUI Qwen Image Edit Nodes
|
||||
|
||||
ComfyUI nodes for Qwen-Image-Edit for system prompt modifications, with multi-reference support and other fun features.
|
||||
|
||||
## Multi-Reference Methods
|
||||
|
||||
The `QwenMultiReferenceHandler` offers three composition methods for combining images:
|
||||
|
||||
- **concat**: Side-by-side layout for character/object comparison. Best with `common_height` resize for aspect preservation.
|
||||
- **grid**: 2x2 layout for balanced influence of all references. Uses uniform dimensions to prevent tensor mismatches.
|
||||
- **offset**: Weighted blending creates single composite. Perfect for style transfer with adjustable influence via weights (e.g., `1.0,1.0,0.5,1.2`).
|
||||
|
||||
## Spatial Reference Tokens FYI
|
||||
|
||||
Qwen-Image-Edit includes precision control tokens for surgical editing:
|
||||
|
||||
- **`<|object_ref_start|>...<|object_ref_end|>`** - Reference specific objects by description
|
||||
- **`<|box_start|>x1,y1,x2,y2<|box_end|>`** - Target rectangular regions (normalized 0-1 coordinates)
|
||||
- **`<|quad_start|>x1,y1,x2,y2,x3,y3,x4,y4<|quad_end|>`** - Define complex quadrilateral areas
|
||||
|
||||
*[Examples and usage patterns →](#spatial-token-examples)*
|
||||
|
||||
## Core Nodes
|
||||
|
||||
### Text Encoding
|
||||
- **QwenVLCLIPLoader**: Loads Qwen2.5-VL models from `models/text_encoders/` folder
|
||||
- **QwenVLTextEncoder**: Enhanced encoder with flexible template control
|
||||
- `apply_template`: Enable/disable system templates
|
||||
- `token_removal`: Choose between auto (ComfyUI), diffsynth (fixed), or none
|
||||
- `mode`: Text-to-image or image_edit (defaults to image_edit)
|
||||
### QwenVLCLIPLoader
|
||||
Loads Qwen2.5-VL models with RoPE position embedding fixes.
|
||||
- **Use for:** Loading any Qwen2.5-VL model from `models/text_encoders/`
|
||||
- **Example:** Text-to-image, image editing workflows
|
||||
|
||||
### Template Building
|
||||
- **QwenTemplateBuilder**: Interactive template builder with presets
|
||||
- 9 presets including DiffSynth defaults, artistic, photorealistic, minimal edit
|
||||
- Custom template mode with system prompt control
|
||||
- Automatic vision token handling for image editing
|
||||
- **QwenTemplateBuilderV2**: Simplified Python-only version
|
||||
- All options visible, no JavaScript required
|
||||
- custom_t2i and custom_edit modes
|
||||
- **QwenTemplateConnector**: Bridges template builder to encoder
|
||||
### QwenVLTextEncoder
|
||||
Main text encoder with vision support and dual image inputs.
|
||||
- **edit_image:** Vision-processed image for semantic understanding
|
||||
- **context_image:** ControlNet-style spatial conditioning (no vision processing)
|
||||
- **Outputs:** conditioning
|
||||
- **Use for:** Text+image encoding with vision token processing
|
||||
- **Example:** "Change dress to red" (edit_image) + pose skeleton (context_image)
|
||||
|
||||
### Helper Nodes
|
||||
- **QwenOptimalResolution**: Auto-resizes images to nearest Qwen-preferred resolution
|
||||
- **QwenResolutionSelector**: Dropdown selector for Qwen resolutions
|
||||
- **QwenTokenInfo**: Reference display for special tokens
|
||||
### QwenMultiReferenceHandler
|
||||
Combines up to 4 images with aspect ratio preservation to prevent distortion.
|
||||
- **Methods:** concat (side-by-side), grid (2x2), offset (weighted blend)
|
||||
- **Resize modes:** match_first, common_height (best for concat), common_width, largest_dims
|
||||
- **Use for:** Character fusion, style transfer, pose references
|
||||
- **Example:** Combine Mona Lisa + Shrek + fighting pose → Mona Lisa fighting Shrek in the specified pose
|
||||
|
||||
### QwenLowresFixNode
|
||||
Two-stage refinement: generate → upscale → polish details.
|
||||
- **Use for:** Quality enhancement of generated images
|
||||
- **Example:** 1024px generation → 1.5x upscale = detail refinement
|
||||
|
||||
## Helper Nodes
|
||||
|
||||
### QwenVLEmptyLatent / QwenVLImageToLatent
|
||||
Creates/converts 16-channel latents for Qwen model.
|
||||
- **Use for:** Latent space operations
|
||||
|
||||
## Template System
|
||||
|
||||
### QwenTemplateBuilder
|
||||
Interactive template builder with style presets.
|
||||
- **Presets:** DiffSynth, artistic, photorealistic, minimal edit, action, etc.
|
||||
- **Use for:** Custom system prompts and specialized generation styles
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Text-to-Image
|
||||
```
|
||||
QwenVLCLIPLoader → QwenVLTextEncoder (mode: text_to_image) → KSampler
|
||||
```
|
||||
|
||||
### Image Editing
|
||||
```
|
||||
LoadImage → QwenVLTextEncoder (edit_image, mode: image_edit) → KSampler
|
||||
```
|
||||
|
||||
### Multi-Reference Composition
|
||||
```
|
||||
LoadImage(3x) → QwenMultiReferenceHandler → QwenVLTextEncoder → KSampler
|
||||
```
|
||||
|
||||
### ControlNet-Style Conditioning
|
||||
```
|
||||
LoadImage(edit) + LoadImage(control) → QwenVLTextEncoder (edit_image + context_image) → KSampler
|
||||
```
|
||||
|
||||
### Quality Enhancement
|
||||
```
|
||||
KSampler → QwenLowresFixNode → Final Image
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
- Clean text encoder focused on vision and language processing
|
||||
- Multi-reference aspect ratio preservation prevents concat distortion
|
||||
- Context image support for ControlNet workflows
|
||||
- Template Builder with 20+ presets
|
||||
- Debug mode with detailed logging
|
||||
- Patterns and patches from DiffSynth code
|
||||
- Two-stage refinement system
|
||||
|
||||
## Model Requirements
|
||||
|
||||
Place Qwen2.5-VL models in `ComfyUI/models/text_encoders/`:
|
||||
- `qwen_2.5_vl_7b.safetensors` (recommended)
|
||||
- Any Qwen2.5-VL checkpoint
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
**Spatial Reference Tokens** (Phase 3 roadmap):
|
||||
```
|
||||
"Change <|object_ref_start|>the red car<|object_ref_end|> to blue"
|
||||
"Replace <|box_start|>0.2,0.3,0.8,0.7<|box_end|> with flowers"
|
||||
```
|
||||
|
||||
**Denoise Guidelines:**
|
||||
- High denoise (0.9-1.0): Full creative reimagining
|
||||
- Low denoise (0.3-0.7): Structure preservation
|
||||
- Use Empty Latent for high denoise, VAE Encode for low denoise
|
||||
|
||||
## Spatial Token Examples
|
||||
|
||||
### Object Reference - Independent Usage
|
||||
Target specific objects by description:
|
||||
```
|
||||
"Change <|object_ref_start|>the red car<|object_ref_end|> to blue while keeping everything else the same"
|
||||
"Make <|object_ref_start|>the woman's dress<|object_ref_end|> flowing in the wind"
|
||||
"Replace <|object_ref_start|>the old wooden door<|object_ref_end|> with a modern glass entrance"
|
||||
```
|
||||
|
||||
### Box Coordinates - Precise Region Control
|
||||
Target rectangular areas with normalized coordinates (0-1):
|
||||
```
|
||||
"Fill <|box_start|>0.2,0.3,0.8,0.7<|box_end|> with blooming cherry blossoms"
|
||||
"Replace the content in <|box_start|>0.0,0.0,0.5,1.0<|box_end|> with a mountain landscape"
|
||||
"Add storm clouds to <|box_start|>0.1,0.0,0.9,0.4<|box_end|>"
|
||||
```
|
||||
|
||||
### Quadrilateral - Complex Shape Targeting
|
||||
Define irregular areas with four corner points:
|
||||
```
|
||||
"Paint graffiti art within <|quad_start|>0.1,0.2,0.6,0.1,0.8,0.7,0.2,0.8<|quad_end|>"
|
||||
"Transform <|quad_start|>0.3,0.1,0.9,0.2,0.7,0.9,0.1,0.6<|quad_end|> into stained glass"
|
||||
```
|
||||
|
||||
### Combined Usage - Multiple Token Types
|
||||
Mix different tokens for complex edits:
|
||||
```
|
||||
"Change <|object_ref_start|>the building<|object_ref_end|> in <|box_start|>0.4,0.2,1.0,0.8<|box_end|> to Gothic architecture"
|
||||
"Make <|object_ref_start|>the tree<|object_ref_end|> seasonal: spring leaves in <|quad_start|>0.2,0.1,0.8,0.0,0.9,0.6,0.1,0.7<|quad_end|>"
|
||||
"Replace <|object_ref_start|>the sky<|object_ref_end|> above <|box_start|>0.0,0.0,1.0,0.4<|box_end|> with aurora borealis"
|
||||
```
|
||||
|
||||
### Multi-Object Coordination
|
||||
Target multiple objects with spatial relationships:
|
||||
```
|
||||
"Change <|object_ref_start|>the left car<|object_ref_end|> to red and <|object_ref_start|>the right car<|object_ref_end|> to blue"
|
||||
"Make <|object_ref_start|>the foreground flowers<|object_ref_end|> roses and <|object_ref_start|>the background trees<|object_ref_end|> cherry blossoms"
|
||||
```
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,9 +37,13 @@ class QwenMultiReferenceHandler:
|
||||
"default": "1.0,1.0,1.0,1.0",
|
||||
"tooltip": "Weights for each image (comma-separated, used in 'offset' blend mode)"
|
||||
}),
|
||||
"resize_mode": (["match_first", "common_height", "common_width", "largest_dims"], {
|
||||
"default": "common_height",
|
||||
"tooltip": "match_first: resize all to image1 size | common_height: same height, keep aspect (uniform in grid) | common_width: same width, keep aspect (uniform in grid) | largest_dims: resize all to largest dimensions"
|
||||
}),
|
||||
"upscale_method": (["nearest-exact", "bilinear", "area", "bicubic", "lanczos"], {
|
||||
"default": "bicubic",
|
||||
"tooltip": "Interpolation method for resizing images to match the first image's resolution."
|
||||
"tooltip": "Interpolation method for resizing images."
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -52,10 +56,16 @@ class QwenMultiReferenceHandler:
|
||||
TITLE = "Multi-Reference Canvas Composer"
|
||||
DESCRIPTION = """Combines multiple images into a single high-resolution canvas for spatial reference.
|
||||
|
||||
• All images are resized to match the dimensions of image1.
|
||||
• 'concat' creates a side-by-side image.
|
||||
• 'grid' creates a 2x2 image layout.
|
||||
• 'offset' creates a weighted blend.
|
||||
Resize modes:
|
||||
• match_first: resize all to image1 dimensions (may distort)
|
||||
• common_height: same height, preserve aspect ratios (uniform dimensions in grid mode)
|
||||
• common_width: same width, preserve aspect ratios (uniform dimensions in grid mode)
|
||||
• largest_dims: resize all to largest width/height found
|
||||
|
||||
Composition methods:
|
||||
• 'concat' creates a side-by-side image
|
||||
• 'grid' creates a 2x2 image layout (requires uniform dimensions)
|
||||
• 'offset' creates a weighted blend
|
||||
|
||||
The output is a single image tensor, ready for the QwenVLTextEncoder."""
|
||||
|
||||
@@ -65,6 +75,7 @@ The output is a single image tensor, ready for the QwenVLTextEncoder."""
|
||||
image3: Optional[torch.Tensor] = None,
|
||||
image4: Optional[torch.Tensor] = None,
|
||||
weights: str = "1.0,1.0,1.0,1.0",
|
||||
resize_mode: str = "common_height",
|
||||
upscale_method: str = "bicubic") -> Tuple[torch.Tensor]:
|
||||
|
||||
# Collect all provided, non-None images
|
||||
@@ -73,21 +84,81 @@ The output is a single image tensor, ready for the QwenVLTextEncoder."""
|
||||
if not images:
|
||||
raise ValueError("At least one image must be provided to the Multi-Reference Handler.")
|
||||
|
||||
# Step 1: Standardize all images to the resolution of the first image
|
||||
# This ensures all parts of the canvas have consistent dimensions.
|
||||
target_h, target_w = images[0].shape[1:3]
|
||||
logger.info(f"[Multi-Reference] Standardizing all images to {target_w}x{target_h}.")
|
||||
# Step 1: Calculate target dimensions based on resize mode
|
||||
if resize_mode == "match_first":
|
||||
# Original behavior: resize all to match first image
|
||||
target_h, target_w = images[0].shape[1:3]
|
||||
logger.info(f"[Multi-Reference] Resizing all images to match first image: {target_w}x{target_h}")
|
||||
|
||||
elif resize_mode == "common_height":
|
||||
# Find common height (use minimum to avoid upscaling)
|
||||
target_h = min(img.shape[1] for img in images)
|
||||
# For grid mode, we need uniform dimensions to avoid tensor mismatch
|
||||
if reference_method == "grid":
|
||||
# Calculate average width to maintain reasonable proportions
|
||||
avg_aspect = sum(img.shape[2] / img.shape[1] for img in images) / len(images)
|
||||
target_w = int(target_h * avg_aspect)
|
||||
logger.info(f"[Multi-Reference] Grid mode: using common dimensions {target_w}x{target_h}")
|
||||
else:
|
||||
logger.info(f"[Multi-Reference] Using common height: {target_h}, aspect ratios preserved")
|
||||
|
||||
elif resize_mode == "common_width":
|
||||
# Find common width (use minimum to avoid upscaling)
|
||||
target_w = min(img.shape[2] for img in images)
|
||||
# For grid mode, we need uniform dimensions to avoid tensor mismatch
|
||||
if reference_method == "grid":
|
||||
# Calculate average height to maintain reasonable proportions
|
||||
avg_aspect = sum(img.shape[1] / img.shape[2] for img in images) / len(images)
|
||||
target_h = int(target_w * avg_aspect)
|
||||
logger.info(f"[Multi-Reference] Grid mode: using common dimensions {target_w}x{target_h}")
|
||||
else:
|
||||
logger.info(f"[Multi-Reference] Using common width: {target_w}, aspect ratios preserved")
|
||||
|
||||
elif resize_mode == "largest_dims":
|
||||
# Use largest width and height found across all images
|
||||
target_h = max(img.shape[1] for img in images)
|
||||
target_w = max(img.shape[2] for img in images)
|
||||
logger.info(f"[Multi-Reference] Using largest dimensions: {target_w}x{target_h}")
|
||||
|
||||
standardized_images = [images[0]]
|
||||
for img in images[1:]:
|
||||
# Use 'stretch' logic to force all images to the same dimensions
|
||||
# Step 2: Resize all images according to the chosen mode
|
||||
standardized_images = []
|
||||
for i, img in enumerate(images):
|
||||
if resize_mode == "match_first":
|
||||
# Stretch to exact target dimensions
|
||||
new_w, new_h = target_w, target_h
|
||||
|
||||
elif resize_mode == "common_height":
|
||||
if reference_method == "grid":
|
||||
# Grid mode requires uniform dimensions
|
||||
new_w, new_h = target_w, target_h
|
||||
else:
|
||||
# Keep aspect ratio, adjust width based on common height
|
||||
aspect_ratio = img.shape[2] / img.shape[1] # w/h
|
||||
new_h = target_h
|
||||
new_w = int(target_h * aspect_ratio)
|
||||
|
||||
elif resize_mode == "common_width":
|
||||
if reference_method == "grid":
|
||||
# Grid mode requires uniform dimensions
|
||||
new_w, new_h = target_w, target_h
|
||||
else:
|
||||
# Keep aspect ratio, adjust height based on common width
|
||||
aspect_ratio = img.shape[1] / img.shape[2] # h/w
|
||||
new_w = target_w
|
||||
new_h = int(target_w * aspect_ratio)
|
||||
|
||||
elif resize_mode == "largest_dims":
|
||||
# Stretch to largest dimensions (may distort)
|
||||
new_w, new_h = target_w, target_h
|
||||
|
||||
# Resize the image
|
||||
resized_img_chw = comfy.utils.common_upscale(
|
||||
img.movedim(-1, 1), # HWC to CHW for upscale function
|
||||
target_w, target_h, upscale_method, "disabled"
|
||||
new_w, new_h, upscale_method, "disabled"
|
||||
)
|
||||
standardized_images.append(resized_img_chw.movedim(1, -1)) # CHW to HWC
|
||||
|
||||
# Step 2: Create the composite canvas based on the chosen method
|
||||
# Step 3: Create the composite canvas based on the chosen method
|
||||
if reference_method == "offset":
|
||||
# Weighted average blend. The result is a single image of target_w x target_h.
|
||||
logger.info(f"[Multi-Reference] Creating composite using 'offset' (blend) method.")
|
||||
|
||||
+28
-61
@@ -119,19 +119,31 @@ class QwenVLCLIPLoader:
|
||||
|
||||
class QwenVLTextEncoder:
|
||||
"""
|
||||
Enhanced text encoder for Qwen2.5-VL with all DiffSynth fixes
|
||||
Text encoder for Qwen2.5-VL with all DiffSynth fixes
|
||||
Uses ComfyUI's internal CLIP infrastructure for compatibility
|
||||
"""
|
||||
|
||||
# DiffSynth-Studio's exact resolution list for Qwen
|
||||
# Resolution list combining DiffSynth-Studio resolutions with modern aspect ratios
|
||||
QWEN_RESOLUTIONS = [
|
||||
(256, 256), (256, 512), (256, 768), (256, 1024), (256, 1280), (256, 1536), (256, 1792),
|
||||
(512, 256), (512, 512), (512, 768), (512, 1024), (512, 1280), (512, 1536), (512, 1792),
|
||||
(768, 256), (768, 512), (768, 768), (768, 1024), (768, 1280), (768, 1536),
|
||||
(1024, 256), (1024, 512), (1024, 768), (1024, 1024), (1024, 1280), (1024, 1536),
|
||||
(1280, 256), (1280, 512), (1280, 768), (1280, 1024), (1280, 1280),
|
||||
(1536, 256), (1536, 512), (1536, 768), (1536, 1024),
|
||||
(1792, 256), (1792, 512)
|
||||
# Square resolutions
|
||||
(1024, 1024), (1328, 1328),
|
||||
|
||||
# Common landscape ratios (optimized for quality)
|
||||
(1328, 800), (1456, 720), (1584, 1056), (1920, 1080), # 16:9
|
||||
(2048, 1024), (1344, 768), (1536, 640),
|
||||
|
||||
# Common portrait ratios
|
||||
(800, 1328), (720, 1456), (1056, 1584), (1080, 1920), # 9:16
|
||||
(1024, 2048), (768, 1344), (640, 1536),
|
||||
|
||||
# Original DiffSynth-Studio resolutions for compatibility
|
||||
(672, 1568), (688, 1504), (752, 1392), (832, 1248),
|
||||
(880, 1184), (944, 1104), (1104, 944), (1184, 880),
|
||||
(1248, 832), (1392, 752), (1504, 688), (1568, 672),
|
||||
|
||||
# Smaller resolutions for low VRAM
|
||||
(512, 512), (768, 768), (512, 768), (768, 512),
|
||||
(1024, 768), (768, 1024), (1024, 512), (512, 1024)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -171,10 +183,6 @@ class QwenVLTextEncoder:
|
||||
"default": False,
|
||||
"tooltip": "Shows detailed processing info in console. Turn on if things aren't working."
|
||||
}),
|
||||
"optimize_resolution": ("BOOLEAN", {
|
||||
"default": True,
|
||||
"tooltip": "ON: Snap to best Qwen resolution (RECOMMENDED) | OFF: Scale to 1M pixels"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,57 +201,27 @@ KEY DECISION: What goes into KSampler.latent_image?
|
||||
ALWAYS connect VAE to this node for reference latents!
|
||||
"""
|
||||
|
||||
def get_optimal_resolution(self, width: int, height: int) -> Tuple[int, int]:
|
||||
"""Find the nearest Qwen-supported resolution preserving aspect ratio"""
|
||||
target_pixels = width * height
|
||||
aspect_ratio = width / height
|
||||
|
||||
best_res = min(
|
||||
self.QWEN_RESOLUTIONS,
|
||||
key=lambda r: abs(r[0] * r[1] - target_pixels) * 0.5 +
|
||||
abs((r[0] / r[1]) - aspect_ratio) * target_pixels * 0.5
|
||||
)
|
||||
|
||||
return best_res
|
||||
|
||||
def encode(self, clip, text: str, mode: str = "text_to_image",
|
||||
edit_image: Optional[torch.Tensor] = None, context_image: Optional[torch.Tensor] = None,
|
||||
vae=None, use_custom_system_prompt: bool = False,
|
||||
token_removal: str = "auto", debug_mode: bool = False,
|
||||
optimize_resolution: bool = True) -> Tuple[Any]:
|
||||
token_removal: str = "auto", debug_mode: bool = False) -> Tuple[Any]:
|
||||
|
||||
images_for_tokenizer = []
|
||||
ref_latent = None
|
||||
context_latent = None
|
||||
original_text = text
|
||||
|
||||
# No resolution controls needed - images will be processed optimally
|
||||
|
||||
# Prepare edit_image if in edit mode
|
||||
if mode == "image_edit" and edit_image is not None:
|
||||
import math
|
||||
import comfy.utils
|
||||
|
||||
if debug_mode:
|
||||
logger.info(f"[Encoder] Input image/canvas shape: {edit_image.shape}")
|
||||
|
||||
samples = edit_image.movedim(-1, 1)
|
||||
|
||||
# Determine target resolution
|
||||
if optimize_resolution:
|
||||
opt_w, opt_h = self.get_optimal_resolution(samples.shape[3], samples.shape[2])
|
||||
width, height = opt_w, opt_h
|
||||
if debug_mode:
|
||||
logger.info(f"[Encoder] Using optimal Qwen resolution: {width}x{height}")
|
||||
else:
|
||||
total = int(1024 * 1024)
|
||||
scale_by = math.sqrt(total / (samples.shape[3] * samples.shape[2]))
|
||||
width = round(samples.shape[3] * scale_by)
|
||||
height = round(samples.shape[2] * scale_by)
|
||||
if debug_mode:
|
||||
logger.info(f"[Encoder] Using legacy 1MP area scaling: {width}x{height}")
|
||||
|
||||
s = comfy.utils.common_upscale(samples, width, height, "area", "disabled")
|
||||
image = s.movedim(1, -1)
|
||||
|
||||
# Use input image as-is for vision processing (no resizing needed)
|
||||
image = edit_image
|
||||
images_for_tokenizer = [image[:, :, :, :3]]
|
||||
|
||||
if vae is not None:
|
||||
@@ -306,22 +284,11 @@ ALWAYS connect VAE to this node for reference latents!
|
||||
|
||||
# Process context_image separately (ControlNet-style)
|
||||
if context_image is not None and vae is not None:
|
||||
import comfy.utils
|
||||
if debug_mode:
|
||||
logger.info(f"[Encoder] Processing context image: {context_image.shape}")
|
||||
|
||||
samples = context_image.movedim(-1, 1)
|
||||
|
||||
# Use same resolution logic as edit_image for consistency
|
||||
if 'width' in locals() and 'height' in locals():
|
||||
context_w, context_h = width, height
|
||||
else: # Fallback if not in edit mode
|
||||
context_w, context_h = self.get_optimal_resolution(samples.shape[3], samples.shape[2])
|
||||
|
||||
s = comfy.utils.common_upscale(samples, context_w, context_h, "area", "disabled")
|
||||
context_img_resized = s.movedim(1, -1)
|
||||
|
||||
context_latent = vae.encode(context_img_resized[:, :, :, :3])
|
||||
# Use context image as-is (no resizing needed)
|
||||
context_latent = vae.encode(context_image[:, :, :, :3])
|
||||
if debug_mode:
|
||||
logger.info(f"[Encoder] Encoded context_image latent shape: {context_latent.shape}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user