forked from django-cms/django-filer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
thumbnail_processors.py
115 lines (101 loc) · 4.34 KB
/
thumbnail_processors.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#-*- coding: utf-8 -*-
import re
try:
import Image
import ImageDraw
except ImportError:
try:
from PIL import Image
from PIL import ImageDraw
except ImportError:
raise ImportError("The Python Imaging Library was not found.")
from easy_thumbnails import processors
from filer.settings import FILER_SUBJECT_LOCATION_IMAGE_DEBUG
RE_SUBJECT_LOCATION = re.compile(r'(\d+),(\d+)$')
def normalize_subject_location(subject_location):
if subject_location:
if isinstance(subject_location, basestring):
m = RE_SUBJECT_LOCATION.match(subject_location)
if m:
return (int(m.group(1)), int(m.group(2)))
else:
try:
return ( int(subject_location[0]), int(subject_location[1]) )
except (TypeError, ValueError), e:
pass
return False
#new signature: im, size, crop=False, upscale=False, **kwargs
def scale_and_crop_with_subject_location(im, size, subject_location=False, crop=False, upscale=False, **kwargs):
"""
Like ``easy_thumbnails.processors.scale_and_crop``, but will use the
coordinates in ``subject_location`` to make sure that that part of the
image is in the center or at least somewhere on the cropped image.
Please not that this does *not* work correctly if the image has been
resized by a previous processor (e.g ``autocrop``).
``crop`` needs to be set for this to work, but any special cropping
parameters will be ignored.
"""
subject_location = normalize_subject_location(subject_location)
if not (subject_location and crop):
# use the normal scale_and_crop
return processors.scale_and_crop(im, size, crop=crop, upscale=upscale, **kwargs)
# for here on we have a subject_location and cropping is on
# --snip-- this is a copy and paste of the first few
# lines of ``scale_and_crop``
source_x, source_y = [float(v) for v in im.size]
target_x, target_y = [float(v) for v in size]
if crop or not target_x or not target_y:
scale = max(target_x / source_x, target_y / source_y)
else:
scale = min(target_x / source_x, target_y / source_y)
# Handle one-dimensional targets.
if not target_x:
target_x = source_x * scale
elif not target_y:
target_y = source_y * scale
if scale < 1.0 or (scale > 1.0 and upscale):
im = im.resize((int(source_x * scale), int(source_y * scale)),
resample=Image.ANTIALIAS)
# --endsnip-- begin real code
# ===============================
# subject location aware cropping
# ===============================
# res_x, res_y: the resolution of the possibly already resized image
res_x, res_y = [float(v) for v in im.size]
# subj_x, subj_y: the position of the subject (maybe already re-scaled)
subj_x = res_x*float(subject_location[0])/source_x
subj_y = res_y*float(subject_location[1])/source_y
# ex, ey:
ex, ey = (res_x-min(res_x, target_x))/2, (res_y-min(res_y, target_y))/2
fx, fy = res_x-ex, res_y-ey
# box_width, box_height: dimensions of the target image
box_width, box_height = fx - ex, fy - ey
# try putting the box in the center around the subject point
# (this will be partially outside of the image in most cases)
tex, tey = subj_x-(box_width/2), subj_y-(box_height/2)
tfx, tfy = subj_x+(box_width/2), subj_y+(box_height/2)
if tex < 0:
# its out of the img to the left, move both to the right until tex is 0
tfx = tfx-tex # tex is negative!)
tex = 0
elif tfx > res_x:
# its out of the img to the right
tex = tex-(tfx-res_x)
tfx = res_x
if tey < 0:
# its out of the img to the top, move both to the bottom until tey is 0
tfy = tfy-tey # tey is negative!)
tey = 0
elif tfy > res_y:
# its out of the img to the bottom
tey = tey-(tfy-res_y)
tfy = res_y
if ex or ey:
crop_box = ((int(tex), int(tey), int(tfx), int(tfy)))
if FILER_SUBJECT_LOCATION_IMAGE_DEBUG:
# draw elipse on focal point for Debugging
draw = ImageDraw.Draw(im)
esize = 10
draw.ellipse( ( (subj_x-esize, subj_y-esize), (subj_x+esize, subj_y+esize)), outline="#FF0000" )
im = im.crop(crop_box)
return im