Update styles/karaoke.py
Browse files- styles/karaoke.py +34 -26
styles/karaoke.py
CHANGED
|
@@ -24,47 +24,60 @@ def draw_frame(draw, img, width, height, style_config, lines, line_metrics, acti
|
|
| 24 |
bottom_reference = height - style_config.marginV
|
| 25 |
start_y_of_block = bottom_reference - total_block_height
|
| 26 |
|
|
|
|
|
|
|
|
|
|
| 27 |
space_w = draw.textlength(" ", font=font)
|
| 28 |
|
| 29 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
words_to_draw = []
|
| 31 |
global_word_counter = 0
|
| 32 |
temp_y = start_y_of_block
|
| 33 |
|
| 34 |
for line_idx, metrics in enumerate(line_metrics):
|
| 35 |
-
# محاسبه اینکه آیا کلمه فعال در این خط قرار دارد یا خیر
|
| 36 |
line_start_idx = sum(len(m["words"]) for m in line_metrics[:line_idx])
|
| 37 |
is_active_on_line = (active_idx >= line_start_idx and active_idx < line_start_idx + len(metrics["words"]))
|
| 38 |
|
| 39 |
-
|
| 40 |
-
dynamic_line_width = metrics["width"] + (style_config.paddingX * 2 if is_active_on_line else 0)
|
| 41 |
cursor_x = (width + dynamic_line_width) / 2 + style_config.x
|
| 42 |
|
| 43 |
-
#
|
| 44 |
-
|
| 45 |
|
| 46 |
for w_i, word in enumerate(metrics["words"]):
|
| 47 |
g_idx = line_start_idx + w_i
|
| 48 |
w_len = metrics["word_widths"][w_i]
|
| 49 |
|
| 50 |
-
# ف
|
| 51 |
-
|
|
|
|
|
|
|
| 52 |
word_x = cursor_x - w_len - current_word_padding
|
| 53 |
|
| 54 |
words_to_draw.append({
|
| 55 |
"text": word, "x": word_x, "y": text_y_pos, "width": w_len,
|
| 56 |
-
"global_idx": global_word_counter
|
|
|
|
| 57 |
})
|
| 58 |
|
| 59 |
-
# جابجایی مکاننما برای کلمه بعدی: (عرض کلمه + فاصله خالی + پدینگ احتمالی)
|
| 60 |
cursor_x -= (w_len + space_w + (current_word_padding * 2))
|
| 61 |
global_word_counter += 1
|
| 62 |
|
| 63 |
temp_y += line_height_px
|
| 64 |
|
| 65 |
VERTICAL_CORRECTION = int(style_config.fontSize * 0.22)
|
| 66 |
-
pad_x = style_config.paddingX
|
| 67 |
-
pad_y = style_config.paddingY
|
| 68 |
|
| 69 |
# 2. رسم کادرها (برای اینکه زیر متن باشند)
|
| 70 |
for item in words_to_draw:
|
|
@@ -75,7 +88,6 @@ def draw_frame(draw, img, width, height, style_config, lines, line_metrics, acti
|
|
| 75 |
|
| 76 |
if style_name == "auto_director" and is_active:
|
| 77 |
should_draw_box = True
|
| 78 |
-
# رنگهای متناوب برای اتو دایرکتور
|
| 79 |
box_color = (0, 215, 255, 255) if item["global_idx"] % 2 == 0 else (255, 0, 128, 255)
|
| 80 |
|
| 81 |
elif style_name == "karaoke_static" and is_active:
|
|
@@ -91,7 +103,7 @@ def draw_frame(draw, img, width, height, style_config, lines, line_metrics, acti
|
|
| 91 |
|
| 92 |
draw.rounded_rectangle([bx1, by1, bx2, by2], radius=style_config.radius, fill=box_color)
|
| 93 |
|
| 94 |
-
# 3. رسم متن
|
| 95 |
for item in words_to_draw:
|
| 96 |
is_active = (item["global_idx"] == active_idx) and getattr(style_config, 'useActiveColor', True)
|
| 97 |
|
|
@@ -104,7 +116,6 @@ def draw_frame(draw, img, width, height, style_config, lines, line_metrics, acti
|
|
| 104 |
|
| 105 |
elif style_name == "auto_director":
|
| 106 |
if is_active:
|
| 107 |
-
# دریافت رنگ کلمه فعال مخصوص auto_director
|
| 108 |
active_hex = style_config.styleActiveColors.get('auto_director', '#ffffff')
|
| 109 |
fill_color = color_parser(active_hex, (255, 255, 255, 255))
|
| 110 |
else:
|
|
@@ -113,21 +124,11 @@ def draw_frame(draw, img, width, height, style_config, lines, line_metrics, acti
|
|
| 113 |
|
| 114 |
elif style_name == "karaoke_static":
|
| 115 |
if is_active:
|
| 116 |
-
# دریافت رنگ کلمه فعال مخصوص karaoke_static
|
| 117 |
active_hex = style_config.styleActiveColors.get('karaoke_static', '#ffffff')
|
| 118 |
fill_color = color_parser(active_hex, (255, 255, 255, 255))
|
| 119 |
else:
|
| 120 |
custom_text_hex = style_config.styleColors.get('karaoke_static', '#ffffff')
|
| 121 |
fill_color = color_parser(custom_text_hex, (255, 255, 255, 255))
|
| 122 |
-
|
| 123 |
-
elif style_name == "auto_director":
|
| 124 |
-
if is_active:
|
| 125 |
-
active_hex = style_config.styleActiveColors.get('auto_director', '#ffffff')
|
| 126 |
-
fill_color = color_parser(active_hex, (255, 255, 255, 255))
|
| 127 |
-
else:
|
| 128 |
-
# خواندن رنگ متن اختصاصی از دیکشنری (پیشفرض سفید)
|
| 129 |
-
custom_text_hex = style_config.styleColors.get('karaoke_static', '#ffffff')
|
| 130 |
-
fill_color = color_parser(custom_text_hex, (255, 255, 255, 255))
|
| 131 |
|
| 132 |
# اعمال رنگ دستی کاربر
|
| 133 |
if word_infos and item["global_idx"] < len(word_infos):
|
|
@@ -135,4 +136,11 @@ def draw_frame(draw, img, width, height, style_config, lines, line_metrics, acti
|
|
| 135 |
if hasattr(w_obj, 'color') and w_obj.color:
|
| 136 |
fill_color = color_parser(w_obj.color, fill_color)
|
| 137 |
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
bottom_reference = height - style_config.marginV
|
| 25 |
start_y_of_block = bottom_reference - total_block_height
|
| 26 |
|
| 27 |
+
pad_x = style_config.paddingX
|
| 28 |
+
pad_y = style_config.paddingY
|
| 29 |
+
|
| 30 |
space_w = draw.textlength(" ", font=font)
|
| 31 |
|
| 32 |
+
# محاسبه متریکهای استاندارد فونت بر اساس کلمه مرجع جهت تراز یکدست عمودی تمام کلمات
|
| 33 |
+
ref_word = "سلام"
|
| 34 |
+
try:
|
| 35 |
+
ref_bbox = draw.textbbox((0, 0), ref_word, font=font, direction='rtl', language='fa')
|
| 36 |
+
standard_text_visual_center_y = (ref_bbox[1] + ref_bbox[3]) / 2.0
|
| 37 |
+
standard_text_offset_y = ref_bbox[1]
|
| 38 |
+
standard_text_h = ref_bbox[3] - ref_bbox[1]
|
| 39 |
+
except:
|
| 40 |
+
standard_text_visual_center_y = style_config.fontSize / 2.0
|
| 41 |
+
standard_text_offset_y = 0
|
| 42 |
+
standard_text_h = style_config.fontSize
|
| 43 |
+
|
| 44 |
+
# 1. محاسبه مختصات همه کلمات با تراز دقیق
|
| 45 |
words_to_draw = []
|
| 46 |
global_word_counter = 0
|
| 47 |
temp_y = start_y_of_block
|
| 48 |
|
| 49 |
for line_idx, metrics in enumerate(line_metrics):
|
|
|
|
| 50 |
line_start_idx = sum(len(m["words"]) for m in line_metrics[:line_idx])
|
| 51 |
is_active_on_line = (active_idx >= line_start_idx and active_idx < line_start_idx + len(metrics["words"]))
|
| 52 |
|
| 53 |
+
dynamic_line_width = metrics["width"] + (pad_x * 2 if is_active_on_line else 0)
|
|
|
|
| 54 |
cursor_x = (width + dynamic_line_width) / 2 + style_config.x
|
| 55 |
|
| 56 |
+
# مرکز عمودی دقیق و هندسی این خط فعلی
|
| 57 |
+
line_center_y = temp_y + (line_height_px / 2.0)
|
| 58 |
|
| 59 |
for w_i, word in enumerate(metrics["words"]):
|
| 60 |
g_idx = line_start_idx + w_i
|
| 61 |
w_len = metrics["word_widths"][w_i]
|
| 62 |
|
| 63 |
+
# استفاده از مقدار ثابت برای جلوگیری از نوسان عمودی کلمات خط
|
| 64 |
+
text_y_pos = line_center_y - standard_text_visual_center_y
|
| 65 |
+
|
| 66 |
+
current_word_padding = pad_x if g_idx == active_idx else 0
|
| 67 |
word_x = cursor_x - w_len - current_word_padding
|
| 68 |
|
| 69 |
words_to_draw.append({
|
| 70 |
"text": word, "x": word_x, "y": text_y_pos, "width": w_len,
|
| 71 |
+
"global_idx": global_word_counter,
|
| 72 |
+
"line_center_y": line_center_y
|
| 73 |
})
|
| 74 |
|
|
|
|
| 75 |
cursor_x -= (w_len + space_w + (current_word_padding * 2))
|
| 76 |
global_word_counter += 1
|
| 77 |
|
| 78 |
temp_y += line_height_px
|
| 79 |
|
| 80 |
VERTICAL_CORRECTION = int(style_config.fontSize * 0.22)
|
|
|
|
|
|
|
| 81 |
|
| 82 |
# 2. رسم کادرها (برای اینکه زیر متن باشند)
|
| 83 |
for item in words_to_draw:
|
|
|
|
| 88 |
|
| 89 |
if style_name == "auto_director" and is_active:
|
| 90 |
should_draw_box = True
|
|
|
|
| 91 |
box_color = (0, 215, 255, 255) if item["global_idx"] % 2 == 0 else (255, 0, 128, 255)
|
| 92 |
|
| 93 |
elif style_name == "karaoke_static" and is_active:
|
|
|
|
| 103 |
|
| 104 |
draw.rounded_rectangle([bx1, by1, bx2, by2], radius=style_config.radius, fill=box_color)
|
| 105 |
|
| 106 |
+
# 3. رسم متن با تراز عمودی کاملاً منطبق بر مرکز هندسی کادر
|
| 107 |
for item in words_to_draw:
|
| 108 |
is_active = (item["global_idx"] == active_idx) and getattr(style_config, 'useActiveColor', True)
|
| 109 |
|
|
|
|
| 116 |
|
| 117 |
elif style_name == "auto_director":
|
| 118 |
if is_active:
|
|
|
|
| 119 |
active_hex = style_config.styleActiveColors.get('auto_director', '#ffffff')
|
| 120 |
fill_color = color_parser(active_hex, (255, 255, 255, 255))
|
| 121 |
else:
|
|
|
|
| 124 |
|
| 125 |
elif style_name == "karaoke_static":
|
| 126 |
if is_active:
|
|
|
|
| 127 |
active_hex = style_config.styleActiveColors.get('karaoke_static', '#ffffff')
|
| 128 |
fill_color = color_parser(active_hex, (255, 255, 255, 255))
|
| 129 |
else:
|
| 130 |
custom_text_hex = style_config.styleColors.get('karaoke_static', '#ffffff')
|
| 131 |
fill_color = color_parser(custom_text_hex, (255, 255, 255, 255))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
# اعمال رنگ دستی کاربر
|
| 134 |
if word_infos and item["global_idx"] < len(word_infos):
|
|
|
|
| 136 |
if hasattr(w_obj, 'color') and w_obj.color:
|
| 137 |
fill_color = color_parser(w_obj.color, fill_color)
|
| 138 |
|
| 139 |
+
# محاسبه مرکز هندسی کادر رسم شده برای قرارگیری دقیق متن در مرکز کادر
|
| 140 |
+
rect_y1 = item["y"] - int(pad_y * 1.3) + VERTICAL_CORRECTION
|
| 141 |
+
rect_y2 = item["y"] + style_config.fontSize + int(pad_y * 1.3) + VERTICAL_CORRECTION
|
| 142 |
+
rect_center_y = (rect_y1 + rect_y2) / 2.0
|
| 143 |
+
|
| 144 |
+
final_text_y = rect_center_y - standard_text_offset_y - (standard_text_h / 2.0)
|
| 145 |
+
|
| 146 |
+
draw.text((item["x"], final_text_y), item["text"], font=font, fill=fill_color, direction='rtl', language='fa')
|