@@ -259,29 +259,44 @@ class BlpImageFile(ImageFile.ImageFile):
259259
260260 def _open (self ) -> None :
261261 self .magic = self .fp .read (4 )
262+ if not _accept (self .magic ):
263+ msg = f"Bad BLP magic { repr (self .magic )} "
264+ raise BLPFormatError (msg )
262265
263- self .fp .seek (5 , os .SEEK_CUR )
264- (self ._blp_alpha_depth ,) = struct .unpack ("<b" , self .fp .read (1 ))
266+ compression = struct .unpack ("<i" , self .fp .read (4 ))[0 ]
267+ if self .magic == b"BLP1" :
268+ alpha = struct .unpack ("<I" , self .fp .read (4 ))[0 ] != 0
269+ else :
270+ encoding = struct .unpack ("<b" , self .fp .read (1 ))[0 ]
271+ alpha = struct .unpack ("<b" , self .fp .read (1 ))[0 ] != 0
272+ alpha_encoding = struct .unpack ("<b" , self .fp .read (1 ))[0 ]
273+ self .fp .seek (1 , os .SEEK_CUR ) # mips
265274
266- self .fp .seek (2 , os .SEEK_CUR )
267275 self ._size = struct .unpack ("<II" , self .fp .read (8 ))
268276
269- if self .magic in (b"BLP1" , b"BLP2" ):
270- decoder = self .magic .decode ()
277+ args : tuple [int , int , bool ] | tuple [int , int , bool , int ]
278+ if self .magic == b"BLP1" :
279+ encoding = struct .unpack ("<i" , self .fp .read (4 ))[0 ]
280+ self .fp .seek (4 , os .SEEK_CUR ) # subtype
281+
282+ args = (compression , encoding , alpha )
283+ offset = 28
271284 else :
272- msg = f"Bad BLP magic { repr ( self . magic ) } "
273- raise BLPFormatError ( msg )
285+ args = ( compression , encoding , alpha , alpha_encoding )
286+ offset = 20
274287
275- self ._mode = "RGBA" if self ._blp_alpha_depth else "RGB"
276- self .tile = [ImageFile ._Tile (decoder , (0 , 0 ) + self .size , 0 , self .mode )]
288+ decoder = self .magic .decode ()
289+
290+ self ._mode = "RGBA" if alpha else "RGB"
291+ self .tile = [ImageFile ._Tile (decoder , (0 , 0 ) + self .size , offset , args )]
277292
278293
279294class _BLPBaseDecoder (ImageFile .PyDecoder ):
280295 _pulls_fd = True
281296
282297 def decode (self , buffer : bytes | Image .SupportsArrayInterface ) -> tuple [int , int ]:
283298 try :
284- self ._read_blp_header ()
299+ self ._read_header ()
285300 self ._load ()
286301 except struct .error as e :
287302 msg = "Truncated BLP file"
@@ -292,25 +307,9 @@ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int
292307 def _load (self ) -> None :
293308 pass
294309
295- def _read_blp_header (self ) -> None :
296- assert self .fd is not None
297- self .fd .seek (4 )
298- (self ._blp_compression ,) = struct .unpack ("<i" , self ._safe_read (4 ))
299-
300- (self ._blp_encoding ,) = struct .unpack ("<b" , self ._safe_read (1 ))
301- (self ._blp_alpha_depth ,) = struct .unpack ("<b" , self ._safe_read (1 ))
302- (self ._blp_alpha_encoding ,) = struct .unpack ("<b" , self ._safe_read (1 ))
303- self .fd .seek (1 , os .SEEK_CUR ) # mips
304-
305- self .size = struct .unpack ("<II" , self ._safe_read (8 ))
306-
307- if isinstance (self , BLP1Decoder ):
308- # Only present for BLP1
309- (self ._blp_encoding ,) = struct .unpack ("<i" , self ._safe_read (4 ))
310- self .fd .seek (4 , os .SEEK_CUR ) # subtype
311-
312- self ._blp_offsets = struct .unpack ("<16I" , self ._safe_read (16 * 4 ))
313- self ._blp_lengths = struct .unpack ("<16I" , self ._safe_read (16 * 4 ))
310+ def _read_header (self ) -> None :
311+ self ._offsets = struct .unpack ("<16I" , self ._safe_read (16 * 4 ))
312+ self ._lengths = struct .unpack ("<16I" , self ._safe_read (16 * 4 ))
314313
315314 def _safe_read (self , length : int ) -> bytes :
316315 assert self .fd is not None
@@ -326,37 +325,41 @@ def _read_palette(self) -> list[tuple[int, int, int, int]]:
326325 ret .append ((b , g , r , a ))
327326 return ret
328327
329- def _read_bgra (self , palette : list [tuple [int , int , int , int ]]) -> bytearray :
328+ def _read_bgra (
329+ self , palette : list [tuple [int , int , int , int ]], alpha : bool
330+ ) -> bytearray :
330331 data = bytearray ()
331- _data = BytesIO (self ._safe_read (self ._blp_lengths [0 ]))
332+ _data = BytesIO (self ._safe_read (self ._lengths [0 ]))
332333 while True :
333334 try :
334335 (offset ,) = struct .unpack ("<B" , _data .read (1 ))
335336 except struct .error :
336337 break
337338 b , g , r , a = palette [offset ]
338339 d : tuple [int , ...] = (r , g , b )
339- if self . _blp_alpha_depth :
340+ if alpha :
340341 d += (a ,)
341342 data .extend (d )
342343 return data
343344
344345
345346class BLP1Decoder (_BLPBaseDecoder ):
346347 def _load (self ) -> None :
347- if self ._blp_compression == Format .JPEG :
348+ self ._compression , self ._encoding , alpha = self .args
349+
350+ if self ._compression == Format .JPEG :
348351 self ._decode_jpeg_stream ()
349352
350- elif self ._blp_compression == 1 :
351- if self ._blp_encoding in (4 , 5 ):
353+ elif self ._compression == 1 :
354+ if self ._encoding in (4 , 5 ):
352355 palette = self ._read_palette ()
353- data = self ._read_bgra (palette )
356+ data = self ._read_bgra (palette , alpha )
354357 self .set_as_raw (data )
355358 else :
356- msg = f"Unsupported BLP encoding { repr (self ._blp_encoding )} "
359+ msg = f"Unsupported BLP encoding { repr (self ._encoding )} "
357360 raise BLPFormatError (msg )
358361 else :
359- msg = f"Unsupported BLP compression { repr (self ._blp_encoding )} "
362+ msg = f"Unsupported BLP compression { repr (self ._encoding )} "
360363 raise BLPFormatError (msg )
361364
362365 def _decode_jpeg_stream (self ) -> None :
@@ -365,8 +368,8 @@ def _decode_jpeg_stream(self) -> None:
365368 (jpeg_header_size ,) = struct .unpack ("<I" , self ._safe_read (4 ))
366369 jpeg_header = self ._safe_read (jpeg_header_size )
367370 assert self .fd is not None
368- self ._safe_read (self ._blp_offsets [0 ] - self .fd .tell ()) # What IS this?
369- data = self ._safe_read (self ._blp_lengths [0 ])
371+ self ._safe_read (self ._offsets [0 ] - self .fd .tell ()) # What IS this?
372+ data = self ._safe_read (self ._lengths [0 ])
370373 data = jpeg_header + data
371374 image = JpegImageFile (BytesIO (data ))
372375 Image ._decompression_bomb_check (image .size )
@@ -383,47 +386,47 @@ def _decode_jpeg_stream(self) -> None:
383386
384387class BLP2Decoder (_BLPBaseDecoder ):
385388 def _load (self ) -> None :
389+ self ._compression , self ._encoding , alpha , self ._alpha_encoding = self .args
390+
386391 palette = self ._read_palette ()
387392
388393 assert self .fd is not None
389- self .fd .seek (self ._blp_offsets [0 ])
394+ self .fd .seek (self ._offsets [0 ])
390395
391- if self ._blp_compression == 1 :
396+ if self ._compression == 1 :
392397 # Uncompressed or DirectX compression
393398
394- if self ._blp_encoding == Encoding .UNCOMPRESSED :
395- data = self ._read_bgra (palette )
399+ if self ._encoding == Encoding .UNCOMPRESSED :
400+ data = self ._read_bgra (palette , alpha )
396401
397- elif self ._blp_encoding == Encoding .DXT :
402+ elif self ._encoding == Encoding .DXT :
398403 data = bytearray ()
399- if self ._blp_alpha_encoding == AlphaEncoding .DXT1 :
400- linesize = (self .size [0 ] + 3 ) // 4 * 8
401- for yb in range ((self .size [1 ] + 3 ) // 4 ):
402- for d in decode_dxt1 (
403- self ._safe_read (linesize ), alpha = bool (self ._blp_alpha_depth )
404- ):
404+ if self ._alpha_encoding == AlphaEncoding .DXT1 :
405+ linesize = (self .state .xsize + 3 ) // 4 * 8
406+ for yb in range ((self .state .ysize + 3 ) // 4 ):
407+ for d in decode_dxt1 (self ._safe_read (linesize ), alpha ):
405408 data += d
406409
407- elif self ._blp_alpha_encoding == AlphaEncoding .DXT3 :
408- linesize = (self .size [ 0 ] + 3 ) // 4 * 16
409- for yb in range ((self .size [ 1 ] + 3 ) // 4 ):
410+ elif self ._alpha_encoding == AlphaEncoding .DXT3 :
411+ linesize = (self .state . xsize + 3 ) // 4 * 16
412+ for yb in range ((self .state . ysize + 3 ) // 4 ):
410413 for d in decode_dxt3 (self ._safe_read (linesize )):
411414 data += d
412415
413- elif self ._blp_alpha_encoding == AlphaEncoding .DXT5 :
414- linesize = (self .size [ 0 ] + 3 ) // 4 * 16
415- for yb in range ((self .size [ 1 ] + 3 ) // 4 ):
416+ elif self ._alpha_encoding == AlphaEncoding .DXT5 :
417+ linesize = (self .state . xsize + 3 ) // 4 * 16
418+ for yb in range ((self .state . ysize + 3 ) // 4 ):
416419 for d in decode_dxt5 (self ._safe_read (linesize )):
417420 data += d
418421 else :
419- msg = f"Unsupported alpha encoding { repr (self ._blp_alpha_encoding )} "
422+ msg = f"Unsupported alpha encoding { repr (self ._alpha_encoding )} "
420423 raise BLPFormatError (msg )
421424 else :
422- msg = f"Unknown BLP encoding { repr (self ._blp_encoding )} "
425+ msg = f"Unknown BLP encoding { repr (self ._encoding )} "
423426 raise BLPFormatError (msg )
424427
425428 else :
426- msg = f"Unknown BLP compression { repr (self ._blp_compression )} "
429+ msg = f"Unknown BLP compression { repr (self ._compression )} "
427430 raise BLPFormatError (msg )
428431
429432 self .set_as_raw (data )
@@ -472,10 +475,15 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
472475
473476 assert im .palette is not None
474477 fp .write (struct .pack ("<i" , 1 )) # Uncompressed or DirectX compression
475- fp .write (struct .pack ("<b" , Encoding .UNCOMPRESSED ))
476- fp .write (struct .pack ("<b" , 1 if im .palette .mode == "RGBA" else 0 ))
477- fp .write (struct .pack ("<b" , 0 )) # alpha encoding
478- fp .write (struct .pack ("<b" , 0 )) # mips
478+
479+ alpha_depth = 1 if im .palette .mode == "RGBA" else 0
480+ if magic == b"BLP1" :
481+ fp .write (struct .pack ("<L" , alpha_depth ))
482+ else :
483+ fp .write (struct .pack ("<b" , Encoding .UNCOMPRESSED ))
484+ fp .write (struct .pack ("<b" , alpha_depth ))
485+ fp .write (struct .pack ("<b" , 0 )) # alpha encoding
486+ fp .write (struct .pack ("<b" , 0 )) # mips
479487 fp .write (struct .pack ("<II" , * im .size ))
480488 if magic == b"BLP1" :
481489 fp .write (struct .pack ("<i" , 5 ))
0 commit comments