Files
1960-utils/Texturing/OptimizeTextures/optimize_textures.py
2025-04-06 21:56:14 +02:00

114 lines
4.1 KiB
Python

from PIL import Image
import sys
import os
import time
import numpy as np
from multiprocessing import Pool, cpu_count, freeze_support
from concurrent.futures import ThreadPoolExecutor
import threading
def process_image(args):
input_path, export_dir, idx, total = args
try:
# Open image and check if it has alpha
currentTex = Image.open(input_path)
has_alpha = currentTex.mode == 'RGBA'
was_resized = False
if has_alpha:
# Get the alpha channel
r, g, b, a = currentTex.split()
# Convert alpha to numpy array to check its values
alpha_array = np.array(a)
# Check if alpha channel is useful (contains values other than 0 or 255)
has_useful_alpha = np.any((alpha_array > 0) & (alpha_array < 255))
if has_useful_alpha:
# If alpha is useful, keep it
if currentTex.size > (2048, 2048):
resizedTex = currentTex.resize((2048, 2048), Image.LANCZOS)
was_resized = True
else:
resizedTex = currentTex
else:
# If alpha is not useful (all black or all white), ignore it
currentTex = currentTex.convert('RGB')
if currentTex.size > (2048, 2048):
resizedTex = currentTex.resize((2048, 2048), Image.LANCZOS)
was_resized = True
else:
resizedTex = currentTex
# Create new RGBA with full opacity
rgba_image = Image.new('RGBA', resizedTex.size)
rgba_image.paste(resizedTex, (0, 0))
resizedTex = rgba_image
else:
# No alpha channel, just resize if needed
if currentTex.size > (2048, 2048):
resizedTex = currentTex.resize((2048, 2048), Image.LANCZOS)
was_resized = True
else:
resizedTex = currentTex
# Convert to RGBA with full opacity
rgba_image = Image.new('RGBA', resizedTex.size)
rgba_image.paste(resizedTex, (0, 0))
resizedTex = rgba_image
# Change the file extension to .tga
output_filename = os.path.splitext(os.path.basename(input_path))[0] + '.tga'
output_path = os.path.join(export_dir, output_filename)
# Save as TGA format
resizedTex.save(output_path, format='TGA')
# Print appropriate message based on whether the file was resized
if was_resized:
print(f"{os.path.basename(input_path)} optimized and converted to TGA ({idx}/{total})")
else:
print(f"{os.path.basename(input_path)} converted to TGA ({idx}/{total})")
except Exception as e:
print(f"Error processing {input_path} ({idx}/{total}): {e}")
def main():
if len(sys.argv) < 2:
print("Please provide the input files.")
sys.exit(1)
inputTexs = sys.argv[1:]
export_dir = os.path.join(os.path.dirname(inputTexs[0]), "optimized")
if not os.path.exists(export_dir):
os.mkdir(export_dir)
total_files = len(inputTexs)
print(f"Starting optimization of {total_files} files")
# Start timing
start_time = time.perf_counter()
args_list = [
(input_path, export_dir, idx + 1, total_files)
for idx, input_path in enumerate(inputTexs)
]
# Check if running as a frozen executable
if getattr(sys, 'frozen', False):
# Use ThreadPoolExecutor when frozen
max_workers = min(32, (os.cpu_count() or 1) + 4)
with ThreadPoolExecutor(max_workers=max_workers) as executor:
list(executor.map(process_image, args_list))
else:
# Use multiprocessing when running from console
with Pool(processes=cpu_count()) as pool:
pool.map(process_image, args_list)
# End timing
end_time = time.perf_counter()
elapsed_time = end_time - start_time
print(f"Textures successfully resized in {elapsed_time:.2f} seconds!")
time.sleep(5)
if __name__ == "__main__":
freeze_support()
main()