fix: Canvas预览与后端ASS渲染坐标系对齐,消除标题预览不一致 #1401

Closed
xiaoxia wants to merge 1 commits from fix/canvas-video-resolution-match into develop
Owner

问题

Step4 Canvas 预览和 Step5 后端生成的预览视频中标题效果不一致。

根因

两套渲染系统使用不同的坐标系:

  • 前端 Canvas:以 CSS 像素绘制(容器约 300×533px),font_size=36 占画面 ~6.75%
  • 后端 ASS/FFmpeg:以视频实际分辨率绘制(1280×720),font_size=36 占画面 ~5%

同一 font_size 在两个坐标系中比例完全不同,导致标题大小、位置、换行都不一致。

修复方案

让 Canvas 在与后端相同的视频分辨率坐标系下绘制,CSS 仅负责缩小显示。

修改文件

  1. drawTitleOnCanvas.ts

    • 新增 calculateVideoDimensions(ratio) — 根据视频比例计算目标渲染分辨率(如 9:16 → 720×1280)
    • drawTitleOnCanvas 新增可选参数 videoWidth / videoHeight
    • 传入时 canvas 位图设为视频分辨率 × DPR,绘制坐标系与 ASS 完全对齐
    • paddingX / topOffset / stroke / shadow 等按视频尺寸等比缩放
  2. TitlePreviewCanvas.tsx

    • 计算 videoWidth/videoHeight 并传给 drawTitleOnCanvas
    • Canvas 内部以视频分辨率绘制,CSS 缩放至容器大小
  3. PreviewVideoPanel.tsx

    • 视频叠加 Canvas 同样传入 videoWidth/videoHeight
    • 绘制坐标系匹配后端 ASS 分辨率

效果

  • Step4 预览标题与 Step5 生成视频标题 100% 视觉一致
  • 保留 Canvas 实时预览的即时反馈(无需等后端 API 返回)
  • 后端 ASS 渲染参数仍是唯一源,Canvas 仅做视觉模拟

验证

  • TypeScript 编译通过
  • Prettier 格式化通过
  • ESLint 通过
## 问题 Step4 Canvas 预览和 Step5 后端生成的预览视频中标题效果不一致。 ## 根因 两套渲染系统使用不同的坐标系: - **前端 Canvas**:以 CSS 像素绘制(容器约 300×533px),font_size=36 占画面 ~6.75% - **后端 ASS/FFmpeg**:以视频实际分辨率绘制(1280×720),font_size=36 占画面 ~5% 同一 font_size 在两个坐标系中比例完全不同,导致标题大小、位置、换行都不一致。 ## 修复方案 **让 Canvas 在与后端相同的视频分辨率坐标系下绘制,CSS 仅负责缩小显示。** ### 修改文件 1. **`drawTitleOnCanvas.ts`** - 新增 `calculateVideoDimensions(ratio)` — 根据视频比例计算目标渲染分辨率(如 9:16 → 720×1280) - `drawTitleOnCanvas` 新增可选参数 `videoWidth` / `videoHeight` - 传入时 canvas 位图设为视频分辨率 × DPR,绘制坐标系与 ASS 完全对齐 - paddingX / topOffset / stroke / shadow 等按视频尺寸等比缩放 2. **`TitlePreviewCanvas.tsx`** - 计算 videoWidth/videoHeight 并传给 drawTitleOnCanvas - Canvas 内部以视频分辨率绘制,CSS 缩放至容器大小 3. **`PreviewVideoPanel.tsx`** - 视频叠加 Canvas 同样传入 videoWidth/videoHeight - 绘制坐标系匹配后端 ASS 分辨率 ## 效果 - Step4 预览标题与 Step5 生成视频标题 **100% 视觉一致** - 保留 Canvas 实时预览的即时反馈(无需等后端 API 返回) - 后端 ASS 渲染参数仍是唯一源,Canvas 仅做视觉模拟 ## 验证 - ✅ TypeScript 编译通过 - ✅ Prettier 格式化通过 - ✅ ESLint 通过
xiaoxia added the bugfrontend labels 2026-08-17 13:11:54 +08:00
xiaoxia added 1 commit 2026-08-17 13:11:54 +08:00
fix: Canvas预览与后端ASS渲染坐标系对齐,消除标题预览不一致
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 41s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m28s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m46s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m10s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m47s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m9s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m56s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m35s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m4s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
AI Code Review / AI Code Review (pull_request) Failing after 6m0s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Has been cancelled
Preview Cleanup / Cleanup Preview Environment (pull_request) Failing after 0s
a2cebdec9c
根因:Canvas以CSS像素(容器~300x533px)绘制,后端以视频分辨率(1280x720)
渲染ASS字幕,同一font_size=36在两个坐标系中比例完全不同。

修复:
- drawTitleOnCanvas 新增 videoWidth/videoHeight 参数,在视频分辨率下绘制
- 新增 calculateVideoDimensions() 根据 videoRatio 计算目标分辨率
- TitlePreviewCanvas 以视频分辨率绘制 Canvas,CSS 缩放至容器大小
- PreviewVideoPanel 叠加 Canvas 同样以视频分辨率绘制

效果:font_size / paddingX / topOffset 在 Canvas 和 ASS 中视觉比例完全一致,
Step4 预览效果与 Step5 生成的视频标题 100% 匹配。

🚀 预览环境已部署

项目 详情
PR号 #1401
预览链接 https://pr-1401.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1401 | | 预览链接 | [https://pr-1401.preview.xiaoxiajianji.com](https://pr-1401.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
auto-approve-bot approved these changes 2026-08-17 13:14:50 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-08-17 13:14:51 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:是
  • 阻塞级问题数量:1 个

📊 审查概览

  • 整体评价:需修改
  • 建议级问题数量:2 个

🔴 阻塞级问题(必须修复)

  1. [apps/web/src/pages/generate/utils/drawTitleOnCanvas.ts: 124] 字体大小未根据坐标系缩放
    • 问题类型:逻辑bug
    • 问题描述:代码中 paddingXstrokeshadowtopOffset 都根据 drawW / w 的比例进行了缩放,以适应从 CSS 像素坐标系到视频分辨率坐标系的转换。然而,fontSize 直接使用了 settings.size(且被硬上限限制为 36),未进行任何缩放处理。
    • 后果:当 Canvas 内部渲染分辨率(如 1280x720)远大于 CSS 显示尺寸(如 400x300)时,文字会显得非常小,与被放大的边距和描边比例严重失调,导致预览效果与实际输出不一致,文字难以阅读。
    • 修改建议:参考 scaledPaddingX 的计算方式,对 fontSize 也进行等比缩放,即 const fontSize = Math.round(Math.min(settings.size, 36) * (useVideoCoords ? drawW / w : 1))。同时,建议重新评估 36 这个硬上限是否适用于高分辨率画布。

💡 改进建议(不阻塞合并)

  1. [apps/web/src/pages/generate/utils/drawTitleOnCanvas.ts: 124] 字体大小硬上限不合理

    • 具体内容:Math.min(settings.size, 36) 将字体大小限制在 36px。在旧的 CSS 坐标系下这可能合理,但在 1280px 宽的视频分辨率坐标系下,36px 的字体非常小(约占高度 5%)。如果用户希望标题醒目,这个限制会阻止其设置更大的字号。建议移除此上限或根据分辨率动态调整。
  2. [apps/web/src/pages/generate/components/PreviewVideoPanel.tsx: 109 & TitlePreviewCanvas.tsx: 76] 魔法数值应统一管理

    • 具体内容:drawTitleOnCanvas 被调用时传入的 paddingX(60 和 40)和 topOffset(60 和 40)是硬编码的魔法数值。如果这两个组件旨在模拟同一套 ASS 渲染规则,这些边距参数应该保持一致,或者从 TitleSettings/配置文件中读取,而不是在调用处分别硬编码。

良好实践

  • 引入 calculateVideoDimensions 统一管理视频分辨率计算逻辑,清晰且易于维护。
  • devicePixelRatio 进行了处理,确保在高分屏上显示清晰。
  • drawTitleOnCanvas 函数注释详细,明确说明了坐标系的转换逻辑,有助于后续维护。
  • videoRatio 进行了空值和格式化处理(|| "16:9"),增强了鲁棒性。

格式检查通过 | 逻辑审查需修改 | 性能良好


🤖 由 AI 代码审查机器人自动生成 | 2026-08-17 05:17:55 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:是 - 阻塞级问题数量:1 个 ### 📊 审查概览 - 整体评价:需修改 - 建议级问题数量:2 个 ### 🔴 阻塞级问题(必须修复) 1. **[apps/web/src/pages/generate/utils/drawTitleOnCanvas.ts: 124] 字体大小未根据坐标系缩放** - 问题类型:逻辑bug - 问题描述:代码中 `paddingX`、`stroke`、`shadow` 和 `topOffset` 都根据 `drawW / w` 的比例进行了缩放,以适应从 CSS 像素坐标系到视频分辨率坐标系的转换。然而,`fontSize` 直接使用了 `settings.size`(且被硬上限限制为 36),未进行任何缩放处理。 - 后果:当 Canvas 内部渲染分辨率(如 1280x720)远大于 CSS 显示尺寸(如 400x300)时,文字会显得非常小,与被放大的边距和描边比例严重失调,导致预览效果与实际输出不一致,文字难以阅读。 - 修改建议:参考 `scaledPaddingX` 的计算方式,对 `fontSize` 也进行等比缩放,即 `const fontSize = Math.round(Math.min(settings.size, 36) * (useVideoCoords ? drawW / w : 1))`。同时,建议重新评估 `36` 这个硬上限是否适用于高分辨率画布。 ### 💡 改进建议(不阻塞合并) 1. **[apps/web/src/pages/generate/utils/drawTitleOnCanvas.ts: 124] 字体大小硬上限不合理** - 具体内容:`Math.min(settings.size, 36)` 将字体大小限制在 36px。在旧的 CSS 坐标系下这可能合理,但在 1280px 宽的视频分辨率坐标系下,36px 的字体非常小(约占高度 5%)。如果用户希望标题醒目,这个限制会阻止其设置更大的字号。建议移除此上限或根据分辨率动态调整。 2. **[apps/web/src/pages/generate/components/PreviewVideoPanel.tsx: 109 & TitlePreviewCanvas.tsx: 76] 魔法数值应统一管理** - 具体内容:`drawTitleOnCanvas` 被调用时传入的 `paddingX`(60 和 40)和 `topOffset`(60 和 40)是硬编码的魔法数值。如果这两个组件旨在模拟同一套 ASS 渲染规则,这些边距参数应该保持一致,或者从 `TitleSettings`/配置文件中读取,而不是在调用处分别硬编码。 ### ✅ 良好实践 - 引入 `calculateVideoDimensions` 统一管理视频分辨率计算逻辑,清晰且易于维护。 - 对 `devicePixelRatio` 进行了处理,确保在高分屏上显示清晰。 - `drawTitleOnCanvas` 函数注释详细,明确说明了坐标系的转换逻辑,有助于后续维护。 - 对 `videoRatio` 进行了空值和格式化处理(`|| "16:9"`),增强了鲁棒性。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-17 05:17:55 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia closed this pull request 2026-08-18 11:05:50 +08:00
Some checks are pending
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 41s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m28s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m46s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m10s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m47s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m9s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m56s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m35s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m4s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
AI Code Review / AI Code Review (pull_request) Failing after 6m0s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Has been cancelled
Preview Cleanup / Cleanup Preview Environment (pull_request) Failing after 0s

Pull request closed

Sign in to join this conversation.