1 from sorl.thumbnail.engines import pil_engine
2 from sorl.thumbnail import parsers
6 # http://timmyomahony.com/blog/custom-cropping-engine-sorl-thumbnail/
8 class CustomCroppingEngine(pil_engine.Engine):
10 A custom sorl.thumbnail engine (using PIL) that first crops an image
11 according to 4 pixel/percentage values in the source image, then scales
12 that crop down to the size specified in the geometry. This is in contrast
13 to sorl.thumbnails default engine which first scales the image down to the
14 specified geometry and applies the crop afterward.
16 def create(self, image, geometry, options):
17 image = self.orientation(image, geometry, options)
18 image = self.colorspace(image, geometry, options)
19 image = self.crop(image, geometry, options)
20 image = self.scale(image, geometry, options)
23 def _crop_parse(self, crop, xy_image, xy_window):
25 Conver the crop string passed by the user to accurate cropping values
26 (This is adapter from the default sorl.thumbnail.parsers.parse_crop)
28 crops = crop.split(' ')
30 raise parsers.ThumbnailParseError('Unrecognized crop option: %s' % crop)
31 x1, y1, x2, y2 = crops
33 def get_offset(crop, epsilon):
34 m = parsers.bgpos_pat.match(crop)
36 raise parsers.ThumbnailParseError('Unrecognized crop option: %s' % crop)
37 value = int(m.group('value')) # we only take ints in the regexp
38 unit = m.group('unit')
40 value = epsilon * value / 100.0
41 return int(max(0, min(value, epsilon)))
42 x1 = get_offset(x1, xy_image[0])
43 y1 = get_offset(y1, xy_image[0])
44 x2 = get_offset(x2, xy_image[1])
45 y2 = get_offset(y2, xy_image[1])
48 def crop(self, image, geometry, options):
49 crop = options['crop']
50 if not crop or crop == 'noop':
52 x_image, y_image = self.get_image_size(image)
53 x1,y1,x2,y2 = self._crop_parse(crop, (x_image, y_image), geometry)
54 return self._crop(image, x1, y1, x2, y2)
56 def _crop(self, image, x1, y1, x2, y2):
57 return image.crop((x1, y1, x2, y2))