位置情報が漏れるよくある経路です。元のファイルをそのまま配信する掲示板に、飼い猫の写真を投稿したとします。撮影したスマホは GPS 座標をファイルに書き込んでいて、掲示板はバイトをそのまま転送しました。画像を無料の EXIF ビューアーに放り込めば、誰でも座標を読み取れます。

EXIF メタデータビューアーを開く →

EXIF はデジタル写真の中で、ほとんどの人が一度も覗いたことがない側面だ。本記事ではメタデータブロックの中身、なぜそれが入っているのか、各 SNS のアップロード時の挙動、そしてサーバーに何もアップロードせずに確認・削除する方法までを通して解説する。

EXIF に実際に含まれるもの

EXIF(Exchangeable image file format)は CIPA と JEITA が維持する規格(現行は Exif 3.0、CIPA DC-008-2023)で、カメラやスマートフォンが画像ファイルに構造化メタデータを埋め込む方法を定めています。1.0 版は 1995 年に公開され、カメラやスマートフォンの JPEG は既定でこれを含みます。

スマートフォンのカメラで撮った 1 枚は、撮影日時よりはるかに多くの情報を運ぶ:

フィールド例書き込まれる理由プライバシーリスク
Make / ModelApple / iPhone 15 Proカメラ識別低 — 数千万台で共通
LensModeliPhone 15 Pro back camera 6.86mm f/1.78編集ソフトのための光学情報低
DateTimeOriginal2024-08-12 14:32:08並び替え・アルバム整理中 — いつどこにいたかが分かる
FNumber / ExposureTime / ISO / FocalLengthf/1.8、1/120s、ISO 80、24mm編集ソフトでの露出再現なし
GPSLatitude / GPSLongitude31.230556° N、121.473611° E地図表示・検索のジオタグ高 — 数メートル単位で位置特定
GPSAltitude15 m海抜情報中
SoftwareiOS 18.1、Photoshop 25.4編集履歴低〜中 — ワークフローが漏れる
SerialNumber(一部の機種)Sony / Canon DSLR など機体個体識別記者には高リスク
ImageUniqueIDシャッターごとの UUID重複排除中

JPEG の application マーカーセグメントには、もう 2 つのメタデータ規格がよく同居している:

  • XMP(Adobe の XML メタデータ)—— Lightroom の編集履歴、評価、キャプション、著作権フィールドを記録。EXIF と同じ APP1 セグメント、または別の APP1 に格納される。
  • IPTC —— より古い報道室発のキャプション・著者・著作権規格。APP13 セグメントに格納される。

スマートフォンの写真では 3 つすべてが揃っていることが多い:撮影パラメータの EXIF が APP1 に、編集情報の XMP がもう 1 つの APP1 に、そして場合によってはデスクトップ製ソフトが APP13 に IPTC を押印している。

JPEG のレイアウト —— 除去で再エンコードが不要な理由

JPEG は連続した 1 つのブロブではない。それぞれ 0xFF で始まるマーカーセグメントの並びだ:

0xFFD8           SOI    Start of Image(画像開始)
0xFFE0           APP0   JFIF 解像度・縦横比
0xFFE1           APP1   EXIF または XMP   ← 個人データはここ
0xFFE1           APP1   XMP(2 つ目もよくある)
0xFFE2           APP2   ICC カラープロファイル
0xFFED           APP13  Photoshop / IPTC
0xFFEE           APP14  Adobe カラー変換マーカー
0xFFDB × 2       DQT    量子化テーブル
0xFFC0           SOF    Start of Frame(画像サイズ)
0xFFC4 × 4       DHT    ハフマンテーブル
0xFFDA           SOS    Start of Scan(圧縮ピクセルデータ開始)
...              エントロピー符号化された圧縮画像データ
0xFFD9           EOI    End of Image(画像終了)

ピクセルデータは SOS と EOI の間にあり、SOS より前はすべてメタデータかデコーダー設定だ。メタデータ除去にピクセルを触る必要はない —— マーカーストリームを歩いて個人データを持つセグメントを落とし、残りを連結すれば終わりだ。

ZeroTool の除去ツールが落とすマーカーは 3 種類:

  • APP1(0xFFE1)—— EXIF と XMP
  • APP13(0xFFED)—— Photoshop / IPTC
  • APP14(0xFFEE)—— Adobe カラー変換

保持されるもの:SOI、APP0(JFIF)、APP2(ICC カラープロファイル、色味を維持)、すべての DQT / SOF / DHT セグメント、SOS マーカー、圧縮ピクセルデータ、EOI。

結果は ピクセル側でバイト単位で同一。劣化なし、再エンコードなし。よくある「Canvas で再描画して EXIF を落とす」パターンと比較すると:

// 劣化あり —— Canvas で再エンコード、画質が落ちる
canvas.getContext('2d').drawImage(img, 0, 0);
canvas.toBlob(blob => save(blob), 'image/jpeg', 0.95);

Canvas 再エンコードは 1 行でどのブラウザでも動くが、保存のたびに新しい JPEG 量子化が走る。3 周もすればエッジが目に見えて柔らかくなり、平坦な色面に色度ブロックが現れる。バイトレベル方式にはそれがない —— クリーンになったファイルは同じ圧縮ピクセルのまま、個人データのセグメントだけが切り取られている。

セグメントを丸ごと落とすことには副作用が二つあります。EXIF の Orientation タグも APP1 と一緒に消えるため、それに頼っていたスマートフォン写真は回転して表示されることがあります。また APP14 は Adobe の CMYK / YCCK JPEG の解釈方法をデコーダーに伝えるため、そうしたファイルは除去後に色がおかしくなることがあります。スマートフォンやカメラが撮る通常の RGB 写真は APP14 に依存しません。

GPS 座標 —— rational から十進度数へ

EXIF 規格は GPS 座標を独特な形式で保存する:3 つの rational 数(度、分、秒)—— それぞれが分子と分母のペア —— と、半球を表す 1 文字(N / S / E / W)。

実例:

GPSLatitudeRef:  N
GPSLatitude:     31/1, 13/1, 50/1
GPSLongitudeRef: E
GPSLongitude:    121/1, 28/1, 25/1

デコード結果:

緯度  = 31 + 13/60 + 50/3600 = 31.230556° N
経度  = 121 + 28/60 + 25/3600 = 121.473611° E

実際の精度は 2 つの要素で決まる:カメラが書き込んだ rational の分母(分母 1 は秒単位の整数解像度で赤道付近で約 30 m。スマートフォンはサブ秒精度のためにずっと大きな分母を使うことが多い)と、元になる GPS フィックスの品質。空が開けた場所で大きな分母の rational を書き込むスマートフォンは、数メートル精度の座標をエンコードできる。ビューアーは単に単位変換をするだけ —— フィックスの品質を改善も悪化もさせない。

ビューアーは両軸を十進度数にデコードし、S / W の符号反転を適用し、ローカルで Google マップの URL を組み立てる。リンクはクリックするまでリクエストを発しない —— その時点まで第三者は座標を見ない。

SNS は実際に何を取り除いているのか

「大手の SNS に投稿したから写真は安全」という素朴な仮定は当てになりません。多くのプラットフォームはどのメタデータを残すかを公開しておらず、他のユーザーに見せる画像とサーバー上の保存コピーは別物のことがあり、アプリのバージョンや送信経路(圧縮画像、「オリジナル」、ファイル添付)でも挙動が変わります。プラットフォームに関係なく言えることは二つです。添付ファイルとして送ったもの(メール、チャットの「ファイルとして送信」、アップロードしたファイルをそのまま配信する issue トラッカー)は通常バイト単位でそのまま届きます。また、プラットフォームがサーバーに原本を保存していれば、他のユーザーに見えなくても位置情報はプラットフォームの手元に残ります。

特定の経路は自分で確かめられます。GPS 付きのテスト写真をアップロードし、他のユーザーと同じ方法でダウンロードして、そのファイルを本ツールで開いてください。投稿前にローカルで除去すれば、この問題は消えます。

よくあるエッジケース

スマートフォンの写真で「EXIF が見つかりません」

写真がスクリーンショット、特定の編集アプリでの書き出し、HEIC から JPEG への変換でメタデータが落ちている経路を経た場合、EXIF ブロックが完全に欠落することがある。ビューアーは「No EXIF metadata found」と表示する —— これはむしろ望ましい状態だ。除去パスは編集ソフトが追加した XMP / IPTC を取り除くために走らせる価値がある。

Photoshop「Web 用に保存」後も EXIF が残る

メタデータを None に設定した「Web 用に保存」は EXIF を除去するが、ICC profile は通常残し、エクスポート過程を記述する XMP ブロックを追加することがある。ZeroTool ビューアーは EXIF のみ読み取る;XMP の中身を確認するには exiftool -xmp:all のような XMP 対応ツールを使う。除去パス自体は XMP の APP1 セグメントも取り除く。

HEIC / HEIF 写真

HEIC は 2017 年以降の iPhone の既定コンテナだ。HEIC は JPEG マーカーではなく ISOBMFF 構造で EXIF を持つ。ZeroTool ツールは設計上 JPEG のみ扱う。HEIC の EXIF を取り除くには、ローカルで exiftool -all= file.heic を使うか、HEIC を JPEG に変換してから除去する。

TIFF / HEIC / PNG ファイル

TIFF は IFD ツリーで EXIF を持ち、JPEG 内部の EXIF と構造が似ているが、ファイルそのものは JPEG マーカーストリームではない。PNG は 2017 年の規格拡張により eXIf チャンクを持てる。ZeroTool ツールは設計上 JPEG のみ受け付ける —— 他形式はローカルで exiftool -all= を使うか、JPEG に変換してから処理する。

25 MB を超えるファイル

ツールはファイル全体をメモリに読み込みます。25 MB を超えると警告を表示し、100 MB を超えるファイルは拒否します。スマートフォンではそれより前にメモリが不足することがあります。多数の大きなファイルをまとめて処理するなら、exiftool -all= や mat2 などのローカル CLI が適しています。

他のツールで同じ除去を再現する

ZeroTool の除去処理は 30 行ほどの JavaScript アルゴリズムだ。同じ操作を他の 3 環境で書くと以下のようになる。

Bash + exiftool —— 業界標準の CLI。Phil Harvey による Perl 製で、Perl 自身のライセンス(Artistic / GPL のデュアル)で配布されている:

# すべてのメタデータを削除(EXIF、XMP、IPTC、ICC)—— ICC を消すと色味がずれる可能性
exiftool -all= photo.jpg

# ICC カラープロファイルを残し、EXIF / XMP / IPTC のみ削除
exiftool -all= --icc_profile:all photo.jpg

# 残った内容を確認(exiftool は元ファイルを photo.jpg_original として残す)
exiftool photo.jpg

Python + Pillow(再エンコード):

from PIL import Image

# 再エンコード —— わずかな画質劣化あり
img = Image.open("photo.jpg")
img.save("photo-clean.jpg", "JPEG", quality=95, optimize=True)

Python + piexif(再エンコードなし):

import piexif

# マーカーストリームを歩いて EXIF のみ削除
piexif.remove("photo.jpg")

ブラウザ JavaScript —— ZeroTool ツールが内部で行っている処理:

async function stripJpegMetadata(file) {
  const buf = await file.arrayBuffer();
  const view = new DataView(buf);
  if (view.getUint16(0) !== 0xFFD8) throw new Error("not a JPEG");

  const keep = [[0, 2]];                  // SOI
  let pos = 2;
  while (pos < view.byteLength - 1) {
    const marker = view.getUint16(pos);
    if (marker === 0xFFDA || marker === 0xFFD9) {
      keep.push([pos, view.byteLength]);  // SOS から EOI まで
      break;
    }
    if ((marker & 0xFF00) !== 0xFF00) break;
    const segLen = view.getUint16(pos + 2);
    const segEnd = pos + 2 + segLen;
    if (marker !== 0xFFE1 && marker !== 0xFFED && marker !== 0xFFEE) {
      keep.push([pos, segEnd]);
    }
    pos = segEnd;
  }

  const total = keep.reduce((s, r) => s + r[1] - r[0], 0);
  const out = new Uint8Array(total);
  let off = 0;
  for (const [a, b] of keep) {
    out.set(new Uint8Array(buf, a, b - a), off);
    off += b - a;
  }
  return new Blob([out.buffer], { type: "image/jpeg" });
}

このスニペットがアルゴリズムの全体だ。残りは確認パネル用の EXIF リーダーである。

ZeroTool ツールとの比較

EXIF ツールは数多くあるが、ZeroTool で何が違うのか:

機能ZeroToolexiftool(CLI)
ローカルで動作、アップロードなしはい(ブラウザタブ内)はい(手元のマシン)
再エンコードせずに除去はい(APP1 / APP13 / APP14 を削除)はい(メタデータだけ書き換え)
オープンソースはい(リポジトリ)はい
GPS 地図リンクありなし(座標を表示)
形式JPEG のみJPEG、HEIC、TIFF、PNG、動画など
バッチ処理なし(1 ファイルずつ)あり(ディレクトリ、-r)

「この写真に EXIF があるか、削除できるか」を 1 回確かめるだけなら、インストール不要のブラウザツールで足ります。バッチ処理や HEIC には exiftool を使いましょう。

プライバシーに関する注記

  • ページは写真をアップロードしません。写真のバイトはブラウザタブ内に留まります。写真には位置情報が含まれうるため、このツールページは Google アナリティクスも AdSense も読み込みません。
  • Google マップディープリンクはローカルで生成される。クリックするまでリクエストは発しない。
  • 除去後のダウンロードは Blob URL で、メモリ残留を避けるため 1 秒後に revoke される。

関連資料

今すぐ写真の EXIF を除去 →