From 610f91408546d7cc1ee3ccf4f1fdfa3af66e7c2f Mon Sep 17 00:00:00 2001 From: lmk <1095689763@qq.com> Date: Tue, 18 Aug 2026 13:43:11 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AD=97=E5=B9=95=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/dto/video/video_caption_dto.go | 14 ++++++++------ service/video/caption_service.go | 21 ++++++++++++++++++--- service/video/template_service.go | 5 +++++ template_example.html | 11 ++++++++++- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/model/dto/video/video_caption_dto.go b/model/dto/video/video_caption_dto.go index 93304fc..4db8656 100644 --- a/model/dto/video/video_caption_dto.go +++ b/model/dto/video/video_caption_dto.go @@ -15,6 +15,7 @@ type CaptionElement struct { Y string `json:"y" d:"center" dc:"垂直位置:top/center/bottom或像素值"` FontSize int `json:"fontSize" d:"36" dc:"字号(type=text有效)"` FontColor string `json:"fontColor" d:"#FFFFFF" dc:"字体颜色"` + TextAlign string `json:"textAlign" d:"center" dc:"水平对齐:left/center/right(默认center,type=text有效)"` FontStroke string `json:"fontStroke" dc:"字体描边,如3px #000000(空=无描边)"` BgColor string `json:"bgColor" dc:"背景色,如#FFFF00,空=透明"` BgOpacity float64 `json:"bgOpacity" d:"1.0" dc:"背景透明度0-1"` @@ -35,12 +36,13 @@ type SubtitleSegment struct { // SubtitleStyle 字幕样式配置 type SubtitleStyle struct { - FontSize int `json:"fontSize" d:"48" dc:"字号(默认48)"` - FontColor string `json:"fontColor" d:"#FFFFFF" dc:"字体颜色(默认白色)"` - BgColor *string `json:"bgColor" dc:"背景色,空字符串=透明(默认#000000)。传空字符串 '' 可去掉背景色"` - BgOpacity *float64 `json:"bgOpacity" dc:"背景透明度0-1(默认0.4)。传0可使背景完全透明"` - X string `json:"x" d:"center" dc:"水平位置:left/center/right或像素值(默认center)"` - Y string `json:"y" d:"65%" dc:"垂直位置:top/center/bottom或像素值或百分比(默认65%)"` + FontSize int `json:"fontSize" d:"38" dc:"字号(默认38)"` + FontColor string `json:"fontColor" d:"#FFFFFF" dc:"字体颜色(默认白色)"` + FontStroke *string `json:"fontStroke" dc:"字体描边,如0.5px #000000(默认0.5px #000000极细)。传空字符串 '' 可去掉描边"` + BgColor *string `json:"bgColor" dc:"背景色,空=透明(默认无背景)。传颜色值如#FFFF00可加背景色"` + BgOpacity *float64 `json:"bgOpacity" dc:"背景透明度0-1(默认0.4,仅在设置bgColor时生效)。传0可使背景完全透明"` + X string `json:"x" d:"center" dc:"水平位置:left/center/right或像素值(默认center)"` + Y string `json:"y" d:"65%" dc:"垂直位置:top/center/bottom或像素值或百分比(默认65%)"` } // ---------- 创建字幕任务 ---------- diff --git a/service/video/caption_service.go b/service/video/caption_service.go index a113760..5bb85a1 100644 --- a/service/video/caption_service.go +++ b/service/video/caption_service.go @@ -625,6 +625,16 @@ func (s *captionService) buildElemStyle(elem dto.CaptionElement, canvasWidth, ca if elem.FontStroke != "" { parts = append(parts, fmt.Sprintf("-webkit-text-stroke:%s;", elem.FontStroke)) } + + // 水平对齐:覆盖全局 .text-element 的居中(flex 容器用 justify-content,多行文字用 text-align) + switch elem.TextAlign { + case "left": + parts = append(parts, "text-align:left;") + parts = append(parts, "justify-content:flex-start;") + case "right": + parts = append(parts, "text-align:right;") + parts = append(parts, "justify-content:flex-end;") + } } return strings.Join(parts, "") @@ -864,9 +874,10 @@ func hexToRGBA(hex string, alpha float64) string { // subtitlesToElements 将外部传入的字幕时间线转为底部字幕元素 func subtitlesToElements(subtitles []dto.SubtitleSegment, style *dto.SubtitleStyle) []dto.CaptionElement { // 应用默认值 - fontSize := 48 + fontSize := 38 fontColor := "#FFFFFF" - bgColor := "#000000" + fontStroke := "0.5px #000000" // 默认极细黑描边 + bgColor := "" // 默认无背景色(透明) bgOpacity := 0.4 if style != nil { if style.FontSize > 0 { @@ -875,9 +886,12 @@ func subtitlesToElements(subtitles []dto.SubtitleSegment, style *dto.SubtitleSty if style.FontColor != "" { fontColor = style.FontColor } - // BgColor/BgOpacity 使用 *string/*float64,精确区分"没传"和"传了零值" + // FontStroke/BgColor/BgOpacity 使用指针,精确区分"没传"和"传了零值" // - 没传字段 → 指针为 nil → 使用默认值 // - 传了 "" 或 0 → 指针非 nil → 按用户意愿设置 + if style.FontStroke != nil { + fontStroke = *style.FontStroke + } if style.BgColor != nil { bgColor = *style.BgColor } @@ -914,6 +928,7 @@ func subtitlesToElements(subtitles []dto.SubtitleSegment, style *dto.SubtitleSty Y: subtitleY, FontSize: fontSize, FontColor: fontColor, + FontStroke: fontStroke, BgColor: bgColor, BgOpacity: bgOpacity, TrackIndex: 10, diff --git a/service/video/template_service.go b/service/video/template_service.go index ff8f41f..4c96fe8 100644 --- a/service/video/template_service.go +++ b/service/video/template_service.go @@ -258,6 +258,11 @@ func (s *templateService) applyStyles(elem *dto.CaptionElement, styles map[strin elem.FontColor = strings.TrimSpace(color) } + // 水平对齐 + if ta, ok := styles["text-align"]; ok { + elem.TextAlign = strings.TrimSpace(ta) + } + // 字体描边(如 -webkit-text-stroke: 3px #000000,白字黑描边效果) if stroke, ok := styles["-webkit-text-stroke"]; ok { elem.FontStroke = strings.TrimSpace(stroke) diff --git a/template_example.html b/template_example.html index fb10fc3..5304e14 100644 --- a/template_example.html +++ b/template_example.html @@ -119,6 +119,9 @@ body { 6. 文字也支持 width(模板指定 width 可覆盖渲染端的默认宽度, 精确控制换行范围,如把文字限定在两张图片之间不压图)。 + + 7. 文字水平对齐支持 text-align: left / center / right + (默认 center 居中;写 left 靠左、right 靠右)。 ====================================================================== --> @@ -214,7 +217,7 @@ body { data-key="product_desc" 产品卖点描述(底部两个图片之间) 最终效果: - - 白字,水平居中,落在 product_image_1 与 product_image_2 之间的空隙里 + - 白字,水平靠左,落在 product_image_1 与 product_image_2 之间的空隙里 - width: calc(100% - 320px) 让文字宽度随画布自适应,正好落在两图空隙内, 任何分辨率下都不会压到图片 - 因为 image_2 图片比较小(比 image_1 矮,只占上面一段), @@ -247,6 +250,10 @@ body { color: #FFFFFF 文字颜色(白色) + text-align: left + 文字水平对齐方式 + → left = 靠左(本元素默认) center = 居中 right = 靠右 + 提示:文字内容里可以用 \n 换行 -->