11import texture2ddecoder
2+ import etcpak
23from PIL import Image
34from copy import copy
45from io import BytesIO
89TF = TextureFormat
910
1011
11- def image_to_texture2d (img : Image , flip : bool = True ):
12- # tex for eventually later usage of compressions
13-
14- tex_format = None
12+ def image_to_texture2d (img : Image , target_texture_format : TF , flip : bool = True ):
1513 if flip :
1614 img = img .transpose (Image .FLIP_TOP_BOTTOM )
1715
18- if img .mode == "RGBA" :
19- tex_format = TextureFormat .RGBA32
20- elif img .mode == "RGB" :
21- tex_format = TextureFormat .RGB24
22- elif img .mode == "A" :
23- tex_format = TextureFormat .Alpha8
16+ # DXT
17+ if target_texture_format in [TF .DXT1 , TF .DXT1Crunched ]:
18+ raw_img = img .convert ("RGBA" ).tobytes ()
19+ enc_img = etcpak .compress_to_dxt1 (raw_img , img .width , img .height )
20+ tex_format = TF .DXT1
21+ elif target_texture_format in [TF .DXT5 , TF .DXT5Crunched ]:
22+ raw_img = img .convert ("RGBA" ).tobytes ()
23+ enc_img = etcpak .compress_to_dxt5 (raw_img , img .width , img .height )
24+ tex_format = TF .DXT5
25+ # ETC
26+ elif target_texture_format in [TF .ETC_RGB4 , TF .ETC_RGB4Crunched , TF .ETC_RGB4_3DS ]:
27+ r , g , b , a = img .split ()
28+ raw_img = Image .merge ("RGBA" , (b , g , r , a )).tobytes ()
29+ enc_img = etcpak .compress_to_etc1 (raw_img , img .width , img .height )
30+ tex_format = TF .ETC_RGB4
31+ elif target_texture_format == TF .ETC2_RGB :
32+ r , g , b , a = img .split ()
33+ raw_img = Image .merge ("RGBA" , (b , g , r , a )).tobytes ()
34+ enc_img = etcpak .compress_to_etc2_rgb (raw_img , img .width , img .height )
35+ tex_format = TF .ETC2_RGB
36+ elif (
37+ target_texture_format in [TF .ETC2_RGBA8 , TF .ETC2_RGBA8Crunched , TF .ETC2_RGBA1 ]
38+ or "_RGB_" in target_texture_format .name
39+ ):
40+ r , g , b , a = img .split ()
41+ raw_img = Image .merge ("RGBA" , (b , g , r , a )).tobytes ()
42+ enc_img = etcpak .compress_to_etc2_rgba (raw_img , img .width , img .height )
43+ tex_format = TF .ETC2_RGBA8
44+ # A
45+ elif target_texture_format == TF .Alpha8 :
46+ enc_img = Image .tobytes ("raw" , "A" )
47+ tex_format = TF .Alpha8
48+ # R
49+ elif target_texture_format in [
50+ TF .R8 ,
51+ TF .R16 ,
52+ TF .RHalf ,
53+ TF .RFloat ,
54+ TF .EAC_R ,
55+ TF .EAC_R_SIGNED ,
56+ ]:
57+ enc_img = Image .tobytes ("raw" , "R" )
58+ tex_format = TF .R8
59+ # RGBA
60+ elif target_texture_format in [
61+ TF .RGB565 ,
62+ TF .RGB24 ,
63+ TF .RGB9e5Float ,
64+ TF .PVRTC_RGB2 ,
65+ TF .PVRTC_RGB4 ,
66+ TF .ATC_RGB4 ,
67+ ]:
68+ enc_img = Image .tobytes ("raw" , "RGB" )
69+ tex_format = TF .RGB24
70+ # everything else defaulted to RGBA
71+ else :
72+ enc_img = img .tobytes ("raw" , "RGBA" )
73+ tex_format = TF .RGBA32
2474
25- return img . tobytes () , tex_format
75+ return enc_img , tex_format
2676
2777
2878def get_image_from_texture2d (texture_2d , flip = True ) -> Image :
@@ -38,9 +88,12 @@ def get_image_from_texture2d(texture_2d, flip=True) -> Image:
3888 image_data = copy (bytes (texture_2d .image_data ))
3989 if not image_data :
4090 return Image .new ("RGB" , (0 , 0 ))
41-
42- texture_format = texture_2d .m_TextureFormat if isinstance (texture_2d , TextureFormat ) else TextureFormat (
43- texture_2d .m_TextureFormat )
91+
92+ texture_format = (
93+ texture_2d .m_TextureFormat
94+ if isinstance (texture_2d .m_TextureFormat , TF )
95+ else TF (texture_2d .m_TextureFormat )
96+ )
4497 selection = CONV_TABLE [texture_format ]
4598
4699 if len (selection ) == 0 :
@@ -53,9 +106,12 @@ def get_image_from_texture2d(texture_2d, flip=True) -> Image:
53106
54107 if "Crunched" in texture_format .name :
55108 version = texture_2d .version
56- if (version [0 ] > 2017 or (version [0 ] == 2017 and version [1 ] >= 3 ) # 2017.3 and up
57- or texture_format == TextureFormat .ETC_RGB4Crunched
58- or texture_format == TextureFormat .ETC2_RGBA8Crunched ):
109+ if (
110+ version [0 ] > 2017
111+ or (version [0 ] == 2017 and version [1 ] >= 3 ) # 2017.3 and up
112+ or texture_format == TF .ETC_RGB4Crunched
113+ or texture_format == TF .ETC2_RGBA8Crunched
114+ ):
59115 image_data = texture2ddecoder .unpack_unity_crunch (image_data )
60116 else :
61117 image_data = texture2ddecoder .unpack_crunch (image_data )
@@ -81,15 +137,21 @@ def swap_bytes_for_xbox(image_data: bytes, build_target: BuildTarget) -> bytes:
81137 :rtype: bytes
82138 """
83139 if (
84- build_target == BuildTarget .XBOX360
140+ build_target == BuildTarget .XBOX360
85141 ): # swap bytes for Xbox confirmed,PS3 not encountered
86142 for i in range (0 , len (image_data ), 2 ):
87- image_data [i : i + 2 ] = image_data [i : i + 2 ][::- 1 ]
143+ image_data [i : i + 2 ] = image_data [i : i + 2 ][::- 1 ]
88144 return image_data
89145
90146
91147def pillow (
92- image_data : bytes , width : int , height : int , mode : str , codec : str , args , swap : tuple = None
148+ image_data : bytes ,
149+ width : int ,
150+ height : int ,
151+ mode : str ,
152+ codec : str ,
153+ args ,
154+ swap : tuple = None ,
93155) -> Image :
94156 img = (
95157 Image .frombytes (mode , (width , height ), image_data , codec , args )
@@ -149,7 +211,13 @@ def eac(image_data: bytes, width: int, height: int, fmt: list):
149211
150212
151213def half (
152- image_data : bytes , width : int , height : int , mode : str , codec : str , args , swap : tuple = None
214+ image_data : bytes ,
215+ width : int ,
216+ height : int ,
217+ mode : str ,
218+ codec : str ,
219+ args ,
220+ swap : tuple = None ,
153221) -> Image :
154222 # convert half-float to int8
155223 stream = BytesIO (image_data )
0 commit comments