| from json.decoder import JSONDecodeError |
| from PIL import Image, ImageDraw |
| from json import loads |
|
|
| DEFAULT_MAPPING = [["0.00:0.50", "0.00:1.00", "1.0"], ["0.50:1.00", "0.00:1.00", "1.0"]] |
| COLORS = ("red", "orange", "yellow", "green", "blue", "indigo", "violet") |
|
|
|
|
| def parse_mapping(data: list) -> list: |
| mapping = [] |
|
|
| for [X, Y, W] in data: |
| if not X.strip(): |
| continue |
|
|
| mapping.append( |
| ( |
| (float(X.split(":")[0]), float(X.split(":")[1])), |
| (float(Y.split(":")[0]), float(Y.split(":")[1])), |
| float(W), |
| ) |
| ) |
|
|
| return mapping |
|
|
|
|
| def validate_mapping(data: list) -> bool: |
| try: |
| for [X, Y, W] in data: |
| if not X.strip(): |
| continue |
|
|
| assert len(X.split(":")) == 2 |
| assert len(Y.split(":")) == 2 |
|
|
| val = [] |
|
|
| val.append(float(X.split(":")[0])) |
| val.append(float(X.split(":")[1])) |
| val.append(float(Y.split(":")[0])) |
| val.append(float(Y.split(":")[1])) |
| float(W) |
|
|
| for v in val: |
| if v < 0.0 or v > 1.0: |
| raise OverflowError |
|
|
| if val[1] < val[0] or val[3] < val[2]: |
| raise IndexError |
|
|
| return True |
|
|
| except AssertionError: |
| print("\n\n[Couple] Incorrect number of : in Mapping...\n\n") |
| return False |
| except ValueError: |
| print("\n\n[Couple] Non-Number in Mapping...\n\n") |
| return False |
| except OverflowError: |
| print("\n\n[Couple] Range must be between 0.0 and 1.0...\n\n") |
| return False |
| except IndexError: |
| print('\n\n[Couple] "to" value must be larger than "from" value...\n\n') |
| return False |
|
|
|
|
| def visualize_mapping(res: str, data: list) -> Image: |
| w, h = res.split("x") |
| p_WIDTH = int(w) |
| p_HEIGHT = int(h) |
|
|
| while p_WIDTH > 1024 or p_HEIGHT > 1024: |
| p_WIDTH //= 2 |
| p_HEIGHT //= 2 |
|
|
| while p_WIDTH < 512 and p_HEIGHT < 512: |
| p_WIDTH *= 2 |
| p_HEIGHT *= 2 |
|
|
| matt = Image.new("RGBA", (p_WIDTH, p_HEIGHT), (0, 0, 0, 64)) |
|
|
| if not (validate_mapping(data)): |
| return matt |
|
|
| lnw = int(max(min(p_WIDTH, p_HEIGHT) / 128, 4.0)) |
|
|
| draw = ImageDraw.Draw(matt) |
|
|
| mapping = parse_mapping(data) |
|
|
| |
| for tile_index in range(len(mapping)): |
| color_index = tile_index % len(COLORS) |
|
|
| (X, Y, W) = mapping[tile_index] |
| x_from = int(p_WIDTH * X[0]) |
| x_to = int(p_WIDTH * X[1]) |
| y_from = int(p_HEIGHT * Y[0]) |
| y_to = int(p_HEIGHT * Y[1]) |
| |
|
|
| |
| draw.rectangle( |
| ((x_from, y_from), (x_to, y_to)), outline=COLORS[color_index], width=lnw |
| ) |
|
|
| return matt |
|
|
|
|
| def reset_mapping() -> list: |
| return DEFAULT_MAPPING |
|
|
|
|
| def add_row_above(data: list, index: int) -> list: |
| if index < 0: |
| return data |
| return data[:index] + [["0.00:1.00", "0.00:1.00", "1.0"]] + data[index:] |
|
|
|
|
| def add_row_below(data: list, index: int = None) -> list: |
| if index is None or index < 0: |
| return data + [["0.25:0.75", "0.25:0.75", "1.0"]] |
| return data[: index + 1] + [["0.25:0.75", "0.25:0.75", "1.0"]] + data[index + 1 :] |
|
|
|
|
| def del_row_select(data: list, index: int) -> list: |
| if index < 0: |
| return data |
| if len(data) == 1: |
| return [["0.0:1.0", "0.0:1.0", "1.0"]] |
| else: |
| del data[index] |
| return data |
|
|
|
|
| def on_paste(data: str) -> list: |
| try: |
| return loads(data) |
| except JSONDecodeError: |
| print("\n[Adv. Mapping] Pasting Old Infotext is not supported...\n") |
| return DEFAULT_MAPPING |
|
|
|
|
| def manual_entry(data: list, new: str, index: int) -> list: |
| if index < 0: |
| return data |
|
|
| v = [round(float(val), 2) for val in new.split(",")] |
|
|
| if v[1] < v[0]: |
| v[0], v[1] = v[1], v[0] |
| if v[3] < v[2]: |
| v[2], v[3] = v[3], v[2] |
|
|
| try: |
| data[index][0] = f"{v[0]:.2f}:{v[1]:.2f}" |
| data[index][1] = f"{v[2]:.2f}:{v[3]:.2f}" |
| except IndexError: |
| data.append([f"{v[0]:.2f}:{v[1]:.2f}", f"{v[2]:.2f}:{v[3]:.2f}", "1.0"]) |
|
|
| return data |
|
|