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()