@@ -259,32 +259,44 @@ class BlpImageFile(ImageFile.ImageFile):
259
259
260
260
def _open (self ) -> None :
261
261
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 )
262
265
266
+ compression = struct .unpack ("<i" , self .fp .read (4 ))[0 ]
263
267
if self .magic == b"BLP1" :
264
- self .fp .seek (4 , os .SEEK_CUR )
265
- (self ._blp_alpha_depth ,) = struct .unpack ("<I" , self .fp .read (4 ))
266
- elif self .magic == b"BLP2" :
267
- self .fp .seek (5 , os .SEEK_CUR )
268
- (self ._blp_alpha_depth ,) = struct .unpack ("<b" , self .fp .read (1 ))
269
- self .fp .seek (2 , os .SEEK_CUR )
268
+ alpha = struct .unpack ("<I" , self .fp .read (4 ))[0 ] != 0
270
269
else :
271
- msg = f"Bad BLP magic { repr (self .magic )} "
272
- raise BLPFormatError (msg )
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
273
274
274
275
self ._size = struct .unpack ("<II" , self .fp .read (8 ))
275
276
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
284
+ else :
285
+ args = (compression , encoding , alpha , alpha_encoding )
286
+ offset = 20
287
+
276
288
decoder = self .magic .decode ()
277
289
278
- self ._mode = "RGBA" if self . _blp_alpha_depth else "RGB"
279
- self .tile = [ImageFile ._Tile (decoder , (0 , 0 ) + self .size , 0 , self . mode )]
290
+ self ._mode = "RGBA" if alpha else "RGB"
291
+ self .tile = [ImageFile ._Tile (decoder , (0 , 0 ) + self .size , offset , args )]
280
292
281
293
282
294
class _BLPBaseDecoder (ImageFile .PyDecoder ):
283
295
_pulls_fd = True
284
296
285
297
def decode (self , buffer : bytes | Image .SupportsArrayInterface ) -> tuple [int , int ]:
286
298
try :
287
- self ._read_blp_header ()
299
+ self ._read_header ()
288
300
self ._load ()
289
301
except struct .error as e :
290
302
msg = "Truncated BLP file"
@@ -295,28 +307,9 @@ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int
295
307
def _load (self ) -> None :
296
308
pass
297
309
298
- def _read_blp_header (self ) -> None :
299
- assert self .fd is not None
300
- self .fd .seek (4 )
301
- (self ._blp_compression ,) = struct .unpack ("<i" , self ._safe_read (4 ))
302
-
303
- if isinstance (self , BLP1Decoder ):
304
- (self ._blp_alpha_depth ,) = struct .unpack ("<I" , self ._safe_read (4 ))
305
- else :
306
- (self ._blp_encoding ,) = struct .unpack ("<b" , self ._safe_read (1 ))
307
- (self ._blp_alpha_depth ,) = struct .unpack ("<b" , self ._safe_read (1 ))
308
- (self ._blp_alpha_encoding ,) = struct .unpack ("<b" , self ._safe_read (1 ))
309
- self .fd .seek (1 , os .SEEK_CUR ) # mips
310
-
311
- self .size = struct .unpack ("<II" , self ._safe_read (8 ))
312
-
313
- if isinstance (self , BLP1Decoder ):
314
- # Only present for BLP1
315
- (self ._blp_encoding ,) = struct .unpack ("<i" , self ._safe_read (4 ))
316
- self .fd .seek (4 , os .SEEK_CUR ) # subtype
317
-
318
- self ._blp_offsets = struct .unpack ("<16I" , self ._safe_read (16 * 4 ))
319
- 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 ))
320
313
321
314
def _safe_read (self , length : int ) -> bytes :
322
315
assert self .fd is not None
@@ -332,37 +325,41 @@ def _read_palette(self) -> list[tuple[int, int, int, int]]:
332
325
ret .append ((b , g , r , a ))
333
326
return ret
334
327
335
- 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 :
336
331
data = bytearray ()
337
- _data = BytesIO (self ._safe_read (self ._blp_lengths [0 ]))
332
+ _data = BytesIO (self ._safe_read (self ._lengths [0 ]))
338
333
while True :
339
334
try :
340
335
(offset ,) = struct .unpack ("<B" , _data .read (1 ))
341
336
except struct .error :
342
337
break
343
338
b , g , r , a = palette [offset ]
344
339
d : tuple [int , ...] = (r , g , b )
345
- if self . _blp_alpha_depth :
340
+ if alpha :
346
341
d += (a ,)
347
342
data .extend (d )
348
343
return data
349
344
350
345
351
346
class BLP1Decoder (_BLPBaseDecoder ):
352
347
def _load (self ) -> None :
353
- if self ._blp_compression == Format .JPEG :
348
+ self ._compression , self ._encoding , alpha = self .args
349
+
350
+ if self ._compression == Format .JPEG :
354
351
self ._decode_jpeg_stream ()
355
352
356
- elif self ._blp_compression == 1 :
357
- if self ._blp_encoding in (4 , 5 ):
353
+ elif self ._compression == 1 :
354
+ if self ._encoding in (4 , 5 ):
358
355
palette = self ._read_palette ()
359
- data = self ._read_bgra (palette )
356
+ data = self ._read_bgra (palette , alpha )
360
357
self .set_as_raw (data )
361
358
else :
362
- msg = f"Unsupported BLP encoding { repr (self ._blp_encoding )} "
359
+ msg = f"Unsupported BLP encoding { repr (self ._encoding )} "
363
360
raise BLPFormatError (msg )
364
361
else :
365
- msg = f"Unsupported BLP compression { repr (self ._blp_encoding )} "
362
+ msg = f"Unsupported BLP compression { repr (self ._encoding )} "
366
363
raise BLPFormatError (msg )
367
364
368
365
def _decode_jpeg_stream (self ) -> None :
@@ -371,8 +368,8 @@ def _decode_jpeg_stream(self) -> None:
371
368
(jpeg_header_size ,) = struct .unpack ("<I" , self ._safe_read (4 ))
372
369
jpeg_header = self ._safe_read (jpeg_header_size )
373
370
assert self .fd is not None
374
- self ._safe_read (self ._blp_offsets [0 ] - self .fd .tell ()) # What IS this?
375
- 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 ])
376
373
data = jpeg_header + data
377
374
image = JpegImageFile (BytesIO (data ))
378
375
Image ._decompression_bomb_check (image .size )
@@ -389,47 +386,47 @@ def _decode_jpeg_stream(self) -> None:
389
386
390
387
class BLP2Decoder (_BLPBaseDecoder ):
391
388
def _load (self ) -> None :
389
+ self ._compression , self ._encoding , alpha , self ._alpha_encoding = self .args
390
+
392
391
palette = self ._read_palette ()
393
392
394
393
assert self .fd is not None
395
- self .fd .seek (self ._blp_offsets [0 ])
394
+ self .fd .seek (self ._offsets [0 ])
396
395
397
- if self ._blp_compression == 1 :
396
+ if self ._compression == 1 :
398
397
# Uncompressed or DirectX compression
399
398
400
- if self ._blp_encoding == Encoding .UNCOMPRESSED :
401
- data = self ._read_bgra (palette )
399
+ if self ._encoding == Encoding .UNCOMPRESSED :
400
+ data = self ._read_bgra (palette , alpha )
402
401
403
- elif self ._blp_encoding == Encoding .DXT :
402
+ elif self ._encoding == Encoding .DXT :
404
403
data = bytearray ()
405
- if self ._blp_alpha_encoding == AlphaEncoding .DXT1 :
406
- linesize = (self .size [0 ] + 3 ) // 4 * 8
407
- for yb in range ((self .size [1 ] + 3 ) // 4 ):
408
- for d in decode_dxt1 (
409
- self ._safe_read (linesize ), alpha = bool (self ._blp_alpha_depth )
410
- ):
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 ):
411
408
data += d
412
409
413
- elif self ._blp_alpha_encoding == AlphaEncoding .DXT3 :
414
- linesize = (self .size [ 0 ] + 3 ) // 4 * 16
415
- 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 ):
416
413
for d in decode_dxt3 (self ._safe_read (linesize )):
417
414
data += d
418
415
419
- elif self ._blp_alpha_encoding == AlphaEncoding .DXT5 :
420
- linesize = (self .size [ 0 ] + 3 ) // 4 * 16
421
- 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 ):
422
419
for d in decode_dxt5 (self ._safe_read (linesize )):
423
420
data += d
424
421
else :
425
- msg = f"Unsupported alpha encoding { repr (self ._blp_alpha_encoding )} "
422
+ msg = f"Unsupported alpha encoding { repr (self ._alpha_encoding )} "
426
423
raise BLPFormatError (msg )
427
424
else :
428
- msg = f"Unknown BLP encoding { repr (self ._blp_encoding )} "
425
+ msg = f"Unknown BLP encoding { repr (self ._encoding )} "
429
426
raise BLPFormatError (msg )
430
427
431
428
else :
432
- msg = f"Unknown BLP compression { repr (self ._blp_compression )} "
429
+ msg = f"Unknown BLP compression { repr (self ._compression )} "
433
430
raise BLPFormatError (msg )
434
431
435
432
self .set_as_raw (data )
0 commit comments