Python "it" Scripting
Adding to the Commands Menu


return to main index


Introduction

Menu items can be added to the Commands menu of the 'it' window relatively easily. Pixar's document,
    "it" Custom Commands
provides a clear explanation of how it is done.

This tutorial presents two examples of 'it' scripting. The first shows how the script "SaveAll.py" can be directly executed from the Commands menu - figure 1. The second example demonstates how the SaveAll can be indirectly executed from simple dialog window - figure 2.



Figure 1



Figure 2


Direct Execution

If the reader already has the SaveAll.py script it should be duplicated and the original saved with another name. To become part of the "it" menu structure the saveAll.py script must implement a sub-class of Pixar's it.It3Command class. The code that does this is shown next.


import it, time, os
from it.It3Command import It3Command
  
class SaveAll(It3Command):
    def __init__(self):
        self.m_menuPath = 'Commands/Save All'
    def Invoke(self):
        self.saveAll()
  
    def saveAll(self, gamma=1.0, quality=100):
        remaining_code_not_shown
        ...
        ...
 
it.commands.append(SaveAll)

For naming consistency SaveAll() has been changed to saveAll(). To make the procedure a method of the SaveAllCommand class it's indentation should match __init__() and Invoke() and it's first argument must be self. As it's name suggests, the Invoke() method is called by "it" when the "Save All" menu item is selected. The class method it.commands.append() creates an additional menu item. The complete source code is here.



Indirect Execution via a Dialog Window

Adding a dialog window is slightly more tricky because a UI must be created using PythonQT. Because saveAll() accepts two explicit inputs it makes sense for the dialog window to provide control over gamma and image quality. For simplicity, this is done using two combo box menu widgets. The full code for the Save All dialog is shown in listing 1.


Listing 1 (SaveAll.py)


# Modified: Nov 16 2014 - checks if images have an existing a numeric extension.
# Modified: Nov 29 2014 - checks if images have a "v#-" prefix ex. "v22-".
import it, time, os
from it.It3Command import It3Command
from PythonQt.QtGui import QDialogButtonBox
from PythonQt.QtGui import QHBoxLayout
from PythonQt.QtGui import QVBoxLayout
from PythonQt.QtGui import QComboBox
  
class SaveAll(It3Command):
    def __init__(self):
        self.m_menuPath = 'Commands/Save All...'
        self.m_dialog = None
        self.m_stdButtons = QDialogButtonBox.Apply|QDialogButtonBox.Cancel
        
    def Invoke(self):
        if self.m_dialog == None:
            self.m_dialog = self.makeUI()
        self.m_dialog.show()
        self.m_dialog.raise_()
        self.m_dialog.activateWindow()
                
    def doit(self):
        gamma = float(self.m_gamma.currentText)
        quality = float(self.m_quality.currentText) * 100.0
        host_dir = self.saveAll(gamma, quality)
        it.app.Info('Images saved to "%s"' % host_dir)
        it.app.RaiseLogWindow()
        
    def makeUI(self):
        dlg = self.CreateDialog('Save All')
        contents = dlg.findChild(QVBoxLayout, 'contents')
  
        layout = QHBoxLayout()
        contents.addLayout(layout)
        label_gamma = QLabel("Gamma ")
        layout.addWidget(label_gamma)
        
        self.m_gamma = QComboBox()
        self.m_gamma.addItems(['1.0','1.8','2.0','2.2'])
        self.m_gamma.setCurrentIndex(3)
        layout.addWidget(self.m_gamma)
  
        layout = QHBoxLayout()
        contents.addLayout(layout)
        label_quality = QLabel("Quality ")
        layout.addWidget(label_quality)
        
        self.m_quality = QComboBox()
        self.m_quality.addItems(['0.5','0.75','1.0'])
        self.m_quality.setCurrentIndex(2)
        layout.addWidget(self.m_quality)
  
        bbox = dlg.findChild(QDialogButtonBox, 'bbox')
        doItButton = bbox.button(QDialogButtonBox.Apply)
        doItButton.setText('Save All')
        doItButton.connect('clicked()', self.doit)
        return dlg
            
    def saveAll(self, gamma=1.0, quality=100):
        localtime = time.asctime( time.localtime(time.time()) )
        localtime = localtime.replace(' ', '_')
        localtime = localtime.replace(':', '_')    
        outname = 'catalog_%s' % localtime
        cwdpath = os.getcwd()
        if len(cwdpath) < 3:
            cwdpath = os.environ['HOME']
            if len(cwdpath) < 3:    
                it.app.Error('Unable to determine the current working directory.')
                it.app.Error('Unable to save the images.')
                it.app.RaiseLogWindow()
                return    
        out_dirpath = os.path.join(cwdpath,outname)
        if not os.path.exists(out_dirpath):
            os.mkdir(out_dirpath)
        aovDict = {}
        cat = it.app.GetCurrentCatalog()
        img_counter = 1
        for i in range (0, cat.GetChildCount()):
            element = cat.GetChild(i)
            imgname = it.os.path.basename( element.GetFilename() )
            if imgname == '_preview':
                continue
            # When "Export Catalog" has been used and the .itcat is re-opened
            # the images will appear as "v1-somename.tif", "v2-somename.tif". Here
            # we strip the "v#-" prefix - Nov 29 2014.
            tokens = imgname.rpartition('-')
            imgname = tokens[2]
            
            # Add a padded numeric extension, 
            # but only if it does not end with digits - Nov 16 2014
            tokens = imgname.rpartition('.')
            if len(tokens[1]) > 0 and self.isaNumber(tokens[2]):
                imgname = tokens[0] + ('.%04d' % img_counter) + '.jpg'
            else:
                imgname = imgname + ('.%04d' % img_counter) + '.jpg'
                            
            out_imgpath = os.path.join(out_dirpath, imgname)
            self.saveImage(element, out_imgpath, gamma, quality)
            img_counter += 1
  
            # Save any AOV's
            for j in range (0, element.GetChildCount()):
                aov = element.GetChild(j)
                aovname = it.os.path.basename( aov.GetFilename() )
                # Remove the extension
                aovname = os.path.splitext(aovname)[0]
                # Maintain unique counters for each AOV
                aov_counter = 1
                if aovDict.has_key(aovname):
                    aov_counter = aovDict[aovname]
                    aov_counter += 1;
                aovDict[aovname] = aov_counter
                
                # Strip a"v#-" prefix
                tokens = aovname.rpartition('-')
                aovname = tokens[2]
                
                # Add a padded numeric extension, again, only if the name doesn't
                # end with digits.
                tokens = aovname.rpartition('.')
                if len(tokens[1]) > 0 and self.isaNumber(tokens[2]):
                    aovname = tokens[0] + ('.%04d' % img_counter) + '.jpg'
                else:
                    aovname = aovname + ('.%04d' % img_counter) + '.jpg'
                #aovname = aovname + ('.%04d' % aov_counter) + '.jpg'
                out_aovpath = os.path.join(out_dirpath, aovname)
                self.saveImage(aov, out_aovpath, gamma, quality)
        return cwdpath
    def saveImage(self, element,path,gamma,quality):
        image = element.GetImage()
        image = image.Gamma(gamma);
        image.SetMetaDataItem('JPEG_QUALITY', quality)
        image.Save(path, ice.constants.FMT_JPEG)
    def isaNumber(self, str):
        try:
            int(str)
            return True
        except ValueError:
            return False    
it.commands.append(SaveAll)






© 2002- Malcolm Kesson. All rights reserved.