1 from PIL import Image, ImageFilter, ImageChops
2 from sorl.thumbnail import utils
6 def dynamic_import(names):
9 # Use rfind rather than rsplit for Python 2.3 compatibility.
10 lastdot = name.rfind('.')
11 modname, attrname = name[:lastdot], name[lastdot + 1:]
12 mod = __import__(modname, {}, {}, [''])
13 imported.append(getattr(mod, attrname))
17 def get_valid_options(processors):
19 Returns a list containing unique valid options from a list of processors
23 for processor in processors:
24 if hasattr(processor, 'valid_options'):
25 valid_options.extend([opt for opt in processor.valid_options
26 if opt not in valid_options])
30 def colorspace(im, requested_size, opts):
31 if 'bw' in opts and im.mode != "L":
33 elif im.mode not in ("L", "RGB", "RGBA"):
34 im = im.convert("RGB")
36 colorspace.valid_options = ('bw',)
39 def autocrop(im, requested_size, opts):
40 if 'autocrop' in opts:
42 bw = bw.filter(ImageFilter.MedianFilter)
44 bg = Image.new("1", im.size, 255)
45 diff = ImageChops.difference(bw, bg)
50 autocrop.valid_options = ('autocrop',)
53 def scale_and_crop(im, requested_size, opts):
54 x, y = [float(v) for v in im.size]
55 xr, yr = [float(v) for v in requested_size]
57 if 'crop' in opts or 'max' in opts:
58 r = max(xr / x, yr / y)
60 r = min(xr / x, yr / y)
62 if r < 1.0 or (r > 1.0 and 'upscale' in opts):
63 im = im.resize((int(x * r), int(y * r)), resample=Image.ANTIALIAS)
65 crop = opts.get('crop') or 'crop' in opts
67 # Difference (for x and y) between new image size and requested size.
68 x, y = [float(v) for v in im.size]
69 dx, dy = (x - min(x, xr)), (y - min(y, yr))
71 # Center cropping (default).
72 ex, ey = dx / 2, dy / 2
73 box = [ex, ey, x - ex, y - ey]
74 # See if an edge cropping argument was provided.
75 edge_crop = (isinstance(crop, basestring) and
76 re.match(r'(?:(-?)(\d+))?,(?:(-?)(\d+))?$', crop))
77 if edge_crop and filter(None, edge_crop.groups()):
78 x_right, x_crop, y_bottom, y_crop = edge_crop.groups()
80 offset = min(x * int(x_crop) / 100, dx)
86 box[2] = x - (dx - offset)
88 offset = min(y * int(y_crop) / 100, dy)
94 box[3] = y - (dy - offset)
95 # See if the image should be "smart cropped".
101 l_sl = im.crop((0, 0, slice, y))
102 r_sl = im.crop((x - slice, 0, x, y))
103 if utils.image_entropy(l_sl) >= utils.image_entropy(r_sl):
110 t_sl = im.crop((0, 0, x, slice))
111 b_sl = im.crop((0, y - slice, x, y))
112 if utils.image_entropy(t_sl) >= utils.image_entropy(b_sl):
117 box = (left, top, right, bottom)
118 # Finally, crop the image!
119 im = im.crop([int(v) for v in box])
121 scale_and_crop.valid_options = ('crop', 'upscale', 'max')
124 def filters(im, requested_size, opts):
126 im = im.filter(ImageFilter.DETAIL)
127 if 'sharpen' in opts:
128 im = im.filter(ImageFilter.SHARPEN)
130 filters.valid_options = ('detail', 'sharpen')