File size: 12,163 Bytes
e85c04d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
from PIL import Image, ImageDraw, ImageFont

# Add this function to get available fonts with fallbacks
def get_font_path(font_name, font_size):
    """Get font path for the selected font with fallbacks"""
    font_mappings = {
        "Impact": [
            "impact.ttf",
            "Impact.ttf", 
            "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
        ],
        "Arial Bold": [
            "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
            "arial-bold.ttf"
        ],
        "Times Bold": [
            "/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf",
            "/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf",
            "times-bold.ttf"
        ],
        "Comic Sans": [
            "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
            "comic.ttf"
        ],
        "Bebas Neue": [
            "/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed-Bold.ttf", 
            "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
            "bebas-neue.ttf"
        ]
    }
    
    # Get font paths for the selected font
    font_paths = font_mappings.get(font_name, [])
    
    # Try each path
    for font_path in font_paths:
        try:
            font = ImageFont.truetype(font_path, font_size)
            print(f"SUCCESS: Loaded {font_name} from {font_path}")
            return font
        except (OSError, IOError):
            continue
    
    # If no specific font found, try default system fonts
    default_paths = [
        "DejaVuSans-Bold.ttf",
        "arial.ttf", 
        "/System/Library/Fonts/Arial.ttf",
        "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
    ]
    
    for font_path in default_paths:
        try:
            font = ImageFont.truetype(font_path, font_size)
            print(f"FALLBACK: Loaded default font from {font_path} for {font_name}")
            return font
        except (OSError, IOError):
            continue
    
    # Final fallback
    try:
        font = ImageFont.load_default()
        print(f"FINAL FALLBACK: Using system default for {font_name}")
        return font
    except Exception:
        print(f"ERROR: Could not load any font for {font_name}")
        return None

# Function to create template images
def create_pattern_template(pattern, width=200, height=120):
    """Create a visual template showing text placement for each pattern"""
    # Create black background
    img = Image.new('RGB', (width, height), color='black')
    draw = ImageDraw.Draw(img)
    
    # Define positions based on pattern
    positions = []
    if pattern == "2-lines-top":
        positions = [(width // 2, int(height * 0.15)), (width // 2, int(height * 0.35))]
    elif pattern == "2-lines-center":
        positions = [(width // 2, int(height * 0.35)), (width // 2, int(height * 0.65))]
    elif pattern == "2-lines-bottom":
        positions = [(width // 2, int(height * 0.65)), (width // 2, int(height * 0.85))]
    elif pattern == "3-lines-top":
        positions = [(width // 2, int(height * 0.15)), (width // 2, int(height * 0.35)), (width // 2, int(height * 0.55))]
    elif pattern == "3-lines-center":
        positions = [(width // 2, int(height * 0.25)), (width // 2, int(height * 0.50)), (width // 2, int(height * 0.75))]
    elif pattern == "3-lines-bottom":
        positions = [(width // 2, int(height * 0.45)), (width // 2, int(height * 0.65)), (width // 2, int(height * 0.85))]
    
    # Draw white rectangles to represent text boxes
    for i, (x, y) in enumerate(positions):
        # Draw white rectangle as text placeholder
        box_width = 60
        box_height = 12
        left = x - box_width // 2
        top = y - box_height // 2
        right = x + box_width // 2
        bottom = y + box_height // 2
        
        draw.rectangle([left, top, right, bottom], fill='white', outline='white')
    
    return img

def get_pattern_template(pattern):
    """Get template for pattern - create on demand to avoid initialization issues"""
    return create_pattern_template(pattern)

# Text Overlay Functions
def add_text_to_image(img, pattern, line1, line2, line3, font_size, color, add_outline, font_name):
    """Overlay 2- or 3-line text on the image in a preset layout."""
    print("=== DEBUG: add_text_to_image called ===")
    print(f"Input image: {type(img)}")
    print(f"Pattern: {pattern}")
    print(f"Lines: [{line1!r}, {line2!r}, {line3!r}]")
    print(f"Font size: {font_size}")
    print(f"Font name: {font_name}")
    print(f"Color: {color!r}")
    print(f"Add outline: {add_outline}")
    
    if img is None:
        print("ERROR: No image provided")
        return None, "Please supply an image first."

    try:
        # Create a working copy
        print(f"Original image mode: {img.mode}, size: {img.size}")
        image = img.convert("RGB")
        print(f"Converted image mode: {image.mode}")
        draw = ImageDraw.Draw(image)
        print("ImageDraw created successfully")

        # UPDATED: Use selected font instead of hardcoded paths
        font = get_font_path(font_name, font_size)
        if font is None:
            return None, f"Could not load font: {font_name}"

        w, h = image.size
        print(f"Image dimensions: {w}x{h}")
        
        # Pattern matching (same as before)
        positions = []
        detected_pattern = "unknown"
        
        pattern_lower = pattern.lower()
        
        if ("2-lines-top" in pattern_lower) or ("2 lines - top" in pattern_lower):
            positions = [(w // 2, int(h * 0.10)), (w // 2, int(h * 0.20))]
            detected_pattern = "2-lines-top"
        elif ("2-lines-bottom" in pattern_lower) or ("2 lines - bottom" in pattern_lower):
            positions = [(w // 2, int(h * 0.80)), (w // 2, int(h * 0.90))]
            detected_pattern = "2-lines-bottom"
        elif ("2-lines-center" in pattern_lower) or ("2 lines - center" in pattern_lower):
            positions = [(w // 2, int(h * 0.45)), (w // 2, int(h * 0.55))]
            detected_pattern = "2-lines-center"
        elif ("3-lines-top" in pattern_lower) or ("3 lines - top" in pattern_lower):
            positions = [(w // 2, int(h * 0.10)), (w // 2, int(h * 0.20)), (w // 2, int(h * 0.30))]
            detected_pattern = "3-lines-top"
        elif ("3-lines-center" in pattern_lower) or ("3 lines - center" in pattern_lower):
            positions = [(w // 2, int(h * 0.40)), (w // 2, int(h * 0.50)), (w // 2, int(h * 0.60))]
            detected_pattern = "3-lines-center"
        elif ("3-lines-bottom" in pattern_lower) or ("3 lines - bottom" in pattern_lower):
            positions = [(w // 2, int(h * 0.70)), (w // 2, int(h * 0.80)), (w // 2, int(h * 0.90))]
            detected_pattern = "3-lines-bottom"
        else:
            print(f"WARNING: Unknown pattern '{pattern}', using 2-lines-center as default")
            positions = [(w // 2, int(h * 0.45)), (w // 2, int(h * 0.55))]
            detected_pattern = "2-lines-center (default)"
            
        print(f"Detected pattern: {detected_pattern}")
        print(f"Text positions calculated: {positions}")

        # Color parsing (same as before)
        original_color = color
        final_color = (255, 255, 255)
        
        if isinstance(color, str):
            if color.startswith('rgba(') and color.endswith(')'):
                print(f"Parsing RGBA string: {color}")
                try:
                    rgba_part = color[5:-1]
                    values = [float(x.strip()) for x in rgba_part.split(',')]
                    if len(values) >= 3:
                        final_color = (int(round(values[0])), int(round(values[1])), int(round(values[2])))
                        print(f"Successfully parsed RGBA {color} to RGB: {final_color}")
                except (ValueError, IndexError) as e:
                    print(f"Error parsing RGBA {color}: {e}, using white")
                    final_color = (255, 255, 255)
            elif color.startswith('#'):
                print(f"Converting hex color {color}")
                hex_color = color.lstrip('#')
                if len(hex_color) == 6:
                    try:
                        final_color = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
                        print(f"Successfully converted hex {color} to RGB: {final_color}")
                    except ValueError as e:
                        print(f"Invalid hex color {color}: {e}, using white")
                        final_color = (255, 255, 255)
        
        print(f"Final color for drawing: {final_color}")
        
        # Draw text (same logic as before)
        lines = [line1, line2, line3]
        print(f"All input lines: {lines}")
        
        active_lines = []
        for i in range(len(positions)):
            if i < len(lines) and lines[i] and lines[i].strip():
                active_lines.append((positions[i], lines[i].strip()))
        
        print(f"Active lines to draw: {len(active_lines)} out of {len(positions)} positions")
        
        text_drawn = False
        
        for i, ((x, y), txt) in enumerate(active_lines):
            print(f"Drawing line {i+1}: '{txt}' at position ({x}, {y}) with font {font_name}")
            
            # Optional outline/stroke
            if add_outline:
                stroke_width = max(1, font_size // 20)
                print(f"Adding outline with stroke width: {stroke_width}")
                
                # Draw text outline (black)
                for dx in [-stroke_width, 0, stroke_width]:
                    for dy in [-stroke_width, 0, stroke_width]:
                        if dx != 0 or dy != 0:
                            try:
                                draw.text((x + dx, y + dy), txt, fill=(0, 0, 0), font=font, anchor="mm")
                            except TypeError:
                                try:
                                    bbox = draw.textbbox((0, 0), txt, font=font)
                                    text_w = bbox[2] - bbox[0]
                                    text_h = bbox[3] - bbox[1]
                                    draw.text((x - text_w//2 + dx, y - text_h//2 + dy), txt, fill=(0, 0, 0), font=font)
                                except Exception:
                                    draw.text((x + dx, y + dy), txt, fill=(0, 0, 0), font=font)
            
            # Draw main text
            try:
                draw.text((x, y), txt, fill=final_color, font=font, anchor="mm")
                print(f"SUCCESS: Main text drawn with {font_name} at ({x}, {y})")
            except TypeError:
                try:
                    bbox = draw.textbbox((0, 0), txt, font=font)
                    text_w = bbox[2] - bbox[0]
                    text_h = bbox[3] - bbox[1]
                    fallback_x = x - text_w//2
                    fallback_y = y - text_h//2
                    draw.text((fallback_x, fallback_y), txt, fill=final_color, font=font)
                    print(f"SUCCESS: Fallback text drawn with {font_name} at ({fallback_x}, {fallback_y})")
                except Exception:
                    draw.text((x, y), txt, fill=final_color, font=font)
                    print(f"SUCCESS: Basic text drawn with {font_name} at ({x}, {y})")
            
            text_drawn = True
            print(f"Completed drawing line {i+1}")

        if not text_drawn:
            print("No text was drawn - all lines were empty")
            return img, "No text to add (all lines were empty)"
        
        print("=== Text drawing completed successfully ===")
        return image, f"✅ {len(active_lines)} lines added! Font: {font_name}, Pattern: {detected_pattern}"
        
    except Exception as e:
        print(f"CRITICAL ERROR in add_text_to_image: {e}")
        import traceback
        traceback.print_exc()
        return None, f"Error adding text: {str(e)}"