Files
photochk/README.md
T
2026-07-27 15:47:02 +00:00

4.9 KiB
Raw Blame History

Photochk

フォルダの中から、中身が同じ写真と見た目が似ている写真を探して一覧にする macOS アプリ。

同じ写真のコピー、リサイズ版、メッセージアプリ経由で再圧縮された版、連写のほぼ同じカット — ファイル名もサイズも違うので Finder では見つからないものを、グループにまとめて見せる。 残す1枚を選んで、ほかをまとめてゴミ箱へ送れる(削除ではないので Finder から戻せる)。

使い方

make run

make build でビルドのみ、make test でテスト。生成物は build/Build/Products/Debug/Photochk.app。

配布用に固めるなら make release(Release ビルド+dist/Photochk-1.0.0.zip)、 /Applications に入れるなら make install。

ビルドは ad-hoc 署名(Developer ID 証明書なし)。自分の Mac でビルドして使う分には問題ないが、 zip を他の Mac に配ると Gatekeeper に止められる。受け取った側は右クリック →「開く」で起動できる。

  1. ツールバーの「フォルダを選ぶ」で対象フォルダを指定する
  2. 左のグループ一覧から選ぶと、右にそのグループの全枚数が並ぶ
  3. 残す1枚以外にチェックを入れる(「一括選択」メニューで「解像度が最も高い1枚を残す」なども選べる)
  4. 「N 枚をゴミ箱へ」で移動する

グループから全部を選ぶことはできない。必ず1枚は残る。

各写真には基準(代表)からの距離が出る。代表以外にもバイト単位で中身が同じファイルがある場合は 「同一 A」のように同じ印が付くので、その中のどれを消しても失われるものがないと分かる。

検出のしくみ

安い判定から順にかけて候補を絞り込む。

  1. 完全同一 — ファイルサイズが同じものだけ SHA-256 を計算して、バイト単位の重複を確定する
  2. 知覚ハッシュ (dHash) — 9×8 のグレースケールに落として隣接ピクセルの明暗を比べ、64bit のハッシュを作る。 ハミング距離が近いペアだけを次に回す
  3. Vision の feature print — 候補ペアに出てくる画像だけ GenerateImageFeaturePrintRequest で 特徴量を計算し、距離で最終判定する
  4. Union-Find — 「同一」「類似」のペアから連結成分を作ってグループにする

各グループの代表は「解像度が最大 → ファイルサイズが最大 → 撮影が最古」で自動的に選ばれる。

判定の厳しさは3段階。しきい値は実写画像で距離を測って決めた(docs/calibration.md)。

段階 何が拾えるか
厳しい コピー・縮小(25% まで)・再圧縮
標準 上記+連写・同一シーンの近いカット
ゆるい 上記+トリミングされた版

対応形式は UTType が画像に該当するものすべて。JPEG / PNG / HEIC / TIFF に加えて各社の RAW も扱える。

分かっている制限

  • 向きが違う写真は別物として扱う。 EXIF の向きを反映した「見た目」で比較しているため、 回転が焼き込まれた版と EXIF で回している版は同じ写真として検出できるが、 実際に 90 度違う向きの写真どうしは検出しない(4方向ぶんの特徴量が必要でコストが4倍になるため)
  • 2回目以降のスキャンは ~/Library/Caches/Photochk/fingerprints.plist のキャッシュで速くなる。 ファイルサイズと更新日時が変わっていれば自動で計算し直す

構成

Sources/Photochk/
├── Models/       PhotoAsset, SimilarityGroup, ScanSettings
├── Core/         走査・ハッシュ・特徴量・グルーピング(UI 非依存)
├── Services/     サムネイル生成、ゴミ箱、フォルダのアクセス権
├── ViewModels/   ScanViewModel
└── Views/        SwiftUI

外部依存なし。SwiftUI / Vision / CryptoKit / ImageIO / QuickLookThumbnailing のみ。 App Sandbox 有効で、アクセスできるのはユーザーが選んだフォルダだけ。

開発

Xcode プロジェクトは XcodeGen で project.yml から生成する(リポジトリには含めない)。

make generate && open Photochk.xcodeproj

必要なもの: macOS 15 以降、Xcode 26 以降、brew install xcodegen。

Tests/PhotochkTests/SnapshotTests.swift は ImageRenderer で写真タイルなどを実際に描画し、 PNG を一時フォルダに書き出す(パスはテスト出力に出る)。レイアウトを変えたら開いて目で確認できる。 List や NavigationSplitView は AppKit 由来で ImageRenderer では描けないため対象外。