import json import copy import math import numpy numpy.set_printoptions(suppress=True) def gen_id(): new_id = 42 while True: yield new_id new_id += 1 def gen_y(): y = 7 while True: yield y y += 3 new_id = gen_id() y_position = gen_y() new_nodes = {} shift_left = 32 def set_transform(node, transform): x_axis = transform[0] y_axis = transform[1] # Assuming there is no vertical shear angle = math.atan2( x_axis[1], x_axis[0]) (sin, cos) = math.sin(angle), math.cos(angle) scale_x = x_axis[0] / cos if math.fabs(cos) > 1e-10 else x_axis[1] / sin shear_x = (sin * y_axis[1] + cos * y_axis[0]) / (sin * sin * scale_x + cos * cos * scale_x); if not numpy.isfinite(shear_x): shear_x = 0.; scale_y = (y_axis[1] - scale_x * sin * shear_x) / cos if math.fabs(cos) > 1e-10 else (scale_x * cos * shear_x - y_axis[0]) / sin translation = transform[2][:2] node["inputs"][1] = {"Value": { "tagged_value": { "DVec2": [translation[0], translation[1]] }, "exposed": False}} node["inputs"][2] = {"Value": { "tagged_value": { "F32": angle }, "exposed": False}} node["inputs"][3] = {"Value": { "tagged_value": { "DVec2": [scale_x, scale_y] }, "exposed": False}} node["inputs"][4] = {"Value": { "tagged_value": { "DVec2": [shear_x, 0] }, "exposed": False}} node["inputs"][5] = {"Value": { "tagged_value": { "DVec2": [0,0] }, "exposed": False}} def to_transform(transform): mat = transform["matrix2"] translation = transform["translation"] return numpy.array([[mat[0], mat[1], 0], [mat[2], mat[3], 0], [translation[0], translation[1], 1]]) def update_layer(layer, indent, layer_node_id, next_id, opacity): data = layer["data"] opacity = opacity * layer["opacity"] y = next(y_position) output = None if "Folder" in data: new_layer_ids = list(map(lambda x, _: x, new_id, data["Folder"]["layers"])) output = new_layer_ids[0] insert_transform = "transform" in layer and (numpy.identity(3) != to_transform(layer["transform"])).any() if insert_transform: node = { "name": "Transform", "implementation": {"Unresolved":{"name": "graphene_core::transform::TransformNode<_, _, _, _, _, _>"}}, "manual_composition":{"Concrete":{"name":"graphene_core::transform::Footprint","size":72,"align":8}}, "metadata": {"position": [-indent-8,y]}, "skip_deduplication": False, "path": None, "manual_composition": {"Concrete": {"name": "graphene_core::transform::Footprint","size": 72,"align": 8}}, "inputs":[{"Node":{"node_id":output,"output_index":0,"lambda":False}}, None, None, None, None, None] } transform_id = next(new_id) new_nodes[str(transform_id)] = node output = transform_id set_transform(node, to_transform(layer["transform"])) indent += 8 for index, layer in enumerate(reversed(data["Folder"]["layers"])): next_index = None if index +1 < len(new_layer_ids): next_index = new_layer_ids[index+1] update_layer(layer, indent + 5, new_layer_ids[index], next_index, opacity) if insert_transform: indent -= 8 if "Layer" in data: network = data["Layer"]["network"] nodes = set(filter(lambda old_id: network["nodes"][old_id]["name"] != "Output", set(network["nodes"]))) new_ids = dict(zip(map(lambda id: int(id), nodes), new_id)) output_node = network["nodes"][str(network["outputs"][0]["node_id"])] shift_left = output_node["metadata"]["position"][0] output = new_ids[int(output_node["inputs"][0]["Node"]["node_id"])] for old_id in nodes: node = network["nodes"][old_id] for node_input in node["inputs"]: if "Node" in node_input: node_input["Node"]["node_id"] = new_ids[node_input["Node"]["node_id"]] if node["name"] == "Transform": node["implementation"]={"Unresolved":{"name": "graphene_core::transform::TransformNode<_, _, _, _, _, _>"}} node["manual_composition"]={"Concrete":{"name":"graphene_core::transform::Footprint","size":72,"align":8}} if node["name"] == "Shape": if not any(map(lambda x: network["nodes"][x]["name"] == "Cull", nodes)): node["metadata"]["position"][1] = y node["metadata"]["position"][0] -= shift_left + 8 + indent if opacity != 1: node["metadata"]["position"][0] -= 8 shape = next(new_id) cull = next(new_id) new_nodes[str(shape)] = copy.deepcopy(node) node["name"] = "Cull" node["inputs"] = [{"Node":{"node_id":shape,"output_index":0,"lambda":False}}] node["manual_composition"] = {"Concrete":{"name":"graphene_core::transform::Footprint","size":72,"align":8}} node["has_primary_output"] = True node["implementation"] = {"Unresolved":{"name":"graphene_core::transform::CullNode<_>"}} if opacity != 1: node["metadata"]["position"][0] += 8 new_nodes[str(cull)] = copy.deepcopy(node) node["name"] = "Opacity" node["inputs"] = [{"Node":{"node_id":cull,"output_index":0,"lambda":False}}, {"Value":{"tagged_value":{"F32":opacity * 100},"exposed":False}}] node["manual_composition"] = None node["has_primary_output"] = True node["implementation"] = {"Unresolved":{"name":"graphene_core::raster::OpacityNode<_>"}} node["metadata"]["position"][0] += 8 + shift_left + indent node["metadata"]["position"][1] = y node["metadata"]["position"][0] -= shift_left + indent new_nodes[str(new_ids[int(old_id)])] = node assert(output == None or str(output) in new_nodes) node_to_input = lambda node_id: {"Node": {"node_id": node_id,"output_index": 0,"lambda": False}} if node_id else {"Value":{"tagged_value":{"GraphicGroup":{"elements":[],"opacity":1.0,"transform":[1.0,0.0,0.0,1.0,0.0,0.0]}},"exposed":True}} node = { "name": "Layer", "inputs": [ node_to_input(output), { "Value": { "tagged_value": { "String": layer["name"] or "Untitled" }, "exposed": False } }, { "Value": { "tagged_value": { "BlendMode": layer["blend_mode"] }, "exposed": False } }, { "Value": { "tagged_value": { "F32": 100.0 }, "exposed": False } }, { "Value": { "tagged_value": { "Bool": True }, "exposed": False } }, { "Value": { "tagged_value": { "Bool": False }, "exposed": False } }, { "Value": { "tagged_value": { "Bool": False }, "exposed": False } }, node_to_input(next_id) ], "manual_composition": None, "has_primary_output": True, "implementation": { "Network": { "inputs": [ 0, 2, 2, 2, 2, 2, 2, 2 ], "outputs": [ { "node_id": 2, "node_output_index": 0 } ], "nodes": { "1": { "name": "Monitor", "inputs": [ { "Node": { "node_id": 0, "output_index": 0, "lambda": False } } ], "manual_composition": { "Concrete": { "name": "graphene_core::transform::Footprint", "size": 72, "align": 8 } }, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_core::memo::MonitorNode<_, _, _>" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": True, "world_state_hash": 0, "path": None }, "2": { "name": "ConstructLayer", "inputs": [ { "Node": { "node_id": 1, "output_index": 0, "lambda": False } }, { "Network": { "Fn": [ { "Concrete": { "name": "graphene_core::transform::Footprint", "size": 72, "align": 8 } }, { "Concrete": { "name": "graphene_core::graphic_element::GraphicGroup", "size": 12, "align": 4 } } ] } } ], "manual_composition": { "Concrete": { "name": "graphene_core::transform::Footprint", "size": 72, "align": 8 } }, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_core::ConstructLayerNode<_, _, _, _, _, _, _, _>" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None }, "0": { "name": "To Graphic Element", "inputs": [ { "Network": { "Generic": "T" } } ], "manual_composition": None, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_core::ToGraphicElementData" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None } }, "disabled": [], "previous_outputs": None } }, "metadata": { "position": [ -indent, y ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None } new_nodes[str(layer_node_id)] = node def migrate(name, new_name): global new_id, new_id ,y_position, new_nodes new_id = gen_id() y_position = gen_y() new_nodes = {} with open(name) as f: document = json.load(f) layer = document["document_legacy"]["root"] data = layer["data"] new_layer_ids = list(map(lambda x, _: x, new_id, data["Folder"]["layers"])) for index, layer in enumerate(reversed(data["Folder"]["layers"])): next_index = None if index + 1 < len(new_layer_ids): next_index = new_layer_ids[index+1] update_layer(layer, 5, new_layer_ids[index], next_index, 1) new_nodes["0"] = { "name": "Output", "inputs": [ { "Node": { "node_id": 42, "output_index": 0, "lambda": False } }, { "Network": { "Concrete": { "name": "graphene_core::application_io::EditorApi", "size": 176, "align": 8 } } } ], "manual_composition": None, "has_primary_output": True, "implementation": { "Network": { "inputs": [ 3, 0 ], "outputs": [ { "node_id": 3, "node_output_index": 0 } ], "nodes": { "1": { "name": "Create Canvas", "inputs": [ { "Node": { "node_id": 0, "output_index": 0, "lambda": False } } ], "manual_composition": None, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_std::wasm_application_io::CreateSurfaceNode" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": True, "world_state_hash": 0, "path": None }, "3": { "name": "RenderNode", "inputs": [ { "Node": { "node_id": 0, "output_index": 0, "lambda": False } }, { "Network": { "Fn": [ { "Concrete": { "name": "graphene_core::transform::Footprint", "size": 72, "align": 8 } }, { "Generic": "T" } ] } }, { "Node": { "node_id": 2, "output_index": 0, "lambda": False } } ], "manual_composition": None, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_std::wasm_application_io::RenderNode<_, _, _>" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None }, "2": { "name": "Cache", "inputs": [ { "Node": { "node_id": 1, "output_index": 0, "lambda": False } } ], "manual_composition": { "Concrete": { "name": "()", "size": 0, "align": 1 } }, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_core::memo::MemoNode<_, _>" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None }, "0": { "name": "EditorApi", "inputs": [ { "Network": { "Concrete": { "name": "graphene_core::application_io::EditorApi", "size": 176, "align": 8 } } } ], "manual_composition": None, "has_primary_output": True, "implementation": { "Unresolved": { "name": "graphene_core::ops::IdentityNode" } }, "metadata": { "position": [ 0, 0 ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None } }, "disabled": [], "previous_outputs": None } }, "metadata": { "position": [ 8, 4 ] }, "skip_deduplication": False, "world_state_hash": 0, "path": None } document = { "document_legacy": { "root": { "visible": True, "name": None, "data": { "Folder": { "next_assignment_id": 0, "layer_ids": [], "layers": [] } }, "transform": { "matrix2": [ 1.0, 0.0, 0.0, 1.0 ], "translation": [ 0.0, 0.0 ] }, "preserve_aspect": True, "pivot": [ 0.5, 0.5 ], "blend_mode": "Normal", "opacity": 1.0 }, "document_network": { "inputs": [], "outputs": [ { "node_id": 0, "node_output_index": 0 } ], "nodes": new_nodes, "disabled": [], "previous_outputs": None }, "commit_hash": "ef46080400bc6c4e069765dd2127306abbc9a94b" }, "saved_document_identifier": 0, "auto_saved_document_identifier": 0, "name": "Untitled Document 10", "version": "0.0.18", "document_mode": "DesignMode", "view_mode": "Normal", "overlays_visible": True, "layer_metadata": [], "layer_range_selection_reference": None, "navigation_handler": { "pan": [ 82.0, 84.0 ], "tilt": 0.0, "zoom": 1.0, "transform_operation": "None", "mouse_position": [ 389.0, 507.0 ], "finish_operation_with_click": False }, "properties_panel_message_handler": { "active_selection": None } } with open(new_name, "w+") as f: json.dump(document, f, indent="\t") migrate("just-a-potted-cactus.graphite","migrated_just_a_potted_cactus.graphite") migrate("valley-of-spires.graphite","migrated_valley_of_spires.graphite")