File size: 5,474 Bytes
ec194df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
be6aa7a
ec194df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2dd83ac
ec194df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1f636f9
ec194df
 
 
1f636f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec194df
1f636f9
ec194df
 
 
 
 
 
 
 
 
 
 
1f636f9
ec194df
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import gradio as gr
from PIL import Image
import numpy as np

def image_to_ascii(image, width=100, chars="@%#*+=-:. "):
    """
    Convert image to ASCII art
    """
    # Convert image to grayscale
    if image.mode != 'L':
        image = image.convert('L')
    
    # Resize image while maintaining aspect ratio
    original_width, original_height = image.size
    aspect_ratio = original_height / original_width
    height = int(width * aspect_ratio * 0.55)  # 0.55 to account for character aspect ratio
    
    # Resize image
    img_resized = image.resize((width, height))
    
    # Convert to numpy array
    pixels = np.array(img_resized)
    
    # Normalize pixels to 0-1 range
    pixels = pixels / 255.0
    
    # Map pixels to ASCII characters
    ascii_chars = list(chars)
    num_chars = len(ascii_chars)
    
    # Create ASCII art
    ascii_art = []
    for row in pixels:
        line = ''.join(ascii_chars[min(int(pixel * num_chars), num_chars - 1)] for pixel in row)
        ascii_art.append(line)
    
    return '\n'.join(ascii_art)

def process_image(image, width, character_set):
    """
    Process the uploaded image and convert to ASCII art
    """
    if image is None:
        return "Please upload an image first!"
    
    try:
        # Define character sets
        char_sets = {
            "Detailed (dense)": "@%#*+=-:. ",
            "Simple (sparse)": "@#*+-. ",
            "Blocks": "█▓▒░ ",
            "Inverted": " .:-=+*#%@",
            "Custom": character_set
        }
        
        chars = char_sets.get(character_set, "@%#*+=-:. ")
        
        ascii_result = image_to_ascii(image, width, chars)
        return f"```\n{ascii_result}\n```"
    except Exception as e:
        return f"Error processing image: {str(e)}"

# Create Gradio interface
with gr.Blocks() as demo:
    gr.Markdown("# Image to ASCII Art Converter")
    gr.Markdown("Convert your images to ASCII art! Upload an image, adjust the width and character set, and see the text-based version of your image.")
    
    with gr.Row():
        with gr.Column():
            image_input = gr.Image(type="pil", label="Upload Image")
            width_slider = gr.Slider(minimum=50, maximum=200, value=100, step=10, label="ASCII Art Width")
            char_set_dropdown = gr.Dropdown(
                choices=["Detailed (dense)", "Simple (sparse)", "Blocks", "Inverted", "Custom"],
                value="Detailed (dense)",
                label="Character Set"
            )
            custom_chars = gr.Textbox(
                value="@%#*+=-:. ",
                label="Custom Character Set (used when 'Custom' is selected)",
                placeholder="Enter characters from darkest to lightest"
            )
            submit_btn = gr.Button("Convert to ASCII")
        
        with gr.Column():
            output_text = gr.Textbox(
                label="ASCII Art Result",
                lines=20,
                max_lines=50,
                show_copy_button=True
            )
            output_image = gr.Image(label="ASCII Art Image Preview", type="pil")
    
    # Update character set based on dropdown selection
    def update_char_set(character_set, custom_chars):
        char_sets = {
            "Detailed (dense)": "@%#*+=-:. ",
            "Simple (sparse)": "@#*+-. ",
            "Blocks": "█▓▒░ ",
            "Inverted": " .:-=+*#%@",
            "Custom": custom_chars
        }
        return char_sets.get(character_set, "@%#*+=-:. ")
    
    # Process function that uses the selected character set
    def process_with_char_set(image, width, character_set, custom_chars):
        char_sets = {
            "Detailed (dense)": "@%#*+=-:. ",
            "Simple (sparse)": "@#*+-. ",
            "Blocks": "█▓▒░ ",
            "Inverted": " .:-=+*#%@",
            "Custom": custom_chars
        }
        chars = char_sets.get(character_set, "@%#*+=-:. ")
        
        if image is None:
            return "Please upload an image first!", None
        
        try:
            ascii_result = image_to_ascii(image, width, chars)
            # Create image preview from ASCII
            lines = ascii_result.split("\n")
            h = len(lines)
            w = max(len(line) for line in lines) if h > 0 else 0
            if w == 0 or h == 0:
                preview = None
            else:
                # Map characters to grayscale values
                unique_chars = list(dict.fromkeys(chars))
                num_chars = len(unique_chars)
                char_to_val = {c: int((i / max(num_chars - 1, 1)) * 255) for i, c in enumerate(unique_chars)}
                img_array = np.zeros((h, w), dtype=np.uint8)
                for y, line in enumerate(lines):
                    for x, ch in enumerate(line):
                        img_array[y, x] = char_to_val.get(ch, 0)
                preview = np.stack([img_array]*3, axis=-1)
            return f"\n{ascii_result}\n", preview
        except Exception as e:
            return f"Error processing image: {str(e)}", None
    
    # Connect the components
    char_set_dropdown.change(
        update_char_set,
        inputs=[char_set_dropdown, custom_chars],
        outputs=custom_chars
    )
    
    submit_btn.click(
        process_with_char_set,
        inputs=[image_input, width_slider, char_set_dropdown, custom_chars],
        outputs=[output_text, output_image]
    )

if __name__ == "__main__":
    demo.launch()