Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -62,57 +62,102 @@ def render_translated_overlay(original_image: Image.Image, text_to_overlay: str,
|
|
62 |
min(original_image.width, bbox[2] + padding), min(original_image.height, bbox[3] + padding))
|
63 |
overlay_width = overlay_box[2] - overlay_box[0]
|
64 |
overlay_height = overlay_box[3] - overlay_box[1]
|
65 |
-
|
66 |
try:
|
67 |
-
sample_x = max(0, int(overlay_box[0]) - 5)
|
|
|
68 |
bg_color = original_image.getpixel((sample_x, sample_y))
|
69 |
-
except (ValueError, IndexError):
|
|
|
70 |
|
71 |
overlay_layer = Image.new("RGBA", (overlay_width, overlay_height), bg_color)
|
72 |
draw = ImageDraw.Draw(overlay_layer)
|
73 |
target_width = overlay_width * 0.90
|
74 |
font_size = 100
|
75 |
final_wrapped_lines = []
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
while font_size > 10:
|
78 |
font = ImageFont.truetype(PERSIAN_FONT_PATH, font_size)
|
79 |
-
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
for word in words:
|
83 |
test_line = (current_line + " " + word).strip()
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
final_font = ImageFont.truetype(PERSIAN_FONT_PATH, font_size)
|
95 |
line_spacing = font_size * 0.3
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
total_text_height = sum(line_heights) + (len(final_wrapped_lines) - 1) * line_spacing
|
98 |
y_start = (overlay_height - total_text_height) / 2
|
99 |
-
|
100 |
current_y = y_start
|
101 |
for i, line in enumerate(final_wrapped_lines):
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
line_bbox = draw.textbbox((0, 0), bidi_line, font=final_font)
|
106 |
line_width = line_bbox[2] - line_bbox[0]
|
107 |
x_position = (overlay_width - line_width) / 2
|
108 |
-
|
109 |
-
|
110 |
-
draw.text((x_position, current_y),
|
111 |
-
|
|
|
|
|
112 |
current_y += line_heights[i] + line_spacing
|
113 |
|
114 |
return overlay_layer, overlay_box
|
115 |
|
|
|
116 |
# --- MAIN VIDEO PROCESSING PIPELINE (WITH FFMPEG CORRECTION) ---
|
117 |
def process_video(video_path, progress=gr.Progress()):
|
118 |
if video_path is None: raise gr.Error("Please upload a video file first.")
|
|
|
62 |
min(original_image.width, bbox[2] + padding), min(original_image.height, bbox[3] + padding))
|
63 |
overlay_width = overlay_box[2] - overlay_box[0]
|
64 |
overlay_height = overlay_box[3] - overlay_box[1]
|
65 |
+
|
66 |
try:
|
67 |
+
sample_x = max(0, int(overlay_box[0]) - 5)
|
68 |
+
sample_y = int((overlay_box[1] + overlay_box[3]) / 2)
|
69 |
bg_color = original_image.getpixel((sample_x, sample_y))
|
70 |
+
except (ValueError, IndexError):
|
71 |
+
bg_color = (25, 25, 25, 255)
|
72 |
|
73 |
overlay_layer = Image.new("RGBA", (overlay_width, overlay_height), bg_color)
|
74 |
draw = ImageDraw.Draw(overlay_layer)
|
75 |
target_width = overlay_width * 0.90
|
76 |
font_size = 100
|
77 |
final_wrapped_lines = []
|
78 |
+
|
79 |
+
# ### --- FIX --- ###: Process RTL text BEFORE line wrapping
|
80 |
+
# First, reshape and process the entire text for proper RTL handling
|
81 |
+
try:
|
82 |
+
reshaped_text = arabic_reshaper.reshape(text_to_overlay)
|
83 |
+
processed_text = get_display(reshaped_text)
|
84 |
+
except Exception as e:
|
85 |
+
print(f"RTL processing error: {e}")
|
86 |
+
processed_text = text_to_overlay # Fallback to original text
|
87 |
+
|
88 |
while font_size > 10:
|
89 |
font = ImageFont.truetype(PERSIAN_FONT_PATH, font_size)
|
90 |
+
|
91 |
+
# ### --- FIX --- ###: Split by spaces but work with processed RTL text
|
92 |
+
words = processed_text.split()
|
93 |
+
if not words:
|
94 |
+
break
|
95 |
+
|
96 |
+
raw_lines = []
|
97 |
+
current_line = ""
|
98 |
+
|
99 |
for word in words:
|
100 |
test_line = (current_line + " " + word).strip()
|
101 |
+
# Test the width with the actual text that will be rendered
|
102 |
+
line_width = draw.textbbox((0, 0), test_line, font=font)[2]
|
103 |
+
|
104 |
+
if line_width <= target_width:
|
105 |
+
current_line = test_line
|
106 |
+
else:
|
107 |
+
if current_line: # Only append if current_line is not empty
|
108 |
+
raw_lines.append(current_line)
|
109 |
+
current_line = word
|
110 |
+
|
111 |
+
if current_line: # Don't forget the last line
|
112 |
+
raw_lines.append(current_line)
|
113 |
+
|
114 |
+
# Calculate total height
|
115 |
+
total_height = 0
|
116 |
+
for line in raw_lines:
|
117 |
+
line_bbox = draw.textbbox((0, 0), line, font=font)
|
118 |
+
line_height = line_bbox[3] - line_bbox[1]
|
119 |
+
total_height += line_height
|
120 |
+
|
121 |
+
if total_height <= overlay_height * 0.9:
|
122 |
+
final_wrapped_lines = raw_lines
|
123 |
+
break
|
124 |
+
else:
|
125 |
+
font_size -= 2
|
126 |
+
|
127 |
+
if not final_wrapped_lines and raw_lines: # Fallback
|
128 |
+
final_wrapped_lines = raw_lines
|
129 |
+
|
130 |
+
# ### --- FIX --- ###: Render with proper spacing
|
131 |
final_font = ImageFont.truetype(PERSIAN_FONT_PATH, font_size)
|
132 |
line_spacing = font_size * 0.3
|
133 |
+
|
134 |
+
# Calculate line heights properly
|
135 |
+
line_heights = []
|
136 |
+
for line in final_wrapped_lines:
|
137 |
+
line_bbox = draw.textbbox((0, 0), line, font=final_font)
|
138 |
+
line_height = line_bbox[3] - line_bbox[1]
|
139 |
+
line_heights.append(line_height)
|
140 |
+
|
141 |
total_text_height = sum(line_heights) + (len(final_wrapped_lines) - 1) * line_spacing
|
142 |
y_start = (overlay_height - total_text_height) / 2
|
143 |
+
|
144 |
current_y = y_start
|
145 |
for i, line in enumerate(final_wrapped_lines):
|
146 |
+
# Calculate line width and center position
|
147 |
+
line_bbox = draw.textbbox((0, 0), line, font=final_font)
|
|
|
|
|
148 |
line_width = line_bbox[2] - line_bbox[0]
|
149 |
x_position = (overlay_width - line_width) / 2
|
150 |
+
|
151 |
+
# Draw shadow for better readability
|
152 |
+
draw.text((x_position + 1, current_y + 1), line, font=final_font, fill=(0, 0, 0, 180))
|
153 |
+
# Draw main text
|
154 |
+
draw.text((x_position, current_y), line, font=final_font, fill=(255, 255, 255, 255))
|
155 |
+
|
156 |
current_y += line_heights[i] + line_spacing
|
157 |
|
158 |
return overlay_layer, overlay_box
|
159 |
|
160 |
+
|
161 |
# --- MAIN VIDEO PROCESSING PIPELINE (WITH FFMPEG CORRECTION) ---
|
162 |
def process_video(video_path, progress=gr.Progress()):
|
163 |
if video_path is None: raise gr.Error("Please upload a video file first.")
|