164 lines
4.6 KiB
Python
164 lines
4.6 KiB
Python
import bpy
|
|
import math
|
|
import numpy as np
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
def alpha_to_color(pixels_data, color):
|
|
"""Convert Alpha to WhiteBG"""
|
|
new_pixels_data = []
|
|
for i in pixels_data:
|
|
height, width, array_d = i.shape
|
|
mask = i[:, :, 3:]
|
|
background = np.array([color[0], color[1], color[2], 1], dtype=np.float32)
|
|
background = np.tile(background, (height * width))
|
|
background = np.reshape(background, (height, width, 4))
|
|
new_pixels_data.append(i * mask + background * (1 - mask))
|
|
# print(new_pixels_data)#Dbg
|
|
return new_pixels_data
|
|
|
|
|
|
def create_array(height, width):
|
|
return np.zeros((height * width * 4), dtype=np.float32)
|
|
|
|
|
|
def read_pixels_data(img, source_height, source_width):
|
|
img_w, img_h = img.size
|
|
|
|
if img_w != source_width:
|
|
scale = abs(img_w / source_width)
|
|
img.scale(int(img_w / scale), int(img_h / scale))
|
|
img_w, img_h = img.size
|
|
|
|
array = create_array(img_h, img_w)
|
|
img.pixels.foreach_get(array)
|
|
array = array.reshape(img_h, img_w, 4)
|
|
|
|
if array.shape[0] != source_height:
|
|
# print('ARRAY SHAPE', array.shape[:], source_height)
|
|
missing_height = int(abs(source_height - img_h) / 2)
|
|
empty_array = create_array(missing_height, source_width)
|
|
empty_array = empty_array.reshape(missing_height, source_width, 4)
|
|
array = np.vstack((empty_array, array, empty_array))
|
|
|
|
return array.reshape(source_height, source_width, 4)
|
|
|
|
|
|
def create_final(output_name, pixels_data, final_height, final_width):
|
|
# print('output_name: ', output_name)
|
|
|
|
new_img = bpy.data.images.get(output_name)
|
|
if new_img:
|
|
bpy.data.images.remove(new_img)
|
|
|
|
new_img = bpy.data.images.new(output_name, final_width, final_height)
|
|
new_img.generated_color = (0, 0, 0, 0)
|
|
|
|
# print('pixels_data: ', pixels_data)
|
|
new_img.pixels.foreach_set(pixels_data)
|
|
|
|
return new_img
|
|
|
|
|
|
def guess_input_format(img_list):
|
|
for i in img_list:
|
|
if i.size[0] == i.size[1]:
|
|
return i.size
|
|
|
|
|
|
def format_files(files, catalog_data):
|
|
img_dict = {}
|
|
for k, v in catalog_data.items():
|
|
if "/" not in k:
|
|
continue
|
|
img_dict[v["name"]] = [f for f in files if v["name"] in f]
|
|
|
|
return img_dict
|
|
|
|
|
|
def mosaic_export(
|
|
files,
|
|
catalog_data,
|
|
row=2,
|
|
columns=2,
|
|
auto_calculate=True,
|
|
bg_color=(
|
|
0.18,
|
|
0.18,
|
|
0.18,
|
|
),
|
|
resize_output=100,
|
|
):
|
|
|
|
img_dict = format_files(files, catalog_data)
|
|
|
|
for cat, files_list in img_dict.items():
|
|
|
|
if not files_list:
|
|
continue
|
|
|
|
for i in bpy.data.images:
|
|
bpy.data.images.remove(i)
|
|
|
|
img_list = []
|
|
|
|
chars = Path(files_list[0]).parts[-4]
|
|
output_dir = str(Path(files_list[0]).parent.parent)
|
|
|
|
ext = "jpg"
|
|
output_name = f"{chars}_{cat}.{ext}"
|
|
|
|
for img in files_list:
|
|
img_list.append(bpy.data.images.load(img, check_existing=True))
|
|
|
|
for i in img_list:
|
|
i.colorspace_settings.name = "Raw"
|
|
|
|
if auto_calculate:
|
|
rows = int(math.sqrt(len(img_list)))
|
|
columns = math.ceil(len(img_list) / rows)
|
|
|
|
if rows * columns < len(img_list):
|
|
raise AttributeError("Grid too small for number of images")
|
|
|
|
src_w, src_h = img_list[0].size
|
|
final_w = src_w * columns
|
|
final_h = src_h * rows
|
|
|
|
img_pixels = [read_pixels_data(img, src_h, src_w) for img in img_list]
|
|
|
|
# Check if there is enough "data" to create an horizontal stack
|
|
##It not, create empty array
|
|
h_stack = []
|
|
total_len = rows * columns
|
|
if len(img_pixels) < total_len:
|
|
for i in range(total_len - len(img_pixels)):
|
|
img_pixels.append(create_array(src_h, src_w).reshape(src_h, src_w, 4))
|
|
|
|
img_pixels = alpha_to_color(img_pixels, bg_color)
|
|
for i in range(0, len(img_pixels), columns):
|
|
h_stack.append(np.hstack(img_pixels[i : i + columns]))
|
|
if rows > 1:
|
|
combined_stack = np.vstack(h_stack[::-1])
|
|
else:
|
|
combined_stack = np.hstack((h_stack[:]))
|
|
|
|
combined_img = create_final(
|
|
output_name, combined_stack.flatten(), final_h, final_w
|
|
)
|
|
|
|
if resize_output != 100:
|
|
w, h = combined_img.size
|
|
combined_img.scale(w * (resize_output * 0.01), h * (resize_output * 0.01))
|
|
|
|
combined_img.filepath_raw = "/".join([output_dir, output_name])
|
|
combined_img.file_format = "JPEG"
|
|
combined_img.save()
|
|
|
|
print(
|
|
f"""
|
|
Image saved: {combined_img.filepath_raw}
|
|
"""
|
|
)
|