feat(fc-cleanup): audits/single_color.py + tests — Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

This commit is contained in:
2026-05-26 01:18:38 -04:00
parent fd80d40a34
commit 900d878d27
2 changed files with 95 additions and 0 deletions
@@ -0,0 +1,53 @@
"""Single-color audit: matches images where one color dominates beyond
the threshold (within the given Euclidean RGB tolerance). The first
canonical implementation — the import-side filter (SkipReason.single_color)
was never wired; FC-Cleanup's audit module is the source of truth and a
future spec can adopt it on the import path too.
"""
from PIL import Image
_THUMB_SIZE = (64, 64)
def evaluate(
pil_image,
*,
threshold: float,
tolerance: int,
) -> bool:
"""True iff the fraction of pixels within `tolerance` (Euclidean RGB
distance) of the dominant color exceeds `threshold`.
Downsamples to 64x64 for speed (~4ms regardless of source size).
Alpha channels are stripped; only RGB is considered. Animated images
use frame 0 (PIL's default after Image.open without seek).
"""
im = pil_image
if im.mode == "RGBA":
im = im.convert("RGB")
elif im.mode not in ("RGB", "L"):
im = im.convert("RGB")
if im.size != _THUMB_SIZE:
im = im.resize(_THUMB_SIZE, Image.Resampling.BILINEAR)
pixels = list(im.getdata())
if not pixels:
return False
# Normalize L-mode pixels to RGB tuples for distance math.
if isinstance(pixels[0], int):
pixels = [(p, p, p) for p in pixels]
# Dominant color = mean RGB.
n = len(pixels)
sum_r = sum(p[0] for p in pixels)
sum_g = sum(p[1] for p in pixels)
sum_b = sum(p[2] for p in pixels)
dom = (sum_r / n, sum_g / n, sum_b / n)
tol_sq = tolerance * tolerance
within = 0
for r, g, b in pixels:
dr = r - dom[0]
dg = g - dom[1]
db = b - dom[2]
if dr * dr + dg * dg + db * db <= tol_sq:
within += 1
return (within / n) > threshold
+42
View File
@@ -0,0 +1,42 @@
"""Tests for the single-color audit rule.
The rule downsamples + measures the fraction of pixels within `tolerance`
(Euclidean RGB distance) of the dominant color. Matches if that fraction
exceeds `threshold`. Single-color content is typically uploaded by
mistake (placeholder/error/preview images) and should be flagged.
"""
from PIL import Image
from backend.app.services.audits import single_color
def test_single_color_evaluate_true_for_uniform_image():
im = Image.new("RGB", (50, 50), (128, 64, 200))
assert single_color.evaluate(im, threshold=0.9, tolerance=10) is True
def test_single_color_evaluate_false_for_diverse_image():
# Half black, half white — no single color dominates.
im = Image.new("RGB", (50, 50), (0, 0, 0))
for x in range(25):
for y in range(50):
im.putpixel((x, y), (255, 255, 255))
assert single_color.evaluate(im, threshold=0.9, tolerance=10) is False
def test_single_color_evaluate_respects_tolerance_widening():
# Gradient image: pixels span 0..50 in R channel. Tight tolerance
# rejects (no concentration), wide tolerance accepts (all near 25).
im = Image.new("RGB", (50, 50), (0, 0, 0))
for x in range(50):
for y in range(50):
im.putpixel((x, y), (x, 0, 0))
assert single_color.evaluate(im, threshold=0.9, tolerance=5) is False
assert single_color.evaluate(im, threshold=0.9, tolerance=50) is True
def test_single_color_evaluate_handles_rgba_input():
# Alpha channel should be ignored — only RGB matters for the rule.
im = Image.new("RGBA", (50, 50), (100, 100, 100, 128))
assert single_color.evaluate(im, threshold=0.9, tolerance=10) is True