opencode-config/docs/handoff/pr-161-density-1024.md
Sergey 746bb7438e
fix(draw-image): use density 72 for 1024x1024 PNG output (#161)
* fix(draw-image): use density 72 for 1024x1024 PNG output

* test(draw-image): assert real PNG dimensions via IHDR decode

* chore(assets): regenerate cover.png at 1024x1024

* docs(handoff): add handoff and ADR for density fix

* docs(handoff): set PR number

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-30 23:31:02 +03:00

3.4 KiB
Raw Blame History

pr title
161 fix(draw-image): use density 72 for 1024x1024 PNG output

Что сделано

Фикс размера PNG draw-image (issue #159) — три изменения:

  1. density 96 → 72.opencode/draw-image/render.mjs:36: sharp(Buffer.from(svg), { density: 72 }). При density:96 SVG 1024×1024 (по viewBox, 1in=72pt) рендерился как 1024 × 96/72 = 1365px. При density:72 → 1024 × 72/72 = 1024px ровно.
  2. Реальные assertions размеров PNG — пустые проверки заменены на decode PNG IHDR chunk (width bytes 16-19, height bytes 20-23, big-endian uint32):
    • tests/e2e.test.ts assertPng1024 — добавлены expect(width).toBe(1024) + expect(height).toBe(1024).
    • tests/render.integration.test.ts тест "renders valid PNG 1024x1024" — добавлены width/height assertions (были только magic bytes).
    • tests/render.optional.integration.test.ts assertPng — добавлены width/height assertions.
  3. Регенерация assets/cover.png — удалены старые assets/cover.png + cover.meta.json, перерендерены через draw-image tool (template=cover, icon=opencode, subtitle). Проверено через sharp().metadata(): 1024×1024 (было 1365×1365).

Тесты: npx vitest run в .opencode/draw-image/ → 55/55 passed (5 прогонов подряд стабильно). Все обновлённые assertions реально проверяют 1024×1024 через IHDR decode.

Почему

density: 96 — историческое значение, дававшее 33% оверсайз (1365 вместо 1024). PNG cover используется в README и slaid098.dev showcase — 1365px ломал layout и не соответствовал контракту meta.size: 1024 в cli.ts:78. Пустые assertions (только magic bytes, без width/height) маскировали баг — тесты «проходили» на 1365×1365, хотя в имени функции буквально assertPng1024. Density 72 — canonical значение для SVG-to-PNG при viewBox в pt (1pt = 1/72in), дающее pixel-perfect 1024×1024.

Pending

Watch out

  • Существующий race condition на .tmp-render.svgcli.ts:64 пишет shared temp SVG в __dirname. При параллельных CLI-вызовах (vitest concurrent) или leftover от ручных прогонов → render.mjs падает с Input Buffer is empty. Это отдельный баг, заведён issue #160 (вне scope #159). На стабильных прогонах (clean tmp) не проявляется. Не чинить в этом PR.
  • Density-фикс меняет хэш всех PNG (computeHash не зависит от density, но generatedAt и пиксели differ) → все cached PNG будут перерендерены при следующем вызове CLI (meta.json hash не меняется, но если файл удалён — re-render). cover.meta.json перегенерирован.
  • buf.readUInt32BE(16) / buf.readUInt32BE(20) — PNG IHDR fixed offset (8 signature + 4 length + 4 "IHDR" = 16 для width, 20 для height). Работает только для стандартных PNG (sharp всегда пишет IHDR первым chunk'ом).