Skip to content

exportAsHtml: ローカル画像を data URI で埋め込む (外部ブラウザ portability) #314

Description

@ymnao

背景

src/lib/export.tsexportAsHtmlmarkdownToHtml を通して HTML ファイルを書き出すが、![alt](./foo.png) などのローカル画像パスをそのまま出力するため、エクスポート後の HTML を外部ブラウザで開くと画像が表示されない (相対パス基準が保存先ディレクトリになり、workspace 内の画像に届かない)。

feature/slide-local-image-resolution ブランチで SlidePreview には resolveHtmlImageSrcs を注入済み。exportAsPdf は共通ヘルパー経由で scripta-asset:// に解決するよう対応済み。HTML export は scripta-asset:// に置換しても外部ブラウザで解決できないため意図的に対象外とした。真の portability には data URI 埋め込みが必要。

やること

  1. 新規 IPC readFileBase64(path): Promise<string> を追加

    • electron/main/ipc/file.ts に handler、electron/preload/api.ts / electron/preload/index.ts に wiring、src/lib/commands.ts にラッパー
    • path-guard 必須: isPathWithinAnyAllowedRoot(path) で workspace 内チェック (scripta-asset handler と同レベルの防御)
    • MIME 判定は拡張子ベース (png / jpg / jpeg / gif / webp / svg / bmp / avif)
  2. async 版 resolversrc/lib/resolve-html-images.ts に追加

    export async function embedHtmlImagesAsDataUri(
      html: string,
      activeTabPath: string | null,
    ): Promise<string>
    • 相対 / 絶対パスを resolveImageSrc 相当のロジックで OS パスに変換
    • readFileBase64 で読み、data:${mime};base64,${b64} に置換
    • http(s) / 既に data:/blob: はそのまま維持
    • fetch 失敗時は元の src を残す (broken image のまま but noisy でない)
  3. exportAsHtml を async ヘルパー経由に更新 (呼び出し側は既に async)

  4. テスト

    • resolve-html-images.test.ts に async 版のケース追加 (fake IPC で base64 を返す)
    • export.test.ts に「exportAsHtml が data URI を埋め込む」regression 追加

スコープ外

  • SlidePreview / exportAsPdf: 既に scripta-asset:// で解決済み。変更不要
  • SVG の inline 化 (<img src="./foo.svg"><svg>...</svg> インライン展開) は別 issue

関連

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions