示例#1
0
def etc(image_data: bytes, width: int, height: int, fmt: list):
    if fmt[0] == 1:
        image_data = texture2ddecoder.decode_etc1(image_data, width, height)
    elif fmt[0] == 2:
        if fmt[1] == "RGB":
            image_data = texture2ddecoder.decode_etc2(image_data, width, height)
        elif fmt[1] == "A1":
            image_data = texture2ddecoder.decode_etc2a1(image_data, width, height)
        elif fmt[1] == "A8":
            image_data = texture2ddecoder.decode_etc2a8(image_data, width, height)
    else:
        raise NotImplementedError("unknown etc mode")
    return Image.frombytes("RGBA", (width, height), image_data, "raw", "BGRA")
示例#2
0
 def get_resource(self, path_id: int):
     obj = self.asset.objects[path_id]
     if obj.type == 'Texture2D':
         data = obj.read()
         if len(data.data) == 0:
             logger.warning("Data doesn't exist")
             return Resource()
         # logger.warning(f"{self.container[path_id]} is {data.format.name}")
         if data.format.name == 'ETC_RGB4':
             # 이미지 포맷: ETC1 -> RGB(A)
             # Alpha 채널도 나오긴 하는데 의미 없어서 자름
             decoded = texture2ddecoder.decode_etc1(data.data, data.width,
                                                    data.height)
             im = np.frombuffer(decoded,
                                np.uint8).reshape(data.height, data.width,
                                                  4)
             im = cv2.flip(im, 0)
             im_a = self.get_alpha_image(path_id)
             # if we have alpha, try to merge
             if im_a is not None:
                 # 알파 채널 이미지가 원래 이미지와 크기가 다른 경우가 있는 경우를 위한 리사이징
                 if im_a.shape[:2] != (data.height, data.width):
                     im_a = cv2.resize(im_a,
                                       None,
                                       fx=data.height / im_a.shape[0],
                                       fy=data.width / im_a.shape[1])
                 im[:, :, 3] = im_a
                 return ResImage(im, data.name)
             else:
                 return ResImage(cv2.cvtColor(im, cv2.COLOR_BGRA2BGR),
                                 data.name)
         elif data.format.name == 'ETC_RGB4Crunched':
             decrunched = texture2ddecoder.unpack_unity_crunch(data.data)
             # 이미지 포맷: ETC1 -> RGB(A)
             # Alpha 채널도 나오긴 하는데 의미 없어서 자름
             decoded = texture2ddecoder.decode_etc1(decrunched, data.width,
                                                    data.height)
             im = np.frombuffer(decoded,
                                np.uint8).reshape(data.height, data.width,
                                                  4)
             im = cv2.flip(im, 0)
             # attempt to find alpha image
             im_a = self.get_alpha_image(path_id)
             # if we have alpha, try to merge
             if im_a is not None:
                 # 알파 채널 이미지가 원래 이미지와 크기가 다른 경우가 있는 경우를 위한 리사이징
                 if im_a.shape[:2] != (data.height, data.width):
                     im_a = cv2.resize(im_a,
                                       None,
                                       fx=data.height / im_a.shape[0],
                                       fy=data.width / im_a.shape[1])
                 im[:, :, 3] = im_a
                 return ResImage(im, data.name)
             else:
                 return ResImage(cv2.cvtColor(im, cv2.COLOR_BGRA2BGR),
                                 data.name)
         elif data.format.name == "ETC2_RGBA8":
             decoded = texture2ddecoder.decode_etc2a8(
                 data.data, data.width, data.height)
             im = np.frombuffer(decoded,
                                np.uint8).reshape(data.height, data.width,
                                                  4)
             return ResImage(cv2.flip(im, 0), data.name)
         elif data.format.name == 'ETC2_RGBA8Crunched':
             decrunched = texture2ddecoder.unpack_unity_crunch(data.data)
             decoded = texture2ddecoder.decode_etc2a8(
                 decrunched, data.width, data.height)
             im = np.frombuffer(decoded,
                                np.uint8).reshape(data.height, data.width,
                                                  4)
             return ResImage(cv2.flip(im, 0), data.name)
         elif data.format.name == 'RGBA32':
             data_size = data.height * data.width * 4
             # 이미지 포맷: RGBA32 -> RGBA
             im = np.frombuffer(data.data[:data_size],
                                dtype=np.uint8).reshape(
                                    data.height, data.width, 4)
             # cv2에서는 BGRA 색역을 쓰기 때문에 변한
             im = cv2.cvtColor(im, cv2.COLOR_RGBA2BGRA)
             # 소전은 뒤집힌거 쓰니까 이미지 뒤집기
             im = cv2.flip(im, 0)
             return ResImage(im, data.name)
         elif data.format.name == 'RGBA4444':
             shape = (data.height, data.width)
             data_size = data.height * data.width * 2
             # numpy array로 변환 (아직 1차원 배열)
             im_array = np.frombuffer(data.data[:data_size], dtype=np.uint8)
             # 비트 시프트 + 값 곱하기 후 3차원 배열로 만든 후 채널별로 분리
             # 0x0 -> 0x00, 0x1 -> 0x11, ... , 0xF -> 0xFF
             im_b, im_r = cv2.split(
                 (np.bitwise_and(im_array >> 4, 0x0f) * 17).reshape(
                     *shape, 2))
             im_a, im_g = cv2.split(
                 (np.bitwise_and(im_array, 0x0f) * 17).reshape(*shape, 2))
             return ResImage(
                 cv2.flip(cv2.merge((im_b, im_g, im_r, im_a)), 0),
                 data.name)
         elif data.format.name == 'ARGB4444':
             shape = (data.height, data.width)
             data_size = data.height * data.width * 2
             # numpy array로 변환 (아직 1차원 배열)
             im_array = np.frombuffer(data.data[:data_size], dtype=np.uint8)
             # 비트 시프트 + 값 곱하기 후 3차원 배열로 만든 후 채널별로 분리
             # 0x0 -> 0x00, 0x1 -> 0x11, ... , 0xF -> 0xFF
             im_g, im_a = cv2.split(
                 (np.bitwise_and(im_array >> 4, 0x0f) * 17).reshape(
                     *shape, 2))
             im_b, im_r = cv2.split(
                 (np.bitwise_and(im_array, 0x0f) * 17).reshape(*shape, 2))
             return ResImage(
                 cv2.flip(cv2.merge((im_b, im_g, im_r, im_a)), 0),
                 data.name)
         elif data.format.name == 'ARGB32':
             # 이미지 포맷: ARGB32 -> RGBA
             # 채널별로 분리 후 다시 합침
             # 이상하게 원래 크기 이상으로 뭔가 데이터가 있는데 딱히 필요는 없어서 모양으로 계산해서 필요한 부분만 슬라이싱
             data_size = data.height * data.width * 4
             im_array = np.frombuffer(data.data[:data_size],
                                      dtype=np.uint8).reshape(
                                          data.height, data.width, 4)
             im_array = cv2.cvtColor(cv2.flip(im_array, 0),
                                     cv2.COLOR_RGBA2BGRA)
             return ResImage(im_array, data.name)
         elif data.format.name == 'Alpha8':
             # 알파 이미지
             shape = (data.height, data.width)
             return ResImage(
                 cv2.flip(
                     np.frombuffer(data.data,
                                   dtype=np.uint8).reshape(shape), 0),
                 data.name)
         elif data.format.name == 'RGB24':
             # 이미지 포맷: RGB24 -> RGB
             # 간단하게 처리
             data_size = data.height * data.width * 3
             im_rgb = np.frombuffer(data.data[:data_size],
                                    dtype=np.uint8).reshape(
                                        data.height, data.width, 3)
             # attempt to find alpha image
             im_a = self.get_alpha_image(path_id)
             if im_a is not None:
                 # 알파 채널 이미지가 원래 이미지와 크기가 다른 경우가 있는 경우를 위한 리사이징
                 if im_a.shape[:2] != (data.height, data.width):
                     im_a = cv2.resize(im_a,
                                       None,
                                       fx=data.height / im_a.shape[0],
                                       fy=data.width / im_a.shape[1])
                 im_a = cv2.flip(
                     im_a, 0
                 )  # will end up flipping alpha twice below.. is there a better way?
                 im_bgra = cv2.cvtColor(im_rgb, cv2.COLOR_RGB2BGRA)
                 try:
                     im_bgra[:, :, 3] = im_a
                 except ValueError:
                     # skip alpha if we can't merge it back, for some odd reason this happens on certain files
                     # (cafe chair texture.. etc) as of Dec 22, 2018 on both TW, and CN beta version
                     logger.warning(
                         "dimension mismatch between converted rgb/alpha data"
                     )
                 return ResImage(cv2.flip(im_bgra, 0), data.name)
             else:
                 return ResImage(
                     cv2.flip(cv2.cvtColor(im_rgb, cv2.COLOR_RGB2BGR), 0),
                     data.name)
         elif data.format.name == 'RGB565':
             im_array = np.frombuffer(data.data, dtype=np.uint8).reshape(
                 data.height, data.width, 2)
             return ResImage(
                 cv2.flip(cv2.cvtColor(im_array, cv2.COLOR_BGR5652BGR), 0),
                 data.name)
         elif data.format.name == 'PVRTC_RGBA4' or data.format.name == 'PVRTC_RGBA2':
             decoded = texture2ddecoder.decode_pvrtc(
                 data.data, data.width, data.height)
             im = np.frombuffer(decoded,
                                np.uint8).reshape(data.height, data.width,
                                                  4)
             return ResImage(cv2.flip(im, 0), data.name)
         else:
             # 모르는 포맷은 그냥 건너뜀
             raise Exception('Unexpected texture format ' +
                             str(data.format))
             return Resource(data.name)
     elif obj.type == 'TextAsset':
         data = obj.read()
         # is there a better way?
         if "/live2d/" in self.container.get(path_id):
             return ResL2D(data.bytes, data.name)
         elif isinstance(data.script, str):
             # 데이터가 일반 텍스트(txt)인경우 str 로 리턴
             return ResText(data.script, data.name)
         else:
             # 아니면 Bytes 형태로 리턴
             return ResBytes(data.bytes, data.name)
     else:
         return Resource()