@@ -2147,16 +2147,18 @@ def save(self, fp, format=None, **params):
21472147
21482148 if format .upper () not in SAVE :
21492149 init ()
2150- if params .pop (' save_all' , False ):
2150+ if params .pop (" save_all" , False ):
21512151 save_handler = SAVE_ALL [format .upper ()]
21522152 else :
21532153 save_handler = SAVE [format .upper ()]
21542154
2155- if params .get (' convert_mode' ):
2155+ if params .get (" convert_mode" ):
21562156 plugin = sys .modules [save_handler .__module__ ]
2157- converted_im = self ._convert_mode (plugin , params )
2158- if converted_im :
2159- return converted_im .save (fp , format , ** params )
2157+ if hasattr (plugin , "_supported_modes" ):
2158+ modes = plugin ._supported_modes ()
2159+ converted_im = self ._convert_mode (modes , params )
2160+ if converted_im :
2161+ return converted_im .save (fp , format , ** params )
21602162
21612163 self .encoderinfo = params
21622164 self .encoderconfig = ()
@@ -2176,32 +2178,57 @@ def save(self, fp, format=None, **params):
21762178 if open_fp :
21772179 fp .close ()
21782180
2179- def _convert_mode (self , plugin , params ):
2180- if not hasattr ( plugin , '_convert_mode' ) :
2181+ def _convert_mode (self , modes , params = {} ):
2182+ if not modes or self . mode in modes :
21812183 return
2182- new_mode = plugin ._convert_mode (self )
2183- if self .mode == 'LA' and new_mode == 'P' :
2184- alpha = self .getchannel ('A' )
2184+ if self .mode == "P" :
2185+ preferred_modes = []
2186+ if "A" in self .im .getpalettemode ():
2187+ preferred_modes .append ("RGBA" )
2188+ preferred_modes .append ("RGB" )
2189+ else :
2190+ preferred_modes = {
2191+ "CMYK" : ["RGB" ],
2192+ "RGB" : ["CMYK" ],
2193+ "RGBX" : ["RGB" ],
2194+ "RGBa" : ["RGBA" , "RGB" ],
2195+ "RGBA" : ["RGB" ],
2196+ "LA" : ["RGBA" , "P" , "L" ],
2197+ "La" : ["LA" , "L" ],
2198+ "L" : ["RGB" ],
2199+ "F" : ["I" ],
2200+ "I" : ["L" , "RGB" ],
2201+ "1" : ["L" ],
2202+ "YCbCr" : ["RGB" ],
2203+ "LAB" : ["RGB" ],
2204+ "HSV" : ["RGB" ],
2205+ }.get (self .mode , [])
2206+ for new_mode in preferred_modes :
2207+ if new_mode in modes :
2208+ break
2209+ else :
2210+ new_mode = modes [0 ]
2211+ if self .mode == "LA" and new_mode == "P" :
2212+ alpha = self .getchannel ("A" )
21852213 # Convert the image into P mode but only use 255 colors
21862214 # in the palette out of 256.
2187- im = self .convert ('L' ) \
2188- .convert ('P' , palette = ADAPTIVE , colors = 255 )
2215+ im = self .convert ("L" ).convert ("P" , palette = ADAPTIVE , colors = 255 )
21892216 # Set all pixel values below 128 to 255, and the rest to 0.
21902217 mask = eval (alpha , lambda px : 255 if px < 128 else 0 )
21912218 # Paste the color of index 255 and use alpha as a mask.
21922219 im .paste (255 , mask )
21932220 # The transparency index is 255.
2194- im .info [' transparency' ] = 255
2221+ im .info [" transparency" ] = 255
21952222 return im
21962223
2197- elif self .mode == 'I' :
2198- im = self .point ([i // 256 for i in range (65536 )], 'L' )
2199- return im .convert (new_mode ) if new_mode != 'L' else im
2224+ elif self .mode == "I" :
2225+ im = self .point ([i // 256 for i in range (65536 )], "L" )
2226+ return im .convert (new_mode ) if new_mode != "L" else im
22002227
2201- elif self .mode in (' RGBA' , 'LA' ) and new_mode in (' RGB' , 'L' ):
2202- fill_color = params .get (' fill_color' , ' white' )
2228+ elif self .mode in (" RGBA" , "LA" ) and new_mode in (" RGB" , "L" ):
2229+ fill_color = params .get (" fill_color" , " white" )
22032230 background = new (new_mode , self .size , fill_color )
2204- background .paste (self , self .getchannel ('A' ))
2231+ background .paste (self , self .getchannel ("A" ))
22052232 return background
22062233
22072234 elif new_mode :
0 commit comments