kopia lustrzana https://github.com/wagtail/wagtail
Implement 'bgcolor' image operation.
Also fixes #3713. Remove alpha channel if converting transparent image to JPEGpull/4182/head
rodzic
c10e050076
commit
1e332b4b67
|
@ -253,6 +253,25 @@ For example, to make the tag always convert the image to a JPEG, use ``format-jp
|
|||
|
||||
You may also use ``format-png`` or ``format-gif``.
|
||||
|
||||
.. _image_background_color
|
||||
|
||||
Background color
|
||||
----------------
|
||||
|
||||
The PNG and GIF image formats both support transparency, but if you want to
|
||||
convert images to JPEG format, the transparency will need to be replaced with a
|
||||
solid background color.
|
||||
|
||||
By default, Wagtail will set the background to white. But if a white background
|
||||
doesn't fit your design, you can specify a color using the ``bgcolor`` filter.
|
||||
|
||||
This filter takes a single argument, which is a CSS 3 or 6 digit hex code
|
||||
representing the color you would like to use:
|
||||
|
||||
.. code-block:: html+Django
|
||||
|
||||
{# Set the image backgrounds to black #}
|
||||
{% image page.photo width-400 bgcolor-000 format-jpeg %}
|
||||
|
||||
.. _jpeg_image_quality:
|
||||
|
||||
|
|
2
setup.py
2
setup.py
|
@ -30,7 +30,7 @@ install_requires = [
|
|||
"beautifulsoup4>=4.5.1,<5.0",
|
||||
"html5lib>=0.999,<1",
|
||||
"Unidecode>=0.04.14,<1.0",
|
||||
"Willow>=1.0,<1.1",
|
||||
"Willow>=1.1,<1.2",
|
||||
"requests>=2.11.1,<3.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import inspect
|
|||
|
||||
from wagtail.images.exceptions import InvalidFilterSpecError
|
||||
from wagtail.images.rect import Rect
|
||||
from wagtail.images.utils import parse_color_string
|
||||
|
||||
|
||||
class Operation:
|
||||
|
@ -236,3 +237,11 @@ class FormatOperation(Operation):
|
|||
|
||||
def run(self, willow, image, env):
|
||||
env['output-format'] = self.format
|
||||
|
||||
|
||||
class BackgroundColorOperation(Operation):
|
||||
def construct(self, color_string):
|
||||
self.color = parse_color_string(color_string)
|
||||
|
||||
def run(self, willow, image, env):
|
||||
return willow.set_background_color_rgb(self.color)
|
||||
|
|
|
@ -395,6 +395,10 @@ class Filter:
|
|||
else:
|
||||
quality = 85
|
||||
|
||||
# If the image has an alpha channel, give it a white background
|
||||
if willow.has_alpha():
|
||||
willow = willow.set_background_color_rgb((255, 255, 255))
|
||||
|
||||
return willow.save_as_jpeg(output, quality=quality, progressive=True, optimize=True)
|
||||
elif output_format == 'png':
|
||||
return willow.save_as_png(output)
|
||||
|
|
|
@ -544,3 +544,44 @@ class TestJPEGQualityFilter(TestCase):
|
|||
fil.run(image, f)
|
||||
|
||||
save.assert_called_with(f, 'JPEG', quality=40, optimize=True, progressive=True)
|
||||
|
||||
|
||||
class TestBackgroundColorFilter(TestCase):
|
||||
def test_original_has_alpha(self):
|
||||
# Checks that the test image we're using has alpha
|
||||
fil = Filter(spec='width-400')
|
||||
image = Image.objects.create(
|
||||
title="Test image",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
out = fil.run(image, BytesIO())
|
||||
|
||||
self.assertTrue(out.has_alpha())
|
||||
|
||||
def test_3_digit_hex(self):
|
||||
fil = Filter(spec='width-400|bgcolor-fff')
|
||||
image = Image.objects.create(
|
||||
title="Test image",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
out = fil.run(image, BytesIO())
|
||||
|
||||
self.assertFalse(out.has_alpha())
|
||||
|
||||
def test_6_digit_hex(self):
|
||||
fil = Filter(spec='width-400|bgcolor-ffffff')
|
||||
image = Image.objects.create(
|
||||
title="Test image",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
out = fil.run(image, BytesIO())
|
||||
|
||||
self.assertFalse(out.has_alpha())
|
||||
|
||||
def test_invalid(self):
|
||||
fil = Filter(spec='width-400|bgcolor-foo')
|
||||
image = Image.objects.create(
|
||||
title="Test image",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
self.assertRaises(ValueError, fil.run, image, BytesIO())
|
||||
|
|
|
@ -10,7 +10,7 @@ Image = get_image_model()
|
|||
|
||||
def get_test_image_file(filename='test.png', colour='white', size=(640, 480)):
|
||||
f = BytesIO()
|
||||
image = PIL.Image.new('RGB', size, colour)
|
||||
image = PIL.Image.new('RGBA', size, colour)
|
||||
image.save(f, 'PNG')
|
||||
return ImageFile(f, name=filename)
|
||||
|
||||
|
|
|
@ -37,3 +37,26 @@ def get_fill_filter_spec_migrations(app_name, rendition_model_name):
|
|||
Rendition.objects.using(db_alias).filter(filter_spec=filter_spec).update(filter=filter)
|
||||
|
||||
return (fill_filter_spec_forward, fill_filter_spec_reverse)
|
||||
|
||||
|
||||
def parse_color_string(color_string):
|
||||
"""
|
||||
Parses a string a user typed into a tuple of 3 integers representing the
|
||||
red, green and blue channels respectively.
|
||||
|
||||
May raise a ValueError if the string cannot be parsed.
|
||||
|
||||
The colour string must be a CSS 3 or 6 digit hex code without the '#' prefix.
|
||||
"""
|
||||
if len(color_string) == 3:
|
||||
r = int(color_string[0], 16) * 17
|
||||
g = int(color_string[1], 16) * 17
|
||||
b = int(color_string[2], 16) * 17
|
||||
elif len(color_string) == 6:
|
||||
r = int(color_string[0:2], 16)
|
||||
g = int(color_string[2:4], 16)
|
||||
b = int(color_string[4:6], 16)
|
||||
else:
|
||||
ValueError('Color string must be either 3 or 6 hexadecimal digits long')
|
||||
|
||||
return r, g, b
|
||||
|
|
|
@ -86,6 +86,7 @@ def register_image_operations():
|
|||
('height', image_operations.WidthHeightOperation),
|
||||
('jpegquality', image_operations.JPEGQualityOperation),
|
||||
('format', image_operations.FormatOperation),
|
||||
('bgcolor', image_operations.BackgroundColorOperation),
|
||||
]
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue