Exemple #1
0
    def save(self):
        metadata = binary.BinaryWriter()
        sectionName = binary.BinaryWriter()
        sectionData = binary.BinaryWriter()
        for fileIndex, fileChunk in enumerate(self.files):
            metadata.writeU4(sectionName.tell())
            metadata.writeU4(sectionData.tell())
            metadata.writeU4(len(fileChunk.data))

            sectionName.writeString(fileChunk.name, 'shift-jis')
            if fileIndex < len(self.files):
                sectionName.write(b'\x00')

            sectionData.write(fileChunk.data)
            sectionData.dsAlign(4, 4)

        sectionName.dsAlign(4, 4)
        
        writer = binary.BinaryWriter()
        writer.write(b'LPC2')
        writer.writeU4(len(self.files))
        writer.writeU4(LaytonPack2.HEADER_BLOCK_SIZE + metadata.tell() + sectionName.tell())
        writer.writeU4(0) # EOFC, not written until end
        writer.writeU4(LaytonPack2.HEADER_BLOCK_SIZE)
        writer.writeU4(LaytonPack2.HEADER_BLOCK_SIZE + metadata.tell())
        writer.writeU4(LaytonPack2.HEADER_BLOCK_SIZE + metadata.tell() + sectionName.tell())
        writer.pad(LaytonPack2.HEADER_BLOCK_SIZE - writer.tell())
        writer.write(metadata.data)
        writer.write(sectionName.data)
        writer.write(sectionData.data)
        writer.insert(writer.tell().to_bytes(4, byteorder = 'little'), 12)

        self.data = writer.data
Exemple #2
0
    def compressRle(self, addHeader=False):
        writer = binary.BinaryWriter()
        reader = binary.BinaryReader(data = self.data)

        tempCompressedByte = b''
        tempCompressedByteLength = 0
        tempUncompressedSection = bytearray(b'')
        compressRepetition = False

        def getRleFlagByte(isCompressed, length):
            if isCompressed:
                return (0x80 | (length - 3)).to_bytes(1, byteorder = 'little')          # Enable MSB compression flag
            return (length - 1).to_bytes(1, byteorder = 'little')
        
        def writeData():
            if len(tempUncompressedSection) > 0:
                writer.write(getRleFlagByte(False, len(tempUncompressedSection)) + tempUncompressedSection)
            if tempCompressedByteLength > 0:
                writer.write(getRleFlagByte(True, tempCompressedByteLength) + tempCompressedByte)
        
        while reader.hasDataRemaining():
            tempByte = reader.read(1)
            if compressRepetition:
                if tempByte == tempCompressedByte:
                    tempCompressedByteLength += 1
                if tempCompressedByteLength == 130 or tempByte != tempCompressedByte:   # If max size has been reached or there's no more repetition
                    compressRepetition = False
                    if tempCompressedByteLength < 3:                                    # Free data if compression won't do much
                        tempUncompressedSection.extend((tempCompressedByte * tempCompressedByteLength) + tempByte)
                    else:                                                               # Else, write uncompressed section, then compressed data
                        writeData()
                        if tempByte == tempCompressedByte:                              # If the compression ended because the max block size was met,
                            tempUncompressedSection = bytearray(b'')                    #     reinitiate the uncompressed section.
                        else:
                            tempUncompressedSection = bytearray(tempByte)               # Else, continue the uncompressed section as normal.
                    tempCompressedByteLength = 0
            else:
                tempUncompressedSection.extend(tempByte)
                if len(tempUncompressedSection) == 128:                                 # Reinitiate block if max size met
                    writeData()
                    tempUncompressedSection = bytearray(b'')
                elif len(tempUncompressedSection) > 1 and tempUncompressedSection[-2] == tempUncompressedSection[-1]:
                    tempCompressedByte = tempByte
                    tempCompressedByteLength = 2
                    compressRepetition = True
                    tempUncompressedSection = tempUncompressedSection[0:-2]
        # Write anything left, as there may be blocks remaining after the reader ran out of data
        writeData()
        if addHeader:
            self.data = bytearray(File.LAYTON_1_COMPRESSION[File.COMP_RLE] + File.COMP_RLE + len(self.data).to_bytes(3, byteorder = 'little') + writer.data)
        else:
            self.data = bytearray(File.COMP_RLE + len(self.data).to_bytes(3, byteorder = 'little') + writer.data)
Exemple #3
0
    def decompressHuffman(self, offsetIn=0):
        reader = binary.BinaryReader(data = self.data)
        reader.seek(offsetIn)
        magic = reader.readUInt(1)
        if magic & 0xF0 != 0x20:
            return False
        elif magic & 0x0F == 0x04:
            useHalfByteBlocks = True
        else:
            useHalfByteBlocks = False

        tempFilesize = reader.readUInt(3)
        tempTreeLength = (reader.readUInt(1) * 2) + 1
        tree = _HuffmanTree.decode(reader, offsetIn, offsetIn + tempTreeLength + 5)
        reader.seek(offsetIn + tempTreeLength + 5)

        writer = binary.BinaryWriter()
        bitsLeft = 0
        currentNode = tree.root
        isMsbNibble = True
        while writer.tell() < tempFilesize:    # Ported from DsDecmp
            while currentNode.data == None:
                if bitsLeft == 0:
                    data = reader.readU4()
                    bitsLeft = 32
                bitsLeft-=1
                nextIsRight = (data & (1 << bitsLeft)) != 0
                if nextIsRight:
                    currentNode = currentNode.right
                else:
                    currentNode = currentNode.left
            
            if useHalfByteBlocks:
                if isMsbNibble:
                    tempIntData = int.from_bytes(currentNode.data, byteorder = 'little') << 4
                else:
                    tempIntData |= int.from_bytes(currentNode.data, byteorder = 'little')        
                    writer.writeInt(tempIntData, 1)
                isMsbNibble = not(isMsbNibble)
            else:
                writer.write(currentNode.data)
            currentNode = tree.root

        if useHalfByteBlocks and not(isMsbNibble):
            writer.writeInt(tempIntData, 1)
        self.data = writer.data[:tempFilesize]
        return True
Exemple #4
0
 def encode(self):
     writer = binary.BinaryWriter()
     writer.write(b'\x00')
     breadthQueue = [self.root]      # Ported from DsDecmp
     while len(breadthQueue) > 0:
         node = breadthQueue[0]
         breadthQueue = breadthQueue[1:]
         if node.data != None:
             writer.write(node.data)
         else:
             tempData = (len(breadthQueue) // 2) & 0x3F
             if node.left.data != None:
                 tempData = tempData | 0x80
             if node.right.data != None:
                 tempData = tempData | 0x40
             breadthQueue.extend((node.left, node.right))
             writer.writeInt(tempData, 1)
     writer.insert(((writer.tell() // 2) - 1).to_bytes(1, byteorder = 'little'), 0)
     return writer.data
Exemple #5
0
 def decompressRle(self, offsetIn=0):
     reader = binary.BinaryReader(data = self.data)
     reader.seek(offsetIn)
     if reader.readUInt(1) != File.COMP_RLE:
         return False
     tempFilesize = reader.readUInt(3)
     writer = binary.BinaryWriter()
     while writer.tell() < tempFilesize:
         flag = int.from_bytes(reader.read(1), byteorder = 'little')
         isCompressed = (flag & 0x80) > 0
         if isCompressed:
             decompressedLength = (flag & 0x7f) + 3
             decompressedData = reader.read(1)
             for _indexByte in range(decompressedLength):
                 writer.write(decompressedData)
         else:
             decompressedLength = (flag & 0x7f) + 1
             writer.write(reader.read(decompressedLength))
     self.data = writer.data
     return True
Exemple #6
0
    def save(self):
        writer = binary.BinaryWriter()
        countColours = countPilPaletteColours(self.image)
        writer.writeU4(countColours)
        for colour in pilPaletteToRgbTriplets(self.image)[0:countColours]:
            r, g, b = colour
            tempEncodedColour = (b << 7) + (g << 2) + (r >> 3)
            writer.writeU2(tempEncodedColour)

        tiles = []
        tilemap = []
        tileOptimisationMap = self.image.resize(
            (self.image.size[0] // 8, self.image.size[1] // 8),
            resample=Image.BILINEAR)
        tileOptimisationMap = tileOptimisationMap.quantize(colors=256)
        tileOptimisationDict = {}

        for yTile in range(self.image.size[1] // 8):
            # TODO - Evaluate each tile for any similar tiles
            for xTile in range(self.image.size[0] // 8):
                tempTile = self.image.crop(
                    (xTile * 8, yTile * 8, (xTile + 1) * 8, (yTile + 1) * 8))
                if tempTile in tiles:
                    tilemap.append(tiles.index(tempTile))
                else:
                    tilemap.append(len(tiles))
                    tiles.append(tempTile)

        writer.writeU4(len(tiles))
        for tile in tiles:
            writer.write(tile.tobytes())

        writer.writeU2(self.image.size[0] // 8)
        writer.writeU2(self.image.size[1] // 8)
        for key in tilemap:
            writer.writeU2(key)

        self.data = writer.data
Exemple #7
0
    def compressHuffman(self, useHalfByteBlocks = False, addHeader=False):
        reader = binary.BinaryReader(data = self.data)
        freqDict = {}
        while reader.hasDataRemaining():    # Build frequency table
            tempByte = [bytes(reader.read(1))]
            if useHalfByteBlocks:
                tempByte[0] = int.from_bytes(tempByte[0], byteorder = 'little')
                tempByte = [(tempByte[0] >> 4).to_bytes(1, byteorder = 'little'), (tempByte[0] & 0x0F).to_bytes(1, byteorder = 'little')]
            for block in tempByte:
                if block not in freqDict.keys():
                    freqDict[block] = _HuffmanCompressionNode(data = block)
                freqDict[block].weight += 1

        nodes = freqDict.values()
        if len(nodes) > 2**9:
            raise Exception("Huffman encode: Tree too long to be encoded!")

        while len(nodes) > 1:   # Build Huffman tree by grouping nodes
            nodes = sorted(nodes, key=lambda huffNode : huffNode.weight)
            newNode = _HuffmanCompressionNode(left = nodes[0], right = nodes[1], weight = nodes[0].weight + nodes[1].weight)
            newNode.left.parent = newNode
            newNode.right.parent = newNode
            nodes = nodes[2:]
            nodes.append(newNode)

        tree = _HuffmanTree(nodes[0])
        
        writer = binary.BinaryWriter()
        if useHalfByteBlocks:
            writer.writeInt(File.COMP_HUFFMAN_4_BIT, 1)
        else:
            writer.writeInt(File.COMP_HUFFMAN_8_BIT, 1)
        writer.writeInt(len(self.data), 3)
        writer.write(tree.encode())
        
        keyDict = {}
        for key in freqDict.keys():
            keyDict[freqDict[key].data] = freqDict[key].getBoolCode()
        
        reader.seek(0)
        compressionBlock = 0
        compressionBlockBitsRemaining = 32
        while reader.hasDataRemaining():    # Ported from DsDecmp
            tempByte = [reader.read(1)]
            if useHalfByteBlocks:
                tempByte[0] = int.from_bytes(tempByte[0], byteorder = 'little')
                tempByte = [(tempByte[0] >> 4).to_bytes(1, byteorder = 'little'), (tempByte[0] & 0x0F).to_bytes(1, byteorder = 'little')]
            for data in tempByte:
                for bit in keyDict[bytes(data)]:
                    if compressionBlockBitsRemaining == 0:
                        writer.writeU4(compressionBlock)
                        compressionBlock = 0
                        compressionBlockBitsRemaining = 32
                    compressionBlockBitsRemaining -= 1
                    if bit:
                        compressionBlock = compressionBlock | (1 << compressionBlockBitsRemaining)
        if compressionBlockBitsRemaining != 32:
            writer.writeU4(compressionBlock)
        writer.dsAlign(4, 4)

        if addHeader:
            if useHalfByteBlocks:
                self.data = File.LAYTON_1_COMPRESSION[File.COMP_HUFFMAN_4_BIT] + writer.data
            else:
                self.data = File.LAYTON_1_COMPRESSION[File.COMP_HUFFMAN_8_BIT] + writer.data
        else:
            self.data = writer.data