2026-01-31
クライアント側で完結する EXIF 解析ツール EXIF Data Extractor を作った話
michimani.net の app 配下で公開している「EXIF Data Extractor」について、なぜ作ったのか、どんな機能を提供しているのか、そしてどう使うことを想定しているのかをまとめます。実際のアプリは https://this.michimani.net/exif から利用できます。
概要
EXIF Data Extractor は、写真ファイルに埋め込まれた EXIF 情報をブラウザ上で解析し、撮影時の設定を一覧で表示するツールです。撮影情報の表示に加えて、必要な情報をコピーしたり、RAW に近い EXIF データの中身を確認できるようにしています。すべての処理はブラウザ内で完結し、画像や EXIF データがサーバーに送信されない点も大きな特徴です。実装上も exifr を使ってブラウザで直接パースし、ファイルをアップロードせずに処理する構成になっています。
実装背景
1. 写真の情報をすばやく取り出したい
ここ数年で一眼レフを使って写真を撮る場面が増え、撮った写真を SNS にアップすることも増えました。その際、写真の情報 (特にレンズやシャッタースピード、F値、ISO) も説明として載せたいと思うようになりました。実際、写真アカではそのような情報を記載してくれている方が多いです。それらの情報は EXIF 情報として持っているため PC やスマホで確認することはできますが、毎回それらをみながら入力したりコピペするのが面倒だと感じていました。
そこで、ブラウザだけで完結し、ドラッグ & ドロップで一気に情報を取り出せる UI にすることで、手元で素早く確認できるツールを目指しました。
2. MakerNote まで扱える EXIF 解析
一般的な EXIF 解析では、カメラ固有の MakerNote をうまく扱えないことがあります。このツールでは exifr を使い、メーカー固有のレンズ情報も拾えるようにしています。実装では exifr.parse のオプションで MakerNote を有効にし、レンズ情報やホワイトバランス、測光モード、フラッシュ情報などを複数の候補キーから引き当てるロジックを組み込んでいます。
3. ブラウザで完結する設計
画像や EXIF 情報には個人情報が含まれる場合があるため、それらをサーバーへ送信されることに抵抗がある人もいます。自分も同様のサービスやツールを使用する際は気を使います。なので、今回実装したツールではあくまでもクライアント側で処理が完結する構成にしています。実装上もサーバーへのアップロード処理は入れておらず、写真内の情報をサーバー側で取得することはありません。ファイルは File オブジェクトから直接 exifr に渡し、解析結果もクライアント内で保持するだけです。
提供する機能
EXIF Data Extractor の主要な機能は以下の通りです。
1. 画像のアップロード (複数対応)
ドラッグ & ドロップまたはクリックで、複数の画像をまとめて読み込めます。画像ファイルのみを受け付けるフィルタを設け、非画像ファイルは弾く仕様です。読み込んだ画像はその場でプレビュー表示されます。
2. 撮影情報の一覧表示
表示する撮影情報は以下の通りです。
- カメラ (Make + Model)
- レンズ
- 絞り値 (Aperture)
- シャッタースピード
- ISO 感度
- 焦点距離
- 35mm 換算焦点距離
- フラッシュ
- 測光モード
- ホワイトバランス
特にレンズ情報は MakerNote やメーカー固有の情報まで拾えるように、複数のフィールドから探索しています。
3. コピー機能
抽出した撮影情報は 2 種類の形式でクリップボードにコピーできます。
- Copy Essential: カメラ名 / レンズ名 / シャッタースピード / 焦点距離 / F 値 / ISO を 1 行にまとめた形式
- Copy All: すべての撮影情報を複数行でまとめた形式
SNS 投稿のテンプレとして使う場合は Essential、詳細記録として残したい場合は All を使う想定です。
実際にコピーされる内容の例は以下の通りです。
Copy Essential
SONY ILCE-7CM2 | FE 50-150mm F2 GM 1/200 81mm F2.0 ISO320
Copy All
Camera: SONY ILCE-7CM2
Lens: FE 50-150mm F2 GM
Aperture: f/2.0
Shutter Speed: 1/200
ISO: 320
Focal Length: 81mm
Focal Length (35mm): 81mm
Flash: Flash did not fire, compulsory flash mode
Metering Mode: Pattern
White Balance: Auto
4. RAW EXIF のデバッグビュー
撮影情報の一覧だけでは確認できないタグもあるため、解析結果の RAW データをツリー表示するビューを用意しています。オブジェクトや配列を展開して確認できるため、未知のタグやメーカー独自タグを調査したいときに便利です。
EXIF 解析の流れ(疑似コード)
実装の流れをざっくり疑似コードにすると以下のようになります。ポイントは「ファイルをそのまま exifr に渡し、結果をクライアント内の状態に格納する」ことです。
onFilesSelected(files):
validImages = files.filter(isImage)
for each file in validImages:
previewUrl = createObjectURL(file)
result = {
id: uuid(),
file,
previewUrl,
isLoading: true,
exifData: null,
rawExifData: null
}
results.push(result)
extractExif(file, result.id)
extractExif(file, id):
try:
exifInfo = exifr.parse(file, {
exif: true,
makerNote: true,
tiff: true,
gps: false,
xmp: false,
...
})
if exifInfo is null:
throw "No EXIF data"
extractedData = {
aperture: formatFNumber(exifInfo.FNumber),
shutterSpeed: formatExposureTime(exifInfo.ExposureTime),
iso: pickIso(exifInfo.ISO, exifInfo.ISOSpeedRatings),
focalLength: formatFocalLength(exifInfo.FocalLength),
focalLength35mm: formatFocalLength(exifInfo.FocalLengthIn35mmFormat),
camera: joinMakeModel(exifInfo.Make, exifInfo.Model),
lens: pickLensFromMultipleFields(exifInfo),
flash: pickFlashFromMultipleFields(exifInfo),
meteringMode: pickMeteringFromMultipleFields(exifInfo),
whiteBalance: pickWhiteBalanceFromMultipleFields(exifInfo)
}
updateResult(id, {
exifData: extractedData,
rawExifData: exifInfo,
isLoading: false
})
catch error:
updateResult(id, {
error: "Failed to extract EXIF data",
isLoading: false
})
まとめ
ブラウザで、特にクライアントのみで処理が完結する EXIF 解析ツール、 EXIF Data Extractor を実装した話でした。
普段の写真整理や SNS 投稿の効率化だけでなく、カメラやレンズの挙動を確認したい場面でも役に立つツールになっていると思います。もし写真をよく撮る方がいたらぜひ https://this.michimani.net/exif で試してみてください。