From 5a1c5bae93f53e54461e5e5e140c05d28f113cd9 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Thu, 15 Oct 2020 15:47:22 +0200 Subject: [PATCH] PypeHarmony and ImageSequenceLoader --- pype/hosts/harmony/__init__.py | 161 +++------- pype/hosts/harmony/js/.eslintrc.json | 15 + .../harmony/js/loaders/ImageSequenceLoader.js | 249 +++++++++++++++ pype/hosts/harmony/js/pype_harmony.js | 158 ++++++++++ .../harmony/load/load_imagesequence.py | 290 +++--------------- 5 files changed, 515 insertions(+), 358 deletions(-) create mode 100644 pype/hosts/harmony/js/.eslintrc.json create mode 100644 pype/hosts/harmony/js/loaders/ImageSequenceLoader.js create mode 100644 pype/hosts/harmony/js/pype_harmony.js diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index fbf5ca6f12..1ffc6d8b6d 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -1,56 +1,44 @@ +# -*- coding: utf-8 -*- +"""Pype Harmony Host implementation.""" import os -import sys from avalon import api, io, harmony -from avalon.vendor import Qt import avalon.tools.sceneinventory + import pyblish.api + from pype import lib from pype.api import config def set_scene_settings(settings): + """Set correct scene settings in Harmony. - signature = harmony.signature("set_scene_settings") - func = """function %s(args) - { - if (args[0]["fps"]) - { - scene.setFrameRate(args[0]["fps"]); - } - if (args[0]["frameStart"] && args[0]["frameEnd"]) - { - var duration = args[0]["frameEnd"] - args[0]["frameStart"] + 1 + Args: + settings (dict): Scene settings. - if (frame.numberOf() < duration) - { - frame.insert( - duration, duration - frame.numberOf() - ); - } + Returns: + dict: Dictionary of settings to set. - scene.setStartFrame(1); - scene.setStopFrame(duration); - } - if (args[0]["resolutionWidth"] && args[0]["resolutionHeight"]) - { - scene.setDefaultResolution( - args[0]["resolutionWidth"], args[0]["resolutionHeight"], 41.112 - ) - } - } - %s - """ % (signature, signature) - harmony.send({"function": func, "args": [settings]}) + """ + harmony.send( + {"function": "PypeHarmony.setSceneSettings", "args": settings}) def get_asset_settings(): + """Get settings on current asset from database. + + Returns: + dict: Scene data. + + """ asset_data = lib.get_asset()["data"] fps = asset_data.get("fps") frame_start = asset_data.get("frameStart") frame_end = asset_data.get("frameEnd") resolution_width = asset_data.get("resolutionWidth") resolution_height = asset_data.get("resolutionHeight") + entity_type = asset_data.get("entityType") scene_data = { "fps": fps, @@ -63,17 +51,25 @@ def get_asset_settings(): try: skip_resolution_check = \ config.get_presets()["harmony"]["general"]["skip_resolution_check"] + skip_timelines_check = \ + config.get_presets()["harmony"]["general"]["skip_timelines_check"] except KeyError: skip_resolution_check = [] + skip_timelines_check = [] if os.getenv('AVALON_TASK') in skip_resolution_check: scene_data.pop("resolutionWidth") scene_data.pop("resolutionHeight") + if entity_type in skip_timelines_check: + scene_data.pop('frameStart', None) + scene_data.pop('frameEnd', None) + return scene_data def ensure_scene_settings(): + """Validate if Harmony scene has valid settings.""" settings = get_asset_settings() invalid_settings = [] @@ -86,23 +82,22 @@ def ensure_scene_settings(): # Warn about missing attributes. if invalid_settings: - print("Starting new QApplication..") - app = Qt.QtWidgets.QApplication.instance() - if not app: - app = Qt.QtWidgets.QApplication(sys.argv) - - message_box = Qt.QtWidgets.QMessageBox() - message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning) msg = "Missing attributes:" for item in invalid_settings: msg += f"\n{item}" - message_box.setText(msg) - message_box.exec_() + + harmony.send( + {"function": "PypeHarmony.message", "args": msg}) set_scene_settings(valid_settings) def check_inventory(): + """Check is scene contains outdated containers. + + If it does it will colorize outdated nodes and display warning message + in Harmony. + """ if not lib.any_outdated(): return @@ -121,86 +116,36 @@ def check_inventory(): outdated_containers.append(container) # Colour nodes. - sig = harmony.signature("set_color") - func = """function %s(args){ - - for( var i =0; i <= args[0].length - 1; ++i) - { - var red_color = new ColorRGBA(255, 0, 0, 255); - node.setColor(args[0][i], red_color); - } - } - %s - """ % (sig, sig) outdated_nodes = [] for container in outdated_containers: if container["loader"] == "ImageSequenceLoader": outdated_nodes.append( harmony.find_node_by_name(container["name"], "READ") ) - harmony.send({"function": func, "args": [outdated_nodes]}) + harmony.send({"function": "PypeHarmony.setColor", "args": outdated_nodes}) # Warn about outdated containers. - print("Starting new QApplication..") - app = Qt.QtWidgets.QApplication(sys.argv) - - message_box = Qt.QtWidgets.QMessageBox() - message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning) msg = "There are outdated containers in the scene." - message_box.setText(msg) - message_box.exec_() - - # Garbage collect QApplication. - del app + harmony.send({"function": "PypeHarmony.message", "args": msg}) def application_launch(): + """Set scene settings and check outdated containers on Harmony startup.""" ensure_scene_settings() check_inventory() def export_template(backdrops, nodes, filepath): + """Export Template to file. - sig = harmony.signature("set_color") - func = """function %s(args) - { + Args: + backdrops (list): List of backdrops to export. + nodes (list): List of nodes to export. + filepath (str): Path where to save Template. - var temp_node = node.add("Top", "temp_note", "NOTE", 0, 0, 0); - var template_group = node.createGroup(temp_node, "temp_group"); - node.deleteNode( template_group + "/temp_note" ); - - selection.clearSelection(); - for (var f = 0; f < args[1].length; f++) - { - selection.addNodeToSelection(args[1][f]); - } - - Action.perform("copy()", "Node View"); - - selection.clearSelection(); - selection.addNodeToSelection(template_group); - Action.perform("onActionEnterGroup()", "Node View"); - Action.perform("paste()", "Node View"); - - // Recreate backdrops in group. - for (var i = 0 ; i < args[0].length; i++) - { - MessageLog.trace(args[0][i]); - Backdrop.addBackdrop(template_group, args[0][i]); - }; - - Action.perform( "selectAll()", "Node View" ); - copyPaste.createTemplateFromSelection(args[2], args[3]); - - // Unfocus the group in Node view, delete all nodes and backdrops - // created during the process. - Action.perform("onActionUpToParent()", "Node View"); - node.deleteNode(template_group, true, true); - } - %s - """ % (sig, sig) + """ harmony.send({ - "function": func, + "function": "PypeHarmony.exportTemplate", "args": [ backdrops, nodes, @@ -211,7 +156,8 @@ def export_template(backdrops, nodes, filepath): def install(): - print("Installing Pype config...") + """Install Pype as host config.""" + print("Installing Pype config ...") plugins_directory = os.path.join( os.path.dirname(os.path.dirname(os.path.dirname(__file__))), @@ -239,17 +185,12 @@ def install(): def on_pyblish_instance_toggled(instance, old_value, new_value): """Toggle node enabling on instance toggles.""" - - sig = harmony.signature("enable_node") - func = """function %s(args) - { - node.setEnable(args[0], args[1]) - } - %s - """ % (sig, sig) try: harmony.send( - {"function": func, "args": [instance[0], new_value]} + { + "function": "PypeHarmony.toggleInstance", + "args": [instance[0], new_value] + } ) except IndexError: print(f"Instance '{instance}' is missing node") diff --git a/pype/hosts/harmony/js/.eslintrc.json b/pype/hosts/harmony/js/.eslintrc.json new file mode 100644 index 0000000000..f88e9716b4 --- /dev/null +++ b/pype/hosts/harmony/js/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "env": { + "browser": true + }, + "extends": [ + "google" + ], + "parserOptions": { + "ecmaVersion": 3 + }, + "rules": { + "no-var": "off", + "comma-dangle": "off" + } +} diff --git a/pype/hosts/harmony/js/loaders/ImageSequenceLoader.js b/pype/hosts/harmony/js/loaders/ImageSequenceLoader.js new file mode 100644 index 0000000000..3aa0648a4f --- /dev/null +++ b/pype/hosts/harmony/js/loaders/ImageSequenceLoader.js @@ -0,0 +1,249 @@ +// *************************************************************************** +// * ImageSequenceLoader * +// *************************************************************************** + + +// check if PypeHarmony is defined and if not, load it. +if (typeof PypeHarmony !== 'undefined') { + var PYPE_HARMONY_JS = System.getenv('PYPE_HARMONY_JS'); + include(PYPE_HARMONY_JS + '/pype_harmony.js'); +} + + +/** + * @namespace + * @classdesc Image Sequence loader JS code. + * @property {Object} loaders Namespace for Loaders JS code. + * @property {Object} Creators Namespace for Creators JS code. + * @property {Object} Publish Namespace for Publish plugins JS code. + */ +ImageSequenceLoader = function() { + this.PNGTransparencyMode = 0; // Premultiplied wih Black + this.TGATransparencyMode = 0; // Premultiplied wih Black + this.SGITransparencyMode = 0; // Premultiplied wih Black + this.LayeredPSDTransparencyMode = 1; // Straight + this.FlatPSDTransparencyMode = 2; // Premultiplied wih White +}; + + +/** + * Get unique column name. + * @function + * @param {string} columnPrefix Column name. + * @return {string} Unique column name. + */ +ImageSequenceLoader.prototype.getUniqueColumnName = function(columnPrefix) { + var suffix = 0; + // finds if unique name for a column + var columnName = columnPrefix; + while (suffix < 2000) { + if (!column.type(columnName)) { + break; + } + + suffix = suffix + 1; + columnName = columnPrefix + '_' + suffix; + } + return columnName; +}; + + +/** + * Import file sequences into Harmony. + * @function + * @param {object} args Arguments for import, see Example. + * @return {string} Read node name + * + * @example + * // Agrguments are in following order: + * var args = [ + * root, // Harmony root + * files, // Files in file sequences + * name, // Node name + * startFrame // Sequence starting frame + * ]; + */ +ImageSequenceLoader.prototype.importFiles = function(args) { + var root = args[0]; + var files = args[1]; + var name = args[2]; + var startFrame = args[3]; + var vectorFormat = null; + var extension = null; + var filename = files[0]; + var pos = filename.lastIndexOf('.'); + if (pos < 0) { + return null; + } + + extension = filename.substr(pos+1).toLowerCase(); + if (extension == 'jpeg') { + extension = 'jpg'; + } + + if (extension == 'tvg') { + vectorFormat = 'TVG'; + extension ='SCAN'; // element.add() will use this. + } + + var elemId = element.add( + name, + 'BW', + scene.numberOfUnitsZ(), + extension.toUpperCase(), + vectorFormat + ); + + if (elemId == -1) { + // hum, unknown file type most likely -- let's skip it. + return null; // no read to add. + } + + var uniqueColumnName = this.getUniqueColumnName(name); + column.add(uniqueColumnName, 'DRAWING'); + column.setElementIdOfDrawing(uniqueColumnName, elemId); + var read = node.add(root, name, 'READ', 0, 0, 0); + var transparencyAttr = node.getAttr( + read, frame.current(), 'READ_TRANSPARENCY' + ); + var opacityAttr = node.getAttr(read, frame.current(), 'OPACITY'); + transparencyAttr.setValue(true); + opacityAttr.setValue(true); + var alignmentAttr = node.getAttr(read, frame.current(), 'ALIGNMENT_RULE'); + alignmentAttr.setValue('ASIS'); + var transparencyModeAttr = node.getAttr( + read, frame.current(), 'applyMatteToColor' + ); + if (extension === 'png') { + transparencyModeAttr.setValue(this.PNGTransparencyMode); + } + if (extension === 'tga') { + transparencyModeAttr.setValue(this.TGATransparencyMode); + } + if (extension === 'sgi') { + transparencyModeAttr.setValue(this.SGITransparencyMode); + } + if (extension === 'psd') { + transparencyModeAttr.setValue(this.FlatPSDTransparencyMode); + } + if (extension === 'jpg') { + transparencyModeAttr.setValue(this.LayeredPSDTransparencyMode); + } + + node.linkAttr(read, 'DRAWING.ELEMENT', uniqueColumnName); + if (files.length === 1) { + // Create a drawing drawing, 'true' indicate that the file exists. + Drawing.create(elemId, 1, true); + // Get the actual path, in tmp folder. + var drawingFilePath = Drawing.filename(elemId, '1'); + PypeHarmony.copyFile(files[0], drawingFilePath); + // Expose the image for the entire frame range. + for (var i =0; i <= frame.numberOf() - 1; ++i) { + timing = startFrame + i; + column.setEntry(uniqueColumnName, 1, timing, '1'); + } + } else { + // Create a drawing for each file. + for (var i =0; i <= files.length - 1; ++i) { + timing = startFrame + i; + // Create a drawing drawing, 'true' indicate that the file exists. + Drawing.create(elemId, timing, true); + // Get the actual path, in tmp folder. + var drawingFilePath = Drawing.filename(elemId, timing.toString()); + PypeHarmony.copyFile(files[i], drawingFilePath); + column.setEntry(uniqueColumnName, 1, timing, timing.toString()); + } + } + var greenColor = new ColorRGBA(0, 255, 0, 255); + node.setColor(read, greenColor); + return read; +}; + + +/** + * Replace files sequences in Harmony. + * @function + * @param {object} args Arguments for import, see Example. + * @return {string} Read node name + * + * @example + * // Agrguments are in following order: + * var args = [ + * files, // Files in file sequences + * name, // Node name + * startFrame // Sequence starting frame + * ]; + */ +ImageSequenceLoader.prototype.replaceFiles = function(args) { + var files = args[0]; + MessageLog.trace(files); + MessageLog.trace(files.length); + var _node = args[1]; + var startFrame = args[2]; + var _column = node.linkedColumn(_node, 'DRAWING.ELEMENT'); + var elemId = column.getElementIdOfDrawing(_column); + // Delete existing drawings. + var timings = column.getDrawingTimings(_column); + for ( var i =0; i <= timings.length - 1; ++i) { + column.deleteDrawingAt(_column, parseInt(timings[i])); + } + var filename = files[0]; + var pos = filename.lastIndexOf('.'); + if (pos < 0) { + return null; + } + var extension = filename.substr(pos+1).toLowerCase(); + if (extension === 'jpeg') { + extension = 'jpg'; + } + + var transparencyModeAttr = node.getAttr( + _node, frame.current(), 'applyMatteToColor' + ); + if (extension === 'png') { + transparencyModeAttr.setValue(this.PNGTransparencyMode); + } + if (extension === 'tga') { + transparencyModeAttr.setValue(this.TGATransparencyMode); + } + if (extension === 'sgi') { + transparencyModeAttr.setValue(this.SGITransparencyMode); + } + if (extension == 'psd') { + transparencyModeAttr.setValue(this.FlatPSDTransparencyMode); + } + if (extension === 'jpg') { + transparencyModeAttr.setValue(this.LayeredPSDTransparencyMode); + } + + if (files.length == 1) { + // Create a drawing drawing, 'true' indicate that the file exists. + Drawing.create(elemId, 1, true); + // Get the actual path, in tmp folder. + var drawingFilePath = Drawing.filename(elemId, '1'); + PypeHarmony.copyFile(files[0], drawingFilePath); + MessageLog.trace(files[0]); + MessageLog.trace(drawingFilePath); + // Expose the image for the entire frame range. + for (var i =0; i <= frame.numberOf() - 1; ++i) { + timing = startFrame + i; + column.setEntry(_column, 1, timing, '1'); + } + } else { + // Create a drawing for each file. + for (var i =0; i <= files.length - 1; ++i) { + timing = startFrame + i; + // Create a drawing drawing, 'true' indicate that the file exists. + Drawing.create(elemId, timing, true); + // Get the actual path, in tmp folder. + var drawingFilePath = Drawing.filename(elemId, timing.toString()); + PypeHarmony.copyFile( files[i], drawingFilePath ); + column.setEntry(_column, 1, timing, timing.toString()); + } + } + var greenColor = new ColorRGBA(0, 255, 0, 255); + node.setColor(_node, greenColor); +}; + +// add self to Pype Loaders +PypeHarmony.Loaders.ImageSequenceLoader = new ImageSequenceLoader(); diff --git a/pype/hosts/harmony/js/pype_harmony.js b/pype/hosts/harmony/js/pype_harmony.js new file mode 100644 index 0000000000..c8de8063c0 --- /dev/null +++ b/pype/hosts/harmony/js/pype_harmony.js @@ -0,0 +1,158 @@ +// *************************************************************************** +// * Pype Harmony Host * +// *************************************************************************** + + +/** + * @namespace + * @classdesc PypeHarmony encapsulate all Pype related functions. + * @property {Object} loaders Namespace for Loaders JS code. + * @property {Object} Creators Namespace for Creators JS code. + * @property {Object} Publish Namespace for Publish plugins JS code. + */ +var PypeHarmony = { + Loaders: {}, + Creators: {}, + Publish: {} +}; + + +/** + * Show message in Harmony. + * @function + * @param {string} message Argument containing message. + */ +PypeHarmony.message = function(message) { + MessageBox.information(message); +}; + + +/** + * Set scene setting based on shot/asset settngs. + * @function + * @param {obj} settings Scene settings. + */ +PypeHarmony.setSceneSettings = function(settings) { + if (settings['fps']) { + scene.setFrameRate(settings['fps']); + } + + if (settings['frameStart'] && settings['frameEnd']) { + var duration = settings['frameEnd'] - settings['frameStart'] + 1; + + if (frame.numberOf() > duration) { + frame.remove(duration, frame.numberOf() - duration); + } + + if (frame.numberOf() < duration) { + frame.insert(duration, duration - frame.numberOf()); + } + + scene.setStartFrame(1); + scene.setStopFrame(duration); + } + if (settings['resolutionWidth'] && settings['resolutionHeight']) { + scene.setDefaultResolution( + settings['resolutionWidth'], settings['resolutionHeight'], 41.112 + ); + } +}; + + +/** + * Set color of nodes. + * @function + * @param {array} nodes List of nodes. + */ +PypeHarmony.setColor = function(nodes) { + for (var i =0; i <= nodes.length - 1; ++i) { + var redColor = new ColorRGBA(255, 0, 0, 255); + node.setColor(nodes[i], redColor); + } +}; + + +/** + * Extract Template into file. + * @function + * @param {array} args Arguments for template extraction. + * + * @example + * // arguments are in this order: + * var args = [backdrops, nodes, templateFilename, templateDir]; + * + */ +PypeHarmony.exportTemplate = function(args) { + var tempNode = node.add('Top', 'temp_note', 'NOTE', 0, 0, 0); + var templateGroup = node.createGroup(tempNode, 'temp_group'); + node.deleteNode( templateGroup + '/temp_note' ); + + selection.clearSelection(); + for (var f = 0; f < args[1].length; f++) { + selection.addNodeToSelection(args[1][f]); + } + + Action.perform('copy()', 'Node View'); + + selection.clearSelection(); + selection.addNodeToSelection(template_group); + Action.perform('onActionEnterGroup()', 'Node View'); + Action.perform('paste()', 'Node View'); + + // Recreate backdrops in group. + for (var i = 0; i < args[0].length; i++) { + MessageLog.trace(args[0][i]); + Backdrop.addBackdrop(template_group, args[0][i]); + }; + + Action.perform('selectAll()', 'Node View' ); + copyPaste.createTemplateFromSelection(args[2], args[3]); + + // Unfocus the group in Node view, delete all nodes and backdrops + // created during the process. + Action.perform('onActionUpToParent()', 'Node View'); + node.deleteNode(template_group, true, true); +}; + + +/** + * Toggle instance in Harmony. + * @function + * @param {array} args Instance name and value. + */ +PypeHarmony.toggleInstance = function(args) { + node.setEnable(args[0], args[1]); +}; + + +/** + * Delete node in Harmony. + * @function + * @param {string} _node Node name. + */ +PypeHarmony.deleteNode = function(_node) { + node.deleteNode(_node, true, true); +}; + + +/** + * Copy file. + * @function + * @param {string} src Source file name. + * @param {string} dst Destination file name. + */ +PypeHarmony.copyFile = function(src, dst) { + var srcFile = new PermanentFile(src); + var dstFile = new PermanentFile(dst); + srcFile.copy(dstFile); +}; + +/** + * create RGBA color from array. + * @function + * @param {array} rgba array of rgba values. + * @return {ColorRGBA} ColorRGBA Harmony class. + */ +PypeHarmony.color = function(rgba) { + return new ColorRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); +}; diff --git a/pype/plugins/harmony/load/load_imagesequence.py b/pype/plugins/harmony/load/load_imagesequence.py index 056d5554ad..7809d890f5 100644 --- a/pype/plugins/harmony/load/load_imagesequence.py +++ b/pype/plugins/harmony/load/load_imagesequence.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +"""Loader for image sequences.""" import os import uuid @@ -6,235 +8,27 @@ import clique from avalon import api, harmony import pype.lib -copy_files = """function copyFile(srcFilename, dstFilename) -{ - var srcFile = new PermanentFile(srcFilename); - var dstFile = new PermanentFile(dstFilename); - srcFile.copy(dstFile); -} -""" - -import_files = """var PNGTransparencyMode = 1; //Premultiplied wih Black -var TGATransparencyMode = 0; //Premultiplied wih Black -var SGITransparencyMode = 0; //Premultiplied wih Black -var LayeredPSDTransparencyMode = 1; //Straight -var FlatPSDTransparencyMode = 2; //Premultiplied wih White - -function getUniqueColumnName( column_prefix ) -{ - var suffix = 0; - // finds if unique name for a column - var column_name = column_prefix; - while(suffix < 2000) - { - if(!column.type(column_name)) - break; - - suffix = suffix + 1; - column_name = column_prefix + "_" + suffix; - } - return column_name; -} - -function import_files(args) -{ - var root = args[0]; - var files = args[1]; - var name = args[2]; - var start_frame = args[3]; - - var vectorFormat = null; - var extension = null; - var filename = files[0]; - - var pos = filename.lastIndexOf("."); - if( pos < 0 ) - return null; - - extension = filename.substr(pos+1).toLowerCase(); - - if(extension == "jpeg") - extension = "jpg"; - if(extension == "tvg") - { - vectorFormat = "TVG" - extension ="SCAN"; // element.add() will use this. - } - - var elemId = element.add( - name, - "BW", - scene.numberOfUnitsZ(), - extension.toUpperCase(), - vectorFormat - ); - if (elemId == -1) - { - // hum, unknown file type most likely -- let's skip it. - return null; // no read to add. - } - - var uniqueColumnName = getUniqueColumnName(name); - column.add(uniqueColumnName , "DRAWING"); - column.setElementIdOfDrawing(uniqueColumnName, elemId); - - var read = node.add(root, name, "READ", 0, 0, 0); - var transparencyAttr = node.getAttr( - read, frame.current(), "READ_TRANSPARENCY" - ); - var opacityAttr = node.getAttr(read, frame.current(), "OPACITY"); - transparencyAttr.setValue(true); - opacityAttr.setValue(true); - - var alignmentAttr = node.getAttr(read, frame.current(), "ALIGNMENT_RULE"); - alignmentAttr.setValue("ASIS"); - - var transparencyModeAttr = node.getAttr( - read, frame.current(), "applyMatteToColor" - ); - if (extension == "png") - transparencyModeAttr.setValue(PNGTransparencyMode); - if (extension == "tga") - transparencyModeAttr.setValue(TGATransparencyMode); - if (extension == "sgi") - transparencyModeAttr.setValue(SGITransparencyMode); - if (extension == "psd") - transparencyModeAttr.setValue(FlatPSDTransparencyMode); - if (extension == "jpg") - transparencyModeAttr.setValue(LayeredPSDTransparencyMode); - - node.linkAttr(read, "DRAWING.ELEMENT", uniqueColumnName); - - if (files.length == 1) - { - // Create a drawing drawing, 'true' indicate that the file exists. - Drawing.create(elemId, 1, true); - // Get the actual path, in tmp folder. - var drawingFilePath = Drawing.filename(elemId, "1"); - copyFile(files[0], drawingFilePath); - // Expose the image for the entire frame range. - for( var i =0; i <= frame.numberOf() - 1; ++i) - { - timing = start_frame + i - column.setEntry(uniqueColumnName, 1, timing, "1"); - } - } else { - // Create a drawing for each file. - for( var i =0; i <= files.length - 1; ++i) - { - timing = start_frame + i - // Create a drawing drawing, 'true' indicate that the file exists. - Drawing.create(elemId, timing, true); - // Get the actual path, in tmp folder. - var drawingFilePath = Drawing.filename(elemId, timing.toString()); - copyFile( files[i], drawingFilePath ); - - column.setEntry(uniqueColumnName, 1, timing, timing.toString()); - } - } - - var green_color = new ColorRGBA(0, 255, 0, 255); - node.setColor(read, green_color); - - return read; -} -import_files -""" - -replace_files = """var PNGTransparencyMode = 1; //Premultiplied wih Black -var TGATransparencyMode = 0; //Premultiplied wih Black -var SGITransparencyMode = 0; //Premultiplied wih Black -var LayeredPSDTransparencyMode = 1; //Straight -var FlatPSDTransparencyMode = 2; //Premultiplied wih White - -function replace_files(args) -{ - var files = args[0]; - MessageLog.trace(files); - MessageLog.trace(files.length); - var _node = args[1]; - var start_frame = args[2]; - - var _column = node.linkedColumn(_node, "DRAWING.ELEMENT"); - var elemId = column.getElementIdOfDrawing(_column); - - // Delete existing drawings. - var timings = column.getDrawingTimings(_column); - for( var i =0; i <= timings.length - 1; ++i) - { - column.deleteDrawingAt(_column, parseInt(timings[i])); - } - - - var filename = files[0]; - var pos = filename.lastIndexOf("."); - if( pos < 0 ) - return null; - var extension = filename.substr(pos+1).toLowerCase(); - - if(extension == "jpeg") - extension = "jpg"; - - var transparencyModeAttr = node.getAttr( - _node, frame.current(), "applyMatteToColor" - ); - if (extension == "png") - transparencyModeAttr.setValue(PNGTransparencyMode); - if (extension == "tga") - transparencyModeAttr.setValue(TGATransparencyMode); - if (extension == "sgi") - transparencyModeAttr.setValue(SGITransparencyMode); - if (extension == "psd") - transparencyModeAttr.setValue(FlatPSDTransparencyMode); - if (extension == "jpg") - transparencyModeAttr.setValue(LayeredPSDTransparencyMode); - - if (files.length == 1) - { - // Create a drawing drawing, 'true' indicate that the file exists. - Drawing.create(elemId, 1, true); - // Get the actual path, in tmp folder. - var drawingFilePath = Drawing.filename(elemId, "1"); - copyFile(files[0], drawingFilePath); - MessageLog.trace(files[0]); - MessageLog.trace(drawingFilePath); - // Expose the image for the entire frame range. - for( var i =0; i <= frame.numberOf() - 1; ++i) - { - timing = start_frame + i - column.setEntry(_column, 1, timing, "1"); - } - } else { - // Create a drawing for each file. - for( var i =0; i <= files.length - 1; ++i) - { - timing = start_frame + i - // Create a drawing drawing, 'true' indicate that the file exists. - Drawing.create(elemId, timing, true); - // Get the actual path, in tmp folder. - var drawingFilePath = Drawing.filename(elemId, timing.toString()); - copyFile( files[i], drawingFilePath ); - - column.setEntry(_column, 1, timing, timing.toString()); - } - } - - var green_color = new ColorRGBA(0, 255, 0, 255); - node.setColor(_node, green_color); -} -replace_files -""" - class ImageSequenceLoader(api.Loader): - """Load images + """Load image sequences. + Stores the imported asset in a container named after the asset. """ + families = ["shot", "render", "image", "plate", "reference"] representations = ["jpeg", "png", "jpg"] def load(self, context, name=None, namespace=None, data=None): + """Plugin entry point. + Args: + context (:class:`pyblish.api.Context`): Context. + name (str, optional): Container name. + namespace (str, optional): Container namespace. + data (dict, optional): Additional data passed into loader. + + """ + self_name = self.__class__.__name__ collections, remainder = clique.assemble( os.listdir(os.path.dirname(self.fname)) ) @@ -257,7 +51,7 @@ class ImageSequenceLoader(api.Loader): name += "_{}".format(uuid.uuid4()) read_node = harmony.send( { - "function": copy_files + import_files, + "function": f"PypeHarmony.Loaders.{self_name}.importFiles", # noqa: E501 "args": ["Top", files, name, 1] } )["result"] @@ -267,11 +61,19 @@ class ImageSequenceLoader(api.Loader): namespace, read_node, context, - self.__class__.__name__, + self_name, nodes=[read_node] ) def update(self, container, representation): + """Update loaded containers. + + Args: + container (dict): Container data. + representation (dict): Representation data. + + """ + self_name = self.__class__.__name__ node = harmony.find_node_by_name(container["name"], "READ") path = api.get_representation_path(representation) @@ -295,50 +97,42 @@ class ImageSequenceLoader(api.Loader): harmony.send( { - "function": copy_files + replace_files, + "function": f"PypeHarmony.Loaders.{self_name}.replaceFiles", "args": [files, node, 1] } ) # Colour node. - sig = harmony.signature("copyFile") - func = """function %s(args){ - for( var i =0; i <= args[0].length - 1; ++i) - { - var red_color = new ColorRGBA(255, 0, 0, 255); - var green_color = new ColorRGBA(0, 255, 0, 255); - if (args[1] == "red"){ - node.setColor(args[0], red_color); - } - if (args[1] == "green"){ - node.setColor(args[0], green_color); - } - } - } - %s - """ % (sig, sig) if pype.lib.is_latest(representation): - harmony.send({"function": func, "args": [node, "green"]}) + harmony.send( + { + "function": "PypeHarmony.setColor", + "args": [node, [0, 255, 0, 255]] + }) else: - harmony.send({"function": func, "args": [node, "red"]}) + harmony.send( + { + "function": "PypeHarmony.setColor", + "args": [node, [255, 0, 0, 255]] + }) harmony.imprint( node, {"representation": str(representation["_id"])} ) def remove(self, container): - node = harmony.find_node_by_name(container["name"], "READ") + """Remove loaded container. + + Args: + container (dict): Container data. - func = """function deleteNode(_node) - { - node.deleteNode(_node, true, true); - } - deleteNode """ + node = harmony.find_node_by_name(container["name"], "READ") harmony.send( - {"function": func, "args": [node]} + {"function": "PypeHarmony.deleteNode", "args": [node]} ) harmony.imprint(node, {}, remove=True) def switch(self, container, representation): + """Switch loaded representations.""" self.update(container, representation)