HearthSim / UnityPack

Python deserialization library for Unity3D Asset format
https://hearthsim.info/
MIT License
720 stars 153 forks source link

Support for ETC_RGB4? #16

Open mcorner opened 7 years ago

mcorner commented 7 years ago
Traceback (most recent call last):
  File "/usr/local/bin/unityextract", line 146, in <module>
    main()
  File "/usr/local/bin/unityextract", line 143, in main
    exit(app.run())
  File "/usr/local/bin/unityextract", line 56, in run
    self.handle_asset(asset)
  File "/usr/local/bin/unityextract", line 127, in handle_asset
    image = d.image
  File "/usr/local/lib/python3.5/site-packages/unitypack/engine/texture.py", line 151, in image
    raise NotImplementedError("Unimplemented format %r" % (self.format))
NotImplementedError: Unimplemented format <TextureFormat.ETC_RGB4: 34>
jleclanche commented 7 years ago

An ETC decoder needs to be added to Pillow for this.

WedgeTalon commented 7 years ago

Python and Unity are both completely new to me, but perhaps you could bundle a decoder:

http://pillow.readthedocs.io/en/latest/handbook/writing-your-own-file-decoder.html

using this tool: http://malideveloper.arm.com/resources/tools/mali-gpu-texture-compression-tool/

and this gist: https://gist.github.com/yin8086/6ce83c5d8e4cf1ac9879

as reference?

jleclanche commented 7 years ago

Thanks. ill take a look.

Edit: Uh, that's no good. It's subprocessing the texture to a separate executable...

WedgeTalon commented 7 years ago

Drat, I didn't catch that.

KevinHru commented 7 years ago

Hi !

And what about that : https://github.com/hglm/texgenpack ?

It is C code but maybe something is possible ?

SirNate0 commented 3 years ago

There is a python library supporting unpacking ETC (and other) images if you are open to using another besides Pillow. Specifically, tex2img. Though I saw in PR #52 that someone may be trying to add Pillow support.

In any case, here's some code using it to unpack ETC and ETC2 images that unityextract doesn't support if anyone finds it useful. I modified unityextract to save as a pickle the image when the format was unsupported first.

# Line 134 of unityextract
                try:
                    image = d.image
                except NotImplementedError as e:
                    print("WARNING: Texture format not implemented. Skipping %r." % (filename),e)
                    print('\tWriting Data Directly')
                    python_data = pickle.dumps(d._obj)
                    self.write_to_file(d.name + ".pickle", python_data, mode="wb")
                    continue

The decompression code:

Show Code ``` #!/usr/bin/python3 import pickle,enum with open('ETC_Image.pickle','rb') as f: data = pickle.load(f) #print(data.keys()) odict_keys(['m_Name', 'm_Width', 'm_Height', 'm_CompleteImageSize', 'm_TextureFormat', 'm_MipCount', 'm_IsReadable', 'm_ReadAllowed', 'm_ImageCount', 'm_TextureDimension', 'm_TextureSettings', 'm_LightmapFormat', 'm_ColorSpace', 'image data', 'm_StreamData']) from enum import IntEnum class TextureFormat(IntEnum): # From UnityPack Alpha8 = 1 ARGB4444 = 2 RGB24 = 3 RGBA32 = 4 ARGB32 = 5 RGB565 = 7 # Direct3D DXT1 = 10 DXT5 = 12 RGBA4444 = 13 BGRA32 = 14 BC6H = 24 BC7 = 25 DXT1Crunched = 28 DXT5Crunched = 29 # PowerVR PVRTC_RGB2 = PVRTC_2BPP_RGB = 30 PVRTC_RGBA2 = PVRTC_2BPP_RGBA = 31 PVRTC_RGB4 = PVRTC_4BPP_RGB = 32 PVRTC_RGBA4 = PVRTC_4BPP_RGBA = 33 # Ericsson (Android) ETC_RGB4 = 34 ATC_RGB4 = 35 ATC_RGBA8 = 36 # Adobe ATF ATF_RGB_DXT1 = 38 ATF_RGBA_JPG = 39 ATF_RGB_JPG = 40 # Ericsson EAC_R = 41 EAC_R_SIGNED = 42 EAC_RG = 43 EAC_RG_SIGNED = 44 ETC2_RGB = 45 ETC2_RGBA1 = 46 ETC2_RGBA8 = 47 # OpenGL / GLES ASTC_RGB_4x4 = 48 ASTC_RGB_5x5 = 49 ASTC_RGB_6x6 = 50 ASTC_RGB_8x8 = 51 ASTC_RGB_10x10 = 52 ASTC_RGB_12x12 = 53 ASTC_RGBA_4x4 = 54 ASTC_RGBA_5x5 = 55 ASTC_RGBA_6x6 = 56 ASTC_RGBA_8x8 = 57 ASTC_RGBA_10x10 = 58 ASTC_RGBA_12x12 = 59 @property def pixel_format(self): if self == TextureFormat.RGB24: return "RGB" elif self == TextureFormat.ARGB32: return "ARGB" elif self == TextureFormat.RGB565: return "RGB;16" elif self == TextureFormat.Alpha8: return "A" elif self == TextureFormat.RGBA4444: return "RGBA;4B" elif self == TextureFormat.ARGB4444: return "RGBA;4B" return "RGBA" for k in data.keys(): if k in ('image data',):#, 'm_StreamData'): print(k,len(data[k])) else: print(k,data[k]) tf = TextureFormat(data['m_TextureFormat']) print(tf) from tex2img import * # Formats ETC1_RGB_NO_MIPMAPS = 0 ETC2PACKAGE_RGB_NO_MIPMAPS = 1 ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD = 2 ETC2PACKAGE_RGBA_NO_MIPMAPS = 3 ETC2PACKAGE_RGBA1_NO_MIPMAPS = 4 ETC2PACKAGE_R_NO_MIPMAPS = 5 ETC2PACKAGE_RG_NO_MIPMAPS = 6 ETC2PACKAGE_R_SIGNED_NO_MIPMAPS = 7 ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS = 8 ETC2PACKAGE_sRGB_NO_MIPMAPS = 9 ETC2PACKAGE_sRGBA_NO_MIPMAPS = 10 ETC2PACKAGE_sRGBA1_NO_MIPMAPS = 11 # TODO: SRGB Check ex_unpack = { TextureFormat.ETC_RGB4 : lambda data,w,h : decompress_etc(data,w,h,ETC1_RGB_NO_MIPMAPS) TextureFormat.ETC2_RGB : lambda data,w,h : decompress_etc(data,w,h,ETC2PACKAGE_RGB_NO_MIPMAPS) TextureFormat.ETC2_RGBA1 : lambda data,w,h : decompress_etc(data,w,h,ETC2PACKAGE_RGBA1_NO_MIPMAPS) TextureFormat.ETC2_RGBA8 : lambda data,w,h : decompress_etc(data,w,h,ETC2PACKAGE_RGBA_NO_MIPMAPS) } from PIL import Image if tf in ex_unpack: img_data,w,h = data['image data'],data['m_Width'],data['m_Height'] name = data['m_Name'] image_data = ex_unpack[tf](img_data,w,h) image = Image.frombytes('RGBA', (w,h), image_data, 'raw') image.save(open(name+'.png','wb'), format="png") ```