Skip to content

Commit 226ba8e

Browse files
authored
Merge pull request #467 from x007xyz/main
feat: 实现字幕超过屏幕宽度换行
2 parents 251f277 + e6454db commit 226ba8e

File tree

1 file changed

+63
-4
lines changed

1 file changed

+63
-4
lines changed

packages/av-cliper/src/clips/embed-subtitles-clip.ts

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,72 @@ export class EmbedSubtitlesClip implements IClip {
136136
this.ready = Promise.resolve(this.meta);
137137
}
138138

139+
#wrapText(text: string, maxWidth: number): string[] {
140+
const lines: string[] = [];
141+
let currentLine = '';
142+
143+
// 检测是否包含中文字符
144+
const hasChinese = /[\u4e00-\u9fff]/.test(text);
145+
146+
if (hasChinese) {
147+
// 中英混合文本:优先在标点符号和英文单词边界换行
148+
for (let i = 0; i < text.length; i++) {
149+
const char = text[i];
150+
const testLine = currentLine + char;
151+
const metrics = this.#ctx.measureText(testLine);
152+
153+
if (metrics.width <= maxWidth) {
154+
currentLine = testLine;
155+
} else {
156+
if (currentLine) {
157+
lines.push(currentLine);
158+
currentLine = char;
159+
} else {
160+
// 单个字符就超宽,强制换行
161+
lines.push(char);
162+
currentLine = '';
163+
}
164+
}
165+
}
166+
if (currentLine) {
167+
lines.push(currentLine);
168+
}
169+
} else {
170+
// 纯英文按单词换行
171+
const words = text.split(' ');
172+
173+
for (const word of words) {
174+
const testLine = currentLine ? `${currentLine} ${word}` : word;
175+
const metrics = this.#ctx.measureText(testLine);
176+
177+
if (metrics.width <= maxWidth) {
178+
currentLine = testLine;
179+
} else {
180+
if (currentLine) {
181+
lines.push(currentLine);
182+
currentLine = word;
183+
} else {
184+
lines.push(word);
185+
}
186+
}
187+
}
188+
189+
if (currentLine) {
190+
lines.push(currentLine);
191+
}
192+
}
193+
194+
return lines;
195+
}
196+
139197
#renderTxt(txt: string) {
198+
const { width, height } = this.#cvs;
199+
const maxTextWidth = width * 0.9; // 留出10%的边距
200+
140201
const lines = txt
141202
.split('\n')
142-
.reverse()
143-
.map((t) => t.trim());
144-
145-
const { width, height } = this.#cvs;
203+
.flatMap((line) => this.#wrapText(line.trim(), maxTextWidth))
204+
.reverse();
146205

147206
const {
148207
color,

0 commit comments

Comments
 (0)