0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

顔写真の原図をサーバーに残さない:ブラウザで derivative を作ってから解析する

0
Posted at

顔写真を扱う Web サービスは、解析そのものより先に「原図がどこに残るか」で詰まりやすい。公開結果 URL、アプリログ、学習データ、メール添付。どれか一つでも残すと、あとから消す設計に作り直す方が高い。

ここでは、無料の顔写真解析をログインなしで出す前提で、サーバーに原図を置かないために実際に並べた順を書く。同じ制約(同意、一時保存、削除の再試行)を後から足す人向けの手順メモ。

先に固定した制約

実装の前に、落とさない約束を先に書いた。

  • 送信前に、写っている人が 18 歳以上であることと、その写真を使ってよい許可があることを確認する
  • 無料経路はアカウントもメールも要求しない
  • 無料結果に公開 URL を付けない
  • 解析が終わったら derivative の削除をすぐ試み、失敗分は後追いで掃除する
  • アップロードした写真をモデル学習に使わない設定にする

「あとで消します」と書いて原図の File をそのまま POST すると、位置情報や機種、撮影時刻が入った EXIF までサーバーに乗る。削除より先に、ブラウザで derivative を作る。

1. ブラウザで描き直す

送るのは原図ではなく、キャンバスに描き直した JPEG だけ。createImageBitmapcanvas.drawImagetoBlob すると、EXIF はコピーされない。長辺は 1600px、JPEG quality は 0.86。サーバーが受け取るファイル名は portrait.jpg

export async function preprocessPhoto(file) {
  const bitmap = await createImageBitmap(file)
  const scale = Math.min(1, 1600 / Math.max(bitmap.width, bitmap.height))
  const canvas = document.createElement('canvas')
  canvas.width = Math.max(1, Math.round(bitmap.width * scale))
  canvas.height = Math.max(1, Math.round(bitmap.height * scale))
  const context = canvas.getContext('2d', { alpha: false })
  context.drawImage(bitmap, 0, 0, canvas.width, canvas.height)
  bitmap.close()
  const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/jpeg', 0.86))
  return new File([blob], 'portrait.jpg', { type: 'image/jpeg' })
}

ブラウザの FaceDetector があれば、顔がゼロ/複数、という警告にだけ使う。アップロードの門にはしていない。未対応のブラウザを落とす理由がない。

明るさやボケの雑なチェックも、縮小キャンバスの輝度でやる。ゲートではなく、「この写真だと寸評が雑になる」と先に伝えるため。

2. 同意と乱用対策を、画像より前に置く

derivative を作ったあと、送信の直前に 18+ と許可の確認を取る。Cloudflare Turnstile とレート制限は IP やブラウザ情報を見るので、肖像そのものより先に置く。解析結果の非公開ページでは、公開アナリティクスを載せない。

ここまででサーバーに届くのは、メタデータのない JPEG と、解析に必要な短い指示だけ。

3. サーバーは中継して、すぐ消す

ブラウザから来た derivative は、安全確認と解析のためだけに一時保存する。モデル呼び出しはサーバー間。終わったら削除を試みる。失敗分は定期ジョブで再試行する。

無料結果は公開ページにしない。有料レポートだけ、推測しにくいリンクの裏に約 30 日置く。入力写真は生成後に消す。

プロバイダ側の保持は相手の規約に依存する、とはっきり書く。自前ストレージを空にしても、モデル API の側までゼロ秒とは言えない。

同じ経路を本番に載せた例

この順を、顔写真の「写り」フィードバックに使っている。

Am I Pretty?

無料は 1 枚、アカウントなし。返ってくるのは Photo Appeal Score と、表情・光・構図・スタイリングの寸評。人の価値や科学的な美の順位ではない。同じ人でも写真が違えば結果は変わる、という前提で作っている。

まだ言えないこと

  • インターネット上のサービスに、完全なセキュリティは言えない
  • プロバイダ内部の保持まで自前では制御できない
  • 削除は「試みる」。リトライがある、ということは失敗しうる
  • これは美の判定器ではない

肖像を扱うなら、公開 URL を先に設計しない方が楽だった。消す経路を後付けすると、メール、CDN、解析ログのどこかに必ず残る。

制約の根拠(スコアの根拠ではない):

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?