From e6454db69dfceb0a410d51f75b806e897ee2b0cd Mon Sep 17 00:00:00 2001 From: "zhangxiang.chen-EFWOM" <1026161550@qq.com> Date: Thu, 18 Sep 2025 15:48:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=AD=97=E5=B9=95?= =?UTF-8?q?=E8=B6=85=E8=BF=87=E5=B1=8F=E5=B9=95=E5=AE=BD=E5=BA=A6=E6=8D=A2?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/clips/embed-subtitles-clip.ts | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/packages/av-cliper/src/clips/embed-subtitles-clip.ts b/packages/av-cliper/src/clips/embed-subtitles-clip.ts index 0cd717d9..ed38e6d0 100644 --- a/packages/av-cliper/src/clips/embed-subtitles-clip.ts +++ b/packages/av-cliper/src/clips/embed-subtitles-clip.ts @@ -136,13 +136,72 @@ export class EmbedSubtitlesClip implements IClip { this.ready = Promise.resolve(this.meta); } + #wrapText(text: string, maxWidth: number): string[] { + const lines: string[] = []; + let currentLine = ''; + + // 检测是否包含中文字符 + const hasChinese = /[\u4e00-\u9fff]/.test(text); + + if (hasChinese) { + // 中英混合文本:优先在标点符号和英文单词边界换行 + for (let i = 0; i < text.length; i++) { + const char = text[i]; + const testLine = currentLine + char; + const metrics = this.#ctx.measureText(testLine); + + if (metrics.width <= maxWidth) { + currentLine = testLine; + } else { + if (currentLine) { + lines.push(currentLine); + currentLine = char; + } else { + // 单个字符就超宽,强制换行 + lines.push(char); + currentLine = ''; + } + } + } + if (currentLine) { + lines.push(currentLine); + } + } else { + // 纯英文按单词换行 + const words = text.split(' '); + + for (const word of words) { + const testLine = currentLine ? `${currentLine} ${word}` : word; + const metrics = this.#ctx.measureText(testLine); + + if (metrics.width <= maxWidth) { + currentLine = testLine; + } else { + if (currentLine) { + lines.push(currentLine); + currentLine = word; + } else { + lines.push(word); + } + } + } + + if (currentLine) { + lines.push(currentLine); + } + } + + return lines; + } + #renderTxt(txt: string) { + const { width, height } = this.#cvs; + const maxTextWidth = width * 0.9; // 留出10%的边距 + const lines = txt .split('\n') - .reverse() - .map((t) => t.trim()); - - const { width, height } = this.#cvs; + .flatMap((line) => this.#wrapText(line.trim(), maxTextWidth)) + .reverse(); const { color,