-from sorl.thumbnail.engines import pil_engine
-from sorl.thumbnail import parsers
-
-
-#
-# Class developed by
-# http://timmyomahony.com/blog/custom-cropping-engine-sorl-thumbnail/
-#
-class CustomCroppingEngine(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):
- """
- Conver the crop string passed by the user to accurate cropping values
- (This is adapter from the default sorl.thumbnail.parsers.parse_crop)
- """
- 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))