"""Golden perceptual-hash relationships and confidence bands.""" import numpy as np from PIL import Image from photo_pipeline.services import hashing from photo_pipeline.services.duplicates import NEAR_MAX, SIMILAR_MAX def _structured(path, seed, size=(256, 192)): rng = np.random.default_rng(seed) w, h = size base = np.zeros((h, w, 3), dtype=np.uint8) for _ in range(6): x0 = int(rng.integers(0, w - 60)) y0 = int(rng.integers(0, h - 60)) base[y0 : y0 + 60, x0 : x0 + 60] = rng.integers(0, 256, 3) grad = np.linspace(0, 120, w, dtype=np.uint8) base[:, :, 0] = np.clip(base[:, :, 0].astype(int) + grad[None, :], 0, 255) Image.fromarray(base).save(path, quality=95) return path def test_phash_is_16_hex_chars(tmp_path): value = hashing.phash(_structured(tmp_path / "a.jpg", 1)) assert len(value) == 16 int(value, 16) # parses as hex def test_identical_pixels_have_zero_distance(tmp_path): a = _structured(tmp_path / "a.jpg", 1) assert hashing.phash_distance(hashing.phash(a), hashing.phash(a)) == 0 def test_resized_copy_stays_within_near_band(tmp_path): a = _structured(tmp_path / "a.jpg", 1) small = tmp_path / "a_small.jpg" with Image.open(a) as image: image.resize((image.width // 2, image.height // 2), Image.LANCZOS).save(small, quality=95) distance = hashing.phash_distance(hashing.phash(a), hashing.phash(small)) assert distance <= NEAR_MAX def test_distinct_images_exceed_similar_band(tmp_path): a = _structured(tmp_path / "a.jpg", 1) b = _structured(tmp_path / "b.jpg", 2) distance = hashing.phash_distance(hashing.phash(a), hashing.phash(b)) assert distance > SIMILAR_MAX def test_phash_is_versioned(): assert hashing.PHASH_VERSION >= 1