@@ -211,7 +211,7 @@ def _bitmap(self, header=0, offset=0):
211211 elif file_info ["compression" ] == self .RAW :
212212 if file_info ["bits" ] == 32 and header == 22 : # 32-bit .cur offset
213213 raw_mode , self .mode = "BGRA" , "RGBA"
214- elif file_info ["compression" ] == self .RLE8 :
214+ elif file_info ["compression" ] in ( self .RLE8 , self . RLE4 ) :
215215 decoder_name = "bmp_rle"
216216 else :
217217 raise OSError (f"Unsupported BMP compression ({ file_info ['compression' ]} )" )
@@ -250,16 +250,18 @@ def _bitmap(self, header=0, offset=0):
250250
251251 # ---------------------------- Finally set the tile data for the plugin
252252 self .info ["compression" ] = file_info ["compression" ]
253+ args = [raw_mode ]
254+ if decoder_name == "bmp_rle" :
255+ args .append (file_info ["compression" ] == self .RLE4 )
256+ else :
257+ args .append (((file_info ["width" ] * file_info ["bits" ] + 31 ) >> 3 ) & (~ 3 ))
258+ args .append (file_info ["direction" ])
253259 self .tile = [
254260 (
255261 decoder_name ,
256262 (0 , 0 , file_info ["width" ], file_info ["height" ]),
257263 offset or self .fp .tell (),
258- (
259- raw_mode ,
260- ((file_info ["width" ] * file_info ["bits" ] + 31 ) >> 3 ) & (~ 3 ),
261- file_info ["direction" ],
262- ),
264+ tuple (args ),
263265 )
264266 ]
265267
@@ -280,6 +282,7 @@ class BmpRleDecoder(ImageFile.PyDecoder):
280282 _pulls_fd = True
281283
282284 def decode (self , buffer ):
285+ rle4 = self .args [1 ]
283286 data = bytearray ()
284287 x = 0
285288 while len (data ) < self .state .xsize * self .state .ysize :
@@ -293,7 +296,16 @@ def decode(self, buffer):
293296 if x + num_pixels > self .state .xsize :
294297 # Too much data for row
295298 num_pixels = max (0 , self .state .xsize - x )
296- data += byte * num_pixels
299+ if rle4 :
300+ first_pixel = o8 (byte [0 ] >> 4 )
301+ second_pixel = o8 (byte [0 ] & 0x0F )
302+ for index in range (num_pixels ):
303+ if index % 2 == 0 :
304+ data += first_pixel
305+ else :
306+ data += second_pixel
307+ else :
308+ data += byte * num_pixels
297309 x += num_pixels
298310 else :
299311 if byte [0 ] == 0 :
@@ -314,9 +326,18 @@ def decode(self, buffer):
314326 x = len (data ) % self .state .xsize
315327 else :
316328 # absolute mode
317- bytes_read = self .fd .read (byte [0 ])
318- data += bytes_read
319- if len (bytes_read ) < byte [0 ]:
329+ if rle4 :
330+ # 2 pixels per byte
331+ byte_count = byte [0 ] // 2
332+ bytes_read = self .fd .read (byte_count )
333+ for byte_read in bytes_read :
334+ data += o8 (byte_read >> 4 )
335+ data += o8 (byte_read & 0x0F )
336+ else :
337+ byte_count = byte [0 ]
338+ bytes_read = self .fd .read (byte_count )
339+ data += bytes_read
340+ if len (bytes_read ) < byte_count :
320341 break
321342 x += byte [0 ]
322343
0 commit comments