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