mirror of
https://github.com/Hommy-master/capcut-mate.git
synced 2026-08-28 23:27:50 +08:00
添加关键词阴影。
This commit is contained in:
@@ -94,6 +94,12 @@ Default shadow when enabled without `*_shadow_info`:
|
||||
|
||||
If `text_effect` resolves to a valid effect, the API resets `text_color` to `#ffffff`, `border_color` to `null`, `has_shadow` to `false`, and disables keyword shadow. Omit/leave `text_effect` null when you need custom colors or shadows.
|
||||
|
||||
### Notes on keyword shadow
|
||||
|
||||
`keyword_has_shadow` / `keyword_shadow_info` work like `keyword_color` / `keyword_border_color`: they stay on the **same caption segment** and do not create an extra text line.
|
||||
|
||||
When keyword shadow is enabled, the caption is split into non-overlapping `styles` partitions: normal ranges get `shadows: []`, keyword ranges get the shadow params. Without keyword shadow fields, the original base + keyword overlay path is unchanged.
|
||||
|
||||
## Fully Annotated Request Example
|
||||
|
||||
`//` comments are for documentation only and are **not** valid in a real request body.
|
||||
|
||||
@@ -107,6 +107,12 @@ POST /openapi/capcut-mate/v1/add_captions
|
||||
|
||||
当 `text_effect` 能解析到有效花字时,系统会将 `text_color` 重置为 `#ffffff`、`border_color` 重置为 `null`、`has_shadow` 重置为 `false`,并禁用关键词阴影(`keyword_has_shadow` 不生效)。若需要自定义颜色/阴影,请不要同时传有效花字。
|
||||
|
||||
#### 关键词阴影如何生效
|
||||
|
||||
`keyword_has_shadow` / `keyword_shadow_info` 与 `keyword_color` / `keyword_border_color` 一样,都作用在**同一条字幕**内,不会新建额外字幕行。
|
||||
|
||||
实现上会把字幕拆成互不重叠的 `styles` 分区:普通文字分区 `shadows: []`,关键词分区写入阴影参数,从而尽量只让关键词带阴影。不传阴影相关字段时,仍走原来的「base + 关键词叠加样式」路径,行为与增加阴影功能前一致。
|
||||
|
||||
## 完整参数请求示例(含注释)
|
||||
|
||||
下列为**全部接口级参数 + captions 全部字段**的示意;`//` 注释仅用于说明,不能直接作为请求体。
|
||||
@@ -370,7 +376,7 @@ curl -X POST https://capcut-mate.jcaigc.cn/openapi/capcut-mate/v1/add_captions \
|
||||
4. **动画名称**:请通过 `get_text_animations` 获取可用名称
|
||||
5. **花字名称**:请通过 `get_text_effects` 获取可用名称或 `effect_id`
|
||||
6. **坐标系统**:`transform_x` / `transform_y` 使用像素,内部会按画布尺寸换算
|
||||
7. **关键词阴影**:仅作用于关键词字符范围;整段阴影由 `has_shadow` / `shadow_info` 控制
|
||||
7. **关键词阴影**:与关键词颜色/描边一样写在同一字幕的 styles 分区内,不另建字幕行;整段阴影仍由 `has_shadow` / `shadow_info` 控制
|
||||
|
||||
## 工作流程
|
||||
|
||||
|
||||
@@ -307,6 +307,8 @@ class TextSegment(VisualSegment):
|
||||
self.bubble = None
|
||||
self.effect = None
|
||||
self.extra_styles = []
|
||||
# 为 True 时 export 使用 extra_styles 作为完整 styles(互不重叠分区),不再叠加全量 base_style
|
||||
self.use_extra_styles_only = False
|
||||
|
||||
@classmethod
|
||||
def create_from_template(cls, text: str, timerange: Timerange, template: "TextSegment") -> "TextSegment":
|
||||
@@ -400,53 +402,58 @@ class TextSegment(VisualSegment):
|
||||
check_flag |= 8
|
||||
if self.background:
|
||||
check_flag |= 16
|
||||
# 整段阴影,或关键词等 extra_styles 上的阴影,都需要打开阴影位
|
||||
has_extra_shadow = any(
|
||||
isinstance(style, dict) and style.get("shadows")
|
||||
for style in self.extra_styles
|
||||
|
||||
if self.use_extra_styles_only and self.extra_styles:
|
||||
styles = list(self.extra_styles)
|
||||
else:
|
||||
# 创建基础样式
|
||||
base_style = {
|
||||
"fill": {
|
||||
"alpha": 1.0,
|
||||
"content": {
|
||||
"render_type": "solid",
|
||||
"solid": {
|
||||
"alpha": 1.0,
|
||||
"color": list(self.style.color)
|
||||
}
|
||||
}
|
||||
},
|
||||
"range": [0, len(self.text.encode('utf-16-le'))],
|
||||
"size": self.style.size,
|
||||
"bold": self.style.bold,
|
||||
"italic": self.style.italic,
|
||||
"underline": self.style.underline,
|
||||
"strokes": [self.border.export_json()] if self.border else []
|
||||
}
|
||||
# 合并基础样式和额外样式(额外样式按 range 覆盖 fill/size/strokes 等)
|
||||
styles = [base_style] + self.extra_styles
|
||||
|
||||
# 素材级 shadow,或 styles 分区内的非空 shadows,都需要打开阴影位
|
||||
has_style_shadows = any(
|
||||
isinstance(style, dict) and bool(style.get("shadows"))
|
||||
for style in styles
|
||||
)
|
||||
if self.shadow or has_extra_shadow:
|
||||
if self.shadow or has_style_shadows:
|
||||
check_flag |= 32
|
||||
|
||||
# 创建基础样式
|
||||
base_style = {
|
||||
"fill": {
|
||||
"alpha": 1.0,
|
||||
"content": {
|
||||
"render_type": "solid",
|
||||
"solid": {
|
||||
"alpha": 1.0,
|
||||
"color": list(self.style.color)
|
||||
}
|
||||
}
|
||||
},
|
||||
"range": [0, len(self.text.encode('utf-16-le'))],
|
||||
"size": self.style.size,
|
||||
"bold": self.style.bold,
|
||||
"italic": self.style.italic,
|
||||
"underline": self.style.underline,
|
||||
"strokes": [self.border.export_json()] if self.border else []
|
||||
}
|
||||
|
||||
# 合并基础样式和额外样式
|
||||
styles = [base_style] + self.extra_styles
|
||||
|
||||
content_json = {
|
||||
"styles": styles,
|
||||
"text": self.text
|
||||
}
|
||||
if self.font:
|
||||
content_json["styles"][0]["font"] = {
|
||||
"id": self.font.resource_id,
|
||||
"path": "D:" # 并不会真正在此处放置字体文件
|
||||
}
|
||||
if self.effect:
|
||||
content_json["styles"][0]["effectStyle"] = {
|
||||
"id": self.effect.effect_id,
|
||||
"path": "C:" # 并不会真正在此处放置素材文件
|
||||
}
|
||||
if self.shadow:
|
||||
content_json["styles"][0]["shadows"] = [self.shadow.export_json()]
|
||||
if styles:
|
||||
if self.font:
|
||||
content_json["styles"][0]["font"] = {
|
||||
"id": self.font.resource_id,
|
||||
"path": "D:" # 并不会真正在此处放置字体文件
|
||||
}
|
||||
if self.effect:
|
||||
content_json["styles"][0]["effectStyle"] = {
|
||||
"id": self.effect.effect_id,
|
||||
"path": "C:" # 并不会真正在此处放置素材文件
|
||||
}
|
||||
# 仅素材级整段阴影写入 styles[0];分区阴影已在各自 style 中
|
||||
if self.shadow:
|
||||
content_json["styles"][0]["shadows"] = [self.shadow.export_json()]
|
||||
|
||||
ret = {
|
||||
"id": self.material_id,
|
||||
|
||||
+225
-72
@@ -242,7 +242,7 @@ def add_captions(
|
||||
bold=bold,
|
||||
has_shadow=has_shadow,
|
||||
shadow_info=shadow_info,
|
||||
text_effect=text_effect
|
||||
text_effect=text_effect,
|
||||
)
|
||||
segment_ids.append(segment_id)
|
||||
text_ids.append(text_id)
|
||||
@@ -418,7 +418,7 @@ def add_caption_to_draft(
|
||||
bold: bool = False,
|
||||
has_shadow: bool = False,
|
||||
shadow_info: Optional[ShadowInfo] = None,
|
||||
text_effect: Optional[str] = None
|
||||
text_effect: Optional[str] = None,
|
||||
) -> Tuple[str, str, dict]:
|
||||
"""
|
||||
向剪映草稿中添加单个字幕
|
||||
@@ -598,7 +598,7 @@ def add_caption_to_draft(
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to add text effect '{text_effect}': {str(e)}")
|
||||
|
||||
# 11. 处理关键词高亮
|
||||
# 11. 处理关键词高亮(颜色/描边/字号/阴影均在同一字幕的 styles 分区内完成,不另建片段)
|
||||
if caption.get('keyword'):
|
||||
keyword_color = caption.get('keyword_color', '#ff7100') # 默认橙色
|
||||
keyword_rgb_color = hex_to_rgb(keyword_color)
|
||||
@@ -617,16 +617,35 @@ def add_caption_to_draft(
|
||||
keyword_has_shadow = False
|
||||
keyword_shadow_info = caption.get('keyword_shadow_info')
|
||||
|
||||
# 应用关键词颜色和字体大小到文本样式中
|
||||
apply_keyword_highlight(
|
||||
text_segment,
|
||||
caption['keyword'],
|
||||
keyword_rgb_color,
|
||||
keyword_font_size,
|
||||
keyword_border_rgb_color,
|
||||
keyword_has_shadow=keyword_has_shadow,
|
||||
keyword_shadow_info=keyword_shadow_info,
|
||||
)
|
||||
if keyword_has_shadow:
|
||||
# 与 keyword_color / keyword_border_color 一样:在同一段字幕内用互不重叠的 styles 分区表达。
|
||||
# 有关键词阴影时改用完整分区,避免「全量 base + 局部 shadows」被剪映当成整段阴影。
|
||||
normal_shadows = None
|
||||
if has_shadow and text_shadow is not None:
|
||||
normal_shadows = [text_shadow.export_json()]
|
||||
# 阴影已写入各 style 分区,清除素材级 shadow,避免再强制写到 styles[0]
|
||||
text_segment.shadow = None
|
||||
apply_keyword_partitioned_styles(
|
||||
text_segment,
|
||||
caption['keyword'],
|
||||
keyword_rgb_color,
|
||||
keyword_font_size,
|
||||
keyword_border_rgb_color,
|
||||
keyword_shadows=_shadow_info_to_export_list(keyword_shadow_info),
|
||||
normal_shadows=normal_shadows,
|
||||
normal_border_rgb=(
|
||||
hex_to_rgb(border_color) if border_color else None
|
||||
),
|
||||
)
|
||||
else:
|
||||
apply_keyword_highlight(
|
||||
text_segment,
|
||||
caption['keyword'],
|
||||
keyword_rgb_color,
|
||||
keyword_font_size,
|
||||
keyword_border_rgb_color,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Applied keyword highlighting: {caption['keyword']} with color {keyword_color}, "
|
||||
f"font size {keyword_font_size}, border color {keyword_border_color or border_color}, "
|
||||
@@ -697,6 +716,187 @@ def add_caption_to_draft(
|
||||
raise CustomException(CustomError.CAPTION_ADD_FAILED)
|
||||
|
||||
|
||||
def _shadow_info_to_export_list(shadow_info: Optional[dict] = None) -> List[dict]:
|
||||
"""将 keyword_shadow_info / 默认阴影转为 styles[].shadows 数组。"""
|
||||
return [_build_text_shadow(shadow_info).export_json()]
|
||||
|
||||
|
||||
def _find_keyword_ranges(text: str, keywords: str) -> List[Tuple[int, int]]:
|
||||
"""按关键词长度优先匹配,返回不重叠的 [start, end) 字符下标区间。"""
|
||||
keyword_list = sorted(
|
||||
(kw.strip() for kw in keywords.split('|') if kw.strip()),
|
||||
key=len,
|
||||
reverse=True,
|
||||
)
|
||||
used = set()
|
||||
ranges: List[Tuple[int, int]] = []
|
||||
for keyword in keyword_list:
|
||||
start_pos = 0
|
||||
while start_pos < len(text):
|
||||
start_pos = text.find(keyword, start_pos)
|
||||
if start_pos == -1:
|
||||
break
|
||||
end_pos = start_pos + len(keyword)
|
||||
if any(i in used for i in range(start_pos, end_pos)):
|
||||
start_pos = end_pos
|
||||
continue
|
||||
ranges.append((start_pos, end_pos))
|
||||
used.update(range(start_pos, end_pos))
|
||||
start_pos = end_pos
|
||||
ranges.sort(key=lambda item: item[0])
|
||||
return ranges
|
||||
|
||||
|
||||
def _build_style_partition(
|
||||
start: int,
|
||||
end: int,
|
||||
*,
|
||||
color: tuple,
|
||||
font_size: float,
|
||||
bold: bool,
|
||||
italic: bool,
|
||||
underline: bool,
|
||||
border_rgb: Optional[tuple] = None,
|
||||
shadows: Optional[List[dict]] = None,
|
||||
include_shadow_field: bool = False,
|
||||
) -> dict:
|
||||
"""构造单个互不重叠的 style 分区(range 使用字符下标,与 keyword_color 历史行为一致)。"""
|
||||
style = {
|
||||
"fill": {
|
||||
"alpha": 1.0,
|
||||
"content": {
|
||||
"render_type": "solid",
|
||||
"solid": {
|
||||
"alpha": 1.0,
|
||||
"color": list(color),
|
||||
},
|
||||
},
|
||||
},
|
||||
"range": [start, end],
|
||||
"size": font_size,
|
||||
"bold": bold,
|
||||
"italic": italic,
|
||||
"underline": underline,
|
||||
"strokes": [],
|
||||
}
|
||||
if border_rgb is not None:
|
||||
style["strokes"] = [{
|
||||
"content": {
|
||||
"solid": {
|
||||
"alpha": 1.0,
|
||||
"color": list(border_rgb),
|
||||
}
|
||||
},
|
||||
"width": 0.08,
|
||||
}]
|
||||
if include_shadow_field:
|
||||
style["shadows"] = list(shadows) if shadows else []
|
||||
return style
|
||||
|
||||
|
||||
def apply_keyword_partitioned_styles(
|
||||
text_segment: TextSegment,
|
||||
keywords: str,
|
||||
keyword_color: tuple,
|
||||
keyword_font_size: float = None,
|
||||
keyword_border_color: tuple = None,
|
||||
keyword_shadows: Optional[List[dict]] = None,
|
||||
normal_shadows: Optional[List[dict]] = None,
|
||||
normal_border_rgb: Optional[tuple] = None,
|
||||
):
|
||||
"""
|
||||
用互不重叠的 styles 分区表达关键词样式(含可选局部阴影)。
|
||||
|
||||
与 add_text_style / keyword_color 相同:仍是同一条字幕,不新建片段。
|
||||
当需要关键词阴影时,必须用完整分区,而不能「全量 base + 局部 shadows 叠加」,
|
||||
否则剪映容易把阴影作用到整段文字。
|
||||
"""
|
||||
text = text_segment.text
|
||||
font_size = keyword_font_size if keyword_font_size is not None else text_segment.style.size
|
||||
keyword_ranges = _find_keyword_ranges(text, keywords)
|
||||
include_shadow_field = bool(keyword_shadows or normal_shadows)
|
||||
|
||||
styles: List[dict] = []
|
||||
cursor = 0
|
||||
for start, end in keyword_ranges:
|
||||
if cursor < start:
|
||||
styles.append(_build_style_partition(
|
||||
cursor,
|
||||
start,
|
||||
color=text_segment.style.color,
|
||||
font_size=text_segment.style.size,
|
||||
bold=text_segment.style.bold,
|
||||
italic=text_segment.style.italic,
|
||||
underline=text_segment.style.underline,
|
||||
border_rgb=normal_border_rgb,
|
||||
shadows=normal_shadows,
|
||||
include_shadow_field=include_shadow_field,
|
||||
))
|
||||
styles.append(_build_style_partition(
|
||||
start,
|
||||
end,
|
||||
color=keyword_color,
|
||||
font_size=font_size,
|
||||
bold=text_segment.style.bold,
|
||||
italic=text_segment.style.italic,
|
||||
underline=text_segment.style.underline,
|
||||
border_rgb=keyword_border_color,
|
||||
shadows=keyword_shadows,
|
||||
include_shadow_field=include_shadow_field,
|
||||
))
|
||||
cursor = end
|
||||
|
||||
if cursor < len(text):
|
||||
styles.append(_build_style_partition(
|
||||
cursor,
|
||||
len(text),
|
||||
color=text_segment.style.color,
|
||||
font_size=text_segment.style.size,
|
||||
bold=text_segment.style.bold,
|
||||
italic=text_segment.style.italic,
|
||||
underline=text_segment.style.underline,
|
||||
border_rgb=normal_border_rgb,
|
||||
shadows=normal_shadows,
|
||||
include_shadow_field=include_shadow_field,
|
||||
))
|
||||
|
||||
if not styles:
|
||||
styles.append(_build_style_partition(
|
||||
0,
|
||||
len(text),
|
||||
color=text_segment.style.color,
|
||||
font_size=text_segment.style.size,
|
||||
bold=text_segment.style.bold,
|
||||
italic=text_segment.style.italic,
|
||||
underline=text_segment.style.underline,
|
||||
border_rgb=normal_border_rgb,
|
||||
shadows=normal_shadows,
|
||||
include_shadow_field=include_shadow_field,
|
||||
))
|
||||
|
||||
text_segment.extra_styles = styles
|
||||
text_segment.use_extra_styles_only = True
|
||||
|
||||
|
||||
def _build_text_shadow(shadow_info: Optional[dict] = None) -> TextShadow:
|
||||
"""根据 shadow_info(或默认值)构造 TextShadow。"""
|
||||
if shadow_info is None:
|
||||
return TextShadow(
|
||||
alpha=0.9,
|
||||
color=hex_to_rgb("#000000"),
|
||||
diffuse=15.0,
|
||||
distance=5.0,
|
||||
angle=-45.0,
|
||||
)
|
||||
return TextShadow(
|
||||
alpha=float(shadow_info.get("shadow_alpha", 1.0)),
|
||||
color=hex_to_rgb(str(shadow_info.get("shadow_color", "#000000"))),
|
||||
diffuse=float(shadow_info.get("shadow_diffuse", 15.0)),
|
||||
distance=float(shadow_info.get("shadow_distance", 5.0)),
|
||||
angle=float(shadow_info.get("shadow_angle", -45.0)),
|
||||
)
|
||||
|
||||
|
||||
def apply_keyword_highlight(
|
||||
text_segment: TextSegment,
|
||||
keywords: str,
|
||||
@@ -707,67 +907,29 @@ def apply_keyword_highlight(
|
||||
keyword_shadow_info: Optional[dict] = None,
|
||||
):
|
||||
"""
|
||||
应用关键词高亮到文本片段
|
||||
|
||||
Args:
|
||||
text_segment: 文本片段对象
|
||||
keywords: 关键词字符串,用'|'分隔多个关键词
|
||||
keyword_color: 关键词颜色的RGB元组 (0-1范围)
|
||||
keyword_font_size: 关键词字体大小,默认为None,使用文本默认字体大小
|
||||
keyword_border_color: 关键词边框颜色的RGB元组 (0-1范围),默认为None
|
||||
keyword_has_shadow: 是否启用关键词阴影,默认 False
|
||||
keyword_shadow_info: 关键词阴影参数字典,字段与 ShadowInfo 一致,默认为None
|
||||
应用关键词高亮到文本片段(颜色 / 字号 / 描边)。
|
||||
|
||||
与历史行为一致:在同一字幕上追加 extra_styles,range 使用字符下标。
|
||||
关键词阴影请走 apply_keyword_partitioned_styles。
|
||||
"""
|
||||
# 分割关键词
|
||||
del keyword_has_shadow, keyword_shadow_info
|
||||
|
||||
keyword_list = keywords.split('|')
|
||||
text = text_segment.text
|
||||
|
||||
# 使用关键词字体大小,如果没有指定则使用文本默认字体大小
|
||||
font_size = keyword_font_size if keyword_font_size is not None else text_segment.style.size
|
||||
|
||||
# 预构建关键词阴影(与字幕级 TextShadow.export_json 格式一致)
|
||||
keyword_shadows = None
|
||||
if keyword_has_shadow:
|
||||
if keyword_shadow_info is None:
|
||||
shadow_rgb_color = hex_to_rgb("#000000")
|
||||
shadow_alpha = 0.9
|
||||
shadow_diffuse = 15.0
|
||||
shadow_distance = 5.0
|
||||
shadow_angle = -45.0
|
||||
else:
|
||||
shadow_rgb_color = hex_to_rgb(keyword_shadow_info.get("shadow_color", "#000000"))
|
||||
shadow_alpha = float(keyword_shadow_info.get("shadow_alpha", 1.0))
|
||||
shadow_diffuse = float(keyword_shadow_info.get("shadow_diffuse", 15.0))
|
||||
shadow_distance = float(keyword_shadow_info.get("shadow_distance", 5.0))
|
||||
shadow_angle = float(keyword_shadow_info.get("shadow_angle", -45.0))
|
||||
keyword_shadows = [{
|
||||
"diffuse": shadow_diffuse / 100.0 / 6, # /6是剪映自带的映射
|
||||
"alpha": shadow_alpha,
|
||||
"distance": shadow_distance,
|
||||
"content": {
|
||||
"solid": {
|
||||
"color": list(shadow_rgb_color),
|
||||
}
|
||||
},
|
||||
"angle": shadow_angle
|
||||
}]
|
||||
|
||||
# 为每个关键词创建高亮样式
|
||||
for keyword in keyword_list:
|
||||
keyword = keyword.strip()
|
||||
if not keyword:
|
||||
continue
|
||||
|
||||
# 查找所有匹配的关键词位置
|
||||
|
||||
start_pos = 0
|
||||
while start_pos < len(text):
|
||||
start_pos = text.find(keyword, start_pos)
|
||||
if start_pos == -1:
|
||||
break
|
||||
|
||||
|
||||
end_pos = start_pos + len(keyword)
|
||||
|
||||
# 创建关键词高亮样式
|
||||
highlight_style = {
|
||||
"fill": {
|
||||
"alpha": 1.0,
|
||||
@@ -775,22 +937,18 @@ def apply_keyword_highlight(
|
||||
"render_type": "solid",
|
||||
"solid": {
|
||||
"alpha": 1.0,
|
||||
"color": list(keyword_color) # 使用关键词颜色
|
||||
"color": list(keyword_color)
|
||||
}
|
||||
}
|
||||
},
|
||||
"range": [start_pos, end_pos],
|
||||
"size": font_size, # 使用关键词字体大小
|
||||
"size": font_size,
|
||||
"bold": text_segment.style.bold,
|
||||
"italic": text_segment.style.italic,
|
||||
"underline": text_segment.style.underline
|
||||
}
|
||||
|
||||
# 处理关键词边框颜色:当keyword_border_color不为None时添加描边
|
||||
# keyword_border_color的值由调用方决定:优先使用keyword_border_color参数,否则使用border_color
|
||||
|
||||
if keyword_border_color is not None:
|
||||
# 使用指定的关键词边框颜色创建描边
|
||||
# 注意:剪映的stroke格式需要包含content.solid结构
|
||||
highlight_style["strokes"] = [{
|
||||
"content": {
|
||||
"solid": {
|
||||
@@ -798,14 +956,9 @@ def apply_keyword_highlight(
|
||||
"color": list(keyword_border_color)
|
||||
}
|
||||
},
|
||||
"width": 0.08 # 默认边框宽度(与剪映内部表示一致)
|
||||
"width": 0.08
|
||||
}]
|
||||
# 注意:当keyword_border_color为None时(即既没有指定keyword_border_color也没有指定border_color),不添加描边
|
||||
|
||||
if keyword_shadows is not None:
|
||||
highlight_style["shadows"] = keyword_shadows
|
||||
|
||||
# 添加到文本片段的额外样式中
|
||||
text_segment.extra_styles.append(highlight_style)
|
||||
start_pos = end_pos
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ def test_keyword_font_size_application():
|
||||
assert len(text_segment.extra_styles) == 1
|
||||
highlight_style = text_segment.extra_styles[0]
|
||||
assert highlight_style["size"] == 20.0 # 验证关键词字体大小是否为20
|
||||
assert highlight_style["range"] == [3, 5] # 验证关键词位置是否正确
|
||||
print("✓ keyword_font_size parameter application test passed")
|
||||
assert highlight_style["range"] == [3, 5] # 字符下标:「你好,」后是「剪映」
|
||||
print("keyword_font_size parameter application test passed")
|
||||
|
||||
|
||||
def test_keyword_font_size_default():
|
||||
|
||||
Reference in New Issue
Block a user