Skip to content

Commit

Permalink
Fixed AYUV and YUV, added BC5_UNORM, R8G8_UNORM
Browse files Browse the repository at this point in the history
 - Fixed AYUV and YUV broken colors
 - Added new image codecs support:
    - BC5_SNORM, R8G8_UNORM

 - All supported codecs - 72
  • Loading branch information
gmh4589 committed Sep 3, 2024
1 parent 1db1906 commit bd00a62
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 40 deletions.
6 changes: 5 additions & 1 deletion codec_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ def __init__(self):
self.rgb = b''

def dds_save(self, y, x, codec, name, data):
self.__getattribute__(codec)()

try:
self.__getattribute__(codec)()
except AttributeError:
self.B8G8R8A8_UNORM()

with open(f'{name}.dds', 'wb') as dds_file:
dds_file.write(b'DDS\x20\x7C\x00\x00\x00' +
Expand Down
51 changes: 33 additions & 18 deletions converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,31 +63,46 @@ def conv_2BPP(data):
return split_array.tobytes()


def AYUV2ARGB(ayuv_bytes, height, width, colors):
def crop_data(data, height, width, colors=4):

bytes_len = width * height * colors

if len(ayuv_bytes) < bytes_len:
if len(data) < bytes_len:
return b''

ayuv_bytes = ayuv_bytes[:bytes_len]
ayuv_image = np.frombuffer(ayuv_bytes, dtype=np.uint8).reshape((height, width, colors))
cropped = data[:bytes_len]
print(len(data), len(cropped))
return np.frombuffer(cropped, dtype=np.uint8).reshape((height, width, colors))


def crop_color(image_data, height, width, a_order=0):
image_data = crop_data(image_data, height, width)
A, R, G, B = image_data[:, :, 0], image_data[:, :, 1], image_data[:, :, 2], image_data[:, :, 3]
order_map = {0: (R, G, B), 1: (A, G, B), 2: (A, R, B), 3: (A, R, G)}
rgb_image = np.stack(order_map.get(a_order, (R, G, B)), axis=-1)

return rgb_image.tobytes()

if colors == 4:
A = ayuv_image[:, :, 0] # Альфа-канал

Y = ayuv_image[:, :, colors - 3]
U = ayuv_image[:, :, colors - 2].astype(np.float32)
V = ayuv_image[:, :, colors - 1].astype(np.float32)
def R4G4B4G4_to_RGB8(image_data, height, width, order='RGBG'):
image = crop_data(image_data, height, width, 2)

R = ((Y + 1.402 * V) / 2.402).clip(0, 255).astype(np.uint8)
G = ((Y - 0.344136 * U - 0.714136 * V) + 269.85936).clip(0, 255).astype(np.uint8)
B = ((Y + 1.772 * U) / 2.772).clip(0, 255).astype(np.uint8)
if order == 'RGBG':
R4 = image[:, :, 0] << 4
G4_1 = image[:, :, 0] >> 4
B4 = image[:, :, 1] << 4
G4_2 = image[:, :, 1] >> 4
elif order == 'GRGB':
G4_1 = image[:, :, 0] << 4
R4 = image[:, :, 0] >> 4
G4_2 = image[:, :, 1] << 4
B4 = image[:, :, 1] >> 4

if colors == 4:
argb_image = np.stack((R, G, B, A), axis=-1)
else:
argb_image = np.stack((R, G, B), axis=-1)
# Преобразование 4 бит в 8 бит (расширение старших бит)
R8 = R4 << 4
G8 = (G4_1 >> 4) | (G4_2 << 4) # Усредняем два зеленых канала
B8 = B4 << 4

argb_image = np.flip(argb_image)
rgb_image = np.stack((R8, G8, B8), axis=-1)

return argb_image.tobytes()
return rgb_image.tobytes()
55 changes: 35 additions & 20 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ def hex_offset_set(self):
self.offset_hexData.setText(hex_offset.replace(char, ''))

def createList(self):
# работает: 70
# проблемы: 45
# работает: 72
# проблемы: 40

currentChange = self.bppInput.currentText()
# bpp = str(int(int(currentChange.replace('BPP', '')) / 3))
Expand All @@ -141,10 +141,10 @@ def createList(self):
# 5-bit RGB with 1-bit alpha chanel, R5G6B5, 16-bit Grayscale
case '16BPP':
codecsList = ['B5G6R5_UNORM', 'B5G5R5A1_UNORM', 'B4G4R4A4_UNORM', 'R16_FLOAT', 'R16_UNORM', 'LA', 'PA',
'I;16L', 'I;16B'
'I;16L', 'I;16B', 'R8G8_UNORM',
# TODO На проверку:
# 'Y216', 'Y416', 'R8G8_SINT', 'R8G8_SNORM', 'R8G8_UINT', 'R8G8_UNORM', 'R16_SINT',
# 'R16_SNORM', 'R16_UINT',
# 'Y216', 'Y416', 'R8G8_SINT', 'R8G8_SNORM', 'R8G8_UINT', 'R16_SINT',
# 'R16_SNORM', 'R16_UINT', 'G4R4G4B4_UNORM', 'R4G4B4G4_UNORM',
]
# 8-bit RGB, HSL, HSV, LAB, YCbCr
case '24BPP':
Expand All @@ -157,18 +157,17 @@ def createList(self):
codecsList = ['RGBA', 'RBGA', 'GBRA', 'GRBA', 'BRGA', 'BGRA', 'ARGB', 'ARBG', 'AGBR', 'AGRB', 'ABRG',
'ABGR', 'CMYK', 'B8G8R8A8_UNORM_SRGB', 'B8G8R8X8_UNORM_SRGB', 'B8G8R8A8_UNORM',
'B8G8R8X8_UNORM', 'R10G10B10A2_UNORM', 'R10G10B10_XR_BIAS_A2_UNORM', 'R32_FLOAT',
'I', 'F', 'AYUV'
'I', 'F', 'AYUV',
# TODO На проверку:
# 'G8R8_G8B8_UNORM', 'R8G8_B8G8_UNORM',
# 'R8G8B8A8_SINT', 'R8G8B8A8_SNORM', 'R8G8B8A8_UINT', 'R8G8B8A8_UNORM',
# 'R8G8B8A8_UNORM_SRGB', 'R9G9B9E5_SHAREDEXP', 'R10G10B10A2_UINT', 'R11G11B10_FLOAT',
# 'R8G8B8A8_SINT', 'R8G8B8A8_SNORM', 'R8G8B8A8_UINT', 'R9G9B9E5_SHAREDEXP',
# 'R10G10B10A2_UNORM', 'R11G11B10_FLOAT',
# 'R10G10B10A2_UNORM', 'R16G16_FLOAT', 'R16G16_SINT', 'R16G16_SNORM', 'R16G16_UINT',
# 'R16G16_UNORM', 'R32_SINT', 'R32_UINT',
]
case '64BPP':
codecsList = ['R16G16B16A16_FLOAT', 'R16G16B16A16_UINT', 'R16G16B16A16_UNORM',
# TODO На проверку:
# 'R16G16B16A16_SINT', 'R16G16B16A16_SNORM', 'R16G16B16A16_SNORM', 'R32G32_FLOAT',
# 'R16G16B16A16_SINT', 'R16G16B16A16_SNORM', 'R32G32_FLOAT',
# 'R32G32_SINT', 'R32G32_UINT',
]
case '96BPP':
Expand All @@ -182,11 +181,11 @@ def createList(self):
# 'R32G32B32A32_SINT', 'R32G32B32A32_UINT'
]
case 'DirectX':
codecsList = ['BC1_UNORM', 'BC2_UNORM', 'BC3_UNORM', 'BC4_UNORM', 'BC5_UNORM', 'BC6H_SF16',
codecsList = ['BC1_UNORM', 'BC2_UNORM', 'BC3_UNORM', 'BC4_UNORM', 'BC5_SNORM', 'BC5_UNORM', 'BC6H_SF16',
'BC6H_UF16', 'BC7_UNORM', 'BC7_UNORM_SRGB', 'BC1_UNORM_SRGB', 'BC2_UNORM_SRGB',
'BC3_UNORM_SRGB',
# TODO На проверку:
# 'BC4_SNORM', 'BC5_SNORM',
# 'BC4_SNORM',
]
case _:
codecsList = []
Expand Down Expand Up @@ -257,11 +256,13 @@ def draw_image(self):
new_image = Image.frombytes(codec, (width, height), image_data)

if codec == 'P':
try:
with open('temp/palette.dat', 'rb') as p_file:
pal = sum([[int.from_bytes(p_file.read(1)) for _ in range(3)] for _ in range(256)], [])

with open('temp/palette.dat', 'rb') as p_file:
pal = sum([[int.from_bytes(p_file.read(1)) for _ in range(3)] for _ in range(256)], [])

new_image.putpalette(pal)
new_image.putpalette(pal)
except FileNotFoundError:
pass

if rotate == self.local["mirror_h"]:
new_image = ImageOps.mirror(new_image)
Expand Down Expand Up @@ -297,13 +298,14 @@ def colorWrapper(self, image_data):
height = int(self.heightInput.value())
codec = readCodec
self.ext = 'webp'
print(len(image_data))

match readCodec:

case 'RGB' | 'HSV' | 'CMYK' | 'YCbCr' | 'RGBA' | 'RGB' | 'PA' | 'LA' | 'F' | \
'RGBX' | 'RGBa' | 'L' | 'I;16L' | 'I;16B' | 'I' | '':
pass
case 'ATI1' | 'ATI2':
case 'ATI1' | 'ATI2' | 'BC5_SNORM' | 'BC5_UNORM' | 'R8G8_UNORM':
self.dds_save(width, height, readCodec)
image = Image.open(f'{self.temp_path}\\temp.dds')
image.save(f'{self.temp_path}\\temp.webp')
Expand All @@ -326,9 +328,22 @@ def colorWrapper(self, image_data):
image_data = image_data.tobytes()
case 'LAB':
self.ext = 'tif'
case 'AYUV' | 'YUV':
codec = 'RGBA' if 'A' in readCodec else 'RGB'
image_data = converter.AYUV2ARGB(image_data, height, width, 4 if 'A' in readCodec else 3)
case 'AYUV':
codec = 'YCbCr'

try:
image_data = image_data[:height * width * 4]
image_data = converter.crop_color(bytes(reversed(list(image_data))), height, width, 0)
new_image = Image.frombytes(codec, (width, height), image_data).rotate(180)
image_data = new_image.tobytes()
except TypeError:
pass
case 'G4R4G4B4_UNORM' | 'R4G4B4G4_UNORM':
codec = 'RGB'
order = readCodec.replace('_UNORM', '').replace('4', '')
image_data = converter.R4G4B4G4_to_RGB8(image_data, height, width, order)
case 'YCbCr' | 'YUV':
codec = 'YCbCr'
case 'HSL':
codec = 'HSV'
image_data = converter.HSL2HSV(image_data)
Expand Down
12 changes: 11 additions & 1 deletion whats_new.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
- Added new image types support:
September 2, 2024

- Fixed AYUV and YUV broken colors
- Added new image codecs support:
- BC5_SNORM, R8G8_UNORM

- All supported codecs - 72

September 2, 2024

- Added new image codecs support:
- Image with palette
- ATI1, ATI2
- AYUV, YUV (need fixes, broken colors)
Expand Down

0 comments on commit bd00a62

Please sign in to comment.