fix: Canvas 内部分辨率不匹配导致画面变形 — 修复 ResizeObserver 未创建问题
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 42s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m4s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m18s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m30s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m6s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m48s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m4s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m5s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m18s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 3m42s
CI/CD Pipeline / Unit Tests (push) Successful in 14m8s
CI/CD Pipeline / Integration Tests (push) Successful in 6m3s
CI/CD Pipeline / CI Gate (push) Failing after 639h21m12s
CI/CD Pipeline / Production Browser E2E (push) Failing after 639h22m8s
CI/CD Pipeline / Canary Release to Production (push) Failing after 639h22m8s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 639h22m10s
CI/CD Pipeline / Build Production Web Image (push) Failing after 639h22m10s
CI/CD Pipeline / Build Production API Image (push) Failing after 639h22m12s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 639h36m13s
CI/CD Pipeline / PR Build API Image (push) Failing after 639h36m17s
CI/CD Pipeline / Frontend Lint (push) Failing after 639h36m19s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 639h36m21s
CI/CD Pipeline / Deploy Production (push) Failing after 639h55m54s
CI/CD Pipeline / PR Build Web Image (push) Failing after 640h10m1s

根因:ResizeObserver useEffect 依赖数组为空 [],组件挂载时 canPlay=false
导致 canvas 未渲染、canvasRef 为 null,effect 直接 return 后永远不会重新执行,
canvas 内部分辨率停留在浏览器默认值 300×150(横屏 2:1),而 CSS 显示为竖屏容器。

修复:
- useEffect 依赖改为 [useWebCodecs, canPlay],canPlay=true 时 canvas 已渲染,
  effect 重新执行并正确创建 ResizeObserver
- 创建 ResizeObserver 前立即通过 getBoundingClientRect 设置 canvas 初始像素分辨率,
  避免首帧使用默认 300×150 导致变形
- computeDrawRect 已正确基于 videoDimRef 做 letterbox 居中绘制,无需修改
This commit is contained in:
xiaoxia
2026-08-20 23:49:57 +08:00
parent 161c1a61b6
commit 95c33f6604
@@ -250,9 +250,17 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
// ── Canvas ResizeObserver ──
const canvasContainerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!useWebCodecs || !canPlay) return
const container = canvasContainerRef.current
const canvas = canvasRef.current
if (!container || !canvas) return
// 立即设置一次 canvas 像素分辨率,避免默认 300×150 导致首帧变形
const initRect = container.getBoundingClientRect()
if (initRect.width > 0 && initRect.height > 0) {
const dpr = window.devicePixelRatio || 1
canvas.width = initRect.width * dpr
canvas.height = initRect.height * dpr
}
const ro = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect
@@ -264,7 +272,7 @@ const FrontendPreviewPlayer: React.FC<FrontendPreviewPlayerProps> = ({
})
ro.observe(container)
return () => ro.disconnect()
}, [])
}, [useWebCodecs, canPlay])
// ── 未就绪 ──
if (!ready || !assets.length) {