Files
CapCutAPI/add_text_impl.py

273 lines
11 KiB
Python
Raw Normal View History

import pyJianYingDraft as draft
from settings.local import IS_CAPCUT_ENV
from util import generate_draft_url, hex_to_rgb
from pyJianYingDraft import trange, Font_type
from typing import Optional, List # add List type hint
from pyJianYingDraft import exceptions
from create_draft import get_or_create_draft
2025-08-01 08:57:32 +08:00
from pyJianYingDraft.text_segment import TextBubble, TextEffect, TextStyleRange
def add_text_impl(
text: str,
start: float,
end: float,
2025-08-01 16:58:53 +08:00
draft_id: str | None = None, # Python 3.10+ 新语法
transform_y: float = -0.8,
transform_x: float = 0,
2025-08-12 15:29:35 +08:00
font: Optional[str] = None,
font_color: str = "#ffffff",
font_size: float = 8.0,
track_name: str = "text_main",
2025-08-01 16:58:53 +08:00
vertical: bool = False,
font_alpha: float = 1.0,
2025-07-13 16:18:27 +08:00
# Border parameters
border_alpha: float = 1.0,
border_color: str = "#000000",
2025-08-01 16:58:53 +08:00
border_width: float = 0.0,
2025-07-13 16:18:27 +08:00
# Background parameters
background_color: str = "#000000",
background_style: int = 1,
2025-08-01 16:58:53 +08:00
background_alpha: float = 0.0,
background_round_radius: float = 0.0,
background_height: float = 0.14,
background_width: float = 0.14,
background_horizontal_offset: float = 0.5,
background_vertical_offset: float = 0.5,
# Shadow parameters
shadow_enabled: bool = False,
shadow_alpha: float = 0.9,
shadow_angle: float = -45.0,
shadow_color: str = "#000000",
shadow_distance: float = 5.0,
shadow_smoothing: float = 0.15,
2025-07-13 16:18:27 +08:00
# Bubble effect
2025-08-01 16:58:53 +08:00
bubble_effect_id: str | None = None,
bubble_resource_id: str | None = None,
2025-07-13 16:18:27 +08:00
# Text effect
2025-08-01 16:58:53 +08:00
effect_effect_id: str | None = None,
intro_animation: str | None = None,
intro_duration: float = 0.5,
outro_animation: str | None = None,
outro_duration: float = 0.5,
width: int = 1080,
height: int = 1920,
2025-07-13 16:18:27 +08:00
fixed_width: float = -1, # Text fixed width ratio, default -1 means not fixed
fixed_height: float = -1, # Text fixed height ratio, default -1 means not fixed
2025-08-01 08:57:32 +08:00
# 多样式文本参数
text_styles: Optional[List[TextStyleRange]] = None, # 文本的不同部分的样式列表
):
"""
2025-07-13 16:18:27 +08:00
Add text subtitle to the specified draft (configurable parameter version)
:param text: Text content
:param start: Start time (seconds)
:param end: End time (seconds)
:param draft_id: Draft ID (optional, default None creates a new draft)
:param transform_y: Y-axis position (default -0.8, bottom of screen)
:param transform_x: X-axis position (default 0, center of screen)
:param font: Font name (supports all fonts in Font_type)
:param font_color: Font color #FFF0FF
:param font_size: Font size (float value, default 8.0)
:param track_name: Track name
:param vertical: Whether to display vertically (default False)
:param font_alpha: Text transparency, range 0.0-1.0 (default 1.0, completely opaque)
:param border_alpha: Border transparency, range 0.0-1.0 (default 1.0)
:param border_color: Border color (default black)
:param border_width: Border width (default 0.0, no border display)
:param background_color: Background color (default black)
:param background_style: Background style (default 1)
:param background_alpha: Background transparency (default 0.0, no background display)
2025-08-01 08:57:32 +08:00
:param background_round_radius: 背景圆角半径范围0.0-1.0默认0.0
:param background_height: 背景高度范围0.0-1.0默认0.14
:param background_width: 背景宽度范围0.0-1.0默认0.14
:param background_horizontal_offset: 背景水平偏移范围0.0-1.0默认0.5
:param background_vertical_offset: 背景垂直偏移范围0.0-1.0默认0.5
:param shadow_enabled: 是否启用阴影默认False
:param shadow_alpha: 阴影透明度范围0.0-1.0默认0.9
:param shadow_angle: 阴影角度范围-180.0-180.0默认-45.0
:param shadow_color: 阴影颜色默认黑色
:param shadow_distance: 阴影距离默认5.0
:param shadow_smoothing: 阴影平滑度范围0.0-1.0默认0.15
2025-07-13 16:18:27 +08:00
:param bubble_effect_id: Bubble effect ID
:param bubble_resource_id: Bubble resource ID
:param effect_effect_id: Text effect ID
:param intro_animation: Intro animation type
:param intro_duration: Intro animation duration (seconds), default 0.5 seconds
:param outro_animation: Outro animation type
:param outro_duration: Outro animation duration (seconds), default 0.5 seconds
:param width: Video width (pixels)
:param height: Video height (pixels)
:param fixed_width: Text fixed width ratio, range 0.0-1.0, default -1 means not fixed
:param fixed_height: Text fixed height ratio, range 0.0-1.0, default -1 means not fixed
2025-08-01 08:57:32 +08:00
:param text_styles: 文本的不同部分的样式列表每个元素是一个TextStyleRange
2025-07-13 16:18:27 +08:00
:return: Updated draft information
"""
2025-07-13 16:18:27 +08:00
# Validate if font is in Font_type
2025-08-12 15:29:35 +08:00
if font is None:
font_type = None
else:
try:
font_type = getattr(Font_type, font)
except:
available_fonts = [attr for attr in dir(Font_type) if not attr.startswith('_')]
raise ValueError(f"Unsupported font: {font}, please use one of the fonts in Font_type: {available_fonts}")
2025-07-13 16:18:27 +08:00
# Validate alpha value range
if not 0.0 <= font_alpha <= 1.0:
2025-07-13 16:18:27 +08:00
raise ValueError("alpha value must be between 0.0 and 1.0")
if not 0.0 <= border_alpha <= 1.0:
2025-07-13 16:18:27 +08:00
raise ValueError("border_alpha value must be between 0.0 and 1.0")
if not 0.0 <= background_alpha <= 1.0:
2025-07-13 16:18:27 +08:00
raise ValueError("background_alpha value must be between 0.0 and 1.0")
2025-07-13 16:18:27 +08:00
# Get or create draft
draft_id, script = get_or_create_draft(
draft_id=draft_id,
width=width,
height=height
)
2025-07-13 16:18:27 +08:00
# Add text track
if track_name is not None:
try:
imported_track = script.get_imported_track(draft.Track_type.text, name=track_name)
2025-07-13 16:18:27 +08:00
# If no exception is thrown, the track already exists
except exceptions.TrackNotFound:
2025-07-13 16:18:27 +08:00
# Track doesn't exist, create a new track
script.add_track(draft.Track_type.text, track_name=track_name)
else:
script.add_track(draft.Track_type.audio)
2025-07-13 16:18:27 +08:00
# Convert hexadecimal color to RGB tuple
try:
rgb_color = hex_to_rgb(font_color)
rgb_border_color = hex_to_rgb(border_color)
except ValueError as e:
2025-07-13 16:18:27 +08:00
raise ValueError(f"Color parameter error: {str(e)}")
2025-07-13 16:18:27 +08:00
# Create text_border
text_border = None
if border_width > 0:
text_border = draft.Text_border(
alpha=border_alpha,
color=rgb_border_color,
width=border_width
)
2025-07-13 16:18:27 +08:00
# Create text_background
text_background = None
if background_alpha > 0:
text_background = draft.Text_background(
color=background_color,
style=background_style,
2025-08-01 08:57:32 +08:00
alpha=background_alpha,
round_radius=background_round_radius,
height=background_height,
width=background_width,
horizontal_offset=background_horizontal_offset,
vertical_offset=background_vertical_offset
)
2025-08-01 08:57:32 +08:00
# 创建text_shadow (阴影)
text_shadow = None
if shadow_enabled:
text_shadow = draft.Text_shadow(
has_shadow=shadow_enabled,
alpha=shadow_alpha,
angle=shadow_angle,
color=shadow_color,
distance=shadow_distance,
smoothing=shadow_smoothing
)
2025-07-13 16:18:27 +08:00
# Create bubble effect
text_bubble = None
if bubble_effect_id and bubble_resource_id:
text_bubble = TextBubble(
effect_id=bubble_effect_id,
resource_id=bubble_resource_id
)
2025-07-13 16:18:27 +08:00
# Create text effect
text_effect = None
if effect_effect_id:
text_effect = TextEffect(
effect_id=effect_effect_id
)
2025-07-13 16:18:27 +08:00
# Convert ratio to pixel value
pixel_fixed_width = -1
pixel_fixed_height = -1
if fixed_width > 0:
pixel_fixed_width = int(fixed_width * script.width)
if fixed_height > 0:
pixel_fixed_height = int(fixed_height * script.height)
2025-07-13 16:18:27 +08:00
# Create text segment (using configurable parameters)
text_segment = draft.Text_segment(
text,
trange(f"{start}s", f"{end-start}s"),
2025-07-13 16:18:27 +08:00
font=font_type, # Use font from Font_type
style=draft.Text_style(
color=rgb_color,
size=font_size,
align=1,
2025-07-13 16:18:27 +08:00
vertical=vertical, # Set whether to display vertically
alpha=font_alpha # Set transparency
),
clip_settings=draft.Clip_settings(transform_y=transform_y, transform_x=transform_x),
border=text_border,
background=text_background,
2025-08-01 08:57:32 +08:00
shadow=text_shadow,
fixed_width=pixel_fixed_width,
fixed_height=pixel_fixed_height
)
2025-08-01 08:57:32 +08:00
# 应用多样式文本设置
if text_styles:
for style_range in text_styles:
# 验证范围有效性
if style_range.start < 0 or style_range.end > len(text) or style_range.start >= style_range.end:
raise ValueError(f"无效的文本范围: [{style_range.start}, {style_range.end}), 文本长度: {len(text)}")
# 应用样式到特定文本范围
text_segment.add_text_style(style_range)
if text_bubble:
text_segment.add_bubble(text_bubble.effect_id, text_bubble.resource_id)
if text_effect:
text_segment.add_effect(text_effect.effect_id)
2025-07-13 16:18:27 +08:00
# Add intro animation
if intro_animation:
try:
if IS_CAPCUT_ENV:
animation_type = getattr(draft.CapCut_Text_intro, intro_animation)
else:
animation_type = getattr(draft.Text_intro, intro_animation)
2025-07-13 16:18:27 +08:00
# Convert seconds to microseconds
duration_microseconds = int(intro_duration * 1000000)
2025-07-13 16:18:27 +08:00
text_segment.add_animation(animation_type, duration_microseconds) # Add intro animation, set duration
except:
2025-07-13 16:18:27 +08:00
print(f"Warning: Unsupported intro animation type {intro_animation}, this parameter will be ignored")
2025-07-13 16:18:27 +08:00
# Add outro animation
if outro_animation:
try:
if IS_CAPCUT_ENV:
animation_type = getattr(draft.CapCut_Text_outro, outro_animation)
else:
animation_type = getattr(draft.Text_outro, outro_animation)
2025-07-13 16:18:27 +08:00
# Convert seconds to microseconds
duration_microseconds = int(outro_duration * 1000000)
2025-07-13 16:18:27 +08:00
text_segment.add_animation(animation_type, duration_microseconds) # Add outro animation, set duration
except:
2025-07-13 16:18:27 +08:00
print(f"Warning: Unsupported outro animation type {outro_animation}, this parameter will be ignored")
2025-07-13 16:18:27 +08:00
# Add text segment to track
script.add_segment(text_segment, track_name=track_name)
return {
"draft_id": draft_id,
"draft_url": generate_draft_url(draft_id)
}