From 45d18636380f73e6de54914369108558283bcc12 Mon Sep 17 00:00:00 2001 From: aardschok Date: Fri, 9 Feb 2018 16:04:35 +0100 Subject: [PATCH] improved extractor and saver --- .../plugins/fusion/create/create_saver.py | 37 +++++++-- .../fusion/publish/_validate_filenames.py | 52 ------------ .../fusion/publish/_validate_frame_range.py | 19 ----- .../fusion/publish/collect_instances.py | 18 ++-- .../fusion/publish/extract_image_sequence.py | 82 ++++++++++--------- .../fusion/publish/validate_unique_name.py | 2 +- 6 files changed, 85 insertions(+), 125 deletions(-) delete mode 100644 colorbleed/plugins/fusion/publish/_validate_filenames.py delete mode 100644 colorbleed/plugins/fusion/publish/_validate_frame_range.py diff --git a/colorbleed/plugins/fusion/create/create_saver.py b/colorbleed/plugins/fusion/create/create_saver.py index 75581da9cc..57420015f8 100644 --- a/colorbleed/plugins/fusion/create/create_saver.py +++ b/colorbleed/plugins/fusion/create/create_saver.py @@ -1,3 +1,5 @@ +import os + import avalon.api from avalon import fusion @@ -6,16 +8,39 @@ class CreateTiffSaver(avalon.api.Creator): name = "tiffDefault" label = "Create Tiff Saver" - hosts = "fusion" - family = "colorbleed.imagesequence" + hosts = ["fusion"] + family = "fusion.saver" def process(self): + file_format = "TiffFormat" + comp = fusion.get_current_comp() + + # todo: improve method of getting current environment + # todo: pref avalon.Session over os.environ + + workdir = os.path.normpath(os.environ["AVALON_WORKDIR"]) + + filename = "{}..tiff".format(self.name) + filepath = os.path.join(workdir, "render", "preview", filename) + with fusion.comp_lock_and_undo_chunk(comp): args = (-32768, -32768) # Magical position numbers saver = comp.AddTool("Saver", *args) - saver.SetAttrs({ - "TOOLS_Name": self.data.get("name", self.name), - 'TOOLST_Clip_FormatID': {1.0: 'TiffFormat'}, - }) + saver.SetAttrs({"TOOLS_Name": self.name}) + + # Setting input attributes is different from basic attributes + # Not confused with "MainInputAttributes" which + saver["Clip"] = filepath + saver["OutputFormat"] = file_format + + # # # Set standard TIFF settings + if saver[file_format] is None: + raise RuntimeError("File format is not set to TiffFormat, " + "this is a bug") + + # Set file format attributes + saver[file_format]["Depth"] = 1 # int8 | int16 | float32 | other + saver[file_format]["SaveAlpha"] = 0 + diff --git a/colorbleed/plugins/fusion/publish/_validate_filenames.py b/colorbleed/plugins/fusion/publish/_validate_filenames.py deleted file mode 100644 index 7f7764fb17..0000000000 --- a/colorbleed/plugins/fusion/publish/_validate_filenames.py +++ /dev/null @@ -1,52 +0,0 @@ -import os - -import pyblish.api - - -class ValidateFileNames(pyblish.api.Validator): - """Ensure all file names follow the same structure - - Filename should have identifiable parts: - - name ( example: Avengers_shot010_preview ) - - frame ( example: #### ) - - extension ( example: tiff ) - - The result when rendering frame 1250 would be as follows: - Avengers_shot010_preview.1250.tiff - - When certain parts need to be rendered out separately for some reason it - is advisable to something all the lines of: - Avengers_shot010_character_beauty.1250.tiff - """ - - order = pyblish.api.ValidatorOrder - label = "Validate File Names (Saver)" - families = ["colorbleed.imagesequence"] - hosts = ["fusion"] - - @classmethod - def get_invalid(cls, instance): - - invalid = [] - - path = instance.data["path"] - basename = os.path.basename(path) - - parts = basename.split(".") - if len(parts) != 3: - invalid.append(instance) - cls.log.error("%s has %i parts, should be 3" - % (instance, len(parts))) - else: - is_numbers = all(i.isdigit() for i in parts[1]) - if len(parts[1]) != 4 or not is_numbers: - cls.log.error("Number padding is not four digits") - invalid.append(instance) - - return invalid - - def process(self, instance): - invalid = self.get_invalid(instance) - if invalid: - raise RuntimeError("Found %i instances with a wrong file name " - "structure" % len(invalid)) diff --git a/colorbleed/plugins/fusion/publish/_validate_frame_range.py b/colorbleed/plugins/fusion/publish/_validate_frame_range.py deleted file mode 100644 index 134180d675..0000000000 --- a/colorbleed/plugins/fusion/publish/_validate_frame_range.py +++ /dev/null @@ -1,19 +0,0 @@ -import pyblish.api - - -class ValidateFrameRange(pyblish.api.InstancePlugin): - """Validate the frame range of the current Saver""" - - order = pyblish.api.ValidatorOrder - label = "Validate Frame Range" - families = ["colorbleed.imagesequence"] - hosts = ["fusion"] - - @classmethod - def get_invalid(cls, instance): - return [] - - def process(self, instance): - invalid = self.get_invalid(instance) - if invalid: - raise RuntimeError("Animation content is invalid. See log.") \ No newline at end of file diff --git a/colorbleed/plugins/fusion/publish/collect_instances.py b/colorbleed/plugins/fusion/publish/collect_instances.py index e04fb1d432..ae8e72c85a 100644 --- a/colorbleed/plugins/fusion/publish/collect_instances.py +++ b/colorbleed/plugins/fusion/publish/collect_instances.py @@ -3,6 +3,8 @@ import re import pyblish.api +from avalon.vendor import clique + def get_comp_render_range(comp): """Return comp's start and end render range.""" @@ -39,21 +41,18 @@ class CollectInstances(pyblish.api.ContextPlugin): start, end = get_comp_render_range(comp) for tool in savers: path = tool["Clip"][comp.TIME_UNDEFINED] - if not path: self.log.warning("Skipping saver because it " "has no path set: {}".format(tool.Name)) continue fname = os.path.basename(path) - _subset, ext = os.path.splitext(fname) + # we don't use the padding + basename, ext = os.path.splitext(fname) + chars = [char for char in basename if + not char.isdigit() and char != "."] - # match all digits and character but no points - match = re.match("([\d\w]+)", _subset) - if not match: - self.log.warning("Skipping save because the file name is not" - "compatible") - subset = match.group(0) + subset = "".join(chars) # Include start and end render frame in label label = "{subset} ({start}-{end})".format(subset=subset, @@ -69,9 +68,10 @@ class CollectInstances(pyblish.api.ContextPlugin): "label": label, "families": ["colorbleed.imagesequence"], "family": "colorbleed.imagesequence", - "tool": tool # keep link to the tool }) + instance.append(tool) # For future use, store the tool + self.log.info("Found: \"%s\" " % path) # Sort/grouped by family (preserving local index) diff --git a/colorbleed/plugins/fusion/publish/extract_image_sequence.py b/colorbleed/plugins/fusion/publish/extract_image_sequence.py index 26264bfcad..e3f406ba39 100644 --- a/colorbleed/plugins/fusion/publish/extract_image_sequence.py +++ b/colorbleed/plugins/fusion/publish/extract_image_sequence.py @@ -1,10 +1,27 @@ import os -import glob -import re import pyblish.api -_frame_regex = re.compile("[0-9]") +from avalon.vendor import clique + + +def get_collection_for_instance(subset, collections): + """Get the collection which matches the subset name + + Args: + subset (str): name of the subset + collections (clique.Collection): + + Returns: + list + """ + for collection in collections: + name = collection.head + if name[-1] == ".": + name = name[:-1] + + if name == subset: + return collection class ExtractImageSequence(pyblish.api.Extractor): @@ -14,7 +31,7 @@ class ExtractImageSequence(pyblish.api.Extractor): """ order = pyblish.api.ExtractorOrder - label = "Extract Image Sequence" + label = "Extract Image Sequence (Local)" families = ["colorbleed.imagesequence"] hosts = ["fusion"] @@ -37,44 +54,33 @@ class ExtractImageSequence(pyblish.api.Extractor): # Get all output paths after render was successful # Note the .ID check, this is to ensure we only have savers - instances = [i for i in context[:] if i.data["tool"].ID == "Saver"] + # Use instance[0] to get the tool + instances = [i for i in context[:] if i[0].ID == "Saver"] for instance in instances: - # Ensure each instance has its files for the integrator - output_path = instance.data["path"] - query = self._create_qeury(output_path) - files = glob.glob(query) + # Ensure each instance has its files for the integrator + output_path = os.path.dirname(instance.data["path"]) + files = os.listdir(output_path) + pattern = clique.PATTERNS["frames"] + collections, remainder = clique.assemble(files, + patterns=[pattern], + minimum_items=1) + + assert not remainder, ("There shouldn't have been a remainder " + "for '%s': %s" % + (instance.data["subset"], + remainder)) + + # Filter collections to ensure specific files are part of + # the instance, store instance's collection if "files" not in instance.data: instance.data["files"] = list() - print("{} files : {}".format(instance.data["subset"], - len(files))) - instance.data["files"].append(files) + subset = instance.data["subset"] + collection = get_collection_for_instance(subset, collections) + + # Add found collection to the instance + instance.data["files"].append(list(collection)) # Ensure the integrator has stagingDir - instance.data["stagingDir"] = os.path.dirname(output_path) - - def _create_qeury(self, instance): - """Create a queriable string for glob - - Args: - instance: instance of current context (comp) - - Returns: - str - """ - - clipname = instance.data["path"] - clip_dir = os.path.dirname(clipname) - basename = os.path.basename(clipname) - _, ext = os.path.splitext(basename) - - match = re.match("([0-9]{4})", basename) - if not match: - query_name = "{}.*.{}".format(instance.data["subset"], ext[1:]) - else: - query_name = basename.replace(match.group(0), ".*.") - - query = os.path.join(clip_dir, query_name) - - return query + instance.data["stagingDir"] = output_path diff --git a/colorbleed/plugins/fusion/publish/validate_unique_name.py b/colorbleed/plugins/fusion/publish/validate_unique_name.py index 6933729eb2..3388263422 100644 --- a/colorbleed/plugins/fusion/publish/validate_unique_name.py +++ b/colorbleed/plugins/fusion/publish/validate_unique_name.py @@ -4,7 +4,7 @@ import pyblish.api class ValidateUniqueSubsetName(pyblish.api.InstancePlugin): """Ensure all instances have a unique subset name""" - order = pyblish.api.ValidatorOrder + order = pyblish.api.ValidatorOrder + 0.1 label = "Validate Unique Subset Names" families = ["colorbleed.imagesequence"] hosts = ["fusion"]