Merge pull request #4556 from ynput/feature/OP-5006_Nuke-publish-colorspaceData-from-rendered-images

This commit is contained in:
Jakub Ježek 2023-03-06 11:52:37 +01:00 committed by GitHub
commit f5ef4597b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 44 deletions

View file

@ -3,12 +3,14 @@ from pprint import pformat
import nuke import nuke
import pyblish.api import pyblish.api
from openpype.hosts.nuke import api as napi from openpype.hosts.nuke import api as napi
from openpype.pipeline import publish
class CollectNukeWrites(pyblish.api.InstancePlugin): class CollectNukeWrites(pyblish.api.InstancePlugin,
publish.ColormanagedPyblishPluginMixin):
"""Collect all write nodes.""" """Collect all write nodes."""
order = pyblish.api.CollectorOrder - 0.48 order = pyblish.api.CollectorOrder + 0.0021
label = "Collect Writes" label = "Collect Writes"
hosts = ["nuke", "nukeassist"] hosts = ["nuke", "nukeassist"]
families = ["render", "prerender", "image"] families = ["render", "prerender", "image"]
@ -66,6 +68,9 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
write_file_path = nuke.filename(write_node) write_file_path = nuke.filename(write_node)
output_dir = os.path.dirname(write_file_path) output_dir = os.path.dirname(write_file_path)
# get colorspace and add to version data
colorspace = napi.get_colorspace_from_node(write_node)
self.log.debug('output dir: {}'.format(output_dir)) self.log.debug('output dir: {}'.format(output_dir))
if render_target == "frames": if render_target == "frames":
@ -128,6 +133,12 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
else: else:
representation['files'] = collected_frames representation['files'] = collected_frames
# inject colorspace data
self.set_representation_colorspace(
representation, instance.context,
colorspace=colorspace
)
instance.data["representations"].append(representation) instance.data["representations"].append(representation)
self.log.info("Publishing rendered frames ...") self.log.info("Publishing rendered frames ...")
@ -145,8 +156,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
instance.data["farm"] = True instance.data["farm"] = True
self.log.info("Farm rendering ON ...") self.log.info("Farm rendering ON ...")
# get colorspace and add to version data # TODO: remove this when we have proper colorspace support
colorspace = napi.get_colorspace_from_node(write_node)
version_data = { version_data = {
"colorspace": colorspace "colorspace": colorspace
} }

View file

@ -4,12 +4,13 @@ import shutil
import pyblish.api import pyblish.api
import clique import clique
import nuke import nuke
from openpype.hosts.nuke import api as napi
from openpype.pipeline import publish from openpype.pipeline import publish
from openpype.lib import collect_frames from openpype.lib import collect_frames
class NukeRenderLocal(publish.ExtractorColormanaged): class NukeRenderLocal(publish.Extractor,
publish.ColormanagedPyblishPluginMixin):
"""Render the current Nuke composition locally. """Render the current Nuke composition locally.
Extract the result of savers by starting a comp render Extract the result of savers by starting a comp render
@ -85,7 +86,7 @@ class NukeRenderLocal(publish.ExtractorColormanaged):
) )
ext = node["file_type"].value() ext = node["file_type"].value()
colorspace = node["colorspace"].value() colorspace = napi.get_colorspace_from_node(node)
if "representations" not in instance.data: if "representations" not in instance.data:
instance.data["representations"] = [] instance.data["representations"] = []

View file

@ -335,9 +335,10 @@ def get_imageio_config(
get_template_data_from_session) get_template_data_from_session)
anatomy_data = get_template_data_from_session() anatomy_data = get_template_data_from_session()
formatting_data = deepcopy(anatomy_data)
# add project roots to anatomy data # add project roots to anatomy data
anatomy_data["root"] = anatomy.roots formatting_data["root"] = anatomy.roots
anatomy_data["platform"] = platform.system().lower() formatting_data["platform"] = platform.system().lower()
# get colorspace settings # get colorspace settings
imageio_global, imageio_host = _get_imageio_settings( imageio_global, imageio_host = _get_imageio_settings(
@ -347,7 +348,7 @@ def get_imageio_config(
if config_host.get("enabled"): if config_host.get("enabled"):
config_data = _get_config_data( config_data = _get_config_data(
config_host["filepath"], anatomy_data config_host["filepath"], formatting_data
) )
else: else:
config_data = None config_data = None
@ -356,7 +357,7 @@ def get_imageio_config(
# get config path from either global or host_name # get config path from either global or host_name
config_global = imageio_global["ocio_config"] config_global = imageio_global["ocio_config"]
config_data = _get_config_data( config_data = _get_config_data(
config_global["filepath"], anatomy_data config_global["filepath"], formatting_data
) )
if not config_data: if not config_data:
@ -372,12 +373,12 @@ def _get_config_data(path_list, anatomy_data):
"""Return first existing path in path list. """Return first existing path in path list.
If template is used in path inputs, If template is used in path inputs,
then it is formated by anatomy data then it is formatted by anatomy data
and environment variables and environment variables
Args: Args:
path_list (list[str]): list of abs paths path_list (list[str]): list of abs paths
anatomy_data (dict): formating data anatomy_data (dict): formatting data
Returns: Returns:
dict: config data dict: config data
@ -389,30 +390,30 @@ def _get_config_data(path_list, anatomy_data):
# first try host config paths # first try host config paths
for path_ in path_list: for path_ in path_list:
formated_path = _format_path(path_, formatting_data) formatted_path = _format_path(path_, formatting_data)
if not os.path.exists(formated_path): if not os.path.exists(formatted_path):
continue continue
return { return {
"path": os.path.normpath(formated_path), "path": os.path.normpath(formatted_path),
"template": path_ "template": path_
} }
def _format_path(tempate_path, formatting_data): def _format_path(template_path, formatting_data):
"""Single template path formating. """Single template path formatting.
Args: Args:
tempate_path (str): template string template_path (str): template string
formatting_data (dict): data to be used for formatting_data (dict): data to be used for
template formating template formatting
Returns: Returns:
str: absolute formated path str: absolute formatted path
""" """
# format path for anatomy keys # format path for anatomy keys
formatted_path = StringTemplate(tempate_path).format( formatted_path = StringTemplate(template_path).format(
formatting_data) formatting_data)
return os.path.abspath(formatted_path) return os.path.abspath(formatted_path)

View file

@ -19,7 +19,7 @@ from .publish_plugins import (
RepairContextAction, RepairContextAction,
Extractor, Extractor,
ExtractorColormanaged, ColormanagedPyblishPluginMixin
) )
from .lib import ( from .lib import (
@ -64,7 +64,7 @@ __all__ = (
"RepairContextAction", "RepairContextAction",
"Extractor", "Extractor",
"ExtractorColormanaged", "ColormanagedPyblishPluginMixin",
"get_publish_template_name", "get_publish_template_name",

View file

@ -3,7 +3,7 @@ from abc import ABCMeta
from pprint import pformat from pprint import pformat
import pyblish.api import pyblish.api
from pyblish.plugin import MetaPlugin, ExplicitMetaPlugin from pyblish.plugin import MetaPlugin, ExplicitMetaPlugin
from openpype.lib.transcoding import VIDEO_EXTENSIONS, IMAGE_EXTENSIONS
from openpype.lib import BoolDef from openpype.lib import BoolDef
from .lib import ( from .lib import (
@ -288,28 +288,29 @@ class Extractor(pyblish.api.InstancePlugin):
return get_instance_staging_dir(instance) return get_instance_staging_dir(instance)
class ExtractorColormanaged(Extractor): class ColormanagedPyblishPluginMixin(object):
"""Extractor base for color managed image data. """Mixin for colormanaged plugins.
Each Extractor intended to export pixel data representation
should inherit from this class to allow color managed data.
Class implements "get_colorspace_settings" and
"set_representation_colorspace" functions used
for injecting colorspace data to representation data for farther
integration into db document.
This class is used to set colorspace data to a publishing
representation. It contains a static method,
get_colorspace_settings, which returns config and
file rules data for the host context.
It also contains a method, set_representation_colorspace,
which sets colorspace data to the representation.
The allowed file extensions are listed in the allowed_ext variable.
The method first checks if the file extension is in
the list of allowed extensions. If it is, it then gets the
colorspace settings from the host context and gets a
matching colorspace from rules. Finally, it infuses this
data into the representation.
""" """
allowed_ext = set(
allowed_ext = [ ext.lstrip(".") for ext in IMAGE_EXTENSIONS.union(VIDEO_EXTENSIONS)
"cin", "dpx", "avi", "dv", "gif", "flv", "mkv", "mov", "mpg", "mpeg", )
"mp4", "m4v", "mxf", "iff", "z", "ifl", "jpeg", "jpg", "jfif", "lut",
"1dl", "exr", "pic", "png", "ppm", "pnm", "pgm", "pbm", "rla", "rpf",
"sgi", "rgba", "rgb", "bw", "tga", "tiff", "tif", "img"
]
@staticmethod @staticmethod
def get_colorspace_settings(context): def get_colorspace_settings(context):
"""Retuns solved settings for the host context. """Returns solved settings for the host context.
Args: Args:
context (publish.Context): publishing context context (publish.Context): publishing context
@ -375,7 +376,10 @@ class ExtractorColormanaged(Extractor):
ext = representation["ext"] ext = representation["ext"]
# check extension # check extension
self.log.debug("__ ext: `{}`".format(ext)) self.log.debug("__ ext: `{}`".format(ext))
if ext.lower() not in self.allowed_ext:
# check if ext in lower case is in self.allowed_ext
if ext.lstrip(".").lower() not in self.allowed_ext:
self.log.debug("Extension is not in allowed extensions.")
return return
if colorspace_settings is None: if colorspace_settings is None:

View file

@ -2,7 +2,8 @@ import pyblish.api
from openpype.pipeline import publish from openpype.pipeline import publish
class ExtractColorspaceData(publish.ExtractorColormanaged): class ExtractColorspaceData(publish.Extractor,
publish.ColormanagedPyblishPluginMixin):
""" Inject Colorspace data to available representations. """ Inject Colorspace data to available representations.
Input data: Input data: