* 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>
27 lines
No EOL
3.4 KiB
Markdown
27 lines
No EOL
3.4 KiB
Markdown
---
|
||
pr: 161
|
||
title: "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.svg`** — `cli.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'ом). |