@@ -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