photolib/photoapp/thumb.py

74 lines
2.4 KiB
Python

import os
import sys
import traceback
from PIL import Image, ImageOps
from multiprocessing import Process
# style tuples: max x, max y, rotate ok)
# rotate ok means x and y maxes can be swapped if it fits the image's aspect ratio better
THUMB_STYLES = {"tiny": (80, 80, False),
"small": (100, 100, False),
"feed": (250, 250, False),
"preview": (1024, 768, True),
"big": (2048, 1536, True)}
def thumb_path(style_name, uuid):
return os.path.join("thumbs", style_name, uuid[0:2], "{}.jpg".format(uuid))
def image_style(image, style_name, orientation):
"""
Given an input PIL Image object, return a scaled/cropped image object of style_name
"""
thumb_width, thumb_height, flip_ok = THUMB_STYLES[style_name]
i_width, i_height = image.size
im_is_rotated = orientation % 2 != 0 or i_height > i_width
if im_is_rotated and flip_ok:
thumb_width, thumb_height = thumb_height, thumb_width
# prevents scale-up (why do i want this?)
thumb_width = min(thumb_width, i_width) if i_width > 0 else thumb_width
thumb_height = min(thumb_height, i_height) if i_height > 0 else thumb_height
image = image.rotate(90 * orientation, expand=True)
return ImageOps.fit(image, (thumb_width, thumb_height), Image.ANTIALIAS)
def image_file_style(src_path, output_path, style_name, orientation):
"""
Given an input and output image paths, create a scaled/cropped image file of style_name
"""
image = Image.open(src_path)
if image.mode != "RGB":
image = image.convert("RGB")
output = image_style(image, style_name, orientation)
output.save(output_path, 'JPEG')
def _image_file_style_process_worker(src_path, output_path, style_name, orientation):
try:
image_file_style(src_path, output_path, style_name, orientation)
except Exception:
traceback.print_exc()
if os.path.exists(output_path):
os.unlink(output_path)
sys.exit(1)
def image_file_style_process(src_path, output_path, style_name, orientation):
"""
Same as image_file_style but the image manipulation is done in a background process
"""
p = Process(target=_image_file_style_process_worker,
args=(src_path, output_path, style_name, orientation))
p.start()
p.join()
if p.exitcode != 0:
return False
return True