Exif が問題になる場面
スマホで撮った写真には Exif という形式でメタデータが埋め込まれています。
撮影日時、カメラの機種名、そして GPS 情報。
ブログやサービスに写真をアップするとき、
何も考えずにアップすると撮影場所が特定できる状態になっていることがあります。
SNS はアップ時に Exif を自動で削除するサービスが多いですが、
自前のサービスや個人ブログだとそのまま公開されることもあるので注意が必要です。
Canvas を経由するだけで Exif は消える
結論から言うと、追加のライブラリは不要です。
画像を Canvas に描画して、そこから再度 Blob に変換するだけで
Exif 情報は取り除かれます。Canvas はピクセルデータしか保持しないので、
メタデータは描画の段階で捨てられます。
async function removeExif(file) {
const bitmap = await createImageBitmap(file);
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(bitmap, 0, 0);
return canvas.convertToBlob({ type: 'image/jpeg', quality: 0.95 });
}
これだけです。リサイズも同時にやるなら前回までのコードと組み合わせるだけで動きます。
本当に消えているか確認する方法
Mac なら「プレビュー」で画像を開いて「ツール → インスペクタを表示」から
Exif タブを見ると確認できます。
コードで確認したい場合は exifr というライブラリが手軽です。
import exifr from 'https://cdn.skypack.dev/exifr';
const before = await exifr.parse(originalFile);
console.log(before); // GPS情報などが見える
const cleanBlob = await removeExif(originalFile);
const after = await exifr.parse(cleanBlob);
console.log(after); // null か空になっていれば OK
注意点が一つ
Canvas 経由で Exif が消えるのは本当ですが、
JPEG の向き(Orientation)情報も一緒に消えます。
スマホで縦向きに撮った写真は、Exif の Orientation で向きを補正しているものがあって、
それを読まずに Canvas に描画すると横向きに表示されることがあります。
import exifr from 'https://cdn.skypack.dev/exifr';
async function drawWithOrientation(file) {
const orientation = await exifr.parse(file, ['Orientation'])
.then(d => d?.Orientation ?? 1);
const bitmap = await createImageBitmap(file);
const { width, height } = getRotatedSize(bitmap, orientation);
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext('2d');
applyOrientation(ctx, orientation, width, height);
ctx.drawImage(bitmap, 0, 0);
return canvas.convertToBlob({ type: 'image/jpeg', quality: 0.95 });
}
function getRotatedSize(bitmap, orientation) {
const rotated = orientation >= 5 && orientation <= 8;
return rotated
? { width: bitmap.height, height: bitmap.width }
: { width: bitmap.width, height: bitmap.height };
}
function applyOrientation(ctx, orientation, w, h) {
const transforms = {
2: () => { ctx.transform(-1, 0, 0, 1, w, 0); },
3: () => { ctx.transform(-1, 0, 0, -1, w, h); },
4: () => { ctx.transform(1, 0, 0, -1, 0, h); },
5: () => { ctx.transform(0, 1, 1, 0, 0, 0); },
6: () => { ctx.transform(0, 1, -1, 0, h, 0); },
7: () => { ctx.transform(0, -1, -1, 0, h, w); },
8: () => { ctx.transform(0, -1, 1, 0, 0, w); },
};
transforms[orientation]?.();
}
向き補正まで入れると少し長くなりますが、
スマホ撮影の画像を扱うなら入れておいた方が無難です。
この連載では Canvas API → Web Worker → 一括処理 → フォーマット変換 → Exif削除
と順番に書いてきましたが、組み合わせれば「複数ファイルを選んで、
WebPに変換しながらリサイズして、Exifも消してまとめてダウンロード」
という処理がライブラリなしでブラウザだけで動きます。
需要があれば全部組み合わせた完成版のコードも書こうと思います。
自分でゼロから実装するのが大変な場合は、
同じ仕組みで動くブラウザツール BulkPicTools も作っているので、
よかったら使ってみてください → https://bulkpictools.com/tools/exif/exif-editor