fix: proper text output and updated README.md
This commit is contained in:
@@ -2,17 +2,32 @@
|
||||
|
||||
A ComfyUI custom node for converting images into IRC art by processing them in pixel blocks and generating both image and text outputs with optimal color selection from a 99-color IRC palette.
|
||||
|
||||
This node is used with [aibird](https://github.com/birdneststream/aibird) to convert images to IRC art.
|
||||
This node is used with [aibird](https://github.com/birdneststream/aibird) to convert text prompts to IRC art that is scrolled in the IRC client.
|
||||
|
||||

|
||||
## Limitations
|
||||
|
||||
- As we have a limited color palette of 99 colors, at times some colors may not match perfect. Overall it matches good enough. I've found the `perceptual_weighted` followed by `weighted_manhattan` to be best.
|
||||
- 16 colors don't work too well, but I've added this for legacy compatibility with some IRC clients that do not support 99 colors.
|
||||
- IRC has a `512 - (ident + host)` byte limit per line. If there's too many half blocks rendered, it may go over this limit and break the display of the ASCII art. Rendering the image with a solid background color can help with this, or using fullblock mode.
|
||||
- I haven't tried with many widths and heights. The current `640px x 448px` is a good fit for making ASCII art that is 80 character blocks wide and 30 character blocks hight. A smaller aspect ratio would fit a lot of half blocks better.
|
||||
|
||||
## Workflow
|
||||
|
||||
An example workflow is provided in `workflows/mircify_example_workflow.json`. At the moment this example is using qwen image lightning, however any model that is decent at making pixel ansi style art can suffice.
|
||||

|
||||
|
||||
An example workflow is provided in `workflows/mircify_example_workflow.json`.
|
||||
|
||||
At the moment this example is using qwen image (gguf), lightning 4 step lora with RES4LYF samplers. However any model that is decent at making pixel ansi style art can suffice.
|
||||
|
||||
## IRC Output
|
||||
|
||||
Pasting the results of the created `.txt` file into IRC, we should be able to see the IRC art rendered in the client.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- **Universal Image Support**: Works with any image dimensions
|
||||
- **Universal Image Support**: Works with any image dimensions, but remember the IRC 512 byte limit per line.
|
||||
- **Color Transfer Integration**: Uses KMeans clustering with multiple distance methods for accurate color mapping
|
||||
- **Block Processing**: Configurable block sizes (default 8x15 pixels)
|
||||
- **Half Block Mode**: Option for 8x7.5 pixel blocks for finer resolution
|
||||
@@ -59,7 +74,7 @@ Converts images into IRC art with both visual and text output.
|
||||
- **processed_image**: Visual representation of the IRC art conversion
|
||||
- **irc_text**: mIRC-formatted text with color codes ready for IRC clients
|
||||
|
||||
### IRC Text Saver (still not working too good with color matching)
|
||||
### IRC Text Saver
|
||||
**Category**: `text/output`
|
||||
|
||||
Saves IRC-formatted text to files for easy copying.
|
||||
@@ -102,7 +117,7 @@ Saves IRC-formatted text to files for easy copying.
|
||||
|
||||
The node uses a two-stage approach:
|
||||
|
||||
1. **Color Transfer Phase**: Applies KMeans clustering with configurable distance methods to map the entire image to the 99-color IRC palette
|
||||
1. **Color Transfer Phase**: Applies KMeans clustering with configurable distance methods to map the entire image to the IRC color palette
|
||||
2. **Block Processing Phase**: Divides the color-corrected image into blocks using dominant color extraction and generates the final IRC art output
|
||||
|
||||
## IRC Color Palette
|
||||
|
||||
+60
-17
@@ -180,21 +180,59 @@ class IRCArtConverter:
|
||||
line_text = ""
|
||||
i = 0
|
||||
while i < len(line_colors):
|
||||
color_code = line_colors[i]
|
||||
count = 1
|
||||
color_entry = line_colors[i]
|
||||
|
||||
# Count consecutive identical colors
|
||||
while i + count < len(line_colors) and line_colors[i + count] == color_code:
|
||||
count += 1
|
||||
|
||||
# Format color code
|
||||
if color_code <= 9:
|
||||
color_format = f"\x03{color_code},{color_code}"
|
||||
# Check if this is half-block mode (tuple) or full-block mode (int)
|
||||
if isinstance(color_entry, tuple):
|
||||
# Half-block mode: (top_color, bottom_color)
|
||||
top_color, bottom_color = color_entry
|
||||
|
||||
if top_color == bottom_color:
|
||||
# Same color - use space with background color, check for compression
|
||||
count = 1
|
||||
# Count consecutive identical same-color tuples
|
||||
while (i + count < len(line_colors) and
|
||||
isinstance(line_colors[i + count], tuple) and
|
||||
line_colors[i + count] == color_entry):
|
||||
count += 1
|
||||
|
||||
# Format color code once
|
||||
if top_color < 10:
|
||||
color_format = f"\x03{top_color},{top_color}"
|
||||
else:
|
||||
color_format = f"\x03{top_color:02d},{top_color:02d}"
|
||||
|
||||
line_text += color_format + (" " * count)
|
||||
i += count
|
||||
else:
|
||||
# Different colors - use half block character (no compression for mixed colors)
|
||||
if top_color < 10 and bottom_color < 10:
|
||||
color_format = f"\x03{top_color},{bottom_color}"
|
||||
elif top_color < 10:
|
||||
color_format = f"\x03{top_color},{bottom_color:02d}"
|
||||
elif bottom_color < 10:
|
||||
color_format = f"\x03{top_color:02d},{bottom_color}"
|
||||
else:
|
||||
color_format = f"\x03{top_color:02d},{bottom_color:02d}"
|
||||
line_text += color_format + "▀"
|
||||
i += 1
|
||||
else:
|
||||
color_format = f"\x03{color_code:02d},{color_code:02d}"
|
||||
|
||||
line_text += color_format + (" " * count)
|
||||
i += count
|
||||
# Full-block mode: single color
|
||||
color_code = color_entry
|
||||
count = 1
|
||||
|
||||
# Count consecutive identical colors
|
||||
while i + count < len(line_colors) and not isinstance(line_colors[i + count], tuple) and line_colors[i + count] == color_code:
|
||||
count += 1
|
||||
|
||||
# Format color code
|
||||
if color_code < 10:
|
||||
color_format = f"\x03{color_code},{color_code}"
|
||||
else:
|
||||
color_format = f"\x03{color_code:02d},{color_code:02d}"
|
||||
|
||||
line_text += color_format + (" " * count)
|
||||
i += count
|
||||
|
||||
return line_text
|
||||
|
||||
@@ -257,13 +295,12 @@ class IRCArtConverter:
|
||||
actual_block_height, width, height, use_16_colors, distance_method
|
||||
)
|
||||
|
||||
# Apply color to image and store for text
|
||||
# Apply color to image
|
||||
irc_color = self.IRC_COLORS[color_idx]
|
||||
irc_color_tensor = torch.tensor(irc_color, dtype=torch.float32) / 255.0
|
||||
output[start_y:end_y, x * block_width:min((x + 1) * block_width, width), :] = irc_color_tensor
|
||||
line_colors.append(color_idx + 1) # IRC codes are 1-based
|
||||
|
||||
# Process second half-block if it exists
|
||||
# Process second half-block if it exists
|
||||
if y + 1 < blocks_y:
|
||||
color_idx2, start_y2, end_y2 = self.process_block(
|
||||
color_transferred_img, x, y + 1, block_width, block_height,
|
||||
@@ -274,6 +311,12 @@ class IRCArtConverter:
|
||||
irc_color2 = self.IRC_COLORS[color_idx2]
|
||||
irc_color_tensor2 = torch.tensor(irc_color2, dtype=torch.float32) / 255.0
|
||||
output[start_y2:end_y2, x * block_width:min((x + 1) * block_width, width), :] = irc_color_tensor2
|
||||
|
||||
# Store both colors as tuple (top, bottom)
|
||||
line_colors.append((color_idx, color_idx2))
|
||||
else:
|
||||
# Last row, only one half-block - use same color for both
|
||||
line_colors.append((color_idx, color_idx))
|
||||
|
||||
text_lines.append(self.format_irc_line(line_colors))
|
||||
else:
|
||||
@@ -291,7 +334,7 @@ class IRCArtConverter:
|
||||
irc_color = self.IRC_COLORS[color_idx]
|
||||
irc_color_tensor = torch.tensor(irc_color, dtype=torch.float32) / 255.0
|
||||
output[start_y:end_y, x * block_width:min((x + 1) * block_width, width), :] = irc_color_tensor
|
||||
line_colors.append(color_idx + 1) # IRC codes are 1-based
|
||||
line_colors.append(color_idx) # Use same index as image
|
||||
|
||||
text_lines.append(self.format_irc_line(line_colors))
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 101 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
Reference in New Issue
Block a user