changes from server
[wolnelektury.git] / apps / picture / engine.py
1 from sorl.thumbnail.engines import pil_engine
2 from sorl.thumbnail import parsers
3
4 #
5 # Class developed by 
6 # http://timmyomahony.com/blog/custom-cropping-engine-sorl-thumbnail/
7 #
8 class CustomCroppingEngine(pil_engine.Engine):
9     """
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.
15     """
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)
21         return image
22
23     def _crop_parse(self, crop, xy_image, xy_window):
24         """
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)
27         """
28         crops = crop.split(' ')
29         if len(crops) != 4:
30             raise parsers.ThumbnailParseError('Unrecognized crop option: %s' % crop)
31         x1, y1, x2, y2 = crops
32
33         def get_offset(crop, epsilon):
34             m = parsers.bgpos_pat.match(crop)
35             if not m:
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')
39             if 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[1])
44         x2 = get_offset(x2, xy_image[0])
45         y2 = get_offset(y2, xy_image[1])
46         return x1, y1, x2, y2
47
48     def crop(self, image, geometry, options):
49         crop = options['crop']
50         if not crop or crop == 'noop':
51             return image
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)
55
56     def _crop(self, image, x1, y1, x2, y2):
57         return image.crop((x1, y1, x2, y2))