Skip to content
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

Adding a Free Transform option #552

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d3a96da
fixing typo, and adding some missing descriptions on options
kckaiwei Jul 20, 2018
66bc87e
adding free transform option
kckaiwei Jul 25, 2018
93b2a6c
adding free transform docs and tests
kckaiwei Jul 29, 2018
b560f0e
Merge branch 'master' into transform
kckaiwei Jul 29, 2018
8d6e6e4
fixing imports and proper test image
kckaiwei Jul 29, 2018
64ebd9e
Merge remote-tracking branch 'origin/transform' into transform
kckaiwei Jul 29, 2018
a9321ea
removing rounded from docs
kckaiwei Jul 29, 2018
42c739b
removing cropbox from docs, since this pull is just for transform
kckaiwei Jul 29, 2018
fe22652
changing if logic for transform
kckaiwei Jul 29, 2018
86e66f7
updating cache to reflect new key (due to new options, and options ar…
kckaiwei Jul 29, 2018
5a59fe8
forgot to update the directory as well
kckaiwei Jul 29, 2018
b905efd
fixing wand test
kckaiwei Jul 29, 2018
c4172d3
making pgmagick _scale use resize, since it is either passed already
kckaiwei Jul 29, 2018
962690a
im
kckaiwei Jul 29, 2018
f6d6f8b
doing the resize according to pgmagick doc
kckaiwei Jul 29, 2018
f0032e7
reverting to old way to scale
kckaiwei Jul 29, 2018
0c63d12
undoing pgmagick engine, changing convert engine (proper one)
kckaiwei Jul 30, 2018
178f82b
changing get_image to get_image_size, since convert_engine's get_imag…
kckaiwei Jul 30, 2018
00e3df1
reverting to "scale" from "resize"
kckaiwei Jul 30, 2018
e7063fe
getting size from the actual image now, instead of source
kckaiwei Jul 30, 2018
5035029
moving transform into extra_options
kckaiwei Sep 13, 2018
a45a9ec
Merge branch 'master' into transform
kckaiwei Sep 13, 2018
1713904
Merge branch 'master' into transform
kckaiwei Sep 14, 2018
47dcbef
reverting some cache paths now that we're using extra_options
kckaiwei Sep 14, 2018
bf6e4e4
Merge remote-tracking branch 'origin/transform' into transform
kckaiwei Sep 14, 2018
91ace16
revert test_storage
kckaiwei Sep 14, 2018
49c0d37
revert test_templatetags
kckaiwei Sep 14, 2018
627ce84
revert test_alternative_resolutions
kckaiwei Sep 14, 2018
0188689
empty commit
kckaiwei Sep 14, 2018
b91f190
empty commit
kckaiwei Sep 14, 2018
8c89e0a
Merge branch 'master' into transform
RDIL Jan 10, 2019
4ad56d8
Merge branch 'master' into transform
RDIL Jan 10, 2019
d48b350
Merge branch 'master' into transform
RDIL Jan 11, 2019
1fda7a4
Merge branch 'master' into transform
RDIL Jan 11, 2019
fc3950d
Merge branch 'master' into transform
kckaiwei Jun 1, 2020
cb910b0
updating underline length in readme
kckaiwei Jun 1, 2020
cbeb704
extending readme underline
kckaiwei Jun 1, 2020
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: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ You can use the 'get_thumbnail'::
See more examples in the section `Low level API examples`_ in the Documentation

Using in combination with other thumbnailers
--------------------------------------------
============================================

Alternatively, you load the templatetags by {% load sorl_thumbnail %}
instead of traditional {% load thumbnail %}. It's especially useful in
Expand Down
7 changes: 6 additions & 1 deletion docs/template.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ cropping options if you don't want to generate unnecessary thumbnails. In case
you are wondering, sorl-thumbnail sorts the options so the order does not
matter, same options but in different order will generate only one thumbnail.

``transform``
^^^^^^^^^^^^^
Transform is a boolean and controls if the image will be free transformed to the
dimensions provided. If set to true, the image will be forcibly resized to the
supplied dimensions and stretch as needed. Default value is ``False``.

``upscale``
^^^^^^^^^^^
Upscale is a boolean and controls if the image can be upscaled or not. For
Expand Down Expand Up @@ -190,7 +196,6 @@ Images are not padded by default, but this can be changed by setting
This is the color to use for padding the image. It defaults to ``#ffffff`` and
can be globally set with the setting ``THUMBNAIL_PADDING_COLOR``.


``options``
^^^^^^^^^^^
Yes this option is called ``options``. This needs to be a context variable that
Expand Down
3 changes: 2 additions & 1 deletion sorl/thumbnail/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ class ThumbnailBackend(object):
'cropbox': None,
'rounded': None,
'padding': settings.THUMBNAIL_PADDING,
'padding_color': settings.THUMBNAIL_PADDING_COLOR,
'padding_color': settings.THUMBNAIL_PADDING_COLOR
}

extra_options = (
('progressive', 'THUMBNAIL_PROGRESSIVE'),
('orientation', 'THUMBNAIL_ORIENTATION'),
('blur', 'THUMBNAIL_BLUR'),
('transform', "THUMBNAIL_TRANSFORM")
)

def file_extension(self, source):
Expand Down
3 changes: 3 additions & 0 deletions sorl/thumbnail/conf/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
# Orientate the thumbnail with respect to source EXIF orientation tag
THUMBNAIL_ORIENTATION = True

# Whether to apply free-transform to the image by default (breaking the aspect ratio lock)
THUMBNAIL_TRANSFORM = False

# This means sorl.thumbnail will generate and serve a generated dummy image
# regardless of the thumbnail source content
THUMBNAIL_DUMMY = False
Expand Down
7 changes: 6 additions & 1 deletion sorl/thumbnail/engines/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,13 @@ def scale(self, image, geometry, options):
Wrapper for ``_scale``
"""
upscale = options['upscale']
transform = options.get('transform', settings.THUMBNAIL_TRANSFORM)
x_image, y_image = map(float, self.get_image_size(image))

if transform:
image = self._scale(image, geometry[0], geometry[1])
return image

if self.flip_dimensions(image):
x_image, y_image = y_image, x_image
factor = self._calculate_scaling_factor(x_image, y_image, geometry, options)
Expand All @@ -84,7 +90,6 @@ def scale(self, image, geometry, options):
width = toint(x_image * factor)
height = toint(y_image * factor)
image = self._scale(image, width, height)

return image

def crop(self, image, geometry, options):
Expand Down
2 changes: 1 addition & 1 deletion tests/thumbnail_tests/test_alternative_resolutions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_retina(self):
# save the 2x resolution version
'save: test/cache/91/bb/[email protected]',
'get_available_name: test/cache/91/bb/[email protected]',
'exists: test/cache/91/bb/[email protected]'
'exists: test/cache/91/bb/[email protected]',
]
self.assertEqual(self.log, actions)

Expand Down
38 changes: 37 additions & 1 deletion tests/thumbnail_tests/test_engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,25 @@ def setUp(self):
'pil_engine' not in settings.THUMBNAIL_ENGINE,
'the other engines fail this test',
)
def test_PIL_freetransform(self):
th = self.BACKEND.get_thumbnail(self.portrait, '100x100', transform=True)
engine = PILEngine()
im = engine.get_image(th)
self.assertEqual(im.width, 100)
self.assertEqual(im.height, 100)

@unittest.skipIf(
'convert_engine' not in settings.THUMBNAIL_ENGINE,
'the other engines fail this test',
)
def test_convert_engine_freetransform(self):
from sorl.thumbnail.engines.convert_engine import Engine as ConvertEngine
th = self.BACKEND.get_thumbnail(self.portrait, '100x100', transform=True)
engine = ConvertEngine()
im = engine.get_image(th)
size = engine.get_image_size(im)
self.assertEqual(size, (100, 100))

def PIL_test_portrait_crop(self):
def mean_pixel(x, y):
values = im.getpixel((x, y))
Expand Down Expand Up @@ -490,6 +509,15 @@ def mean_pixel(x, y):
'wand_engine' not in settings.THUMBNAIL_ENGINE,
'the other engines fail this test',
)

def test_wand_engine_freetransform(self):
from sorl.thumbnail.engines.wand_engine import Engine as WandEngine
th = self.BACKEND.get_thumbnail(self.portrait, '100x100', transform=True)
engine = WandEngine()
im = engine.get_image(th)
self.assertEqual(im.width, 100)
self.assertEqual(im.height, 100)

def wand_test_cropbox(self):
from sorl.thumbnail.engines.wand_engine import Engine as WandEngine
th = self.BACKEND.get_thumbnail(self.portrait, '100x100', cropbox="0,50,100,150")
Expand All @@ -504,6 +532,15 @@ def wand_test_cropbox(self):
'pgmagick_engine' not in settings.THUMBNAIL_ENGINE,
'the other engines fail this test',
)

def test_pgmagick_engine_freetransform(self):
from sorl.thumbnail.engines.pgmagick_engine import Engine as PgmagickEngine
th = self.BACKEND.get_thumbnail(self.portrait, '100x100', transform=True)
engine = PgmagickEngine()
im = engine.get_image(th)
self.assertEqual(im.width(100), 100)
self.assertEqual(im.height(100), 100)

def pgmagick_test_cropbox(self):
from sorl.thumbnail.engines.pgmagick_engine import Engine as PgMagickEngine
th = self.BACKEND.get_thumbnail(self.portrait, '100x100', cropbox="0,50,100,150")
Expand All @@ -527,7 +564,6 @@ def convert_test_cropbox(self):
# If the crop went well, then it should scale to 100x100 perfectly
self.assertEqual(im["size"], (100, 100))


class DummyTestCase(unittest.TestCase):
def setUp(self):
self.BACKEND = get_module_class(settings.THUMBNAIL_BACKEND)()
Expand Down