Skip to content

load_image_copernicus

ImageCopernicusLoader

Bases: HoudiniLoader

Load images into Copernicus network.

We prefer to create the node inside the 'active' Copernicus network because Copernicus does not seem to have the equivalent of an "Object Merge" COP node, so we cannot merge nodes from another Cop network.

Source code in client/ayon_houdini/plugins/load/load_image_copernicus.py
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
class ImageCopernicusLoader(plugin.HoudiniLoader):
    """Load images into Copernicus network.

    We prefer to create the node inside the 'active' Copernicus network
    because Copernicus does not seem to have the equivalent of an
    "Object Merge" COP node, so we cannot merge nodes from another Cop network.
    """

    product_types = {
        "imagesequence",
        "review",
        "render",
        "plate",
        "image",
        "online",
    }
    label = "Load Image (Copernicus)"
    representations = {"*"}
    order = -10

    icon = "code-fork"
    color = "orange"

    @classmethod
    def apply_settings(cls, project_settings):
        # Copernicus was introduced in Houdini 20.5.
        if hou.applicationVersion() < (20, 5, 0):
            cls.enabled = False
            return None
        return super().apply_settings(project_settings)

    def load(self, context, name=None, namespace=None, data=None):
        # Format file name, Houdini only wants forward slashes
        path = self.filepath_from_context(context)
        path = self.format_path(path, representation=context["representation"])

        # Define node name
        namespace = namespace if namespace else context["folder"]["name"]
        node_name = "{}_{}".format(namespace, name) if namespace else name

        # Create node in the active COP network
        network = lib.find_active_network(
            category=hou.copNodeTypeCategory(),
            default=None
        )
        if network is None:
            # If no active network, use a COP network
            network = get_image_ayon_container()

        node = network.createNode("file", node_name=node_name)
        node.moveToGoodPosition()

        node.setParms({
            "filename": path,
            # Add the default "C" file AOV
            "aovs": 1,
            "aov1": "C",
        })

        # Imprint it manually
        data = {
            "schema": "ayon:container-3.0",
            "id": AYON_CONTAINER_ID,
            "name": node_name,
            "namespace": namespace,
            "loader": str(self.__class__.__name__),
            "representation": context["representation"]["id"],
        }

        lib.imprint(node, data, folder="AYON")

        return node

    def update(self, container, context):
        repre_entity = context["representation"]
        node = container["node"]

        # Update the file path
        file_path = self.filepath_from_context(context)
        file_path = self.format_path(file_path, repre_entity)

        parms = {
            "filename": file_path,
            "representation": repre_entity["id"],
        }

        # Update attributes
        node.setParms(parms)

    def remove(self, container):
        node = container["node"]

        # Let's clean up the IMAGES COP2 network
        # if it ends up being empty and we deleted
        # the last file node. Store the parent
        # before we delete the node.
        parent = node.parent()

        node.destroy()

        if parent.path() == f"{pipeline.AYON_CONTAINERS}/{COPNET_NAME}":
            parent.destroy()

    @staticmethod
    def format_path(path, representation):
        """Format file path correctly for single image or sequence."""
        ext = os.path.splitext(path)[-1]

        # The path is either a single file or sequence in a folder.
        is_sequence = bool(representation["context"].get("frame"))
        if is_sequence:
            folder, filename = os.path.split(path)
            filename = re.sub(r"(.*)\.(\d+){}$".format(re.escape(ext)),
                              "\\1.$F4{}".format(ext),
                              filename)
            path = os.path.join(folder, filename)

        path = os.path.normpath(path)
        path = path.replace("\\", "/")
        return path

    def switch(self, container, representation):
        self.update(container, representation)

format_path(path, representation) staticmethod

Format file path correctly for single image or sequence.

Source code in client/ayon_houdini/plugins/load/load_image_copernicus.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@staticmethod
def format_path(path, representation):
    """Format file path correctly for single image or sequence."""
    ext = os.path.splitext(path)[-1]

    # The path is either a single file or sequence in a folder.
    is_sequence = bool(representation["context"].get("frame"))
    if is_sequence:
        folder, filename = os.path.split(path)
        filename = re.sub(r"(.*)\.(\d+){}$".format(re.escape(ext)),
                          "\\1.$F4{}".format(ext),
                          filename)
        path = os.path.join(folder, filename)

    path = os.path.normpath(path)
    path = path.replace("\\", "/")
    return path

get_image_ayon_container()

The Copernicus node must be in a Copernicus network.

So we maintain a single entry point within AYON_CONTAINERS, just for ease of use.

Source code in client/ayon_houdini/plugins/load/load_image_copernicus.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def get_image_ayon_container():
    """The Copernicus node must be in a Copernicus network.

    So we maintain a single entry point within AYON_CONTAINERS,
    just for ease of use.

    """
    root_container = pipeline.get_or_create_ayon_container()
    image_container = root_container.node(COPNET_NAME)
    if not image_container:
        image_container = root_container.createNode(
            "copnet", node_name=COPNET_NAME
        )
        image_container.moveToGoodPosition()

    return image_container