Skip to content

Instantly share code, notes, and snippets.

@shazow
Last active August 29, 2015 13:57
Show Gist options
  • Save shazow/9655002 to your computer and use it in GitHub Desktop.
Save shazow/9655002 to your computer and use it in GitHub Desktop.
Thumbnailing helpers.
from math import ceil
def resize_dimensions(x, y, max_width=None, max_height=None, min_side=None, max_side=None):
if not any([max_width, max_height, min_side, max_side]):
return x, y
original_x, original_y = x, y
priority_width = True
if max_width and x > max_width:
ratio = max_width / float(x)
x *= ratio
y *= ratio
if max_height and y > max_height:
priority_width = False
ratio = max_height / float(y)
y *= ratio
x *= ratio
biggest_side = max(x, y)
if max_side and biggest_side > max_side:
priority_width = x == biggest_side
ratio = float(max_side) / biggest_side
x *= ratio
y *= ratio
smallest_side = min(x, y)
if min_side and smallest_side > min_side:
priority_width = x == smallest_side
ratio = float(min_side) / smallest_side
x *= ratio
y *= ratio
if priority_width:
x = round(x)
y = ceil((x / original_x) * original_y)
else:
y = round(y)
x = ceil((y / original_y) * original_x)
return int(x), int(y)
def crop_center(width, height, target_width, target_height):
"""
Only crops if the image is bigger than targets.
"""
left = max(0, int(round((width - target_width) / 2.0)))
top = max(0, int(round((height - target_height) / 2.0)))
right = int(round((width + min(width, target_width)) / 2.0))
bottom = int(round((height + min(height, target_height)) / 2.0))
return left, top, right, bottom
def _path_trim(abs_path, rel_path):
cur_dir = os.path.dirname(rel_path)
while cur_dir:
abs_path = os.path.dirname(abs_path)
cur_dir = os.path.dirname(cur_dir)
return abs_path
def _get_thumbnail_path(file_name, file_path, file_url, size):
thumb_dir = os.path.join(_path_trim(file_path, file_name), 'thumbs')
thumb_url = os.path.join(_path_trim(file_url, file_name), 'thumbs')
filedir, filename = os.path.split(file_name)
basename, format = os.path.splitext(filename)
thumb_filename = basename + '_' + size + format
path = os.path.join(thumb_dir, filedir, thumb_filename)
url = os.path.join(thumb_url, filedir, thumb_filename)
return path, url
def thumbnail(file, ...):
"""
This function is a disaster due to restrictions in Django templatetags. Removed the disasterous parts. Enter at your own peril.
"""
time_started = time.time()
if not os.path.exists(file.path):
log.error("thumbnail: Original image does not exist: %s" % file.path)
return "" # TODO: Return a placeholder URL?
# ...
target_path, target_url = _get_thumbnail_path(file.name, file.path, file.url, size_name)
if os.path.exists(target_path):
# Does the thumb already exist?
if os.path.getmtime(file.path) <= os.path.getmtime(target_path):
# Still valid
return target_url
elif not os.path.isdir(os.path.dirname(target_path)):
# Does the directory need to be created?
os.makedirs(os.path.dirname(target_path))
# Get original x, y
try:
image = Image.open(file.path)
except IOError, e:
raise ValueError("Failed to open image path: %s (error: %s)" % (file.path, e))
if image.mode == 'P':
# Some people have uploaded jpeg images that are actually PNGs -- deal with this
image = image.convert('RGB')
original_x, original_y = image.size
x, y = resize_dimensions(original_x, original_y, max_width=max_width, max_height=max_height, min_side=min_side, max_side=max_side)
image.thumbnail([x, y], Image.ANTIALIAS)
if crop_size:
box = crop_center(x, y, crop_width, crop_height)
image = image.crop(box)
try:
image.save(target_path, "JPEG", quality=85, optimize=True)
except IOError:
image.save(target_path, "JPEG", quality=85)
time_elapsed = time.time() - time_started
log.info("Created new thumbnail in %s seconds: %s" % (time_elapsed, target_path))
return target_url
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment