progress
This commit is contained in:
154
tools/make_ora.py
Normal file
154
tools/make_ora.py
Normal file
@@ -0,0 +1,154 @@
|
||||
import argparse
|
||||
import os
|
||||
import zipfile
|
||||
import tempfile
|
||||
import shutil
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
NUM_LAYERS = 4
|
||||
MASKS_PER_LAYER = 3
|
||||
NOISE_SCALES = [4, 16, 64]
|
||||
|
||||
|
||||
def noise_mask(w, h, scale):
|
||||
sw = max(1, w // scale)
|
||||
sh = max(1, h // scale)
|
||||
|
||||
noise = np.random.rand(sh, sw)
|
||||
img = Image.fromarray((noise * 255).astype(np.uint8), "L")
|
||||
img = img.resize((w, h), Image.BILINEAR)
|
||||
|
||||
return img
|
||||
|
||||
|
||||
def build_stack_xml(w, h, groups):
|
||||
image = ET.Element(
|
||||
"image",
|
||||
{"version": "0.0.3", "w": str(w), "h": str(h)}
|
||||
)
|
||||
|
||||
root_stack = ET.SubElement(image, "stack")
|
||||
|
||||
for group in groups:
|
||||
|
||||
group_el = ET.SubElement(
|
||||
root_stack,
|
||||
"stack",
|
||||
{"name": group["name"]}
|
||||
)
|
||||
|
||||
for layer in group["layers"]:
|
||||
ET.SubElement(
|
||||
group_el,
|
||||
"layer",
|
||||
{
|
||||
"name": layer["name"],
|
||||
"src": layer["src"],
|
||||
"opacity": "1.0"
|
||||
}
|
||||
)
|
||||
|
||||
return ET.tostring(image, encoding="utf-8", xml_declaration=True)
|
||||
|
||||
|
||||
def build_ora(input_png, output_ora):
|
||||
|
||||
base = Image.open(input_png).convert("RGBA")
|
||||
w, h = base.size
|
||||
|
||||
tmp = tempfile.mkdtemp()
|
||||
|
||||
try:
|
||||
|
||||
data_dir = os.path.join(tmp, "data")
|
||||
thumb_dir = os.path.join(tmp, "Thumbnails")
|
||||
|
||||
os.makedirs(data_dir)
|
||||
os.makedirs(thumb_dir)
|
||||
|
||||
groups = []
|
||||
|
||||
for i in range(NUM_LAYERS):
|
||||
|
||||
group_layers = []
|
||||
|
||||
base_path = f"data/layer_{i}.png"
|
||||
base.save(os.path.join(tmp, base_path))
|
||||
|
||||
group_layers.append({
|
||||
"name": "base",
|
||||
"src": base_path
|
||||
})
|
||||
|
||||
for j in range(MASKS_PER_LAYER):
|
||||
|
||||
mask = noise_mask(w, h, NOISE_SCALES[j])
|
||||
|
||||
mask_path = f"data/layer_{i}_mask_{j}.png"
|
||||
mask.save(os.path.join(tmp, mask_path))
|
||||
|
||||
group_layers.append({
|
||||
"name": f"mask {j}",
|
||||
"src": mask_path
|
||||
})
|
||||
|
||||
groups.append({
|
||||
"name": f"group {i}",
|
||||
"layers": group_layers
|
||||
})
|
||||
|
||||
stack_xml = build_stack_xml(w, h, groups)
|
||||
|
||||
with open(os.path.join(tmp, "stack.xml"), "wb") as f:
|
||||
f.write(stack_xml)
|
||||
|
||||
with open(os.path.join(tmp, "mimetype"), "w") as f:
|
||||
f.write("image/openraster")
|
||||
|
||||
base.save(os.path.join(tmp, "mergedimage.png"))
|
||||
|
||||
thumb = base.copy()
|
||||
thumb.thumbnail((256, 256))
|
||||
thumb.save(os.path.join(thumb_dir, "thumbnail.png"))
|
||||
|
||||
with zipfile.ZipFile(output_ora, "w") as z:
|
||||
|
||||
z.write(
|
||||
os.path.join(tmp, "mimetype"),
|
||||
"mimetype",
|
||||
compress_type=zipfile.ZIP_STORED
|
||||
)
|
||||
|
||||
for root, _, files in os.walk(tmp):
|
||||
for file in files:
|
||||
|
||||
if file == "mimetype":
|
||||
continue
|
||||
|
||||
full = os.path.join(root, file)
|
||||
rel = os.path.relpath(full, tmp)
|
||||
|
||||
z.write(full, rel)
|
||||
|
||||
finally:
|
||||
shutil.rmtree(tmp)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate ORA with grouped layers and mask layers"
|
||||
)
|
||||
|
||||
parser.add_argument("input_png")
|
||||
parser.add_argument("output_ora")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
build_ora(args.input_png, args.output_ora)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user