位置情報が漏れるよくある経路です。元のファイルをそのまま配信する掲示板に、飼い猫の写真を投稿したとします。撮影したスマホは GPS 座標をファイルに書き込んでいて、掲示板はバイトをそのまま転送しました。画像を無料の EXIF ビューアーに放り込めば、誰でも座標を読み取れます。
EXIF はデジタル写真の中で、ほとんどの人が一度も覗いたことがない側面だ。本記事ではメタデータブロックの中身、なぜそれが入っているのか、各 SNS のアップロード時の挙動、そしてサーバーに何もアップロードせずに確認・削除する方法までを通して解説する。
EXIF に実際に含まれるもの
EXIF(Exchangeable image file format)は CIPA と JEITA が維持する規格(現行は Exif 3.0、CIPA DC-008-2023)で、カメラやスマートフォンが画像ファイルに構造化メタデータを埋め込む方法を定めています。1.0 版は 1995 年に公開され、カメラやスマートフォンの JPEG は既定でこれを含みます。
スマートフォンのカメラで撮った 1 枚は、撮影日時よりはるかに多くの情報を運ぶ:
| フィールド | 例 | 書き込まれる理由 | プライバシーリスク |
|---|---|---|---|
Make / Model | Apple / iPhone 15 Pro | カメラ識別 | 低 — 数千万台で共通 |
LensModel | iPhone 15 Pro back camera 6.86mm f/1.78 | 編集ソフトのための光学情報 | 低 |
DateTimeOriginal | 2024-08-12 14:32:08 | 並び替え・アルバム整理 | 中 — いつどこにいたかが分かる |
FNumber / ExposureTime / ISO / FocalLength | f/1.8、1/120s、ISO 80、24mm | 編集ソフトでの露出再現 | なし |
GPSLatitude / GPSLongitude | 31.230556° N、121.473611° E | 地図表示・検索のジオタグ | 高 — 数メートル単位で位置特定 |
GPSAltitude | 15 m | 海抜情報 | 中 |
Software | iOS 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 と XMPAPP13(0xFFED)—— Photoshop / IPTCAPP14(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 で何が違うのか:
| 機能 | ZeroTool | exiftool(CLI) |
|---|---|---|
| ローカルで動作、アップロードなし | はい(ブラウザタブ内) | はい(手元のマシン) |
| 再エンコードせずに除去 | はい(APP1 / APP13 / APP14 を削除) | はい(メタデータだけ書き換え) |
| オープンソース | はい(リポジトリ) | はい |
| GPS 地図リンク | あり | なし(座標を表示) |
| 形式 | JPEG のみ | JPEG、HEIC、TIFF、PNG、動画など |
| バッチ処理 | なし(1 ファイルずつ) | あり(ディレクトリ、-r) |
「この写真に EXIF があるか、削除できるか」を 1 回確かめるだけなら、インストール不要のブラウザツールで足ります。バッチ処理や HEIC には exiftool を使いましょう。
プライバシーに関する注記
- ページは写真をアップロードしません。写真のバイトはブラウザタブ内に留まります。写真には位置情報が含まれうるため、このツールページは Google アナリティクスも AdSense も読み込みません。
- Google マップディープリンクはローカルで生成される。クリックするまでリクエストは発しない。
- 除去後のダウンロードは Blob URL で、メモリ残留を避けるため 1 秒後に revoke される。
関連資料
- CIPA Exif 3.0 規格(DC-008-2023) —— 公式規格
- JPEG ファイル構造 —— Wikipedia によるマーカーセグメント概観
- MDN: FileReader —— バイト読み取りに使うブラウザ API
- MDN: DataView —— バイナリ解析向けのエンディアン対応リード
- exiftool(Phil Harvey) —— 業界標準のコマンドライン メタデータツール
- 相性の良い ZeroTool ツール:Image to Base64、WebP コンバーター、SVG to PNG コンバーター、QR コードデコーダー