-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimage_utils.py
More file actions
67 lines (48 loc) · 1.72 KB
/
image_utils.py
File metadata and controls
67 lines (48 loc) · 1.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""Shared image utilities for resizing and hashing."""
import hashlib
from io import BytesIO
from PIL import Image
def compute_hash(image_bytes: bytes) -> str:
"""Compute SHA256 hash of image bytes for deduplication.
Returns first 32 hex chars (128 bits) for reasonable storage.
"""
return hashlib.sha256(image_bytes).hexdigest()[:32]
def resize_image(img: Image.Image, max_size: int = 1024) -> Image.Image:
"""Resize image so smallest dimension is at most max_size.
Args:
img: PIL Image
max_size: Target for smallest dimension (default: 1024)
Returns:
Resized PIL Image (or original if already small enough)
"""
w, h = img.size
if min(w, h) <= max_size:
return img
if w < h:
new_w = max_size
new_h = int(h * max_size / w)
else:
new_h = max_size
new_w = int(w * max_size / h)
return img.resize((new_w, new_h), Image.LANCZOS)
def process_image(image_bytes: bytes, max_size: int = 1024) -> tuple:
"""Process image bytes: resize and compute hash.
Args:
image_bytes: Raw image bytes
max_size: Target for smallest dimension
Returns:
(processed_bytes, width, height, sha256_hash, format)
"""
img = Image.open(BytesIO(image_bytes))
# Convert to RGB if needed
if img.mode != "RGB":
img = img.convert("RGB")
# Resize
img = resize_image(img, max_size)
# Save to bytes (deterministic encoding)
buffer = BytesIO()
img.save(buffer, format="JPEG", quality=90)
processed_bytes = buffer.getvalue()
# Compute hash on final processed bytes
image_hash = compute_hash(processed_bytes)
return processed_bytes, img.width, img.height, image_hash, "jpeg"