kopia lustrzana https://github.com/wagtail/wagtail
Merge branch 'image-backend-tweaks' of https://github.com/kaedroho/wagtail into kaedroho-image-backend-tweaks
commit
b8cb6f8dcf
|
@ -1,6 +1,7 @@
|
|||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
||||
class InvalidImageBackendError(ImproperlyConfigured):
|
||||
pass
|
||||
|
||||
|
@ -8,23 +9,22 @@ class InvalidImageBackendError(ImproperlyConfigured):
|
|||
class BaseImageBackend(object):
|
||||
def __init__(self, params):
|
||||
self.quality = getattr(settings, 'IMAGE_COMPRESSION_QUALITY', 85)
|
||||
|
||||
|
||||
def open_image(self, input_file):
|
||||
"""
|
||||
Open an image and return the backend specific image object to pass
|
||||
to other methods. The object return has to have a size attribute
|
||||
Open an image and return the backend specific image object to pass
|
||||
to other methods. The object return has to have a size attribute
|
||||
which is a tuple with the width and height of the image and a format
|
||||
attribute with the format of the image.
|
||||
"""
|
||||
raise NotImplementedError('subclasses of BaseImageBackend must provide an open_image() method')
|
||||
|
||||
|
||||
|
||||
def save_image(self, image, output):
|
||||
"""
|
||||
Save the image to the output
|
||||
"""
|
||||
raise NotImplementedError('subclasses of BaseImageBackend must provide a save_image() method')
|
||||
|
||||
|
||||
def resize(self, image, size):
|
||||
"""
|
||||
resize image to the requested size, using highest quality settings
|
||||
|
@ -32,11 +32,9 @@ class BaseImageBackend(object):
|
|||
"""
|
||||
raise NotImplementedError('subclasses of BaseImageBackend must provide an resize() method')
|
||||
|
||||
|
||||
def crop_to_centre(self, image, size):
|
||||
raise NotImplementedError('subclasses of BaseImageBackend must provide a crop_to_centre() method')
|
||||
|
||||
|
||||
def resize_to_max(self, image, size):
|
||||
"""
|
||||
Resize image down to fit within the given dimensions, preserving aspect ratio.
|
||||
|
@ -58,10 +56,8 @@ class BaseImageBackend(object):
|
|||
final_size = (target_width, int(original_height * horz_scale))
|
||||
else:
|
||||
final_size = (int(original_width * vert_scale), target_height)
|
||||
|
||||
return self.resize(image, final_size)
|
||||
|
||||
|
||||
return self.resize(image, final_size)
|
||||
|
||||
def resize_to_min(self, image, size):
|
||||
"""
|
||||
|
@ -87,7 +83,6 @@ class BaseImageBackend(object):
|
|||
|
||||
return self.resize(image, final_size)
|
||||
|
||||
|
||||
def resize_to_width(self, image, target_width):
|
||||
"""
|
||||
Resize image down to the given width, preserving aspect ratio.
|
||||
|
@ -104,7 +99,6 @@ class BaseImageBackend(object):
|
|||
|
||||
return self.resize(image, final_size)
|
||||
|
||||
|
||||
def resize_to_height(self, image, target_height):
|
||||
"""
|
||||
Resize image down to the given height, preserving aspect ratio.
|
||||
|
@ -121,7 +115,6 @@ class BaseImageBackend(object):
|
|||
|
||||
return self.resize(image, final_size)
|
||||
|
||||
|
||||
def resize_to_fill(self, image, size):
|
||||
"""
|
||||
Resize down and crop image to fill the given dimensions. Most suitable for thumbnails.
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from base import BaseImageBackend
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .base import BaseImageBackend
|
||||
import PIL.Image
|
||||
|
||||
|
||||
class PillowBackend(BaseImageBackend):
|
||||
def __init__(self, params):
|
||||
super(PillowBackend, self).__init__(params)
|
||||
|
@ -32,4 +35,4 @@ class PillowBackend(BaseImageBackend):
|
|||
top = (original_height - final_height) / 2
|
||||
return image.crop(
|
||||
(left, top, left + final_width, top + final_height)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from .base import BaseImageBackend
|
||||
|
||||
from wand.image import Image
|
||||
from wand.api import library
|
||||
|
||||
|
||||
class WandBackend(BaseImageBackend):
|
||||
def __init__(self, params):
|
||||
|
@ -10,6 +11,7 @@ class WandBackend(BaseImageBackend):
|
|||
|
||||
def open_image(self, input_file):
|
||||
image = Image(file=input_file)
|
||||
image.wand = library.MagickCoalesceImages(image.wand)
|
||||
return image
|
||||
|
||||
def save_image(self, image, output, format):
|
||||
|
@ -18,8 +20,9 @@ class WandBackend(BaseImageBackend):
|
|||
image.save(file=output)
|
||||
|
||||
def resize(self, image, size):
|
||||
image.resize(size[0], size[1])
|
||||
return image
|
||||
new_image = image.clone()
|
||||
new_image.resize(size[0], size[1])
|
||||
return new_image
|
||||
|
||||
def crop_to_centre(self, image, size):
|
||||
(original_width, original_height) = image.size
|
||||
|
@ -34,7 +37,9 @@ class WandBackend(BaseImageBackend):
|
|||
|
||||
left = (original_width - final_width) / 2
|
||||
top = (original_height - final_height) / 2
|
||||
image.crop(
|
||||
|
||||
new_image = image.clone()
|
||||
new_image.crop(
|
||||
left=left, top=top, right=left + final_width, bottom=top + final_height
|
||||
)
|
||||
return image
|
||||
return new_image
|
||||
|
|
|
@ -194,27 +194,25 @@ class Filter(models.Model):
|
|||
generate an output image with this filter applied, returning it
|
||||
as another django.core.files.File object
|
||||
"""
|
||||
|
||||
backend = get_image_backend(backend_name)
|
||||
|
||||
|
||||
if not self.method:
|
||||
self._parse_spec_string()
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
output = StringIO.StringIO()
|
||||
backend.save_image(image, output, file_format)
|
||||
|
||||
|
||||
# and then close the input file
|
||||
input_file.close()
|
||||
|
||||
|
||||
# generate new filename derived from old one, inserting the filter spec string before the extension
|
||||
input_filename_parts = os.path.basename(input_file.name).split('.')
|
||||
|
@ -224,7 +222,6 @@ class Filter(models.Model):
|
|||
output_filename = '.'.join(output_filename_parts)
|
||||
|
||||
output_file = File(output, name=output_filename)
|
||||
|
||||
|
||||
return output_file
|
||||
|
||||
|
|
|
@ -84,10 +84,10 @@ class TestRenditions(TestCase):
|
|||
# default backend should be pillow
|
||||
backend = get_image_backend()
|
||||
self.assertTrue(isinstance(backend, PillowBackend))
|
||||
|
||||
|
||||
def test_minification(self):
|
||||
rendition = self.image.get_rendition('width-400')
|
||||
|
||||
|
||||
# Check size
|
||||
self.assertEqual(rendition.width, 400)
|
||||
self.assertEqual(rendition.height, 300)
|
||||
|
@ -121,7 +121,7 @@ class TestRenditions(TestCase):
|
|||
|
||||
# Check that they are the same object
|
||||
self.assertEqual(first_rendition, second_rendition)
|
||||
|
||||
|
||||
|
||||
class TestRenditionsWand(TestCase):
|
||||
def setUp(self):
|
||||
|
@ -141,18 +141,18 @@ class TestRenditionsWand(TestCase):
|
|||
|
||||
def test_minification(self):
|
||||
rendition = self.image.get_rendition('width-400')
|
||||
|
||||
|
||||
# Check size
|
||||
self.assertEqual(rendition.width, 400)
|
||||
self.assertEqual(rendition.height, 300)
|
||||
|
||||
|
||||
def test_resize_to_max(self):
|
||||
rendition = self.image.get_rendition('max-100x100')
|
||||
|
||||
|
||||
# Check size
|
||||
self.assertEqual(rendition.width, 100)
|
||||
self.assertEqual(rendition.height, 75)
|
||||
|
||||
|
||||
def test_resize_to_min(self):
|
||||
rendition = self.image.get_rendition('min-120x120')
|
||||
|
||||
|
@ -174,7 +174,7 @@ class TestRenditionsWand(TestCase):
|
|||
|
||||
# Check that they are the same object
|
||||
self.assertEqual(first_rendition, second_rendition)
|
||||
|
||||
|
||||
|
||||
class TestImageTag(TestCase):
|
||||
def setUp(self):
|
||||
|
|
Ładowanie…
Reference in New Issue