Exemplo n.º 1
0
    def _open(self):
        io = self._io
        io.seek(0)

        magic = IOHelper.read_ascii_string(io, 16)
        if magic != FILE_MAGIC:
            raise Exception('Not NPK File.')

        [count] = IOHelper.read_struct(io, 'i')

        files = []
        for i in range(count):
            offset, size = IOHelper.read_struct(io, '<2i')
            name_data = NPK._decrypt_name(io.read(256))
            try:
                name = name_data.decode('euc_kr')
                name = name[:name.find('\x00')]
            except:
                name = name_data[:name_data.find(b'\x00')].decode(
                    'euc_kr', errors='ignore')
                print('Bad Filename: ', name_data)

            file = {
                'name': name,
                'offset': offset,
                'size': size,
                'data': None,
            }
            files.append(file)

        self._files = files
Exemplo n.º 2
0
    def _indexes_to_raw(data, color_board):
        with BytesIO(data) as io_indexes:
            with BytesIO() as io_raw:
                temp = IOHelper.read_struct(io_indexes, '<B', False)
                while temp is not None:
                    [index] = temp
                    IOHelper.write_struct(io_raw, '<4B', *color_board[index])
                    temp = IOHelper.read_struct(io_indexes, '<B', False)
                data_raw = IOHelper.read_range(io_raw)

        return data_raw
Exemplo n.º 3
0
    def _open_color_board(self):
        io = self._io

        [count] = IOHelper.read_struct(io, 'i')

        colors = []
        for i in range(count):
            color = IOHelper.read_struct(io, '<4B')
            colors.append(color)

        return colors
Exemplo n.º 4
0
    def _open_images(self, count):
        io = self._io
        version = self._version
        images = []

        for i in range(count):
            image = {}

            [fmt] = IOHelper.read_struct(io, '<i')
            image['format'] = fmt

            if fmt == IMAGE_FORMAT_LINK:
                [link] = IOHelper.read_struct(io, '<i')
                image['link'] = link
            else:
                extra, w, h, size, x, y, mw, mh = IOHelper.read_struct(
                    io, '<8i')

                # fix size to real size.
                if (version == FILE_VERSION_1 or version
                        == FILE_VERSION_2) and extra == IMAGE_EXTRA_NONE:
                    size = w * h * PIX_SIZE[fmt]

                image['extra'] = extra
                image['w'] = w
                image['h'] = h
                image['size'] = size
                image['x'] = x
                image['y'] = y
                image['mw'] = mw
                image['mh'] = mh
                # temp
                image['data'] = None

                if extra == IMAGE_EXTRA_MAP_ZLIB:
                    keep_1, map_index, lx, ly, rx, ry, rotate = IOHelper.read_struct(
                        io, '<7i')
                    image['keep_1'] = keep_1
                    image['map_index'] = map_index
                    image['left'] = lx
                    image['top'] = ly
                    image['right'] = rx
                    image['bottom'] = ry
                    # horizontal, vertical
                    image['rotate'] = rotate

                if self._version == FILE_VERSION_1:
                    image['offset'] = io.tell()
                    io.seek(size, SEEK_CUR)

            images.append(image)

        return images
Exemplo n.º 5
0
    def load_file(self, index):
        file = self._files[index]

        if file['data'] is None:
            if file['size'] != 0:
                file['data'] = IOHelper.read_range(self._io, file['offset'],
                                                   file['size'])
            else:
                print('size is zero, read all data.')
                file['data'] = IOHelper.read_range(self._io, file['offset'],
                                                   -1)

        return file['data']
Exemplo n.º 6
0
    def load_file(self, index):
        file = self._files[index]

        if file['data'] is None:
            file['data'] = IOHelper.read_range(self._io, file['offset'],
                                               file['size'])

        return file['data']
Exemplo n.º 7
0
    def _png_to_nximg(data, image_format):
        data_nximg = bytes()

        with BytesIO(data) as io_png:
            with BytesIO() as io_nximg:
                png = PngImageFile(io_png)
                w, h = png.width, png.height

                if image_format == IMAGE_FORMAT_1555:
                    for y in range(h):
                        for x in range(w):
                            [r, g, b, a] = png.getpixel((x, y))
                            IOHelper.write_struct(io_nximg, "<2B",
                                                  *NXColor.to_1555(r, g, b, a))
                elif image_format == IMAGE_FORMAT_4444:
                    for y in range(h):
                        for x in range(w):
                            [r, g, b, a] = png.getpixel((x, y))
                            IOHelper.write_struct(io_nximg, "<2B",
                                                  *NXColor.to_4444(r, g, b, a))
                elif image_format == IMAGE_FORMAT_8888:
                    for y in range(h):
                        for x in range(w):
                            [r, g, b, a] = png.getpixel((x, y))
                            IOHelper.write_struct(io_nximg, "<4B", b, g, r, a)
                else:
                    raise Exception('Unsupport image format: %s' %
                                    image_format)

                data_nximg = IOHelper.read_range(io_nximg)

        return data_nximg, w, h
Exemplo n.º 8
0
def raw_to_png(data, w, h, rotate=0):
    raw_image = Image.frombytes('RGBA', (w, h), data)

    if rotate == 1:
        raw_image = raw_image.transpose(Image.ROTATE_90)

    with BytesIO() as io_png:
        raw_image.save(io_png, 'png')
        data_png = IOHelper.read_range(io_png)

    return data_png
Exemplo n.º 9
0
    def load_image_map(self, index):
        io = self._io
        map_image = self._map_images[index]

        if map_image['data'] is not None:
            return map_image['data']

        data = IOHelper.read_range(io, map_image['offset'],
                                   map_image['data_size'])
        data = zlib.decompress(data)
        map_image['data'] = data

        return data
Exemplo n.º 10
0
def dds_to_png(data, box=None, rotate=0):
    with BytesIO(data) as io_dds:
        map_image = DdsImageFile(io_dds)
        if box is not None:
            map_image = map_image.crop(box)

        if rotate == 1:
            map_image = map_image.transpose(Image.ROTATE_90)

        with BytesIO() as io_png:
            map_image.save(io_png, 'png')
            data_png = IOHelper.read_range(io_png)

    return data_png
Exemplo n.º 11
0
    def data(self, index):
        if index < len(self._files):
            file = self._files[index]  # type: dict
            if file['data'] is None:
                if not file['is_zip']:
                    data = IOHelper.read_range(self._io, file['offset'],
                                               file['data_size'])
                    file['data'] = data
                else:
                    raise Exception('Unsupport File.')
            else:
                data = file['data']

            return data
Exemplo n.º 12
0
    def save(self, io=None):
        # load all file data.
        self.load_all()
        files = self._files

        if io is None:
            io = self._io

        # clean file.
        io.seek(0)
        io.truncate()

        head_data = b''

        # build head in memory.
        with BytesIO() as io_head:
            IOHelper.write_ascii_string(io_head, FILE_MAGIC)
            count = len(files)
            IOHelper.write_struct(io_head, 'i', count)

            # count file offset.
            # magic(16) + count(4) + info(264 * n) + hash(32)
            offset = 52 + count * 264

            for file in files:
                file['offset'] = offset
                file['size'] = len(file['data'])
                IOHelper.write_struct(io_head, '<2i', file['offset'],
                                      file['size'])
                if isinstance(file['name'], str):
                    name_data = file['name'].encode(encoding='euc_kr')
                elif isinstance(file['name'], bytes):
                    name_data = file['name']
                else:
                    raise Exception('Filename type Error: %s(%s)' %
                                    (file['name'], type(file['name'])))
                name = NPK._decrypt_name(name_data)
                io_head.write(name)

                offset += file['size']

            head_data = IOHelper.read_range(io_head)

        io.write(head_data)
        # write hash.
        io.write(
            hashlib.sha256(head_data[:len(head_data) // 17 * 17]).digest())

        for file in files:
            io.seek(file['offset'])
            io.write(file['data'])
Exemplo n.º 13
0
    def load(io: FileIO):
        instance = MPK(io)
        magic = IOHelper.read_ascii_string(io, 4)
        if magic == MPK_MAGIC:
            version, count = IOHelper.read_struct(io, '<2i')
            io.seek(52, SEEK_CUR)
            instance.set_version(version)
            for i in range(count):
                is_zip, index, offset, data_size, zip_size = IOHelper.read_struct(
                    io, '<2i3q')
                name_data = io.read(224)
                name = name_data[:name_data.find(b'\x00')].decode(
                    encoding='ascii')
                instance.insert_file({
                    'is_zip': is_zip != 0,
                    'index': index,
                    'offset': offset,
                    'data_size': data_size,
                    'zip_size': zip_size,
                    'name': name,
                    'data': None,
                })

        return instance
Exemplo n.º 14
0
    def load_image(self, index):
        io = self._io
        image = self._images[index]

        if image['format'] == IMAGE_FORMAT_LINK:
            return None

        if image['data'] is not None:
            return image['data']

        data = IOHelper.read_range(io, image['offset'], image['size'])

        if image['extra'] == IMAGE_EXTRA_ZLIB:
            data = zlib.decompress(data)
        elif image['extra'] != IMAGE_EXTRA_NONE:
            raise Exception('Unknown Extra Type.', image['extra'])

        image['data'] = data

        return data
Exemplo n.º 15
0
    def _open_map_images(self, map_count):
        io = self._io

        map_images = []
        for i in range(map_count):
            keep, fmt, index, data_size, raw_size, w, h = IOHelper.read_struct(
                io, '<7i')
            map_image = {
                'keep': keep,
                'format': fmt,
                'index': index,
                'data_size': data_size,
                'raw_size': raw_size,
                'w': w,
                'h': h,
                'data': None,
            }
            map_images.append(map_image)

        return map_images
Exemplo n.º 16
0
    def save(self, io=None):
        # load all file data.
        self.load_all()
        files = self._files

        if io is None:
            io = self._io

        # clean file.
        io.seek(0)
        io.truncate()

        # build head in memory.
        with BytesIO() as io_head:
            IOHelper.write_ascii_string(io_head, FILE_MAGIC)
            count = len(files)
            IOHelper.write_struct(io_head, 'i', count)

            # count file offset.
            # magic(16) + count(4) + info(264 * n) + hash(32)
            offset = 52 + count * 264

            for file in files:
                IOHelper.write_struct(io_head, '<2i', file['offset'],
                                      file['size'])
                name = NPK._decrypt_name(file['name'].encode(encoding='ascii'))
                io_head.write(name)

                offset += file['size']

            head_data = IOHelper.read_range(io_head)

        io.write(head_data)
        # write hash.
        io.write(
            hashlib.sha256(head_data[:len(head_data) // 17 * 17]).digest())

        for file in files:
            io.seek(file['offset'])
            io.write(file['data'])
Exemplo n.º 17
0
 def print_exception(type, value, tb):
     with StringIO() as io:
         traceback.print_exception(type, value, tb, file=io)
         err_str = IOHelper.read_range(io)
     print(err_str)
     QMessageBox.warning(None, '错误:', err_str)
Exemplo n.º 18
0
    def _open(self):
        io = self._io
        io.seek(0)

        magic = IOHelper.read_ascii_string(io, 18)
        if magic == FILE_MAGIC or magic == FILE_MAGIC_OLD:
            if magic == FILE_MAGIC:
                # images_size without version,count,extra(color_board,map_images)...
                [images_size] = IOHelper.read_struct(io, 'i')
            else:
                # unknown.
                [unknown] = IOHelper.read_struct(io, 'h')
                images_size = 0

            # keep: 0
            [keep, version, img_count] = IOHelper.read_struct(io, '<3i')
            self._version = version

            if version == FILE_VERSION_4:
                # single color board.
                self._color_board = self._open_color_board()
            elif version == FILE_VERSION_5:
                # map image.
                map_count, file_size = IOHelper.read_struct(io, '<2i')
                self._color_board = self._open_color_board()
                self._map_images = self._open_map_images(map_count)
            elif version == FILE_VERSION_6:
                # multiple color board.
                color_boards = []

                [color_board_count] = IOHelper.read_struct(io, 'i')
                for i in range(color_board_count):
                    color_board = self._open_color_board()
                    color_boards.append(color_board)

                self._color_boards = color_boards

            images = self._open_images(img_count)
            self._images = images

            # count image offset.
            if version != FILE_VERSION_1:
                # behind header.
                if images_size != 0:
                    offset = images_size + 32
                else:
                    offset = io.tell()

                if version == FILE_VERSION_5:
                    map_images = self._map_images
                    for i in range(len(map_images)):
                        map_image = map_images[i]
                        map_image['offset'] = offset
                        offset += map_image['data_size']
                for i in range(len(images)):
                    image = images[i]
                    if image['format'] != IMAGE_FORMAT_LINK and image[
                            'extra'] != IMAGE_EXTRA_MAP_ZLIB:
                        image['offset'] = offset
                        offset += image['size']
        else:
            raise Exception('Not IMG File.')
Exemplo n.º 19
0
    def save(self, io=None):
        self.load_all()
        images = self._images
        color_board = self._color_board
        color_boards = self._color_boards
        map_images = self._map_images
        version = self._version

        images_data = []

        # compress data, get size, add to data_list.
        if version == FILE_VERSION_5:
            for map_image in sorted(map_images):
                data = map_image['data']
                map_image['raw_size'] = len(data)
                data = zlib.compress(data)
                map_image['data_size'] = len(data)

                images_data.append(data)
        else:
            for image in images:
                if image['format'] != IMAGE_FORMAT_LINK:
                    data = image['data']
                    if image['extra'] == IMAGE_EXTRA_ZLIB or image[
                            'extra'] == IMAGE_EXTRA_MAP_ZLIB:
                        data = zlib.compress(data)
                    image['size'] = len(data)

                    images_data.append(data)

        images_size = self._save_count_images_size()
        file_size = self._save_count_file_size(images_size, images_data)

        if io is None:
            io = self._io

        io.seek(0)
        io.truncate()

        with BytesIO() as io_head:
            if version == FILE_VERSION_1:
                IOHelper.write_ascii_string(io_head, FILE_MAGIC_OLD)
                # TODO: unknown, now be zero.
                IOHelper.write_struct(io_head, 'h', 0)
            else:
                # images_size
                IOHelper.write_ascii_string(io_head, FILE_MAGIC)
                IOHelper.write_struct(io_head, 'i', images_size)

            # keep, version, img_count
            IOHelper.write_struct(io_head, '<3i', 0, version, len(images))

            is_ver5 = version == FILE_VERSION_5

            if is_ver5:
                # map_count, file_size
                IOHelper.write_struct(io_head, '<2i', len(map_images),
                                      file_size)

            if version == FILE_VERSION_4 or is_ver5:
                # color_count
                IOHelper.write_struct(io_head, 'i', len(color_board))
                for color in color_board:
                    # color
                    IOHelper.write_struct(io_head, '<4B', *color)

            if is_ver5:
                for map_image in map_images:
                    IOHelper.write_struct(io_head, '<7i', map_image['keep'],
                                          map_image['format'],
                                          map_image['index'],
                                          map_image['data_size'],
                                          map_image['raw_size'],
                                          map_image['w'], map_image['h'])

            if version == FILE_VERSION_6:
                # color_board count.
                IOHelper.write_struct(io_head, 'i', len(color_boards))
                for color_board_v6 in color_boards:
                    # color_count
                    IOHelper.write_struct(io_head, 'i', len(color_board_v6))
                    for color in color_board_v6:
                        # color
                        IOHelper.write_struct(io_head, '<4B', *color)

            for image in images:
                # format
                IOHelper.write_struct(io_head, 'i', image['format'])
                if image['format'] == IMAGE_FORMAT_LINK:
                    # link
                    IOHelper.write_struct(io_head, 'i', image['link'])
                else:
                    # extra, w, h, size, x, y, mw, mh
                    IOHelper.write_struct(io_head, '<8i', image['extra'],
                                          image['w'], image['h'],
                                          image['size'], image['x'],
                                          image['y'], image['mw'], image['mh'])
                    if image['extra'] == IMAGE_EXTRA_MAP_ZLIB:
                        # keep_1, map_index, left, top, right, bottom, rotate
                        IOHelper.write_struct(io_head, '<7i', image['keep_1'],
                                              image['map_index'],
                                              image['left'], image['top'],
                                              image['right'], image['bottom'],
                                              image['rotate'])

            head_data = IOHelper.read_range(io_head)

        io.write(head_data)

        for data in images_data:
            io.write(data)
Exemplo n.º 20
0
    def _nximg_to_raw(data, image_format, w=None, box=None):
        data_raw = bytes()
        ps = PIX_SIZE[image_format]

        with BytesIO(data) as io_nximg:
            with BytesIO() as io_raw:
                if image_format == IMAGE_FORMAT_1555:
                    if box is not None and w is not None:
                        [left, top, right, bottom] = box
                        for y in range(top, bottom):
                            o = y * w * ps
                            for x in range(left, right):
                                io_nximg.seek(o + x * ps)
                                temp = IOHelper.read_struct(
                                    io_nximg, '<2B', False)
                                if temp is not None:
                                    [v1, v2] = temp
                                    IOHelper.write_struct(
                                        io_raw, '<4B',
                                        *NXColor.from_1555(v1, v2))
                    else:
                        temp = IOHelper.read_struct(io_nximg, '<2B', False)
                        while temp is not None:
                            [v1, v2] = temp
                            IOHelper.write_struct(io_raw, '<4B',
                                                  *NXColor.from_1555(v1, v2))

                            temp = IOHelper.read_struct(io_nximg, '<2B', False)
                elif image_format == IMAGE_FORMAT_4444:
                    if box is not None and w is not None:
                        [left, top, right, bottom] = box
                        for y in range(top, bottom):
                            o = y * w * ps
                            for x in range(left, right):
                                io_nximg.seek(o + x * ps)
                                temp = IOHelper.read_struct(
                                    io_nximg, '<2B', False)
                                if temp is not None:
                                    [v1, v2] = temp
                                    IOHelper.write_struct(
                                        io_raw, '<4B',
                                        *NXColor.from_4444(v1, v2))
                    else:
                        temp = IOHelper.read_struct(io_nximg, '<2B', False)
                        while temp is not None:
                            [v1, v2] = temp
                            IOHelper.write_struct(io_raw, '<4B',
                                                  *NXColor.from_4444(v1, v2))

                            temp = IOHelper.read_struct(io_nximg, '<2B', False)
                elif image_format == IMAGE_FORMAT_8888:
                    if box is not None and w is not None:
                        [left, top, right, bottom] = box
                        for y in range(top, bottom):
                            o = y * w * ps
                            for x in range(left, right):
                                io_nximg.seek(o + x * ps)
                                temp = IOHelper.read_struct(
                                    io_nximg, '<4B', False)
                                if temp is not None:
                                    [b, g, r, a] = temp
                                    IOHelper.write_struct(
                                        io_raw, '<4B', r, g, b, a)
                    else:
                        temp = IOHelper.read_struct(io_nximg, '<4B', False)
                        while temp is not None:
                            [b, g, r, a] = temp
                            IOHelper.write_struct(io_raw, '<4B', r, g, b, a)

                            temp = IOHelper.read_struct(io_nximg, '<4B', False)
                else:
                    raise Exception('Unsupport Image Format.', image_format)

                data_raw = IOHelper.read_range(io_raw)

        return data_raw