@@ -44,46 +44,19 @@ def save(self, **kwargs):
44
44
super ().save (** kwargs )
45
45
46
46
def get_thumbnail_url (self ):
47
- crop_x , crop_y , crop_size = (
48
- self .meta_data .get ('crop_x' ), self .meta_data .get ('crop_y' ), self .meta_data .get ('crop_size' )
47
+ crop_x , crop_y , crop_size , gravity = (
48
+ self .meta_data .get ('crop_x' ), self .meta_data .get ('crop_y' ), self .meta_data .get ('crop_size' ),
49
+ self .meta_data .get ('gravity' )
49
50
)
50
- thumbnail_path = self .get_thumbnail_path (crop_x , crop_y , crop_size )
51
+ thumbnail_path = self .get_thumbnail_path (crop_x , crop_y , crop_size , gravity )
51
52
if not default_storage .exists (thumbnail_path ):
52
53
try :
53
54
image = Image .open (default_storage .open (self .file_path ))
54
55
image = self .orientate_top (image )
55
56
if crop_x is None or crop_y is None or crop_size is None :
56
57
image = self .crop_centered (image )
57
58
else :
58
- # with cropping, the expected resizing could be done using:
59
- # `image = image.crop((crop_x, crop_y, crop_x + crop_size, crop_y + crop_size))`
60
- # however, for small selections or images in low resolution this might result
61
- # in blurry preview images. We therefore want to use at least `thumbnail_size`
62
- # pixels from the original image
63
- min_size = max (crop_size , self .thumbnail_size )
64
- off_size = min_size / 2 - crop_size / 2
65
- min_x = max (crop_x - off_size , 0 )
66
- min_y = max (crop_y - off_size , 0 )
67
- if min_x + min_size > image .width :
68
- min_x = max (image .width - min_size , 0 )
69
- max_x = image .width
70
- else :
71
- max_x = min_x + min_size
72
- if min_y + min_size > image .height :
73
- min_y = max (image .height - min_size , 0 )
74
- max_y = image .height
75
- else :
76
- max_y = min_y + min_size
77
- # correct thumbnailing for low resolution images with an aspect ratio unequal to 1
78
- if round (max_x - min_x ) > round (max_y - min_y ):
79
- off_size = (max_x - min_x - max_y + min_y ) / 2
80
- min_x += off_size
81
- max_x -= off_size
82
- elif round (max_x - min_x ) < round (max_y - min_y ):
83
- off_size = (max_y - min_y - max_x + min_x ) / 2
84
- min_y += off_size
85
- max_y -= off_size
86
- image = image .crop ((min_x , min_y , max_x , max_y ))
59
+ image = self .crop_eccentric (image , crop_x , crop_y , crop_size , gravity )
87
60
image .thumbnail ((self .thumbnail_size , self .thumbnail_size ))
88
61
(default_storage .base_location / thumbnail_path .parent ).mkdir (parents = True , exist_ok = True )
89
62
image .save (default_storage .open (thumbnail_path , 'wb' ), image .format )
@@ -124,3 +97,54 @@ def crop_centered(self, image):
124
97
right = width
125
98
bottom = (height + width ) / 2
126
99
return image .crop ((left , top , right , bottom ))
100
+
101
+ def crop_eccentric (self , image , crop_x , crop_y , crop_size , gravity ):
102
+ """
103
+ with cropping, the expected resizing could be done using:
104
+ `image = image.crop((crop_x, crop_y, crop_x + crop_size, crop_y + crop_size))`
105
+ however, for small selections or images in low resolution this might result
106
+ in blurry preview images. We therefore want to use at least `thumbnail_size`
107
+ pixels from the original image
108
+ """
109
+ min_size = max (crop_size , self .thumbnail_size )
110
+ off_size = min_size - crop_size
111
+
112
+ # horizontal thumbnailing
113
+ if gravity in ('e' , 'ne' , 'se' ):
114
+ max_x = min (crop_x + min_size , image .width )
115
+ min_x = max (max_x - min_size , 0 )
116
+ elif gravity in ('w' , 'nw' , 'sw' ):
117
+ min_x = max (crop_x - off_size , 0 )
118
+ else :
119
+ min_x = max (crop_x - off_size / 2 , 0 )
120
+ if min_x + min_size > image .width :
121
+ min_x = max (image .width - min_size , 0 )
122
+ max_x = image .width
123
+ else :
124
+ max_x = min_x + min_size
125
+
126
+ # vertical thumbnailing
127
+ if gravity in ('s' , 'se' , 'sw' ):
128
+ max_y = min (crop_y + min_size , image .height )
129
+ min_y = max (max_y - min_size , 0 )
130
+ elif gravity in ('n' , 'ne' , 'nw' ):
131
+ min_y = max (crop_y - off_size , 0 )
132
+ else :
133
+ min_y = max (crop_y - off_size / 2 , 0 )
134
+ if min_y + min_size > image .height :
135
+ min_y = max (image .height - min_size , 0 )
136
+ max_y = image .height
137
+ else :
138
+ max_y = min_y + min_size
139
+
140
+ # correct thumbnailing for low resolution images with an aspect ratio unequal to 1
141
+ if round (max_x - min_x ) > round (max_y - min_y ):
142
+ off_size = (max_x - min_x - max_y + min_y ) / 2
143
+ min_x += off_size
144
+ max_x -= off_size
145
+ elif round (max_x - min_x ) < round (max_y - min_y ):
146
+ off_size = (max_y - min_y - max_x + min_x ) / 2
147
+ min_y += off_size
148
+ max_y -= off_size
149
+
150
+ return image .crop ((min_x , min_y , max_x , max_y ))
0 commit comments