Files
workinf_Blender_Wasm/tools/web/generate-image-resource-fixtures.py
2026-08-12 04:47:48 -04:00

120 lines
4.7 KiB
Python

import os
import pathlib
import sys
import bpy
PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n"
def save_generated_png(path, name, color):
image = bpy.data.images.new(name, width=8, height=8, alpha=True)
image.generated_color = color
image.filepath_raw = str(path)
image.file_format = "PNG"
image.save()
bpy.data.images.remove(image)
def material_object(name, image, x):
mesh = bpy.data.meshes.new(f"{name}Mesh")
mesh.from_pydata([(-1, -1, 0), (1, -1, 0), (0, 1, 0)], [], [(0, 1, 2)])
obj = bpy.data.objects.new(name, mesh)
obj.location.x = x
bpy.context.scene.collection.objects.link(obj)
material = bpy.data.materials.new(f"{name}Material")
material.use_nodes = True
texture = material.node_tree.nodes.new("ShaderNodeTexImage")
texture.image = image
material.node_tree.links.new(
texture.outputs["Color"], material.node_tree.nodes["Principled BSDF"].inputs["Base Color"])
mesh.materials.append(material)
def generate_library(path):
bpy.ops.wm.read_factory_settings(use_empty=True)
image = bpy.data.images.new("LinkedLibraryTexture", width=16, height=8, alpha=True)
image.generated_color = (0.1, 0.7, 0.3, 1.0)
image.use_fake_user = True
bpy.ops.wm.save_as_mainfile(filepath=str(path), compress=False)
def generate_matrix(output_dir, library_path, tile_paths):
bpy.ops.wm.read_factory_settings(use_empty=True)
generated = bpy.data.images.new("GeneratedTexture", width=12, height=6, alpha=True)
generated.generated_type = "COLOR_GRID"
generated.generated_color = (0.2, 0.4, 0.8, 1.0)
material_object("GeneratedImageObject", generated, -4.5)
udim = bpy.data.images.load(str(tile_paths[0]), check_existing=False)
udim.name = "UDIMTexture"
udim.source = "TILED"
udim.filepath = str(tile_paths[0]).replace("1001", "<UDIM>")
if udim.tiles.get(1002) is None:
udim.tiles.new(1002, label="Second Tile")
udim.pack()
material_object("UDIMImageObject", udim, -1.5)
missing = bpy.data.images.new("MissingExternalTexture", width=1, height=1)
missing.source = "FILE"
missing.filepath = "//missing/not-present.png"
material_object("MissingImageObject", missing, 1.5)
with bpy.data.libraries.load(str(library_path), link=True) as (data_from, data_to):
if "LinkedLibraryTexture" not in data_from.images:
raise RuntimeError("linked resource library image is missing")
data_to.images = ["LinkedLibraryTexture"]
linked = data_to.images[0]
material_object("LinkedImageObject", linked, 4.5)
output = output_dir / "image_resource_matrix.blend"
bpy.ops.wm.save_as_mainfile(filepath=str(output), compress=False)
print(
"image-resource-generated "
f"fixture={output} udim_tiles={[tile.number for tile in udim.tiles]} "
f"udim_packed={len(udim.packed_files)}")
def generate_corrupt(output_dir, png_path):
bpy.ops.wm.read_factory_settings(use_empty=True)
image = bpy.data.images.load(str(png_path), check_existing=False)
image.name = "CorruptPackedTexture"
image.pack()
material_object("CorruptPackedImageObject", image, 0)
output = output_dir / "corrupt_packed_image.blend"
bpy.ops.wm.save_as_mainfile(filepath=str(output), compress=False)
data = output.read_bytes()
signature_offset = data.find(PNG_SIGNATURE)
if signature_offset < 0 or data.find(PNG_SIGNATURE, signature_offset + 1) >= 0:
raise RuntimeError("expected exactly one packed PNG signature in corrupt fixture")
output.write_bytes(data[:signature_offset] + b"BROKEN!!" + data[signature_offset + 8:])
print(f"image-resource-corrupted fixture={output} payloadOffset={signature_offset}")
def main(output_directory):
output_dir = pathlib.Path(output_directory).resolve()
support_dir = output_dir / "resources"
support_dir.mkdir(parents=True, exist_ok=True)
tile_1001 = support_dir / "udim_1001.png"
tile_1002 = support_dir / "udim_1002.png"
corrupt_png = support_dir / "corrupt_source.png"
bpy.ops.wm.read_factory_settings(use_empty=True)
save_generated_png(tile_1001, "Tile1001Source", (1.0, 0.1, 0.1, 1.0))
save_generated_png(tile_1002, "Tile1002Source", (0.1, 0.2, 1.0, 1.0))
save_generated_png(corrupt_png, "CorruptSource", (0.8, 0.2, 0.7, 1.0))
library_path = support_dir / "image_resource_library.blend"
generate_library(library_path)
generate_matrix(output_dir, library_path, (tile_1001, tile_1002))
generate_corrupt(output_dir, corrupt_png)
if __name__ == "__main__":
arguments = sys.argv[sys.argv.index("--") + 1:]
if len(arguments) != 1:
raise SystemExit("usage: blender -b --python generate-image-resource-fixtures.py -- output-directory")
main(arguments[0])