40 lines
1.2 KiB
Python
40 lines
1.2 KiB
Python
"""Small-thumbnail quality heuristics. Never delete or modify source photos."""
|
|||
|
|
|
||
|
|
import hashlib
|
||
|
|
from io import BytesIO
|
||
|
|
|
||
|
|
from PIL import Image, ImageFilter, ImageOps, ImageStat
|
||
|
|
|
||
|
|
|
||
|
|
def photo_quality(data):
|
||
|
|
with Image.open(BytesIO(data)) as source:
|
||
|
|
image = ImageOps.exif_transpose(source).convert("L")
|
||
|
|
image.thumbnail((256, 256))
|
||
|
|
brightness = ImageStat.Stat(image).mean[0]
|
||
|
|
edges = image.filter(ImageFilter.FIND_EDGES)
|
||
|
|
sharpness = ImageStat.Stat(
|
||
|
|
edges.crop((2, 2, max(3, image.width - 2), max(3, image.height - 2)))
|
||
|
|
).var[0]
|
||
|
|
small = image.resize((9, 8))
|
||
|
|
pixels = list(small.tobytes())
|
||
|
|
bits = "".join(
|
||
|
|
"1" if pixels[y * 9 + x] > pixels[y * 9 + x + 1] else "0"
|
||
|
|
for y in range(8)
|
||
|
|
for x in range(8)
|
||
|
|
)
|
||
|
|
return {
|
||
|
|
"brightness": round(brightness, 2),
|
||
|
|
"sharpness": round(sharpness, 2),
|
||
|
|
"fingerprint": f"{int(bits, 2):016x}",
|
||
|
|
"sha256": hashlib.sha256(data).hexdigest(),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def passes(result, source):
|
||
|
|
return (
|
||
|
|
result["sharpness"] >= source.minimum_sharpness
|
||
|
|
and source.minimum_brightness
|
||
|
|
<= result["brightness"]
|
||
|
|
<= source.maximum_brightness
|
||
|
|
)
|