From dba8d78a2abc79583d64016c46b6aa5df13916bb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 20 May 2025 10:53:37 +0200 Subject: [PATCH 01/12] Refactors color space conversion with oiiotool Consolidates color space conversion logic into a dedicated `oiiotool_transcode` function for better flexibility and clarity. This change introduces support for display/view transformations, enhancing the tool's ability to handle complex color management workflows. It also fixes issues with conflicting color space parameters and improves handling of source and target display/view configurations. --- client/ayon_core/lib/transcoding.py | 170 ++++++++++++++++-- .../publish/extract_color_transcode.py | 42 +++-- .../plugins/publish/extract_thumbnail.py | 10 +- 3 files changed, 184 insertions(+), 38 deletions(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index 8c84e1c4dc..6648f5219e 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -977,7 +977,60 @@ def convert_colorspace( additional_command_args=None, logger=None, ): - """Convert source file from one color space to another. + """Backward compatibility function for convert_colorspace. + + Args: + input_path (str): Path to input file that should be converted. + output_path (str): Path to output file where result will be stored. + config_path (str): Path to OCIO config file. + source_colorspace (str): OCIO valid color space of source files. + target_colorspace (str, optional): OCIO valid target color space. + If filled, 'view' and 'display' must be empty. + view (str, optional): Name for target viewer space (OCIO valid). + Both 'view' and 'display' must be filled (if not 'target_colorspace'). + display (str, optional): Name for target display-referred reference space. + Both 'view' and 'display' must be filled (if not 'target_colorspace'). + additional_command_args (list, optional): Additional arguments for oiiotool + (like binary depth for .dpx). + logger (logging.Logger, optional): Logger used for logging. + + Returns: + None: Function returns None. + + Raises: + ValueError: If parameters are misconfigured. + """ + return oiiotool_transcode( + input_path, + output_path, + config_path, + source_colorspace, + target_colorspace=target_colorspace, + target_display=display, + target_view=view, + additional_command_args=additional_command_args, + logger=logger, + ) + + +def oiiotool_transcode( + input_path, + output_path, + config_path, + source_colorspace, + source_display=None, + source_view=None, + target_colorspace=None, + target_display=None, + target_view=None, + additional_command_args=None, + logger=None, +): + """Transcode source file to other with colormanagement. + + Oiiotool also support additional arguments for transcoding. + For more information, see the official documentation: + https://openimageio.readthedocs.io/en/latest/oiiotool.html Args: input_path (str): Path that should be converted. It is expected that @@ -989,17 +1042,26 @@ def convert_colorspace( sequence in 'file.FRAMESTART-FRAMEEND#.ext', `output.1-3#.tif`) config_path (str): path to OCIO config file source_colorspace (str): ocio valid color space of source files + source_display (str, optional): name for source display-referred + reference space (ocio valid). If provided, source_view must also be + provided, and source_colorspace will be ignored + source_view (str, optional): name for source viewer space (ocio valid) + If provided, source_display must also be provided, and + source_colorspace will be ignored target_colorspace (str): ocio valid target color space if filled, 'view' and 'display' must be empty - view (str): name for viewer space (ocio valid) - both 'view' and 'display' must be filled (if 'target_colorspace') - display (str): name for display-referred reference space (ocio valid) + target_display (str): name for target display-referred reference space + (ocio valid) both 'view' and 'display' must be filled (if + 'target_colorspace') + target_view (str): name for target viewer space (ocio valid) both 'view' and 'display' must be filled (if 'target_colorspace') additional_command_args (list): arguments for oiiotool (like binary depth for .dpx) logger (logging.Logger): Logger used for logging. + Raises: ValueError: if misconfigured + """ if logger is None: logger = logging.getLogger(__name__) @@ -1024,23 +1086,99 @@ def convert_colorspace( "--ch", channels_arg ]) - if all([target_colorspace, view, display]): - raise ValueError("Colorspace and both screen and display" - " cannot be set together." - "Choose colorspace or screen and display") - if not target_colorspace and not all([view, display]): - raise ValueError("Both screen and display must be set.") + # Validate input parameters + if all([target_colorspace, target_view, target_display]): + raise ValueError( + "Colorspace and both screen and display cannot be set together." + "Choose colorspace or screen and display" + ) + + if all([source_view, source_display]) and source_colorspace: + logger.warning( + "Both source display/view and source_colorspace provided. " + "Using source display/view pair and ignoring source_colorspace." + ) + + if not target_colorspace and not all([target_view, target_display]): + raise ValueError( + "Both screen and display must be set if target_colorspace is not " + "provided." + ) + + if ((source_view and not source_display) or + (source_display and not source_view)): + raise ValueError( + "Both source_view and source_display must be provided if using " + "display/view inputs." + ) if additional_command_args: oiio_cmd.extend(additional_command_args) + # Handle the different conversion cases if target_colorspace: - oiio_cmd.extend(["--colorconvert:subimages=0", - source_colorspace, - target_colorspace]) - if view and display: - oiio_cmd.extend(["--iscolorspace", source_colorspace]) - oiio_cmd.extend(["--ociodisplay:subimages=0", display, view]) + # Case 1: Converting to a named colorspace + if all([source_view, source_display]): + # First convert from source display/view to a role/reference space + # that can be used with colorconvert + # For example, converting to "scene_linear" or an appropriate + # intermediate space + # This is a two-step conversion process since there's no direct + # display/view to colorspace command + # This could be a config parameter or determined from OCIO config + tmp_role_space = "scene_linear" + oiio_cmd.extend([ + "--ociodisplay:inverse=1:subimages=0", source_display, + source_view, "--colorconvert:subimages=0", tmp_role_space, + target_colorspace, + ]) + else: + # Standard color space to color space conversion + oiio_cmd.extend([ + "--colorconvert:subimages=0", source_colorspace, + target_colorspace, + ]) + else: # Using display/view target + if all([source_view, source_display]): + if source_display == target_display and source_view == target_view: + # No conversion needed if source and target display/view are + # the same + logger.debug( + "Source and target display/view pairs are identical. " + "No color conversion needed." + ) + elif source_display == target_display: + # When only the view changes but display stays the same + # First convert from source view to a reference space, then to + # target view + # This could be configured + tmp_role_space = "scene_linear" + oiio_cmd.extend([ + "--ociodisplay:inverse=1:subimages=0", + source_display, + source_view, + "--ociodisplay:subimages=0", + target_display, + target_view, + ]) + else: + # Complete display/view pair conversion + # Similar approach: go through a reference space + # This could be configured + tmp_role_space = "scene_linear" + oiio_cmd.extend([ + "--ociodisplay:inverse=1:subimages=0", + source_display, + source_view, "--ociodisplay:subimages=0", + target_display, + target_view, + ]) + else: + # Standard conversion from colorspace to display/view + oiio_cmd.extend([ + "--iscolorspace", source_colorspace, + "--ociodisplay:subimages=0", target_display, target_view, + ]) oiio_cmd.extend(["-o", output_path]) diff --git a/client/ayon_core/plugins/publish/extract_color_transcode.py b/client/ayon_core/plugins/publish/extract_color_transcode.py index 6cf30857a4..f61379189c 100644 --- a/client/ayon_core/plugins/publish/extract_color_transcode.py +++ b/client/ayon_core/plugins/publish/extract_color_transcode.py @@ -11,7 +11,7 @@ from ayon_core.lib import ( is_oiio_supported, ) from ayon_core.lib.transcoding import ( - convert_colorspace, + oiiotool_transcode, ) from ayon_core.lib.profiles_filtering import filter_profiles @@ -94,6 +94,8 @@ class ExtractOIIOTranscode(publish.Extractor): colorspace_data = repre["colorspaceData"] source_colorspace = colorspace_data["colorspace"] + source_display = colorspace_data.get("display") + source_view = colorspace_data.get("view") config_path = colorspace_data.get("config", {}).get("path") if not config_path or not os.path.exists(config_path): self.log.warning("Config file doesn't exist, skipping") @@ -124,7 +126,7 @@ class ExtractOIIOTranscode(publish.Extractor): transcoding_type = output_def["transcoding_type"] - target_colorspace = view = display = None + target_colorspace = target_view = target_display = None # NOTE: we use colorspace_data as the fallback values for # the target colorspace. if transcoding_type == "colorspace": @@ -136,18 +138,20 @@ class ExtractOIIOTranscode(publish.Extractor): colorspace_data.get("colorspace")) elif transcoding_type == "display_view": display_view = output_def["display_view"] - view = display_view["view"] or colorspace_data.get("view") - display = ( + target_view = ( + display_view["view"] + or colorspace_data.get("view")) + target_display = ( display_view["display"] or colorspace_data.get("display") ) # both could be already collected by DCC, # but could be overwritten when transcoding - if view: - new_repre["colorspaceData"]["view"] = view - if display: - new_repre["colorspaceData"]["display"] = display + if target_view: + new_repre["colorspaceData"]["view"] = target_view + if target_display: + new_repre["colorspaceData"]["display"] = target_display if target_colorspace: new_repre["colorspaceData"]["colorspace"] = \ target_colorspace @@ -166,16 +170,18 @@ class ExtractOIIOTranscode(publish.Extractor): new_staging_dir, output_extension) - convert_colorspace( - input_path, - output_path, - config_path, - source_colorspace, - target_colorspace, - view, - display, - additional_command_args, - self.log + oiiotool_transcode( + input_path=input_path, + output_path=output_path, + config_path=config_path, + source_colorspace=source_colorspace, + target_colorspace=target_colorspace, + target_display=target_display, + target_view=target_view, + source_display=source_display, + source_view=source_view, + additional_command_args=additional_command_args, + logger=self.log ) # cleanup temporary transcoded files diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index 3a428c46a7..f65308121b 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -15,7 +15,7 @@ from ayon_core.lib import ( path_to_subprocess_arg, run_subprocess, ) -from ayon_core.lib.transcoding import convert_colorspace +from ayon_core.lib.transcoding import oiiotool_transcode from ayon_core.lib.transcoding import VIDEO_EXTENSIONS, IMAGE_EXTENSIONS @@ -431,13 +431,15 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): oiio_default_view = display_and_view["view"] try: - convert_colorspace( + oiiotool_transcode( src_path, dst_path, colorspace_data["config"]["path"], colorspace_data["colorspace"], - display=repre_display or oiio_default_display, - view=repre_view or oiio_default_view, + source_display=colorspace_data.get("display"), + source_view=colorspace_data.get("view"), + target_display=repre_display or oiio_default_display, + target_view=repre_view or oiio_default_view, target_colorspace=oiio_default_colorspace, additional_command_args=resolution_arg, logger=self.log, From 08f6b61a3e5f4d91d8a4d7247024a14fe9067d27 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 20 May 2025 11:19:14 +0200 Subject: [PATCH 02/12] Adds deprecation decorator and marks function Introduces a `deprecated` decorator to mark functions as deprecated, issuing a warning when they are called. The `convert_colorspace` function is marked as deprecated, advising users to switch to `oiiotool_transcode`. --- client/ayon_core/lib/transcoding.py | 90 +++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index 6648f5219e..e62873184d 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -6,6 +6,8 @@ import collections import tempfile import subprocess import platform +import warnings +import functools from typing import Optional import xml.etree.ElementTree @@ -67,6 +69,48 @@ VIDEO_EXTENSIONS = { } + +def deprecated(new_destination): + """Mark functions as deprecated. + + It will result in a warning being emitted when the function is used. + """ + + func = None + if callable(new_destination): + func = new_destination + new_destination = None + + def _decorator(decorated_func): + if new_destination is None: + warning_message = ( + " Please check content of deprecated function to figure out" + " possible replacement." + ) + else: + warning_message = " Please replace your usage with '{}'.".format( + new_destination + ) + + @functools.wraps(decorated_func) + def wrapper(*args, **kwargs): + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + ( + "Call to deprecated function '{}'" + "\nFunction was moved or removed.{}" + ).format(decorated_func.__name__, warning_message), + category=DeprecationWarning, + stacklevel=4 + ) + return decorated_func(*args, **kwargs) + return wrapper + + if func is None: + return _decorator + return _decorator(func) + + def get_transcode_temp_directory(): """Creates temporary folder for transcoding. @@ -966,6 +1010,8 @@ def convert_ffprobe_fps_to_float(value): return dividend / divisor +# --- Deprecated functions --- +@deprecated("oiiotool_transcode") def convert_colorspace( input_path, output_path, @@ -977,7 +1023,7 @@ def convert_colorspace( additional_command_args=None, logger=None, ): - """Backward compatibility function for convert_colorspace. + """DEPRECATED function use `oiiotool_transcode` instead Args: input_path (str): Path to input file that should be converted. @@ -1105,8 +1151,10 @@ def oiiotool_transcode( "provided." ) - if ((source_view and not source_display) or - (source_display and not source_view)): + if ( + (source_view and not source_display) + or (source_display and not source_view) + ): raise ValueError( "Both source_view and source_display must be provided if using " "display/view inputs." @@ -1128,14 +1176,18 @@ def oiiotool_transcode( # This could be a config parameter or determined from OCIO config tmp_role_space = "scene_linear" oiio_cmd.extend([ - "--ociodisplay:inverse=1:subimages=0", source_display, - source_view, "--colorconvert:subimages=0", tmp_role_space, + "--ociodisplay:inverse=1:subimages=0", + source_display, + source_view, + "--colorconvert:subimages=0", + tmp_role_space, target_colorspace, ]) else: # Standard color space to color space conversion oiio_cmd.extend([ - "--colorconvert:subimages=0", source_colorspace, + "--colorconvert:subimages=0", + source_colorspace, target_colorspace, ]) else: # Using display/view target @@ -1147,10 +1199,9 @@ def oiiotool_transcode( "Source and target display/view pairs are identical. " "No color conversion needed." ) - elif source_display == target_display: - # When only the view changes but display stays the same - # First convert from source view to a reference space, then to - # target view + else: + # Complete display/view pair conversion + # Similar approach: go through a reference space # This could be configured tmp_role_space = "scene_linear" oiio_cmd.extend([ @@ -1161,23 +1212,14 @@ def oiiotool_transcode( target_display, target_view, ]) - else: - # Complete display/view pair conversion - # Similar approach: go through a reference space - # This could be configured - tmp_role_space = "scene_linear" - oiio_cmd.extend([ - "--ociodisplay:inverse=1:subimages=0", - source_display, - source_view, "--ociodisplay:subimages=0", - target_display, - target_view, - ]) else: # Standard conversion from colorspace to display/view oiio_cmd.extend([ - "--iscolorspace", source_colorspace, - "--ociodisplay:subimages=0", target_display, target_view, + "--iscolorspace", + source_colorspace, + "--ociodisplay:subimages=0", + target_display, + target_view, ]) oiio_cmd.extend(["-o", output_path]) From 4ebf35dd8b68ef10a66551ef47276516a291e360 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 20 May 2025 11:26:28 +0200 Subject: [PATCH 03/12] Refactors docstring formatting in transcoding Improves readability by adjusting docstring formatting in the `convert_colorspace` function. This change ensures consistent documentation style and enhances clarity. --- client/ayon_core/lib/transcoding.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index e62873184d..4f985d5128 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -69,7 +69,6 @@ VIDEO_EXTENSIONS = { } - def deprecated(new_destination): """Mark functions as deprecated. @@ -1033,11 +1032,13 @@ def convert_colorspace( target_colorspace (str, optional): OCIO valid target color space. If filled, 'view' and 'display' must be empty. view (str, optional): Name for target viewer space (OCIO valid). - Both 'view' and 'display' must be filled (if not 'target_colorspace'). - display (str, optional): Name for target display-referred reference space. - Both 'view' and 'display' must be filled (if not 'target_colorspace'). - additional_command_args (list, optional): Additional arguments for oiiotool - (like binary depth for .dpx). + Both 'view' and 'display' must be filled + (if not 'target_colorspace'). + display (str, optional): Name for target display-referred + reference space. Both 'view' and 'display' must be filled + (if not 'target_colorspace'). + additional_command_args (list, optional): Additional arguments + for oiiotool (like binary depth for .dpx). logger (logging.Logger, optional): Logger used for logging. Returns: From 0b20e49eda6eb85b3b3c32039ee24a3880fc12e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Fri, 6 Jun 2025 16:07:06 +0200 Subject: [PATCH 04/12] Update client/ayon_core/pipeline/colorspace.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/pipeline/colorspace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/pipeline/colorspace.py b/client/ayon_core/pipeline/colorspace.py index a7d1d80b0a..41241e17ca 100644 --- a/client/ayon_core/pipeline/colorspace.py +++ b/client/ayon_core/pipeline/colorspace.py @@ -1404,7 +1404,7 @@ def _get_display_view_colorspace_name(config_path, display, view): """ config = _get_ocio_config(config_path) colorspace = config.getDisplayViewColorSpaceName(display, view) - # Special token. See https://opencolorio.readthedocs.io/en/latest/guides/authoring/authoring.html#shared-views # noqa + # Special token. See https://opencolorio.readthedocs.io/en/latest/guides/authoring/authoring.html#shared-views # noqa if colorspace == "": colorspace = display From 21737339d37432cc62f83d88839711f6dc5e32fd Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:46:23 +0200 Subject: [PATCH 05/12] rename 'oiiotool_transcode' to 'oiio_color_convert' --- client/ayon_core/lib/transcoding.py | 8 ++++---- .../ayon_core/plugins/publish/extract_color_transcode.py | 4 ++-- client/ayon_core/plugins/publish/extract_thumbnail.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index 4f985d5128..97e9f417f0 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -1010,7 +1010,7 @@ def convert_ffprobe_fps_to_float(value): # --- Deprecated functions --- -@deprecated("oiiotool_transcode") +@deprecated("oiio_color_convert") def convert_colorspace( input_path, output_path, @@ -1022,7 +1022,7 @@ def convert_colorspace( additional_command_args=None, logger=None, ): - """DEPRECATED function use `oiiotool_transcode` instead + """DEPRECATED function use `oiio_color_convert` instead Args: input_path (str): Path to input file that should be converted. @@ -1047,7 +1047,7 @@ def convert_colorspace( Raises: ValueError: If parameters are misconfigured. """ - return oiiotool_transcode( + return oiio_color_convert( input_path, output_path, config_path, @@ -1060,7 +1060,7 @@ def convert_colorspace( ) -def oiiotool_transcode( +def oiio_color_convert( input_path, output_path, config_path, diff --git a/client/ayon_core/plugins/publish/extract_color_transcode.py b/client/ayon_core/plugins/publish/extract_color_transcode.py index 9759b340c7..152e0a27ea 100644 --- a/client/ayon_core/plugins/publish/extract_color_transcode.py +++ b/client/ayon_core/plugins/publish/extract_color_transcode.py @@ -11,7 +11,7 @@ from ayon_core.lib import ( is_oiio_supported, ) from ayon_core.lib.transcoding import ( - oiiotool_transcode, + oiio_color_convert, ) from ayon_core.lib.profiles_filtering import filter_profiles @@ -170,7 +170,7 @@ class ExtractOIIOTranscode(publish.Extractor): new_staging_dir, output_extension) - oiiotool_transcode( + oiio_color_convert( input_path=input_path, output_path=output_path, config_path=config_path, diff --git a/client/ayon_core/plugins/publish/extract_thumbnail.py b/client/ayon_core/plugins/publish/extract_thumbnail.py index 4d51405f01..541082352b 100644 --- a/client/ayon_core/plugins/publish/extract_thumbnail.py +++ b/client/ayon_core/plugins/publish/extract_thumbnail.py @@ -15,7 +15,7 @@ from ayon_core.lib import ( path_to_subprocess_arg, run_subprocess, ) -from ayon_core.lib.transcoding import oiiotool_transcode +from ayon_core.lib.transcoding import oiio_color_convert from ayon_core.lib.transcoding import VIDEO_EXTENSIONS, IMAGE_EXTENSIONS @@ -431,7 +431,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): oiio_default_view = display_and_view["view"] try: - oiiotool_transcode( + oiio_color_convert( src_path, dst_path, colorspace_data["config"]["path"], From 28978f07c654446c3af3b64e54cc93bff879bd56 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:50:21 +0200 Subject: [PATCH 06/12] use standard conditions --- client/ayon_core/lib/transcoding.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index 97e9f417f0..01a21615b5 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -1134,19 +1134,13 @@ def oiio_color_convert( ]) # Validate input parameters - if all([target_colorspace, target_view, target_display]): + if target_colorspace and target_view and target_display: raise ValueError( "Colorspace and both screen and display cannot be set together." "Choose colorspace or screen and display" ) - if all([source_view, source_display]) and source_colorspace: - logger.warning( - "Both source display/view and source_colorspace provided. " - "Using source display/view pair and ignoring source_colorspace." - ) - - if not target_colorspace and not all([target_view, target_display]): + if not target_colorspace and not target_view and not target_display: raise ValueError( "Both screen and display must be set if target_colorspace is not " "provided." @@ -1161,6 +1155,12 @@ def oiio_color_convert( "display/view inputs." ) + if source_view and source_display and source_colorspace: + logger.warning( + "Both source display/view and source_colorspace provided. " + "Using source display/view pair and ignoring source_colorspace." + ) + if additional_command_args: oiio_cmd.extend(additional_command_args) From 3eb88ae8506eac6dbbd8fd8f94abf88703c7bc72 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:50:34 +0200 Subject: [PATCH 07/12] use 'view' instead of 'screen' --- client/ayon_core/lib/transcoding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index 01a21615b5..7a4fd65e7c 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -1136,7 +1136,7 @@ def oiio_color_convert( # Validate input parameters if target_colorspace and target_view and target_display: raise ValueError( - "Colorspace and both screen and display cannot be set together." + "Colorspace and both view and display cannot be set together." "Choose colorspace or screen and display" ) From 2b209044ed4861668b908ee08f2115805eb0fa77 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:50:44 +0200 Subject: [PATCH 08/12] better conditions order --- client/ayon_core/lib/transcoding.py | 83 ++++++++++++----------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index 7a4fd65e7c..bf88e187ae 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -1165,64 +1165,51 @@ def oiio_color_convert( oiio_cmd.extend(additional_command_args) # Handle the different conversion cases - if target_colorspace: - # Case 1: Converting to a named colorspace - if all([source_view, source_display]): - # First convert from source display/view to a role/reference space - # that can be used with colorconvert - # For example, converting to "scene_linear" or an appropriate - # intermediate space + # Source view and display are known + if source_view and source_display: + if target_colorspace: # This is a two-step conversion process since there's no direct # display/view to colorspace command # This could be a config parameter or determined from OCIO config - tmp_role_space = "scene_linear" + # Use temporarty role space 'scene_linear' + color_convert_args = ("scene_linear", target_colorspace) + elif source_display != target_display or source_view != target_view: + # Complete display/view pair conversion + # - go through a reference space + color_convert_args = (target_display, target_view) + else: + color_convert_args = None + logger.debug( + "Source and target display/view pairs are identical." + " No color conversion needed." + ) + + if color_convert_args: oiio_cmd.extend([ "--ociodisplay:inverse=1:subimages=0", source_display, source_view, "--colorconvert:subimages=0", - tmp_role_space, - target_colorspace, - ]) - else: - # Standard color space to color space conversion - oiio_cmd.extend([ - "--colorconvert:subimages=0", - source_colorspace, - target_colorspace, - ]) - else: # Using display/view target - if all([source_view, source_display]): - if source_display == target_display and source_view == target_view: - # No conversion needed if source and target display/view are - # the same - logger.debug( - "Source and target display/view pairs are identical. " - "No color conversion needed." - ) - else: - # Complete display/view pair conversion - # Similar approach: go through a reference space - # This could be configured - tmp_role_space = "scene_linear" - oiio_cmd.extend([ - "--ociodisplay:inverse=1:subimages=0", - source_display, - source_view, - "--ociodisplay:subimages=0", - target_display, - target_view, - ]) - else: - # Standard conversion from colorspace to display/view - oiio_cmd.extend([ - "--iscolorspace", - source_colorspace, - "--ociodisplay:subimages=0", - target_display, - target_view, + *color_convert_args ]) + elif target_colorspace: + # Standard color space to color space conversion + oiio_cmd.extend([ + "--colorconvert:subimages=0", + source_colorspace, + target_colorspace, + ]) + else: + # Standard conversion from colorspace to display/view + oiio_cmd.extend([ + "--iscolorspace", + source_colorspace, + "--ociodisplay:subimages=0", + target_display, + target_view, + ]) + oiio_cmd.extend(["-o", output_path]) logger.debug("Conversion command: {}".format(" ".join(oiio_cmd))) From f673abebc8393c9fdce5faf18291d2015fa0b039 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 19 Jun 2025 10:29:45 +0200 Subject: [PATCH 09/12] use 'view' instead of 'screen' Co-authored-by: Roy Nieterau --- client/ayon_core/lib/transcoding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index bf88e187ae..a4edf0aa1c 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -1142,7 +1142,7 @@ def oiio_color_convert( if not target_colorspace and not target_view and not target_display: raise ValueError( - "Both screen and display must be set if target_colorspace is not " + "Both view and display must be set if target_colorspace is not " "provided." ) From 2228037656b8eeaa400fcaab1329c6416dbc050f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 3 Jul 2025 09:57:20 +0200 Subject: [PATCH 10/12] Adds target color space data extraction to OIIO transcode processor. - Introduces extraction of `targetOCIOColorspace`, `targetOCIODisplay`, and `targetOCIOView` from instance data. - Removes redundant assignment of `target_colorspace`, `target_display`, and `target_view`. --- client/ayon_core/plugins/publish/extract_color_transcode.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_color_transcode.py b/client/ayon_core/plugins/publish/extract_color_transcode.py index ef718b8d02..7083d5094c 100644 --- a/client/ayon_core/plugins/publish/extract_color_transcode.py +++ b/client/ayon_core/plugins/publish/extract_color_transcode.py @@ -85,6 +85,11 @@ class ExtractOIIOTranscode(publish.Extractor): new_representations = [] repres = instance.data["representations"] for idx, repre in enumerate(list(repres)): + # target space, display and view might be defined upstream + target_colorspace = instance.data.get("targetOCIOColorspace") + target_display = instance.data.get("targetOCIODisplay") + target_view = instance.data.get("targetOCIOView") + self.log.debug("repre ({}): `{}`".format(idx + 1, repre["name"])) if not self._repre_is_valid(repre): continue @@ -126,7 +131,6 @@ class ExtractOIIOTranscode(publish.Extractor): transcoding_type = output_def["transcoding_type"] - target_colorspace = target_view = target_display = None # NOTE: we use colorspace_data as the fallback values for # the target colorspace. if transcoding_type == "colorspace": From 00cfb962e4f748aaec7e68b25d6d9c89833ee39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 14 Jul 2025 14:38:41 +0200 Subject: [PATCH 11/12] Update client/ayon_core/lib/transcoding.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> --- client/ayon_core/lib/transcoding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/lib/transcoding.py b/client/ayon_core/lib/transcoding.py index a4edf0aa1c..b3958863fe 100644 --- a/client/ayon_core/lib/transcoding.py +++ b/client/ayon_core/lib/transcoding.py @@ -1136,7 +1136,7 @@ def oiio_color_convert( # Validate input parameters if target_colorspace and target_view and target_display: raise ValueError( - "Colorspace and both view and display cannot be set together." + "Colorspace and both view and display cannot be set together." "Choose colorspace or screen and display" ) From db2c1858d5a0014d27a16ecf138075f437b096a6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 8 Sep 2025 16:10:49 +0200 Subject: [PATCH 12/12] Updates color space handling in OIIO transcode. Temporarily disables upstream OCIO color space logic. Uses 'colorspaceDisplay' and 'colorspaceView' instead. This is a temporary workaround. --- .../ayon_core/plugins/publish/extract_color_transcode.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_color_transcode.py b/client/ayon_core/plugins/publish/extract_color_transcode.py index 24820f7022..8b351c7f31 100644 --- a/client/ayon_core/plugins/publish/extract_color_transcode.py +++ b/client/ayon_core/plugins/publish/extract_color_transcode.py @@ -88,9 +88,12 @@ class ExtractOIIOTranscode(publish.Extractor): repres = instance.data["representations"] for idx, repre in enumerate(list(repres)): # target space, display and view might be defined upstream - target_colorspace = instance.data.get("targetOCIOColorspace") - target_display = instance.data.get("targetOCIODisplay") - target_view = instance.data.get("targetOCIOView") + # TODO: address https://github.com/ynput/ayon-core/pull/1268#discussion_r2156555474 + # Implement upstream logic to handle target_colorspace, + # target_display, target_view in other DCCs + target_colorspace = False + target_display = instance.data.get("colorspaceDisplay") + target_view = instance.data.get("colorspaceView") self.log.debug("repre ({}): `{}`".format(idx + 1, repre["name"])) if not self._repre_is_valid(repre):