Spaces:
Sleeping
Sleeping
| from PIL import Image, ImageDraw, ImageFont | |
| config = { | |
| "ids": ["simple_bar"], | |
| "name": "Simple Bar", | |
| "panels": ["font", "size", "position"], | |
| "default_font": "vazir" | |
| } | |
| # قالب HTML برای نمایش زنده در ادیتور (فرانتاند) | |
| frontend_template = """ | |
| <div style="display: flex; flex-direction: column; align-items: center; position: relative; transform: translateY(-20px);"> | |
| <!-- نوار پیشرفت --> | |
| <div style=" | |
| position: relative; | |
| width: 13em; | |
| height: 6px; | |
| margin-bottom: 0px; | |
| direction: ltr; | |
| flex-shrink: 0; | |
| "> | |
| <!-- خط سفید زیرین --> | |
| <div style=" | |
| position: absolute; top: 0; left: 0; width: 100%; height: 5px; | |
| background-color: #ffffff; border-radius: 10px; margin-top: 1.5px; | |
| "></div> | |
| <!-- نوار زرد پرشونده --> | |
| <div style=" | |
| position: absolute; top: 0; left: 0; height: 10px; | |
| background-color: #FDD835; border-radius: 10px; | |
| box-shadow: 0 0 8px var(--progress-shadow, rgba(253, 216, 53, 0.6)); | |
| /* --- تغییرات اصلی اینجا هستند --- */ | |
| width: calc(100% - var(--progress, 100%)); /* اصلاح جهت حرکت از چپ به راست */ | |
| transition: width 0.25s linear; /* افزایش زمان برای حرکت روانتر */ | |
| "></div> | |
| </div> | |
| <!-- کادر متن --> | |
| <div style=" | |
| position: absolute; | |
| top: 100%; | |
| margin-top: 20px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| background-color: rgba(0, 0, 0, 0.5); | |
| color: #ffffff; | |
| padding: 10px 30px; | |
| border-radius: 15px; | |
| text-align: center; | |
| white-space: normal; | |
| width: max-content; | |
| white-space: normal; | |
| font-family: inherit; | |
| font-weight: normal; | |
| line-height: 1.6; | |
| ">{{WORD}}</div> | |
| </div> | |
| """ | |
| # منطق تولید ویدیو (بکاند) | |
| def draw_frame(draw, img, width, height, style_config, lines, line_metrics, active_idx, font, color_parser, word_infos=None): | |
| is_rtl = getattr(style_config, 'text_direction', 'rtl') != 'ltr' | |
| # دریافت رنگ کادر اصلی از تنظیمات (کلید اختصاصی simple_bar_main_box) | |
| bg_hex = style_config.styleBgColors.get('simple_bar_main_box', '#00000080') | |
| box_color = color_parser(bg_hex, (0, 0, 0, 128)) | |
| # دریافت رنگ متن از تنظیمات (تغییر جدید) | |
| custom_hex = style_config.styleColors.get('simple_bar', '#ffffff') | |
| text_color = color_parser(custom_hex, (255, 255, 255, 255)) | |
| track_color = (255, 255, 255, 255) # سفید کامل برای خط زیرین | |
| # دریافت رنگ نوار پیشرفت (پیشفرض: زرد) | |
| # ساخت کلید اختصاصی: simple_bar_progress | |
| progress_key = f"{style_config.name}_progress" | |
| bar_hex = style_config.styleBgColors.get(progress_key, '#FDD835') | |
| bar_color = color_parser(bar_hex, (253, 216, 53, 255)) | |
| # تنظیمات هندسی | |
| padding_x = 30 | |
| padding_y = 10 | |
| radius = 15 | |
| bar_margin_bottom = 20 | |
| # 1. آمادهسازی متن (چند خطی) | |
| line_height_px = int(style_config.fontSize * 1.5) | |
| text_h = len(lines) * line_height_px | |
| # پیدا کردن عرض عریضترین خط | |
| text_w = 0 | |
| for line in lines: | |
| line_str = " ".join(line) | |
| try: w = draw.textlength(line_str, font=font, direction=getattr(style_config, 'text_direction', 'rtl'), language=getattr(style_config, 'lang_code', 'fa')) | |
| except: w = font.getlength(line_str) | |
| if w > text_w: text_w = w | |
| # 2. محاسبه ابعاد کادر متن | |
| box_w = text_w + (padding_x * 2) | |
| box_h = text_h + (padding_y * 2) | |
| center_x = width / 2 + (style_config.x or 0) | |
| # تغییر: نقطه شروع (بالای کادر) را ثابت میگیریم تا نوار زرد جابجا نشود | |
| top_y = height - style_config.marginV | |
| box_x1 = center_x - (box_w / 2) | |
| box_y1 = top_y | |
| box_x2 = center_x + (box_w / 2) | |
| box_y2 = top_y + box_h | |
| # 3. محاسبه درصد پیشرفت | |
| # اصلاح باگ NoneType: بررسی میکنیم اگر None بود صفر در نظر بگیرد | |
| current_t = style_config.current_render_time | |
| if current_t is None: | |
| current_t = 0.0 | |
| total_dur = style_config.total_video_duration | |
| if total_dur is None or total_dur == 0: | |
| total_dur = 1.0 | |
| progress = 0.0 | |
| if total_dur > 0: | |
| progress = max(0.0, min(1.0, current_t / total_dur)) | |
| # 4. ابعاد نوار پیشرفت (ثابت نگه داشتن عرض نوار در کل پروژه) | |
| # با این ضریب (13) عرض نوار بر اساس حداکثر ظرفیت 5 کلمه بزرگ تنظیم و ثابت میشود | |
| bar_w_total = style_config.fontSize * 13 | |
| bar_x_start = center_x - (bar_w_total / 2) | |
| # موقعیت عمودی نوار (بالای باکس متن) | |
| # ارتفاع نوار 6 پیکسل است، ترَک 3 پیکسل. وسطچین عمودی نسبت به هم. | |
| track_y_center = box_y1 - bar_margin_bottom - 3 | |
| # 5. رسم خط سفید (Track) | |
| track_h = 4 | |
| draw.rounded_rectangle( | |
| [bar_x_start, track_y_center - (track_h/2), bar_x_start + bar_w_total, track_y_center + (track_h/2)], | |
| radius=10, fill=track_color | |
| ) | |
| # 6. رسم نوار زرد (Progress) | |
| bar_h = 10 | |
| filled_w = bar_w_total * progress | |
| if filled_w > 0: | |
| draw.rounded_rectangle( | |
| [bar_x_start, track_y_center - (bar_h/2), bar_x_start + filled_w, track_y_center + (bar_h/2)], | |
| radius=10, fill=bar_color | |
| ) | |
| # 7. رسم کادر سیاه شفاف | |
| draw.rounded_rectangle([box_x1, box_y1, box_x2, box_y2], radius=radius, fill=box_color) | |
| # 8. رسم متن (حلقه روی خطوط) | |
| # محاسبه نقطه شروع عمودی برای وسطچین کردن کل بلوک متن | |
| current_text_y = box_y1 + (box_h - text_h) / 2 | |
| # متغیرهای کمکی برای رسم کلمه به کلمه | |
| word_idx_counter = 0 | |
| space_w = draw.textlength(" ", font=font) | |
| for line in lines: | |
| # محاسبه عرض کل خط برای وسطچین کردن | |
| line_str = " ".join(line) | |
| try: lw = draw.textlength(line_str, font=font, direction=getattr(style_config, 'text_direction', 'rtl'), language=getattr(style_config, 'lang_code', 'fa')) | |
| except: lw = font.getlength(line_str) | |
| # نقطه شروع رسم (وسطچین) بر اساس جهت زبان | |
| cursor_x = (center_x + (lw / 2)) if is_rtl else (center_x - (lw / 2)) | |
| for word in line: | |
| try: w_len = draw.textlength(word, font=font, direction=getattr(style_config, 'text_direction', 'rtl'), language=getattr(style_config, 'lang_code', 'fa')) | |
| except: w_len = font.getlength(word) | |
| # 1. تنظیم رنگ پیشفرض | |
| current_word_fill = text_color | |
| # 2. اعمال رنگ کلمه فعال (Active Word) | |
| if getattr(style_config, 'useActiveColor', True) and active_idx != -1 and word_idx_counter == active_idx: | |
| active_hex = style_config.styleActiveColors.get('simple_bar', '#ffffff') | |
| current_word_fill = color_parser(active_hex, text_color) | |
| # 3. بررسی رنگ اختصاصی کاربر (اولویت بالاتر) | |
| if word_infos and word_idx_counter < len(word_infos): | |
| w_info = word_infos[word_idx_counter] | |
| if hasattr(w_info, 'color') and w_info.color: | |
| current_word_fill = color_parser(w_info.color, text_color) | |
| # منطق تایپ حرف به حرف برای بکاند | |
| display_word = word | |
| draw_x = (cursor_x - w_len) if is_rtl else cursor_x | |
| should_draw = True | |
| is_typewriter = getattr(style_config, 'typewriter', False) | |
| if is_typewriter and word_infos and word_idx_counter < len(word_infos): | |
| w_info = word_infos[word_idx_counter] | |
| current_t = getattr(style_config, 'current_render_time', 0.0) | |
| if current_t < w_info.start: | |
| should_draw = False | |
| elif current_t >= w_info.start and current_t < w_info.end: | |
| char_len = len(word) | |
| progress = (current_t - w_info.start) / max(0.001, w_info.end - w_info.start) | |
| visible_chars = min(char_len, int(progress * char_len) + 1) | |
| display_word = word[:visible_chars] | |
| # محاسبه عرض حروف تایپ شده برای چسبیدن به راست | |
| try: sub_w = draw.textlength(display_word, font=font, direction=getattr(style_config, 'text_direction', 'rtl'), language=getattr(style_config, 'lang_code', 'fa')) | |
| except: sub_w = font.getlength(display_word) | |
| draw_x = (cursor_x - sub_w) if is_rtl else draw_x | |
| # رسم کلمه | |
| if should_draw and display_word: | |
| draw.text((draw_x, current_text_y), display_word, font=font, fill=current_word_fill, direction=getattr(style_config, 'text_direction', 'rtl'), language=getattr(style_config, 'lang_code', 'fa')) | |
| # حرکت به کلمه بعدی (بر اساس جهت زبان) | |
| cursor_x += (-(w_len + space_w) if is_rtl else (w_len + space_w)) | |
| word_idx_counter += 1 | |
| current_text_y += line_height_px |