Moved parse_filter_spec into a utils method

This commit is contained in:
Karl Hobley 2014-07-16 13:11:24 +01:00
parent 227765359b
commit 9b2c9f1883
2 changed files with 41 additions and 50 deletions

View file

@ -1,5 +1,4 @@
import os.path
import re
from six import BytesIO
@ -21,7 +20,7 @@ from unidecode import unidecode
from wagtail.wagtailadmin.taggable import TagSearchable
from wagtail.wagtailimages.backends import get_image_backend
from wagtail.wagtailsearch import indexed
from .utils import validate_image_format
from wagtail.wagtailimages.utils import validate_image_format, parse_filter_spec
@python_2_unicode_compatible
@ -144,49 +143,6 @@ class Filter(models.Model):
"""
spec = models.CharField(max_length=255, db_index=True)
OPERATION_NAMES = {
'max': 'resize_to_max',
'min': 'resize_to_min',
'width': 'resize_to_width',
'height': 'resize_to_height',
'fill': 'resize_to_fill',
'original': 'no_operation',
}
def __init__(self, *args, **kwargs):
super(Filter, self).__init__(*args, **kwargs)
self.method = None # will be populated when needed, by parsing the spec string
def _parse_spec_string(self):
# parse the spec string and save the results to
# self.method_name and self.method_arg. There are various possible
# formats to match against:
# 'original'
# 'width-200'
# 'max-320x200'
if self.spec == 'original':
self.method_name = Filter.OPERATION_NAMES['original']
self.method_arg = None
return
match = re.match(r'(width|height)-(\d+)$', self.spec)
if match:
self.method_name = Filter.OPERATION_NAMES[match.group(1)]
self.method_arg = int(match.group(2))
return
match = re.match(r'(max|min|fill)-(\d+)x(\d+)$', self.spec)
if match:
self.method_name = Filter.OPERATION_NAMES[match.group(1)]
width = int(match.group(2))
height = int(match.group(3))
self.method_arg = (width, height)
return
# Spec is not one of our recognised patterns
raise ValueError("Invalid image filter spec: %r" % self.spec)
def process_image(self, input_file, backend_name='default'):
"""
Given an input image file as a django.core.files.File object,
@ -195,17 +151,16 @@ class Filter(models.Model):
"""
backend = get_image_backend(backend_name)
if not self.method:
self._parse_spec_string()
method_name, method_arg = parse_filter_spec(self.spec)
# If file is closed, open it
input_file.open('rb')
image = backend.open_image(input_file)
file_format = image.format
method = getattr(backend, self.method_name)
image = method(image, self.method_arg)
# Call method
method = getattr(backend, method_name)
image = method(image, method_arg)
output = BytesIO()
backend.save_image(image, output, file_format)

View file

@ -1,4 +1,5 @@
import os
import re
from PIL import Image
@ -26,3 +27,38 @@ def validate_image_format(f):
# Check that the internal format matches the extension
if image.format.upper() != extension.upper():
raise ValidationError(_("Not a valid %s image. Please use a gif, jpeg or png file with the correct file extension.") % (extension.upper()))
# TODO: Cache results from this method in something like Python 3.2s LRU cache (available in Django 1.7 as django.utils.lru_cache)
def parse_filter_spec(filter_spec):
# parse the spec string and save the results to
# self.method_name and self.method_arg. There are various possible
# formats to match against:
# 'original'
# 'width-200'
# 'max-320x200'
OPERATION_NAMES = {
'max': 'resize_to_max',
'min': 'resize_to_min',
'width': 'resize_to_width',
'height': 'resize_to_height',
'fill': 'resize_to_fill',
'original': 'no_operation',
}
# original
if filter_spec == 'original':
return OPERATION_NAMES['original'], None
# width/height
match = re.match(r'(width|height)-(\d+)$', filter_spec)
if match:
return OPERATION_NAMES[match.group(1)], int(match.group(2))
# max/min/fill
match = re.match(r'(max|min|fill)-(\d+)x(\d+)$', filter_spec)
if match:
width = int(match.group(2))
height = int(match.group(3))
return OPERATION_NAMES[match.group(1)], (width, height)