Last active
September 29, 2015 18:37
-
-
Save timmyomahony/1647660 to your computer and use it in GitHub Desktop.
Custom sorl.thumbnail engine to perform specific crops
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sorl.thumbnail.engines import pil_engine | |
from sorl.thumbnail import parsers | |
class CropperEngine(pil_engine.Engine): | |
""" | |
A custom sorl.thumbnail engine (using PIL) that first crops an image according to 4 pixel/percentage | |
values in the source image, then scales that crop down to the size specified in the geometry. This is | |
in contrast to sorl.thumbnails default engine which first scales the image down to the specified geometry | |
and applies the crop afterward. | |
""" | |
def create(self, image, geometry, options): | |
image = self.orientation(image, geometry, options) | |
image = self.colorspace(image, geometry, options) | |
image = self.crop(image, geometry, options) | |
image = self.scale(image, geometry, options) | |
return image | |
def _crop_parse(self, crop, xy_image, xy_window): | |
""" Taken from sorl.thumbnail.parsers.crop_parse and (roughly!) adapted here """ | |
crops = crop.split(' ') | |
if len(crops) != 4: | |
raise parsers.ThumbnailParseError('Unrecognized crop option: %s' % crop) | |
x1, y1, x2, y2 = crops | |
def get_offset(crop, epsilon): | |
m = parsers.bgpos_pat.match(crop) | |
if not m: | |
raise parsers.ThumbnailParseError('Unrecognized crop option: %s' % crop) | |
value = int(m.group('value')) # we only take ints in the regexp | |
unit = m.group('unit') | |
if unit == '%': | |
value = epsilon * value / 100.0 | |
return int(max(0, min(value, epsilon))) | |
x1 = get_offset(x1, xy_image[0]) | |
y1 = get_offset(y1, xy_image[1]) | |
x2 = get_offset(x2, xy_image[0]) | |
y2 = get_offset(y2, xy_image[1]) | |
return x1, y1, x2, y2 | |
def crop(self, image, geometry, options): | |
crop = options['crop'] | |
if not crop or crop == 'noop': | |
return image | |
x_image, y_image = self.get_image_size(image) | |
x1,y1,x2,y2 = self._crop_parse(crop, (x_image, y_image), geometry) | |
return self._crop(image, x1, y1, x2, y2) | |
def _crop(self, image, x1, y1, x2, y2): | |
return image.crop((x1, y1, x2, y2)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def get_crop(): | |
""" | |
An example of how to use the custom cropping engine inline. | |
x1, y1, x2, y2 are percentage based values of where to apply the crop (they can also be pixel based) | |
""" | |
img = ... // The full-size source image | |
x1 = 10 | |
y1 = 10 | |
x2 = 80 | |
y2 = 50 | |
use_cropper = True | |
if self.use_cropper: | |
# Swap engines | |
old = default.engine | |
default.engine = CropperEngine() | |
crop = get_thumbnail( | |
self.source, | |
"%sx%s" % (crop_width, crop_height), | |
crop="%s%% %s%% %s%% %s%%" % (int(x1), int(y1), int(x2), int(y2))) | |
# Replace normal engine | |
default.engine = old | |
return crop |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment