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")
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()