mirror of
https://github.com/pinry/pinry.git
synced 2025-11-13 08:35:41 +01:00
Only load Image once when creating all three Thumbnail sizes.
This commit is contained in:
@@ -1,13 +1,45 @@
|
||||
from contextlib import contextmanager
|
||||
from io import BytesIO
|
||||
import PIL
|
||||
from PIL import Image
|
||||
|
||||
|
||||
@contextmanager
|
||||
def open_django_file(fieldfile):
|
||||
fieldfile.open()
|
||||
try:
|
||||
yield fieldfile
|
||||
finally:
|
||||
fieldfile.close()
|
||||
|
||||
|
||||
def scale_and_crop_iter(image, options):
|
||||
"""
|
||||
Generator which will yield several variations on the input image.
|
||||
Resize, crop and/or change quality of image.
|
||||
|
||||
:param image: Source image file
|
||||
:param type: :class:`django.core.files.images.ImageFile
|
||||
|
||||
:param`options: List of option dictionaries, See scale_and_crop_single
|
||||
argument names for available keys.
|
||||
:type options: list of dict
|
||||
"""
|
||||
with open_django_file(image) as img:
|
||||
im = Image.open(img)
|
||||
im.load()
|
||||
for opts in options:
|
||||
# Use already-loaded file when cropping.
|
||||
yield scale_and_crop_single(im, **opts)
|
||||
|
||||
|
||||
# this neat function is based on easy-thumbnails
|
||||
def scale_and_crop(image, size, crop=False, upscale=False, quality=None):
|
||||
def scale_and_crop_single(image, size, crop=False, upscale=False, quality=None):
|
||||
"""
|
||||
Resize, crop and/or change quality of an image.
|
||||
|
||||
:param image: Source image file
|
||||
:param type: :class:`django.core.files.images.ImageFile`
|
||||
:param type: :class:`PIL.Image`
|
||||
|
||||
:param size: Size as width & height, zero as either means unrestricted
|
||||
:type size: tuple of two int
|
||||
@@ -24,15 +56,7 @@ def scale_and_crop(image, size, crop=False, upscale=False, quality=None):
|
||||
:return: Handled image
|
||||
:rtype: class:`PIL.Image`
|
||||
"""
|
||||
# Open image and store format/metadata.
|
||||
image.open()
|
||||
im = Image.open(image)
|
||||
im_format, im_info = im.format, im.info
|
||||
if quality:
|
||||
im_info['quality'] = quality
|
||||
|
||||
# Force PIL to load image data.
|
||||
im.load()
|
||||
im = image
|
||||
|
||||
source_x, source_y = [float(v) for v in im.size]
|
||||
target_x, target_y = [float(v) for v in size]
|
||||
@@ -68,6 +92,31 @@ def scale_and_crop(image, size, crop=False, upscale=False, quality=None):
|
||||
im = im.crop(box)
|
||||
|
||||
# Close image and replace format/metadata, as PIL blows this away.
|
||||
im.format, im.info = im_format, im_info
|
||||
image.close()
|
||||
# We mutate the quality, but needs to passed into save() to actually
|
||||
# do anything.
|
||||
info = image.info
|
||||
if quality is not None:
|
||||
info['quality'] = quality
|
||||
im.format, im.info = image.format, info
|
||||
return im
|
||||
|
||||
|
||||
def write_image_in_memory(img):
|
||||
# save to memory
|
||||
buf = BytesIO()
|
||||
try:
|
||||
img.save(buf, img.format, **img.info)
|
||||
except IOError:
|
||||
if img.info.get('progression'):
|
||||
orig_MAXBLOCK = PIL.ImageFile.MAXBLOCK
|
||||
temp_MAXBLOCK = 1048576
|
||||
if orig_MAXBLOCK >= temp_MAXBLOCK:
|
||||
raise
|
||||
PIL.ImageFile.MAXBLOCK = temp_MAXBLOCK
|
||||
try:
|
||||
img.save(buf, img.format, **img.info)
|
||||
finally:
|
||||
PIL.ImageFile.MAXBLOCK = orig_MAXBLOCK
|
||||
else:
|
||||
raise
|
||||
return buf
|
||||
|
||||
Reference in New Issue
Block a user