@@ -18,7 +18,7 @@ class StdImageFileDescriptor(ImageFileDescriptor):
1818 """The variation property of the field is accessible in instance cases."""
1919
2020 def __set__ (self , instance , value ):
21- super (StdImageFileDescriptor , self ).__set__ (instance , value )
21+ super ().__set__ (instance , value )
2222 self .field .set_variations (instance )
2323
2424
@@ -170,7 +170,7 @@ class StdImageField(ImageField):
170170 'width' : float ('inf' ),
171171 'height' : float ('inf' ),
172172 'crop' : False ,
173- 'resample' : Image .ANTIALIAS
173+ 'resample' : Image .ANTIALIAS ,
174174 }
175175
176176 def __init__ (self , verbose_name = None , name = None , variations = None ,
@@ -236,8 +236,9 @@ def __init__(self, verbose_name=None, name=None, variations=None,
236236
237237 def add_variation (self , name , params ):
238238 variation = self .def_variation .copy ()
239+ variation ["kwargs" ] = {}
239240 if isinstance (params , (list , tuple )):
240- variation .update (dict (zip (("width" , "height" , "crop" ), params )))
241+ variation .update (dict (zip (("width" , "height" , "crop" , "kwargs" ), params )))
241242 else :
242243 variation .update (params )
243244 variation ["name" ] = name
@@ -287,3 +288,65 @@ def save_form_data(self, instance, data):
287288 if file and file ._committed and file != data :
288289 file .delete (save = False )
289290 super ().save_form_data (instance , data )
291+
292+
293+ class JPEGFieldFile (StdImageFieldFile ):
294+
295+ @classmethod
296+ def get_variation_name (cls , file_name , variation_name ):
297+ path = super ().get_variation_name (file_name , variation_name )
298+ path , ext = os .path .splitext (path )
299+ return '%s.jpeg' % path
300+
301+ @classmethod
302+ def process_variation (cls , variation , image ):
303+ """Process variation before actual saving."""
304+ save_kargs = {}
305+ file_format = 'JPEG'
306+ save_kargs ['format' ] = file_format
307+
308+ resample = variation ['resample' ]
309+
310+ factor = 1
311+ while image .size [0 ] / factor \
312+ > 2 * variation ['width' ] \
313+ and image .size [1 ] * 2 / factor \
314+ > 2 * variation ['height' ]:
315+ factor *= 2
316+ if factor > 1 :
317+ image .thumbnail (
318+ (int (image .size [0 ] / factor ),
319+ int (image .size [1 ] / factor )),
320+ resample = resample
321+ )
322+
323+ size = variation ['width' ], variation ['height' ]
324+ size = tuple (int (i ) if i != float ('inf' ) else i
325+ for i in size )
326+
327+ # http://stackoverflow.com/a/21669827
328+ image = image .convert ('RGB' )
329+ save_kargs ['optimize' ] = True
330+ save_kargs ['quality' ] = 'web_high'
331+ if size [0 ] * size [1 ] > 10000 : # roughly <10kb
332+ save_kargs ['progressive' ] = True
333+
334+ if variation ['crop' ]:
335+ image = ImageOps .fit (
336+ image ,
337+ size ,
338+ method = resample
339+ )
340+ else :
341+ image .thumbnail (
342+ size ,
343+ resample = resample
344+ )
345+
346+ save_kargs .update (variation ['kwargs' ])
347+
348+ return image , save_kargs
349+
350+
351+ class JPEGField (StdImageField ):
352+ attr_class = JPEGFieldFile
0 commit comments