import os, json from wand.image import Image from wand.drawing import Drawing from shortuuid import uuid from math import sqrt def split(image, width, height, pieces): image_file = os.path.basename(image) name = os.path.splitext(image_file)[0] output = f"chaospuzzles/puzzles/{name}" print(f"Creating the {name} folder") try: os.makedirs(output) os.makedirs(f"{output}/pieces") os.makedirs(f"{output}/clusters") except OSError: pass print("Calculating rows and columns... ", end="") piece_side, rows, columns = area_to_pieces(width, height, pieces) print(f"Done!") print(f"{rows * columns} pieces, {rows} rows by {columns} columns") print("Splitting in tiles... ", end="") # copy the source image to the puzzles folder and split it into tiles with Image(filename=image) as img: img.save(filename=f"{output}/{image_file}") for y in range(columns): for x in range(rows): x_start = x * piece_side y_start = y * piece_side x_end = x_start + piece_side y_end = y_start + piece_side with img[x_start:x_end, y_start:y_end] as piece: piece.save(filename=f"{output}/pieces/{name}-{x}-{y}.jpg") print("Done!") # create an id for each piece and store it into a pieces.json file and generate the retro image for the puzzle print("Calculating the ID for each piece... ", end="") pieces = [] with Image(width=width, height=height) as retro: draw = Drawing() draw.font_size = 11 draw.text_alignment = "center" for x in range(rows): row = [] for y in range(columns): # generate a random ID for each piece ID = uuid()[:4] # write the id in the center of each piece draw.text( int(x * piece_side + piece_side / 2), int(y * piece_side + piece_side / 2), f"{name}\n{ID}", ) # store the id in the pieces dictionary row.append(ID) pieces.append(row) print("Done!") print("Generating the picture to print behind the puzzle... ", end="") draw(retro) retro.save(filename=f"{output}/{name}_retro.png") print("Done!") print("Writing pieces.json ", end="") with open(f"{output}/pieces.json", "w") as file: file.write(json.dumps(pieces)) print("Done!") print("Writing adjacents.json ", end="") adjacents = {} for x in range(rows): for y in range(columns): current = pieces[x][y] if y > 0: n = pieces[x][y - 1] else: n = None if y < columns - 1: s = pieces[x][y + 1] else: s = None if x > 0: w = pieces[x - 1][y] else: w = None if x < rows - 1: e = pieces[x + 1][y] else: e = None adjacents[current] = (n, e, s, w) with open(f"{output}/adjacents.json", "w") as file: file.write(json.dumps(adjacents)) print("Done!") # info.json file with all the info about the puzzle print("Writing info.json ", end="") with open(f"{output}/info.json", "w") as file: file.write( json.dumps( { "name": name, "rows": rows, "columns": columns, "width": width, "height": height, "image": image_file, "clusters": [], } ) ) print("Done!") def area_to_pieces(width, height, pieces): area = width * height piece_area = area / pieces piece_side = sqrt(piece_area) pieces_h = int(width / piece_side) pieces_v = int(height / piece_side) return (int(piece_side), pieces_h, pieces_v) # test split( "chaospuzzles/static/img/katamari.jpg", 3368, # width 2380, # height 500, # pieces )