iOS Safari で canvas の画像を保存させる(download 属性 / Web Share / 長押し)
iOS では `<a download>` が Blob URL で動かない不具合が繰り返し出ており、ホーム画面追加の standalone PWA では利用者を閉じ込めるバグも記録されている。一番手は `navigator.canShare({ files })` で分岐する Web Share API Level 2、次に新規タブで開いて長押し保存、`<a download>` は Android / デスクトップ向けの補助に回す。
調査時点: 2026-06。公開プロジェクト frost-mosaic(なぞった所をモザイクにする PWA)で、加工した canvas を iPhone に保存させる方法を調べたもの。iOS のバージョンで挙動が変わる領域なので、最終確認は実機で行う。
<a download> の信頼性
- Safari のブラウザタブ: Blob URL のダウンロード不具合が Safari 12 時代から報告され続けている(WebKit Bug #190351)。2018 年に一度 FIXED になったが Safari 14 でも再現報告があり、iOS 17.4.1 で Blob URL が一時的に動かなくなり 17.5 beta で直った例もある
- ホーム画面追加の standalone モード: WebKit Bug #236943 “File download link traps user in PWA” が記録されている。ダウンロードリンクをタップすると PWA 内に閉じ込められ、戻れない
- File System Access API は iOS Safari 未対応
standalone PWA では <a download> を主な手段にしない。
Web Share API Level 2(navigator.share({ files }))
iOS 15 以降の Safari でファイル共有に対応し、standalone モードでも使える。canvas から得た Blob を File に包んで渡すと、iOS の共有シートから「画像を保存」が選べる。
async function saveCanvas(canvas: HTMLCanvasElement): Promise<void> { const blob = await new Promise<Blob | null>((r) => canvas.toBlob(r, "image/png")); if (!blob) throw new Error("toBlob failed"); const file = new File([blob], "image.png", { type: "image/png" });
if (navigator.canShare?.({ files: [file] })) { // iOS Safari では title を付けると画像ではなくテキストとして共有される報告があるため省く await navigator.share({ files: [file] }); return; } // フォールバックへ}条件は 3 つ。HTTPS 上であること、navigator.canShare({ files }) で事前確認すること、click などのユーザー操作(transient activation)から呼ぶこと。
長押し保存のフォールバック
window.open() で canvas を data URL として新規タブに開き、「画像を長押しして保存」と手順を文字で案内する。Web Share が使えない古い iOS や、共有シートを閉じてしまった場合の受け皿になる。
フォールバック順
navigator.canShare({ files })が true → Web Share API Level 2 で共有シートへ- 新規タブで開いて長押し保存を案内
<a download>(Android / デスクトップ向けの主な手段、iOS では補助)
iOS 以外では 3 を先に試してよい。分岐は UA 判定ではなく canShare の結果で行う。
canvas 再エンコードで EXIF / GPS が落ちる
Canvas API はピクセルデータだけを扱うため、drawImage() で描いた時点で EXIF・IPTC・XMP・GPS などのメタデータは捨てられる。canvas.toBlob("image/png") の出力には元画像のメタデータが含まれない。多くのオンライン EXIF 除去ツールがこの挙動を意図的に使っており、「保存時に位置情報が落ちる」というプライバシー説明の根拠になる。
対応状況の確認(2026-06)
canvas.toBlob(): Baseline Widely Available。iOS Safari でも動くimageSmoothingEnabled: Baseline Widely Available(2017 年以降)。-webkit-などのベンダープレフィックスは不要。古い記事のコードを写すと冗長なプレフィックスが残る- モザイク(ピクセル化)は「縮小 →
imageSmoothingEnabled = false→ 拡大」で実装できる。ブロックサイズはプレビューで調整できるようにする
未確認事項
- Safari 18 / iOS 18 で
download属性が standalone PWA で正式対応したかの一次確認 touchmoveのスロットリングやpassive: falseの要否など、iOS Safari でのフリーハンド描画パスの精度に関する既知問題
関連
更新履歴
- 2026-06-15: 初版(ローカル調査ノート)
- 2026-10-17: Wiki へ移植、概念ページとして再構成
出典
- https://bugs.webkit.org/show_bug.cgi?id=190351
- https://developer.apple.com/forums/thread/751063
- https://developer.apple.com/forums/thread/665812
- https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share
- https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
- https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled
- https://whatwg.whatwg.narkive.com/390yGl2I/add-exif-metadata-support-in-canvas-toblob
同じトピック — Web
- 単一画面の Canvas ツールのスタック選定(vanilla TS / Svelte / Preact と PWA ツーリング)
- DAM カラオケ検索(clubdam)の挙動と制約
- Core Web Vitals と画像最適化
- favicon の最小構成(SVG + ICO + apple-touch-icon + manifest)
- フロントエンドのフレームワークとツールの動き(2025)
- HTML-in-Canvas API
- HTML-in-Canvas の実現性(a11y・性能・セットアップ・シェーダー)
- 日本語 Web フォントのライセンスとサブセット化
- 個人サイトのライブウィジェットと外部 API の制限
- モダン CSS / Web API の対応状況(2025-2026)
- OPFS(Origin Private File System)
- Google Places API のキーの守り方(ブラウザ露出 vs サーバ中継)
- iOS の PWA 制限
- 機能別 React / TS ライブラリ対応表(2026-04 時点)
- URL 長の上限と日本語の URL エンコード膨張
- 書き出すテキストファイルの UTF-8 BOM と Markdown 継続行
- 縦書き Web の実装(writing-mode・ルビ・圏点・縦中横・禁則)
- PWA の Web Share Target(Android)の実測と落とし穴
- WebAssembly(Wasm)
- YouTube oEmbed で動画タイトルとチャンネル名を取る