@@ -44,46 +44,19 @@ def save(self, **kwargs):
4444 super ().save (** kwargs )
4545
4646 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' )
4950 )
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 )
5152 if not default_storage .exists (thumbnail_path ):
5253 try :
5354 image = Image .open (default_storage .open (self .file_path ))
5455 image = self .orientate_top (image )
5556 if crop_x is None or crop_y is None or crop_size is None :
5657 image = self .crop_centered (image )
5758 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 )
8760 image .thumbnail ((self .thumbnail_size , self .thumbnail_size ))
8861 (default_storage .base_location / thumbnail_path .parent ).mkdir (parents = True , exist_ok = True )
8962 image .save (default_storage .open (thumbnail_path , 'wb' ), image .format )
@@ -124,3 +97,54 @@ def crop_centered(self, image):
12497 right = width
12598 bottom = (height + width ) / 2
12699 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