@@ -212,7 +212,9 @@ def _bitmap(self, header=0, offset=0):
212212 if file_info ["bits" ] == 32 and header == 22 : # 32-bit .cur offset
213213 raw_mode , self .mode = "BGRA" , "RGBA"
214214 elif file_info ["compression" ] == self .RLE8 :
215- decoder_name = "bmp_rle"
215+ decoder_name = "bmp_rle8"
216+ elif file_info ["compression" ] == self .RLE4 :
217+ decoder_name = "bmp_rle4"
216218 else :
217219 raise OSError (f"Unsupported BMP compression ({ file_info ['compression' ]} )" )
218220
@@ -227,7 +229,7 @@ def _bitmap(self, header=0, offset=0):
227229 palette = read (padding * file_info ["colors" ])
228230 greyscale = True
229231 indices = (
230- (0 , 255 )
232+ (0 , file_info [ "colors" ] )
231233 if file_info ["colors" ] == 2
232234 else list (range (file_info ["colors" ]))
233235 )
@@ -276,7 +278,7 @@ def _open(self):
276278 self ._bitmap (offset = offset )
277279
278280
279- class BmpRleDecoder (ImageFile .PyDecoder ):
281+ class BmpRle8Decoder (ImageFile .PyDecoder ):
280282 _pulls_fd = True
281283
282284 def decode (self , buffer ):
@@ -328,6 +330,68 @@ def decode(self, buffer):
328330 return - 1 , 0
329331
330332
333+ class BmpRle4Decoder (ImageFile .PyDecoder ):
334+ _pulls_fd = True
335+
336+ def decode (self , buffer ):
337+ data = bytearray ()
338+ x = 0
339+ while len (data ) < self .state .xsize * self .state .ysize :
340+ pixels = self .fd .read (1 )
341+ byte = self .fd .read (1 )
342+ if not pixels or not byte :
343+ break
344+ num_pixels = pixels [0 ]
345+ if num_pixels :
346+ # encoded mode
347+ if x + num_pixels > self .state .xsize :
348+ # Too much data for row
349+ num_pixels = max (0 , self .state .xsize - x )
350+ first_pixel = o8 (byte [0 ] >> 4 )
351+ second_pixel = o8 (byte [0 ] & 0x0f )
352+ for index in range (num_pixels ):
353+ if index % 2 == 0 :
354+ data += first_pixel
355+ else :
356+ data += second_pixel
357+ x += num_pixels
358+ else :
359+ if byte [0 ] == 0 :
360+ # end of line
361+ while len (data ) % self .state .xsize != 0 :
362+ data += b"\x00 "
363+ x = 0
364+ elif byte [0 ] == 1 :
365+ # end of bitmap
366+ break
367+ elif byte [0 ] == 2 :
368+ # delta
369+ bytes_read = self .fd .read (2 )
370+ if len (bytes_read ) < 2 :
371+ break
372+ right , up = self .fd .read (2 )
373+ data += b"\x00 " * (right + up * self .state .xsize )
374+ x = len (data ) % self .state .xsize
375+ else :
376+ # absolute mode (2 pixels per byte)
377+ total_bytes_to_read = byte [0 ] // 2
378+ bytes_read = self .fd .read (total_bytes_to_read )
379+ for byte_read in bytes_read :
380+ first_pixel = o8 (byte_read >> 4 )
381+ data += first_pixel
382+ second_pixel = o8 (byte_read & 0x0f )
383+ data += second_pixel
384+ if len (bytes_read ) < total_bytes_to_read :
385+ break
386+ x += byte [0 ]
387+
388+ # align to 16-bit word boundary
389+ if self .fd .tell () % 2 != 0 :
390+ self .fd .seek (1 , os .SEEK_CUR )
391+ rawmode = "L" if self .mode == "L" else "P"
392+ self .set_as_raw (bytes (data ), (rawmode , 0 , self .args [- 1 ]))
393+ return - 1 , 0
394+
331395# =============================================================================
332396# Image plugin for the DIB format (BMP alias)
333397# =============================================================================
@@ -433,7 +497,8 @@ def _save(im, fp, filename, bitmap_header=True):
433497
434498Image .register_mime (BmpImageFile .format , "image/bmp" )
435499
436- Image .register_decoder ("bmp_rle" , BmpRleDecoder )
500+ Image .register_decoder ("bmp_rle8" , BmpRle8Decoder )
501+ Image .register_decoder ("bmp_rle4" , BmpRle4Decoder )
437502
438503Image .register_open (DibImageFile .format , DibImageFile , _dib_accept )
439504Image .register_save (DibImageFile .format , _dib_save )
0 commit comments