class ShenmueModel: HRCM = 0x4D435248 TEXD = 0x44584554 PVRT = 0x54525650 def __init__(self, filepath): self.fp = os.path.basename(filepath) self.bs = BitStream(filepath) self.iff = self.bs.readUInt() self.texOfs = self.bs.readUInt() def writePngImages(self): #Seek to texture offset self.bs.seek_set(self.texOfs) #Check offset for texture definition iff = self.bs.readUInt() if iff != ShenmueModel.TEXD: return 0 iffLen = self.bs.readUInt() #Read number of textures nbTex = self.bs.readUInt() texBase = os.path.splitext(self.fp)[0] #Loop through each texture for i in range(nbTex): #Look for pvr file header if not self.bs.find(ShenmueModel.PVRT): return 0 #Length of pvrFile pvrLen = self.bs.readUInt() pvr = PvrTexture(self.bs, False, True) bitmap = pvr.getBitmap() if len(bitmap) == 0: continue texName = "output/%s_%02d.png" % (texBase, i) print(texName) png.from_array(bitmap, 'RGBA').save(texName) return 1
class PvmArchive: #File Format Constants PVMH = 0x484D5650 PVRT = 0x54525650 def __init__(self, filepath): self.bs = BitStream(filepath) self.texList = self.readHeader() print(self.texList) def readHeader(self): #Create array texList = [] #Check for PVMH file header iff = self.bs.readUInt() if iff != PvmArchive.PVMH: return 0 #Offset of first texture entry texOfs = self.bs.readUInt() self.bs.setOffset() #Read flags and number of textures flags = self.bs.readUShort() nbTex = self.bs.readUShort() for i in range(nbTex): tex = {'id': self.bs.readUShort()} if flags & BIT_3: #Filename bit flag tex['name'] = self.bs.readStr(0x1C) if flags & BIT_2: #File format bitflag tex['format'] = self.bs.readUShort() if flags & BIT_1: #File dimensions bit flag tex['size'] = self.bs.readUShort() if flags & BIT_0: #Global Index bit flag tex['index'] = self.bs.readUInt() texList.append(tex) self.bs.seek_set(texOfs) return texList def writePngImages(self): #Loop through each texture for tex in self.texList: self.bs.seek_set(0) offset = self.bs.tell() % 4 self.bs.seek_cur(offset) #Look for PVRT file header if not self.bs.find(PvmArchive.PVRT): #If not found, raise an error print("PVRT not found: 0x%x" % self.bs.tell()) return 0 #Length of pvr texture pvrLen = self.bs.readUInt() self.bs.setOffset() #Create PvrImage to convert bitmap print("Name: %s, Pos: 0x%x" % (tex['name'], self.bs.tell())) pvr = PvrTexture(self.bs, False, True) bitmap = pvr.getBitmap() imgName = "output/" + tex['name'] + '.png' png.from_array(bitmap, 'RGBA').save(imgName) #img = Image.open(imgName) #img = img.rotate(180) #img.save(imgName) print("") return 1