File size: 5,916 Bytes
dc2831e
 
269525c
 
0483ea7
7690d86
3d45539
 
dc2831e
3d45539
 
 
 
 
 
 
 
 
 
7690d86
3d45539
 
 
7690d86
3d45539
7690d86
 
 
 
 
 
dc2831e
3d45539
7690d86
 
 
7d205dd
0063f85
3d45539
0063f85
3d45539
7d205dd
 
3d45539
7d205dd
412ae09
3d45539
7d205dd
 
 
 
 
 
 
 
 
 
 
 
 
412ae09
 
7d205dd
3d45539
7d205dd
 
7690d86
7d205dd
7690d86
 
 
 
 
269525c
3d45539
b70654b
 
 
 
 
3d45539
b70654b
3d45539
b70654b
 
 
 
 
 
 
 
 
 
 
 
3d45539
7690d86
 
3d45539
 
 
 
 
 
 
 
 
 
 
 
 
0483ea7
3d45539
 
7690d86
 
3d45539
 
 
 
 
 
 
 
7690d86
3d45539
0063f85
7690d86
3d45539
 
 
 
 
 
7690d86
 
3d45539
7690d86
 
dc2831e
3d45539
 
 
 
 
 
 
 
 
 
 
a6146e8
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
import gradio as gr
import requests
from PIL import Image, ImageDraw, ImageFont
import textwrap
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
import random
import time

# Constants for image styles
IMAGE_STYLES = {
    "Realistic": "",
    "Cartoon": "cartoon style",
    "Watercolor": "watercolor painting style",
    "Sketch": "pencil sketch style",
    "Anime": "anime style"
}

def download_image(prompt, index, style):
    try:
        style_prompt = f"{prompt}, {IMAGE_STYLES[style]}" if style != "Realistic" else prompt
        url = f"https://pollinations.ai/p/{style_prompt.replace(' ', '_')}"
        response = requests.get(url, timeout=15)
        response.raise_for_status()
        image_filename = f'generated_image_{index}_{int(time.time())}.jpg'
        with open(image_filename, 'wb') as file:
            file.write(response.content)
        return image_filename
    except requests.RequestException as e:
        print(f"Error downloading image {index}: {e}")
        return None

def add_text_to_image(image_path, text, font_size, text_color):
    try:
        img = Image.open(image_path)
        draw = ImageDraw.Draw(img)
        
        try:
            font = ImageFont.truetype("arial.ttf", font_size)
        except IOError:
            font = ImageFont.load_default().font_variant(size=font_size)
        
        img_width, img_height = img.size
        max_text_width = int(img_width * 0.9)
        lines = textwrap.wrap(text, width=40)
        
        line_height = font.getbbox("hg")[3] + 5
        text_height = line_height * len(lines)
        
        overlay = Image.new('RGBA', img.size, (0, 0, 0, 0))
        overlay_draw = ImageDraw.Draw(overlay)
        overlay_draw.rectangle([(0, img_height - text_height - 20), (img_width, img_height)], 
                               fill=(0, 0, 0, 180))
        
        img = img.convert('RGBA')
        img = Image.alpha_composite(img, overlay)
        draw = ImageDraw.Draw(img)
        
        y_text = img_height - text_height - 10
        for line in lines:
            bbox = font.getbbox(line)
            line_width = bbox[2] - bbox[0]
            x_text = (img_width - line_width) / 2
            draw.text((x_text, y_text), line, font=font, fill=text_color)
            y_text += line_height
        
        img_with_text = f'text_added_{os.path.basename(image_path)}'
        img = img.convert('RGB')
        img.save(img_with_text)
        return img_with_text
    except Exception as e:
        print(f"Error adding text to image: {e}")
        return None

def process_story_lines(story, style, font_size, text_color, progress=gr.Progress()):
    lines = [line.strip() for line in story.split('\n') if line.strip()]
    images_with_text = []
    
    def process_line(idx, line):
        prompt = line.replace(" ", "_")
        img_file = download_image(prompt, idx, style)
        if img_file:
            return add_text_to_image(img_file, line, font_size, text_color)
        return None

    with ThreadPoolExecutor(max_workers=5) as executor:
        future_to_idx = {executor.submit(process_line, idx, line): idx for idx, line in enumerate(lines)}
        for future in progress.tqdm(as_completed(future_to_idx), total=len(lines), desc="Processing images"):
            idx = future_to_idx[future]
            result = future.result()
            if result:
                images_with_text.append((idx, result))
    
    return [img for _, img in sorted(images_with_text)]

def visualize_story_images(story, style, font_size, text_color):
    if not story.strip():
        return []
    return process_story_lines(story, style, font_size, text_color)

def preview_image(story, style, font_size, text_color):
    if not story.strip():
        return None
    lines = [line.strip() for line in story.split('\n') if line.strip()]
    if not lines:
        return None
    preview_line = random.choice(lines)
    img_file = download_image(preview_line, 0, style)
    if img_file:
        return add_text_to_image(img_file, preview_line, font_size, text_color)
    return None

with gr.Blocks(css="#gallery {height: 600px}") as iface:
    gr.Markdown("# πŸ“šβœ¨ Story Visualizer")
    
    with gr.Row():
        with gr.Column(scale=2):
            story_input = gr.Textbox(lines=10, placeholder="Enter your story here...", label="Story Input")
        with gr.Column(scale=1):
            style_dropdown = gr.Dropdown(choices=list(IMAGE_STYLES.keys()), value="Realistic", label="Image Style")
            font_size_slider = gr.Slider(minimum=20, maximum=60, value=30, step=2, label="Font Size")
            text_color_picker = gr.ColorPicker(value="#FFFFFF", label="Text Color")
            preview_button = gr.Button("Preview", variant="secondary")
            visualize_button = gr.Button("Visualize Story", variant="primary")
    
    preview_output = gr.Image(label="Preview", height=300)
    gallery_output = gr.Gallery(label="Visualized Story", show_label=False, elem_id="gallery", columns=2, rows=2, height="auto")
    
    preview_button.click(
        fn=preview_image,
        inputs=[story_input, style_dropdown, font_size_slider, text_color_picker],
        outputs=[preview_output]
    )
    
    visualize_button.click(
        fn=visualize_story_images,
        inputs=[story_input, style_dropdown, font_size_slider, text_color_picker],
        outputs=[gallery_output]
    )

    gr.Markdown("""
    ## How to use:
    1. Enter your story in the text box, with each line representing a scene.
    2. Choose an image style from the dropdown menu.
    3. Adjust the font size and text color as desired.
    4. Click "Preview" to see how a random scene from your story might look.
    5. When you're happy with the settings, click "Visualize Story" to generate images for all scenes.
    
    Enjoy bringing your story to life! πŸŽ¨πŸ“–
    """)

iface.launch(share=True)