@@ -11,11 +11,11 @@ import {
1111 generateRichCaptionFrame ,
1212 createDefaultGeneratorConfig ,
1313 createWebPainter ,
14+ buildCaptionLayoutConfig ,
1415 parseSubtitleToWords ,
1516 CanvasRichCaptionAssetSchema ,
1617 type CanvasRichCaptionAsset ,
1718 type CaptionLayout ,
18- type CaptionLayoutConfig ,
1919 type RichCaptionGeneratorConfig ,
2020 type WordTiming
2121} from "@shotstack/shotstack-canvas" ;
@@ -217,8 +217,9 @@ export class RichCaptionPlayer extends Player {
217217 this . validatedAsset = canvasValidation . data ;
218218
219219 const { width, height } = this . getSize ( ) ;
220- const layoutConfig = this . buildLayoutConfig ( this . validatedAsset , width , height ) ;
221- const canvasTextMeasurer = this . createCanvasTextMeasurer ( ) ;
220+ const layoutConfig = buildCaptionLayoutConfig ( this . validatedAsset , width , height ) ;
221+ const letterSpacing = this . validatedAsset ?. style ?. letterSpacing ;
222+ const canvasTextMeasurer = this . createCanvasTextMeasurer ( letterSpacing ) ;
222223 if ( canvasTextMeasurer ) {
223224 layoutConfig . measureTextWidth = canvasTextMeasurer ;
224225 }
@@ -250,9 +251,10 @@ export class RichCaptionPlayer extends Player {
250251 this . layoutEngine = new CaptionLayoutEngine ( this . fontRegistry ) ;
251252
252253 const { width, height } = this . getSize ( ) ;
253- const layoutConfig = this . buildLayoutConfig ( this . validatedAsset , width , height ) ;
254+ const layoutConfig = buildCaptionLayoutConfig ( this . validatedAsset , width , height ) ;
254255
255- const canvasTextMeasurer = this . createCanvasTextMeasurer ( ) ;
256+ const letterSpacing = this . validatedAsset ?. style ?. letterSpacing ;
257+ const canvasTextMeasurer = this . createCanvasTextMeasurer ( letterSpacing ) ;
256258 if ( canvasTextMeasurer ) {
257259 layoutConfig . measureTextWidth = canvasTextMeasurer ;
258260 }
@@ -500,51 +502,16 @@ export class RichCaptionPlayer extends Player {
500502 return payload ;
501503 }
502504
503- private buildLayoutConfig ( asset : CanvasRichCaptionAsset , frameWidth : number , frameHeight : number ) : CaptionLayoutConfig {
504- const { font, style, align, padding : rawPadding } = asset ;
505-
506- let padding : { top : number ; right : number ; bottom : number ; left : number } ;
507- if ( typeof rawPadding === "number" ) {
508- padding = { top : rawPadding , right : rawPadding , bottom : rawPadding , left : rawPadding } ;
509- } else if ( rawPadding ) {
510- const p = rawPadding as { top ?: number ; right ?: number ; bottom ?: number ; left ?: number } ;
511- padding = { top : p . top ?? 0 , right : p . right ?? 0 , bottom : p . bottom ?? 0 , left : p . left ?? 0 } ;
512- } else {
513- padding = { top : 0 , right : 0 , bottom : 0 , left : 0 } ;
514- }
515-
516- const totalHorizontalPadding = padding . left + padding . right ;
517- const availableWidth = totalHorizontalPadding > 0 ? frameWidth - totalHorizontalPadding : frameWidth * 0.9 ;
518-
519- const fontSize = font ?. size ?? 24 ;
520- const lineHeight = style ?. lineHeight ?? 1.2 ;
521- const availableHeight = frameHeight - padding . top - padding . bottom ;
522- const maxLines = Math . max ( 1 , Math . min ( 10 , Math . floor ( availableHeight / ( fontSize * lineHeight ) ) ) ) ;
523-
524- return {
525- frameWidth,
526- frameHeight,
527- availableWidth,
528- maxLines,
529- verticalAlign : align ?. vertical ?? "middle" ,
530- horizontalAlign : align ?. horizontal ?? "center" ,
531- padding,
532- fontSize,
533- fontFamily : font ?. family ?? "Roboto" ,
534- fontWeight : String ( font ?. weight ?? "400" ) ,
535- letterSpacing : style ?. letterSpacing ?? 0 ,
536- lineHeight,
537- textTransform : ( style ?. textTransform as CaptionLayoutConfig [ "textTransform" ] ) ?? "none" ,
538- pauseThreshold : this . resolvedPauseThreshold
539- } ;
540- }
541-
542- private createCanvasTextMeasurer ( ) : ( ( text : string , font : string ) => number ) | undefined {
505+ private createCanvasTextMeasurer ( letterSpacing ?: number ) : ( ( text : string , font : string ) => number ) | undefined {
543506 try {
544507 const measureCanvas = document . createElement ( "canvas" ) ;
545508 const ctx = measureCanvas . getContext ( "2d" ) ;
546509 if ( ! ctx ) return undefined ;
547510
511+ if ( letterSpacing ) {
512+ ( ctx as unknown as Record < string , unknown > ) [ "letterSpacing" ] = `${ letterSpacing } px` ;
513+ }
514+
548515 return ( text : string , font : string ) : number => {
549516 ctx . font = font ;
550517 return ctx . measureText ( text ) . width ;
@@ -684,8 +651,9 @@ export class RichCaptionPlayer extends Player {
684651
685652 if ( ! this . layoutEngine ) return ;
686653
687- const layoutConfig = this . buildLayoutConfig ( this . validatedAsset , width , height ) ;
688- const canvasTextMeasurer = this . createCanvasTextMeasurer ( ) ;
654+ const layoutConfig = buildCaptionLayoutConfig ( this . validatedAsset , width , height ) ;
655+ const letterSpacing = this . validatedAsset ?. style ?. letterSpacing ;
656+ const canvasTextMeasurer = this . createCanvasTextMeasurer ( letterSpacing ) ;
689657 if ( canvasTextMeasurer ) {
690658 layoutConfig . measureTextWidth = canvasTextMeasurer ;
691659 }
0 commit comments