# Builds 1024² gen canvases from the per-part UV masks: the island silhouette # (padded bbox, aspect-true, centered) as parchment white on black. The exact # same transform is recomputed in composite.gd to map results back into UV space. # Run headless: # tinqs.console.exe --headless --path tattoo-test -s res://prep.gd extends SceneTree const MASK_DIR := "C:/Users/CAN/tinqs-ltd/tattoo-test/masks/" const OUT_DIR := "C:/Users/CAN/tinqs-ltd/tattoo-test/gen-v4/" const PARTS := ["arm_r", "arm_l", "leg_r", "leg_l", "chest", "back"] const CANVAS := 1024 const MARGIN := 48 # silhouette keeps this distance from canvas edges const PAD := 24 # px padding around the mask bbox in UV space const PARCHMENT := Color(0.97, 0.94, 0.88) func _init() -> void: DirAccess.make_dir_recursive_absolute(OUT_DIR) for part: String in PARTS: var mask := Image.load_from_file(MASK_DIR + "mask_" + part + ".png") var t := transform_for(mask) var rect: Rect2i = t["rect"] var s: float = t["scale"] var off: Vector2 = t["offset"] var canvas := Image.create(CANVAS, CANVAS, false, Image.FORMAT_RGBA8) canvas.fill(Color(0, 0, 0)) for cy in CANVAS: for cx in CANVAS: var mx := int((cx - off.x) / s) + rect.position.x var my := int((cy - off.y) / s) + rect.position.y if mx < rect.position.x or my < rect.position.y \ or mx >= rect.end.x or my >= rect.end.y: continue if mask.get_pixel(mx, my).r > 0.5: canvas.set_pixel(cx, cy, PARCHMENT) var path := OUT_DIR + "canvas_" + part + ".png" canvas.save_png(path) print("CANVAS %s rect=%s scale=%.4f offset=%.1f,%.1f saved=%s" % [part, rect, s, off.x, off.y, path]) quit() # shared with composite.gd — keep in sync static func transform_for(mask: Image) -> Dictionary: var size := mask.get_width() var minx := size var maxx := -1 var miny := size var maxy := -1 for y in size: for x in size: if mask.get_pixel(x, y).r > 0.5: minx = mini(minx, x) maxx = maxi(maxx, x) miny = mini(miny, y) maxy = maxi(maxy, y) var rect := Rect2i( maxi(minx - PAD, 0), maxi(miny - PAD, 0), mini(maxx + PAD + 1, size) - maxi(minx - PAD, 0), mini(maxy + PAD + 1, size) - maxi(miny - PAD, 0)) var s := minf( float(CANVAS - 2 * MARGIN) / rect.size.x, float(CANVAS - 2 * MARGIN) / rect.size.y) var off := Vector2( (CANVAS - rect.size.x * s) * 0.5, (CANVAS - rect.size.y * s) * 0.5) return {"rect": rect, "scale": s, "offset": off}