掲示板に飼い猫の写真を投稿する。20 分後、見知らぬ人がコメント欄であなたの住むマンション名を当ててみせる。ストーカー行為ではない —— 写真を無料の EXIF ビューアーに放り込んだだけだ。撮影に使ったスマホは、数メートル単位の GPS 座標をファイルに書き込んでいた。掲示板はバイトをそのまま転送し、ブラウザのタブを開ける人なら誰でも読み取れる状態になっていた。

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

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

EXIF に実際に含まれるもの

EXIF(Exchangeable Image File Format、交換可能画像ファイル形式)は CIPA が維持する規格(DC-008-Translation-2023, “EXIF 2.32”)で、カメラやスマートフォンが構造化メタデータを画像ファイルに埋め込む方法を定めている。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 周もすればエッジが目に見えて柔らかくなり、平坦な色面に色度ブロックが現れる。バイトレベル方式にはそれがない —— クリーンになったファイルは同じ圧縮ピクセルのまま、個人データのセグメントだけが切り取られている。

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 は実際に何を取り除いているのか

「Twitter に投稿したから写真は安全」という素朴な仮定は、プラットフォームと送信経路に依存する。公式声明とリバースエンジニアリングの報告は食い違うことがあり、プラットフォームは方針を変える。2025 年下半期時点のおおまかな状況:

プラットフォームデフォルトのアップロード挙動注意点
Twitter / X公開画像から EXIF を除去DM は残ることがある。一部クライアントの「オリジナル画質」アップロードでは保持されることも
Facebook表示時に EXIF の大半を除去、サーバー側にはコピーを保持一部の API クエリでオリジナルが返ることがある
InstagramEXIF を除去画像を強めに再エンコード、GPS も削除
Reddit (i.redd.it)EXIF を除去外部画像ホスト(imgur など)へのリンクはホスト側のポリシー次第
LINE / WeChatチャット画像が「圧縮」モードのとき EXIF を除去「オリジナル」送信では EXIF を完全保持
WhatsApp通常送信時に EXIF を除去「ドキュメントとして送信」では保持
Discordアップロード経路とファイル種別で挙動が変わる自分の経路を確認するか、ローカルで先に除去
メール添付素通りクライアントが再エンコードしない限り EXIF はそのまま
GitHub / GitLab issue 画像素通りEXIF 保持

教訓:プラットフォームを当てにしない。投稿前にローカルで除去すれば、この問題は消える。

よくあるエッジケース

スマートフォンの写真で「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 を超えるファイル

最近のラップトップでは 100 MB 以下のファイルなら問題なくブラウザで解析・除去できる。スマートフォンは RAM が厳しい場合がある。ツールは 25 MB で警告を出し、100 MB を超えると OOM クラッシュを避けるため拒否する。多数の大ファイルをバッチ処理するなら、ローカル CLI の exiftool -all=mat2 が適切なツールだ。

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

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

# 対象タグが消えていることを確認(ICC profile と JFIF マーカーは
# 色を正しく再現するため意図的に残している)
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 で何が違うのか:

機能ZeroToolexifremover.commetadata2go.comexifcleaner(デスクトップ)
100% ブラウザ完結はいはい(自称)いいえ(サーバーアップロード)はい
バイトレベル除去(再エンコードなし)はいドキュメント不明該当なしはい
無料・登録不要はいはいはいはい
オープンソースはい(リポジトリいいえいいえはい
GPS マップリンク内蔵はいいいえ一部いいえ
HEIC / TIFF設計上 JPEG のみ一部はいはい
バッチ処理なし(単一ファイル)あり(セッションあたり最大 20 枚)一部有料はい

率直に言って:「この写真に EXIF があるか、削除できるか」を 1 度確認したいだけなら、ブラウザ系ツールはどれも仕事をこなす。バッチ処理ならデスクトップの exifcleaner や CLI の exiftool のほうが速く、HEIC にも対応する。ZeroTool の強みはバイトレベルの保証、透明なオープンソース、そして「除去が実際に何をしているか」を多言語ドキュメントで説明していることだ。

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

  • ページは写真をアップロードしない。写真のバイトはブラウザタブ内に留まる。サイト全体のアナリティクスイベント(ページビュー、parsed イベント、download_cleaned イベント)は ZeroTool の集計に送られるが、ファイル内容は一切含まない —— サイト内の他のページと同じく「動作が起きた」事実だけを記録する。
  • Google マップディープリンクはローカルで生成される。クリックするまでリクエストは発しない。
  • 除去後のダウンロードは Blob URL で、メモリ残留を避けるため 1 秒後に revoke される。

関連資料

今すぐ写真の EXIF を除去 →