137 lines
5.4 KiB
Python
137 lines
5.4 KiB
Python
import struct
|
||
import os
|
||
import sys
|
||
from PIL import Image
|
||
|
||
def extract_textures_from_file(filename, output_dir="textures"):
|
||
"""
|
||
Извлекает текстуры из файла в отдельные PNG файлы с индексированными цветами
|
||
"""
|
||
|
||
# Создаем директорию для выходных файлов
|
||
os.makedirs(output_dir, exist_ok=True)
|
||
|
||
# Читаем файл
|
||
with open(filename, 'rb') as f:
|
||
fil = f.read()
|
||
|
||
# Получаем список смещений текстур
|
||
tx_offsets = []
|
||
first_addr = struct.unpack('<I', fil[0:4])[0]
|
||
tx_offsets.append(first_addr)
|
||
|
||
reader = 4
|
||
while reader < first_addr:
|
||
addr = struct.unpack('<I', fil[reader:reader+4])[0]
|
||
if addr == 0:
|
||
break
|
||
tx_offsets.append(addr)
|
||
reader += 4
|
||
|
||
print(f"Найдено {len(tx_offsets)} текстурных блоков")
|
||
|
||
# Обрабатываем каждую текстуру
|
||
for a in range(len(tx_offsets) - 1):
|
||
try:
|
||
reader = tx_offsets[a]
|
||
|
||
# Читаем CLUT и информацию об изображении
|
||
clut_mode = struct.unpack('<I', fil[reader:reader+4])[0]
|
||
image_mode = struct.unpack('<I', fil[reader+4:reader+8])[0]
|
||
reader += 8
|
||
|
||
# Читаем CLUT (палитру цветов)
|
||
clut_size = struct.unpack('<I', fil[reader:reader+4])[0]
|
||
clut_x = struct.unpack('<H', fil[reader+4:reader+6])[0]
|
||
clut_y = struct.unpack('<H', fil[reader+6:reader+8])[0]
|
||
clut_w = struct.unpack('<H', fil[reader+8:reader+10])[0]
|
||
clut_h = struct.unpack('<H', fil[reader+10:reader+12])[0]
|
||
reader += 12
|
||
|
||
# Читаем данные палитры
|
||
current_clut = []
|
||
clut_data_remains = clut_size - 12
|
||
while clut_data_remains > 0:
|
||
color_code = struct.unpack('<H', fil[reader:reader+2])[0]
|
||
current_clut.append(color_code)
|
||
clut_data_remains -= 2
|
||
reader += 2
|
||
|
||
# Читаем информацию об изображении
|
||
image_size = struct.unpack('<I', fil[reader:reader+4])[0]
|
||
image_x = struct.unpack('<H', fil[reader+4:reader+6])[0] * 2
|
||
image_y = struct.unpack('<H', fil[reader+6:reader+8])[0] - 256
|
||
image_w = struct.unpack('<H', fil[reader+8:reader+10])[0] * 2
|
||
image_h = struct.unpack('<H', fil[reader+10:reader+12])[0]
|
||
reader += 12
|
||
|
||
print(f"Текстура {a}: {image_w}x{image_h}, CLUT: {len(current_clut)} цветов")
|
||
|
||
# Создаем палитру для PIL
|
||
palette = []
|
||
for color_code in current_clut:
|
||
# Конвертируем из формата PS1 (15-bit) в 24-bit RGB
|
||
r = (color_code & 0x1F) * 8
|
||
g = ((color_code & 0x3E0) >> 5) * 8
|
||
b = ((color_code & 0x7C00) >> 10) * 8
|
||
palette.extend([r, g, b])
|
||
|
||
# Дополняем палитру до 256 цветов (если нужно)
|
||
while len(palette) < 768: # 256 цветов * 3 канала
|
||
palette.append(0)
|
||
|
||
# Создаем изображение с индексированными цветами
|
||
img_data = []
|
||
image_data_remains = image_size - 12
|
||
|
||
for y in range(image_h):
|
||
row = []
|
||
for x in range(image_w):
|
||
if image_data_remains > 0:
|
||
color_index = fil[reader]
|
||
row.append(color_index)
|
||
reader += 1
|
||
image_data_remains -= 1
|
||
else:
|
||
row.append(0) # Заполняем нулями если данные закончились
|
||
img_data.append(row)
|
||
|
||
# Создаем изображение из данных
|
||
img = Image.new('P', (image_w, image_h))
|
||
|
||
# Заполняем пиксели
|
||
for y in range(image_h):
|
||
for x in range(image_w):
|
||
if y < len(img_data) and x < len(img_data[y]):
|
||
img.putpixel((x, y), img_data[y][x])
|
||
|
||
# Устанавливаем палитру
|
||
img.putpalette(palette)
|
||
|
||
# Сохраняем как PNG
|
||
output_filename = os.path.join(output_dir, f"texture_{a:03d}.png")
|
||
img.save(output_filename, 'PNG')
|
||
|
||
print(f"Сохранено: {output_filename}")
|
||
|
||
except Exception as e:
|
||
print(f"Ошибка при обработке текстуры {a}: {e}")
|
||
continue
|
||
|
||
def main():
|
||
if len(sys.argv) != 2:
|
||
print("Использование: python extract.py <имя_файла>")
|
||
sys.exit(1)
|
||
|
||
filename = sys.argv[1]
|
||
|
||
if not os.path.exists(filename):
|
||
print(f"Файл {filename} не найден!")
|
||
sys.exit(1)
|
||
|
||
print(f"Обрабатываю файл: {filename}")
|
||
extract_textures_from_file(filename)
|
||
print("Готово!")
|
||
|
||
if __name__ == "__main__":
|
||
main() |