# Photochk フォルダの中から、中身が同じ写真と見た目が似ている写真を探して一覧にする macOS アプリ。 同じ写真のコピー、リサイズ版、メッセージアプリ経由で再圧縮された版、連写のほぼ同じカット — ファイル名もサイズも違うので Finder では見つからないものを、グループにまとめて見せる。 残す1枚を選んで、ほかをまとめてゴミ箱へ送れる(削除ではないので Finder から戻せる)。 ## 使い方 ```bash 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](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` から生成する(リポジトリには含めない)。 ```bash make generate && open Photochk.xcodeproj ``` 必要なもの: macOS 15 以降、Xcode 26 以降、`brew install xcodegen`。 `Tests/PhotochkTests/SnapshotTests.swift` は `ImageRenderer` で写真タイルなどを実際に描画し、 PNG を一時フォルダに書き出す(パスはテスト出力に出る)。レイアウトを変えたら開いて目で確認できる。 `List` や `NavigationSplitView` は AppKit 由来で `ImageRenderer` では描けないため対象外。