X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/334e476e48d0e34cf2c3cc940eeb9e5b52b3103b..df053d3c7f0f292d1ab4d3407313da6fd7489222:/apps/picture/engine.py diff --git a/apps/picture/engine.py b/apps/picture/engine.py new file mode 100644 index 000000000..a4435ae05 --- /dev/null +++ b/apps/picture/engine.py @@ -0,0 +1,57 @@ +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[0]) + x2 = get_offset(x2, xy_image[1]) + 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))