Skip to content

Simplify customization of render_variation #188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions stdimage/management/commands/rendervariations.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def render(field, images, count, replace, do_render):
variations=field.variations,
replace=replace,
storage=field.storage.deconstruct()[0],
field_class=field.attr_class,
)
for file_name in images
)
Expand All @@ -78,6 +79,7 @@ def render_field_variations(kwargs):
kwargs['storage'] = get_storage_class(kwargs['storage'])()
do_render = kwargs.pop('do_render')
if callable(do_render):
kwargs.pop('field_class')
do_render = do_render(**kwargs)
if do_render:
render_variations(**kwargs)
100 changes: 54 additions & 46 deletions stdimage/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,63 +62,71 @@ def render_variation(cls, file_name, variation, replace=False,
if storage.exists(variation_name):
if replace:
storage.delete(variation_name)
logger.info('File "{}" already exists and has been replaced.')
logger.info('File "{}" already exists and has been replaced.',
variation_name)
else:
logger.info('File "{}" already exists.')
logger.info('File "{}" already exists.', variation_name)
return variation_name

resample = variation['resample']

ImageFile.LOAD_TRUNCATED_IMAGES = True
with storage.open(file_name) as f:
with Image.open(f) as img:
save_kargs = {}
file_format = img.format

if cls.is_smaller(img, variation):
factor = 1
while img.size[0] / factor \
> 2 * variation['width'] \
and img.size[1] * 2 / factor \
> 2 * variation['height']:
factor *= 2
if factor > 1:
img.thumbnail(
(int(img.size[0] / factor),
int(img.size[1] / factor)),
resample=resample
)

size = variation['width'], variation['height']
size = tuple(int(i) if i != float('inf') else i
for i in size)

if file_format == 'JPEG':
# http://stackoverflow.com/a/21669827
img = img.convert('RGB')
save_kargs['optimize'] = True
save_kargs['quality'] = 'web_high'
if size[0] * size[1] > 10000: # roughly <10kb
save_kargs['progressive'] = True

if variation['crop']:
img = ImageOps.fit(
img,
size,
method=resample
)
else:
img.thumbnail(
size,
resample=resample
)

img, save_kargs = cls.process_variation(variation, image=img)
with BytesIO() as file_buffer:
img.save(file_buffer, file_format, **save_kargs)
img.save(file_buffer, **save_kargs)
f = ContentFile(file_buffer.getvalue())
storage.save(variation_name, f)
return variation_name

@classmethod
def process_variation(cls, variation, image):
"""Process variation before actual saving."""
save_kargs = {}
file_format = image.format
save_kargs['format'] = file_format

resample = variation['resample']

if cls.is_smaller(image, variation):
factor = 1
while image.size[0] / factor \
> 2 * variation['width'] \
and image.size[1] * 2 / factor \
> 2 * variation['height']:
factor *= 2
if factor > 1:
image.thumbnail(
(int(image.size[0] / factor),
int(image.size[1] / factor)),
resample=resample
)

size = variation['width'], variation['height']
size = tuple(int(i) if i != float('inf') else i
for i in size)

if file_format == 'JPEG':
# http://stackoverflow.com/a/21669827
image = image.convert('RGB')
save_kargs['optimize'] = True
save_kargs['quality'] = 'web_high'
if size[0] * size[1] > 10000: # roughly <10kb
save_kargs['progressive'] = True

if variation['crop']:
image = ImageOps.fit(
image,
size,
method=resample
)
else:
image.thumbnail(
size,
resample=resample
)

return image, save_kargs

@classmethod
def get_variation_name(cls, file_name, variation_name):
"""Return the variation file name based on the variation."""
Expand Down
4 changes: 2 additions & 2 deletions stdimage/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ def pre_save_delete_callback(sender, instance, **kwargs):


def render_variations(file_name, variations, replace=False,
storage=default_storage):
storage=default_storage, field_class=StdImageFieldFile):
"""Render all variations for a given field."""
for key, variation in variations.items():
StdImageFieldFile.render_variation(
field_class.render_variation(
file_name, variation, replace, storage
)