OracleZoom / geometry.py
dipta007's picture
Drop the comparison slider, drag the zoom point, allow 8 steps
56bd6cc verified
Raw
History Blame Contribute Delete
1.72 kB
"""Crop geometry for the zoom. Pure PIL, no model code, so it stays cheap to test."""
from PIL import Image
PROCESS_SIZE = 512
def resize_and_center_crop(img, size=PROCESS_SIZE):
"""CoZ's entry crop: shortest side to `size`, then the centre square."""
w, h = img.size
scale = size / min(w, h)
nw, nh = int(w * scale), int(h * scale)
img = img.resize((nw, nh), Image.LANCZOS)
left, top = (nw - size) // 2, (nh - size) // 2
return img.crop((left, top, left + size, top + size))
def window_rect(size, upscale, center=(0.5, 0.5)):
"""The next level's field of view: a 1/upscale square around `center`, clamped inside."""
w, h = size
nw, nh = w // upscale, h // upscale
left = min(max(int(center[0] * w - nw / 2), 0), w - nw)
top = min(max(int(center[1] * h - nh / 2), 0), h - nh)
return left, top, left + nw, top + nh
def zoom_window(img, upscale, center=(0.5, 0.5)):
return img.crop(window_rect(img.size, upscale, center))
def nested_rects(size, levels, upscale=4, center=(0.5, 0.5)):
"""Where each zoom step lands, in the coordinates of the first canvas.
Stops early once a window would be under a pixel wide. The recursion itself never
degenerates, because every step resizes its crop back up to the full canvas, but drawing
all those steps onto the one original canvas does run out of pixels.
"""
rects, rect = [], (0, 0, size[0], size[1])
for _ in range(levels):
side = rect[2] - rect[0]
if side // upscale < 1:
break
l, t, r, b = window_rect((side, side), upscale, center)
rect = (rect[0] + l, rect[1] + t, rect[0] + r, rect[1] + b)
rects.append(rect)
return rects