def gather_image_property(export_settings, blender_object, target, property_name, property_definition, hubs_config):
    blender_image = getattr(target, property_name)

    if blender_image:
        image_data = ExportImage.from_blender_image(blender_image)
        if image_data.empty():
            return None

        mime_type = gltf2_blender_gather_image.__gather_mime_type((), image_data, export_settings)
        name = gltf2_blender_gather_image.__gather_name(image_data, export_settings)

        uri = gltf2_blender_gather_image.__gather_uri(image_data, mime_type, name, export_settings)
        buffer_view = gltf2_blender_gather_image.__gather_buffer_view(image_data, mime_type, name, export_settings)

        return gltf2_blender_gather_image.__make_image(
            buffer_view,
            None,
            None,
            mime_type,
            name,
            uri,
            export_settings
        )
    else:
        return None
def __get_image_data(sockets_or_slots, export_settings) -> ExportImage:
    # For shared resources, such as images, we just store the portion of data that is needed in the glTF property
    # in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary
    # resources.
    if __is_socket(sockets_or_slots):
        results = [
            __get_tex_from_socket(socket, export_settings)
            for socket in sockets_or_slots
        ]
        composed_image = ExportImage()
        for result, socket in zip(results, sockets_or_slots):
            if result.shader_node.image.channels == 0:
                gltf2_io_debug.print_console(
                    "WARNING",
                    "Image '{}' has no color channels and cannot be exported.".
                    format(result.shader_node.image))
                continue

            # rudimentarily try follow the node tree to find the correct image data.
            src_chan = Channel.R
            for elem in result.path:
                if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB):
                    src_chan = {
                        'R': Channel.R,
                        'G': Channel.G,
                        'B': Channel.B,
                    }[elem.from_socket.name]

            dst_chan = None

            # some sockets need channel rewriting (gltf pbr defines fixed channels for some attributes)
            if socket.name == 'Metallic':
                dst_chan = Channel.B
            elif socket.name == 'Roughness':
                dst_chan = Channel.G
            elif socket.name == 'Occlusion' and len(
                    sockets_or_slots) > 1 and sockets_or_slots[1] is not None:
                dst_chan = Channel.R
            elif socket.name == 'Alpha' and len(
                    sockets_or_slots) > 1 and sockets_or_slots[1] is not None:
                dst_chan = Channel.A

            if dst_chan is not None:
                composed_image.fill_image(result.shader_node.image, dst_chan,
                                          src_chan)

                # Since metal/roughness are always used together, make sure
                # the other channel is filled.
                if socket.name == 'Metallic' and not composed_image.is_filled(
                        Channel.G):
                    composed_image.fill_white(Channel.G)
                elif socket.name == 'Roughness' and not composed_image.is_filled(
                        Channel.B):
                    composed_image.fill_white(Channel.B)
            else:
                # copy full image...eventually following sockets might overwrite things
                composed_image = ExportImage.from_blender_image(
                    result.shader_node.image)

        return composed_image

    elif __is_slot(sockets_or_slots):
        texture = __get_tex_from_slot(sockets_or_slots[0])
        image = ExportImage.from_blender_image(texture.image)
        return image
    else:
        raise NotImplementedError()
def __get_image_data(sockets, export_settings) -> ExportImage:
    # For shared resources, such as images, we just store the portion of data that is needed in the glTF property
    # in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary
    # resources.
    results = [
        __get_tex_from_socket(socket, export_settings) for socket in sockets
    ]
    composed_image = ExportImage()
    for result, socket in zip(results, sockets):
        if result.shader_node.image.channels == 0:
            gltf2_io_debug.print_console(
                "WARNING",
                "Image '{}' has no color channels and cannot be exported.".
                format(result.shader_node.image))
            continue

        # Assume that user know what he does, and that channels/images are already combined correctly for pbr
        # If not, we are going to keep only the first texture found
        # Example : If user set up 2 or 3 different textures for Metallic / Roughness / Occlusion
        # Only 1 will be used at export
        # This Warning is displayed in UI of this option
        if export_settings['gltf_keep_original_textures']:
            composed_image = ExportImage.from_original(
                result.shader_node.image)

        else:
            # rudimentarily try follow the node tree to find the correct image data.
            src_chan = Channel.R
            for elem in result.path:
                if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB):
                    src_chan = {
                        'R': Channel.R,
                        'G': Channel.G,
                        'B': Channel.B,
                    }[elem.from_socket.name]
                if elem.from_socket.name == 'Alpha':
                    src_chan = Channel.A

            dst_chan = None

            # some sockets need channel rewriting (gltf pbr defines fixed channels for some attributes)
            if socket.name == 'Metallic':
                dst_chan = Channel.B
            elif socket.name == 'Roughness':
                dst_chan = Channel.G
            elif socket.name == 'Occlusion':
                dst_chan = Channel.R
            elif socket.name == 'Alpha':
                dst_chan = Channel.A
            elif socket.name == 'Clearcoat':
                dst_chan = Channel.R
            elif socket.name == 'Clearcoat Roughness':
                dst_chan = Channel.G

            if dst_chan is not None:
                composed_image.fill_image(result.shader_node.image, dst_chan,
                                          src_chan)

                # Since metal/roughness are always used together, make sure
                # the other channel is filled.
                if socket.name == 'Metallic' and not composed_image.is_filled(
                        Channel.G):
                    composed_image.fill_white(Channel.G)
                elif socket.name == 'Roughness' and not composed_image.is_filled(
                        Channel.B):
                    composed_image.fill_white(Channel.B)
            else:
                # copy full image...eventually following sockets might overwrite things
                composed_image = ExportImage.from_blender_image(
                    result.shader_node.image)

    return composed_image