Skip to content

PDF export: box-shadowをprint時にラスタライズしてPreview.appの黒矩形を解消#153

Merged
mizzy merged 3 commits into
mainfrom
issue-150-pdf-shadow-flatten
Jul 6, 2026
Merged

PDF export: box-shadowをprint時にラスタライズしてPreview.appの黒矩形を解消#153
mizzy merged 3 commits into
mainfrom
issue-150-pdf-shadow-flatten

Conversation

@mizzy

@mizzy mizzy commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Closes #150

問題

peitho export pdfのPDFをmacOS Preview.app / Quick Look / sipsで開くと、box-shadow付き要素の周りに硬いエッジの黒い矩形が出る。HTMLスライドやpoppler/ChromeのPDFビューアでは出ない。

根本原因(測定済み)

Chrome --print-to-pdfはぼかし付きbox-shadowを「黒塗り + /SMask /S /Luminosity ExtGState + ぼかしをラスタライズしたDeviceGray画像」としてPDF化する。Quartz系レンダラはこのLuminosity SMaskを誤合成し、マスクBBox境界までの黒矩形として描画する。Issue #142(Type 4シェーディング)と同族のQuartzの透明度処理問題。

修正

pdf_flatten.jsをグラデーションflattenと同じ思想で拡張し、print時にbox-shadowをラスタライズする:

  • 外側シャドウ: シャドウのみをcanvasでRGBA PNGに描き(CTM非依存のshadowパラメータを明示SCALE倍)、.peitho-slide直下にposition:absolute; z-index:-1のレイヤーとして敷く
  • insetシャドウ: border-boxクリップ + even-odd中空パスで描き、background-imageの最上層としてprepend
  • 適用は要素単位でall-or-nothing。parse不能値・分断要素・祖先transform・canvas上限超過などはconsole.errorして元のまま残す(既存flattenと同じフォールバックポリシー、サイレントパスなし)

検証

  • Red→Green: 実装なしでは新E2Eが/S /Luminosityアサートで失敗することを確認
  • E2E 4本green(既存gradient/nonempty + 新規outer/inset)
  • 実デッキ(peitho-intro)をexportし、pdfseparate+sips(Quartz = Preview.appと同じエンジン)でA/B確認: 黒矩形が消え、柔らかい影だけが残る。PDF全体で/S /Luminosityは0件
  • 全ゲート: cargo test --workspace ×3 / clippy -D warnings / fmt / bindings drift / npm build+test+typecheck / shell.js・measure.js drift すべてpass
  • 5ラウンドセルフレビュー完了(Round 5でinset E2E欠落を検出し追加)

設計記録: docs/plans/2026-07-06-pdf-shadow-flatten.md

🤖 Generated with Claude Code

mizzy and others added 3 commits July 6, 2026 21:15
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…angles

Chrome --print-to-pdf emits blurred CSS box-shadows as /S /Luminosity
soft masks that macOS Quartz renderers (Preview.app, Quick Look, sips)
mis-composite into hard-edged black rectangles. Extend pdf_flatten.js
to rasterize supported shadows to RGBA PNGs at print time: outer
shadows become an absolutely positioned layer behind the element,
inset shadows become the topmost background-image layer. Unsupported
values fall back to the original shadow with a console.error, same
policy as the gradient flatten.

Closes #150

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mizzy mizzy merged commit a4c189f into main Jul 6, 2026
3 checks passed
@mizzy mizzy deleted the issue-150-pdf-shadow-flatten branch July 6, 2026 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PDF export: box-shadowがPreview.appで黒い矩形として描画される

1 participant