File size: 3,123 Bytes
3b1a0c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
from PIL import Image
import tempfile
import os

DEFAULT_ASCII_CHARS = '@#S%?*+;:,. '

def resize_image(image, new_width):
    width, height = image.size
    aspect_ratio = height / width
    new_height = int(aspect_ratio * new_width * 0.55)
    return image.resize((new_width, new_height))

def to_grayscale(image):
    return image.convert('L')

def pixel_to_ascii(image, ascii_chars):
    pixels = list(image.getdata())
    return ''.join([ascii_chars[pixel * len(ascii_chars) // 256] for pixel in pixels])

def image_to_ascii(image, ascii_chars, new_width):
    image = resize_image(image, new_width)
    image = to_grayscale(image)
    ascii_str = pixel_to_ascii(image, ascii_chars)
    img_width = image.width
    return '\n'.join([ascii_str[i:i+img_width] for i in range(0, len(ascii_str), img_width)])

def generate_ascii_art(input_image, ascii_chars, density):
    if input_image is None:
        return "Please upload an image.", None
    
    # Ensure the ASCII characters are in descending order of darkness
    ascii_chars = ''.join(sorted(set(ascii_chars), key=lambda c: -ord(c)))
    
    # Calculate new width based on density
    new_width = int(density)
    
    ascii_art = image_to_ascii(input_image, ascii_chars, new_width)
    
    with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as temp_file:
        temp_file.write(ascii_art)
    
    return ascii_art, temp_file.name

def process_and_download(input_image, ascii_chars, density):
    ascii_art, temp_file_path = generate_ascii_art(input_image, ascii_chars, density)
    return ascii_art, temp_file_path

custom_css = """
#ascii-output {
    font-family: monospace;
    white-space: pre;
    overflow-x: auto;
    font-size: 5px;
    line-height: 1;
}
"""

with gr.Blocks(css=custom_css) as iface:
    gr.Markdown("# Image to ASCII Art Converter")
    gr.Markdown("Upload an image, choose ASCII characters, set density, convert to ASCII art, and download the result!")
    
    with gr.Row():
        input_image = gr.Image(type="pil", label="Upload Image")
    
    with gr.Row():
        ascii_chars_input = gr.Textbox(
            label="ASCII Characters", 
            value=DEFAULT_ASCII_CHARS,
            info="Enter characters from darkest to lightest. The script will remove duplicates and sort them."
        )
    
    with gr.Row():
        density_slider = gr.Slider(
            minimum=50,
            maximum=600,
            value=200,
            step=10,
            label="ASCII Art Density",
            info="Higher values create denser, more detailed ASCII art."
        )
    
    with gr.Row():
        convert_button = gr.Button("Convert to ASCII")
    
    with gr.Row():
        ascii_output = gr.Textbox(label="ASCII Art Output", elem_id="ascii-output", lines=50)
    
    with gr.Row():
        download_button = gr.File(label="Download ASCII Art")
    
    convert_button.click(
        process_and_download,
        inputs=[input_image, ascii_chars_input, density_slider],
        outputs=[ascii_output, download_button]
    )

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