@@ -142,28 +142,30 @@ class VtfPF(IntEnum):
142
142
VtfPF .UV88 ,
143
143
)
144
144
145
- BLOCK_COMPRESSED = (
146
- VtfPF .DXT1 ,
147
- VtfPF .DXT1_ONEBITALPHA ,
148
- VtfPF .DXT3 ,
149
- VtfPF .DXT5 )
145
+ BLOCK_COMPRESSED = (VtfPF .DXT1 , VtfPF .DXT1_ONEBITALPHA , VtfPF .DXT3 , VtfPF .DXT5 )
150
146
SUPPORTED_FORMATS = RGBA_FORMATS + RGB_FORMATS + LA_FORMATS + L_FORMATS
151
- HEADER_V70 = ' <I2HI2H4x3f4xfIbI2b'
152
- HEADER_V72 = ' <I2HI2H4x3f4xfIbI2bH'
153
- HEADER_V73 = ' <I2HI2H4x3f4xfIbI2bH3xI8x'
147
+ HEADER_V70 = " <I2HI2H4x3f4xfIbI2b"
148
+ HEADER_V72 = " <I2HI2H4x3f4xfIbI2bH"
149
+ HEADER_V73 = " <I2HI2H4x3f4xfIbI2bH3xI8x"
154
150
155
151
156
- # fmt: off
157
152
def _get_texture_size (pixel_format : VtfPF , width , height ):
158
153
if pixel_format in (VtfPF .DXT1 , VtfPF .DXT1_ONEBITALPHA ):
159
154
return width * height // 2
160
- elif pixel_format in (VtfPF .DXT3 , VtfPF .DXT5 ,) + L_FORMATS :
155
+ elif (
156
+ pixel_format
157
+ in (
158
+ VtfPF .DXT3 ,
159
+ VtfPF .DXT5 ,
160
+ )
161
+ + L_FORMATS
162
+ ):
161
163
return width * height
162
164
elif pixel_format in LA_FORMATS :
163
165
return width * height * 2
164
- elif pixel_format in ( VtfPF .RGB888 ,) :
166
+ elif pixel_format == VtfPF .RGB888 :
165
167
return width * height * 3
166
- elif pixel_format in ( VtfPF .RGBA8888 ,) :
168
+ elif pixel_format == VtfPF .RGBA8888 :
167
169
return width * height * 4
168
170
raise VTFException (f"Unsupported VTF pixel format: { pixel_format } " )
169
171
@@ -181,17 +183,13 @@ def _get_mipmap_count(width: int, height: int):
181
183
182
184
def closest_power (x ):
183
185
possible_results = round (log (x , 2 )), ceil (log (x , 2 ))
184
- return 2 ** min (possible_results , key = lambda z : abs (x - 2 ** z ))
185
-
186
-
187
- # fmt: on
186
+ return 2 ** min (possible_results , key = lambda z : abs (x - 2 ** z ))
188
187
189
188
190
189
class VtfImageFile (ImageFile .ImageFile ):
191
190
format = "VTF"
192
191
format_description = "Valve Texture Format"
193
192
194
- # fmt: off
195
193
def _open (self ):
196
194
if not _accept (self .fp .read (12 )):
197
195
raise SyntaxError ("not a VTF file" )
@@ -200,16 +198,26 @@ def _open(self):
200
198
if version <= (7 , 2 ):
201
199
header = VTFHeader (
202
200
* struct .unpack (HEADER_V70 , self .fp .read (struct .calcsize (HEADER_V70 ))),
203
- 0 , 0 , 0 , 0 , 0 )
201
+ 0 ,
202
+ 0 ,
203
+ 0 ,
204
+ 0 ,
205
+ 0 ,
206
+ )
204
207
self .fp .seek (header .header_size )
205
- elif ( 7 , 2 ) <= version < (7 , 3 ):
208
+ elif version < (7 , 3 ):
206
209
header = VTFHeader (
207
210
* struct .unpack (HEADER_V72 , self .fp .read (struct .calcsize (HEADER_V72 ))),
208
- 0 , 0 , 0 , 0 )
211
+ 0 ,
212
+ 0 ,
213
+ 0 ,
214
+ 0 ,
215
+ )
209
216
self .fp .seek (header .header_size )
210
- elif ( 7 , 3 ) <= version < (7 , 5 ):
217
+ elif version < (7 , 5 ):
211
218
header = VTFHeader (
212
- * struct .unpack (HEADER_V73 , self .fp .read (struct .calcsize (HEADER_V73 ))))
219
+ * struct .unpack (HEADER_V73 , self .fp .read (struct .calcsize (HEADER_V73 )))
220
+ )
213
221
self .fp .seek (header .header_size )
214
222
else :
215
223
raise VTFException (f"Unsupported VTF version: { version } " )
@@ -232,7 +240,7 @@ def _open(self):
232
240
233
241
data_start = self .fp .tell ()
234
242
data_start += _get_texture_size (low_format , header .low_width , header .low_height )
235
- min_res = ( 4 if pixel_format in BLOCK_COMPRESSED else 1 )
243
+ min_res = 4 if pixel_format in BLOCK_COMPRESSED else 1
236
244
for mip_id in range (header .mipmap_count - 1 , 0 , - 1 ):
237
245
mip_width = max (header .width >> mip_id , min_res )
238
246
mip_height = max (header .height >> mip_id , min_res )
@@ -256,22 +264,21 @@ def _open(self):
256
264
else :
257
265
raise VTFException (f"Unsupported VTF pixel format: { pixel_format } " )
258
266
self .tile = [tile ]
259
- # fmt: on
260
267
261
268
262
269
def _save (im , fp , filename ):
263
270
im : Image .Image
264
271
if im .mode not in ("RGB" , "RGBA" ):
265
272
raise OSError (f"cannot write mode { im .mode } as VTF" )
266
- arguments = im .encoderinfo
267
- pixel_format = VtfPF (arguments .get (' pixel_format' , VtfPF .RGBA8888 ))
268
- version = arguments .get (' version' , (7 , 4 ))
273
+ encoderinfo = im .encoderinfo
274
+ pixel_format = VtfPF (encoderinfo .get (" pixel_format" , VtfPF .RGBA8888 ))
275
+ version = encoderinfo .get (" version" , (7 , 4 ))
269
276
flags = CompiledVtfFlags (0 )
270
- if 'A' in im .mode :
277
+ if "A" in im .mode :
271
278
if pixel_format == VtfPF .DXT1_ONEBITALPHA :
272
279
flags |= CompiledVtfFlags .ONEBITALPHA
273
280
elif pixel_format == VtfPF .DXT1 :
274
- im = im .convert (' RGB' )
281
+ im = im .convert (" RGB" )
275
282
else :
276
283
flags |= CompiledVtfFlags .EIGHTBITALPHA
277
284
@@ -281,21 +288,32 @@ def _save(im, fp, filename):
281
288
mipmap_count = _get_mipmap_count (width , height )
282
289
283
290
thumb_buffer = BytesIO ()
284
- thumb = im .convert (' RGB' )
291
+ thumb = im .convert (" RGB" )
285
292
thumb .thumbnail (((min (16 , width )), (min (16 , height ))))
286
293
thumb = thumb .resize ((closest_power (thumb .width ), closest_power (thumb .height )))
287
- ImageFile ._save (thumb , thumb_buffer , [("bcn" , (0 , 0 ) + thumb .size , 0 , (1 , 'DXT1' ))])
288
-
289
- header = VTFHeader (0 , width , height , flags ,
290
- 1 , 0 , 1.0 , 1.0 , 1.0 ,
291
- 1.0 , pixel_format , mipmap_count , VtfPF .DXT1 ,
292
- thumb .width , thumb .height ,
293
- 1 , 2 )
294
-
295
- fp .write (
296
- b"VTF\x00 "
297
- + struct .pack ('<2I' , * version )
294
+ ImageFile ._save (thumb , thumb_buffer , [("bcn" , (0 , 0 ) + thumb .size , 0 , (1 , "DXT1" ))])
295
+
296
+ header = VTFHeader (
297
+ 0 ,
298
+ width ,
299
+ height ,
300
+ flags ,
301
+ 1 ,
302
+ 0 ,
303
+ 1.0 ,
304
+ 1.0 ,
305
+ 1.0 ,
306
+ 1.0 ,
307
+ pixel_format ,
308
+ mipmap_count ,
309
+ VtfPF .DXT1 ,
310
+ thumb .width ,
311
+ thumb .height ,
312
+ 1 ,
313
+ 2 ,
298
314
)
315
+
316
+ fp .write (b"VTF\x00 " + struct .pack ("<2I" , * version ))
299
317
if version < (7 , 2 ):
300
318
size = struct .calcsize (HEADER_V70 ) + 12
301
319
header = header ._replace (header_size = size + (16 - size % 16 ))
@@ -309,15 +327,15 @@ def _save(im, fp, filename):
309
327
header = header ._replace (header_size = size + (16 - size % 16 ))
310
328
fp .write (struct .pack (HEADER_V73 , * header ))
311
329
else :
312
- raise VTFException (f' Unsupported version { version } ' )
330
+ raise VTFException (f" Unsupported version { version } " )
313
331
314
332
if version > (7 , 2 ):
315
- fp .write (b' \x01 \x00 \x00 \x00 ' )
316
- fp .write (struct .pack ('<I' , header .header_size ))
317
- fp .write (b' \x30 \x00 \x00 \x00 ' )
318
- fp .write (struct .pack ('<I' , header .header_size + len (thumb_buffer .getbuffer ())))
333
+ fp .write (b" \x01 \x00 \x00 \x00 " )
334
+ fp .write (struct .pack ("<I" , header .header_size ))
335
+ fp .write (b" \x30 \x00 \x00 \x00 " )
336
+ fp .write (struct .pack ("<I" , header .header_size + len (thumb_buffer .getbuffer ())))
319
337
else :
320
- fp .write (b' \x00 ' * (16 - fp .tell () % 16 ))
338
+ fp .write (b" \x00 " * (16 - fp .tell () % 16 ))
321
339
fp .write (thumb_buffer .getbuffer ())
322
340
323
341
for mip_id in range (mipmap_count - 1 , 0 , - 1 ):
@@ -326,11 +344,13 @@ def _save(im, fp, filename):
326
344
mip = im .resize ((mip_width , mip_height ))
327
345
buffer_size = mip_width * mip_height // 2
328
346
extents = (0 , 0 ) + mip .size
329
- ImageFile ._save (mip , fp ,
330
- [("bcn" , extents , fp .tell (), (1 , 'DXT1' ))], buffer_size )
347
+ ImageFile ._save (
348
+ mip , fp , [("bcn" , extents , fp .tell (), (1 , "DXT1" ))], buffer_size
349
+ )
331
350
buffer_size = im .width * im .height // 2
332
- ImageFile ._save (im , fp ,
333
- [("bcn" , (0 , 0 ) + im .size , fp .tell (), (1 , 'DXT1' ))], buffer_size )
351
+ ImageFile ._save (
352
+ im , fp , [("bcn" , (0 , 0 ) + im .size , fp .tell (), (1 , "DXT1" ))], buffer_size
353
+ )
334
354
335
355
336
356
def _accept (prefix ):
0 commit comments