RMS "it"
Sample TCL Scripts


return to main index


Introduction

Pixar's Image Tool ("it") has a scripting interface based on TCL (Tool Command Language) and a language called IO. This page presents a few TCL scripts the reader might find useful. The reader should review the tutorial,
    "RMS:Setup for Mel, Rman, Slim & the Image Tool"
It provides a framework for setting up a directory structure for RenderMan Studio as well as information about environment variables and initialization files.


Present Working Directory

The Image Tool has a console that will accept commands, either those that are native to "it" or custom commands defined in .tcl scripts sourced at start-up. Some commands accept the name of a file that will either be loaded or saved by "it". A script determines the full path to a file relative to the present working directory of the console. When launched from Maya the PWD will generally be Maya's project directory. It is adviseable to check the PWD before running any commands that accept the name of an image file.

Right mouse click in the catalog window and choose Windows->Console from the popup menu. A console window will open. Enter the pwd command shown in figure 1.



Figure 1


To change directory use the cd command followed by an absolute or relative path - figure 2.



Figure 2



Saving "it" Images as JPEG files

The script in listing 1 enables an image to be saved as a jpeg. A description of the basic way the script can be used is given in the tutorial "RMS:Setup for Mel, Rman, Slim & the Image Tool". The proc (saveJPG) implemented by the script provides two default values. The first sets the gamma correction to 2.2. The second default sets the jpeg quality to 100%. If the default values of gamma and jpeg quality are acceptable the current catalog image can be saved using the following command.

 % saveJPG "test.jpg"

Aternatively, as shown in figure 3, the gamma and quality may be explicitly set.




Figure 3


Listing 1 (saveJPG.tcl)


# M.Kesson Dec 2010, modified Sept 2011
proc saveJPG { name { gamma 2.2 } { quality 100} } {
    set path [file join [pwd] $name]    
    set cat [it GetCurrentCatalog]
    set img [$cat GetCurrentImage]
    set handle [$img GetHandle]
    ::RAT::LogMsg NOTICE "saving image to \"$path\""
    
    it IceExpr "result := $handle Gamma($gamma)"    
    set expression "result SetMetaDataItem(\"JPEG_QUALITY\", $quality) ; "
    append expression "result Save(\"$path\", IceOutputType Jpeg)"
    it IceExpr $expression
    
    $cat DeleteImage [$cat GetCurrentImage]
    }


Saving All Images

The script in listing 2 enables all the images in a "it" catalog (figure 4) to be saved as a sequence of number jpeg files. The script automatically saves the images in a date and time stamped directory. For example,



Figure 5


would result in the creation of a directory, within the present working directory, with a name of the following form,

    Catalog_Jan31_13_06

This script also sets gamma to 2.2 and jpeg quality to 100%. Those default values may also be explicitly set as shown in figure 5.


Figure 4


Listing 2 (saveAll.tcl)


# A utility proc for saving ALL the images from the "it" window as
# numbered jpeg files. The images are saved in a folder with a
# date and time-stamped name, for example, 
#        Catalog_Oct06_07_28/image.0001.jpg
# Useage
# The proc can be used as follows,
#    % saveAll
# To specify a gamma of 2.1 enter this command,
#    % saveAll 2.1
# To specify both gamma and quality enter this command,
#    % saveAll 2.1 50
#
# M.Kesson Jan 21 2010
# updated Oct 6 2010
# Modified 1/31/11   Added gamma correction
# Modified 11/19/11  The user must use cd to change directory
#                    to the folder in which they wish to save an images.
# Modified 1/10/12   Added "set result" to line 40. RMS4 throws errors 
#                    without an assignment. Images named "_preview" are
#                    ignored.
proc saveAll { { gamma 2.2 } { quality 100 } } {
    set catelogName [getDateTime]
    set pwdPath [pwd]
    if { [string length $pwdPath] < 3 } {
        set line1 "Unable to determine your present working directory:\n"
        set line2 "       Unable to save the images.\n"
        set msg $line1$line2
        ::RAT::LogMsg ERROR $msg
        return
        }
    set path [file join $pwdPath $catelogName]
    if { [file exists $path] == 0 } {
        set result [file mkdir $path]
        }
    # We create a proxy image name so that we can process the
    # actual images in a consistent fashion
    set path [file join $path "image.jpg"]
    
    # If the user has provided a file extension we'll remove
    # it from the path
    set ext [file extension $path]
    if { [string length $ext] > 0 } {
        set len [expr [string length $path] - [string length $ext] - 1]
        set path [string range $path 0 $len]
        }
        
    # Check if the user has specified a relative path.
    # Relative paths begin with "./" or "../"
    if { [string equal -length 1 $path "."] } {
        set path [file join [pwd] $path]
        }
    
    # Get a list of the images in the catalog
    set cat [it GetCurrentCatalog]
    set imageList [$cat GetImageList]
    set num 1
    foreach img $imageList {
        set imgH [$img GetHandle]
        set name [$img GetFilename]
        if { [string equal $name "_preview"]  } {
            ::RAT::LogMsg NOTICE "skipping $name"
            continue
            }
        # Apply padding to the numeric extension.
        set fullpath "$path.[getPadding $num].jpg"
        saveImage $imgH $fullpath $gamma $quality
        incr num
        
        # The image may have sub-images ie. AOVs
        set subimageList [$img GetImageList]
        if { [llength $subimageList] > 0 } {
            foreach subimg $subimageList {
                set subimgH [$subimg GetHandle]
                set fullpath "$path.[getPadding $num].jpg"
                saveImage $subimgH $fullpath $gamma $quality
                incr num
                }
            }    
        }
    incr num -1
    if {$num > 0} {
        if {$num == 1} {
            set line "Saved one image in \"$path\"\n" 
        } else {
            set line "Saved $num images in \"$path\"\n"
        }
    } 
    ::RAT::LogMsg NOTICE $line
    }
  
#=====================================
# Local utility procs
#=====================================
proc saveImage { handle path gamma quality } {
    # Apply gamma correction
    it IceExpr "result := $handle Gamma($gamma)"
        
    set expression "result SetMetaDataItem(\"JPEG_QUALITY\", $quality);"
    append expression "result Save(\"$path\", IceOutputType Jpeg)"
    it IceExpr $expression
    set cat [it GetCurrentCatalog]
    $cat DeleteImage [$cat GetCurrentImage]
    }
        
proc getPadding { num } {
    if { $num < 10 }  { return "000$num"}
    if { $num < 100}  { return "00$num" }
    if { $num < 1000} { return "0$num" }
    return "$num"
    }
        
proc getDateTime { } {
    set out "Catalog_"
    set date [clock format [clock scan now]]
    set date [split $date " "]
    append out [lindex $date 1]
    append out [lindex $date 2]
    append out "_"
    set time [split [lindex $date 3] :]
    append out [lindex $time 0]
    append out "_"
    append out [lindex $time 1]
    return $out
    }


Resizing an Image

The script in listing 3 implements a proc named resizeImage that enables an image to be scaled to a specific width. The proc can be invoked in three ways.

1   Resize the current catalog image to the default width of 400 pixels.

     % resizeImage

    The resized image is added to the catalog.
2   Resize the current catalog image to a specific width.

     % resizeImage 500

    The resized image is added to the catalog.
3   Resize a source image read from the hard disk.

     % resizeImage 450 "image_name.ext"

    The resized image is added to the catalog and saved to disk.



Listing 3 (resizeImage.tcl)


# M.Kesson Sept 2011
set count 0
proc resizeImage { { newWidth 400 } { imageName "" } } {
    global count
    
    set pwdPath [pwd]
    ::RMS::LogMsg INFO "Current directory is $pwdPath"
    
    # If an image name has been specified and we assume the 
    # "cd" has been used to change to the directory in 
    # which the image file is to be found.
    if { [string length $imageName] > 0 } {
        set path [file join $pwdPath $imageName]
        if { [file exists $path] == 0 } {
            ::RMS::LogMsg ERROR "Cannot find $path"
            ::RMS::LogMsg INFO "Use \"cd\" to set the correct directory."
            ::RMS::LogMsg INFO "Use \"pwd\" to check the present working directory." 
            return
            }
        # Put the image into the catalog    
        [ice::load $path -h $imageName]
        }
    set cat [it GetCurrentCatalog]
    set img [$cat GetCurrentImage]
    set imgH [$img GetHandle]
    set bounds [$img GetSize]
        
    # scaling factor 
    set oldWidth [lindex $bounds 0]
    set scaling [expr double($newWidth)/$oldWidth]
    set newHeight [expr [lindex $bounds 1] * $scaling]
    set iceExpr "resized_$count := $imgH Reformat(list(0,0,$newWidth,$newHeight), 1, 0);"
    it IceExpr $iceExpr
        
    # Only if an image file has been resized do we go
    # ahead and save it to disk.
    if { [string length $imageName] > 0 } {
        # Remove the image that was read from disk.
        $cat DeleteImage $img
        # Assume the file extension is 4 characters in length (including the period)
        set ext [string range $imageName end-3 end]
        set name [string range $imageName 0 end-4]
        append name "_$newWidth"
        append name $ext
        
        set outPath [file join $pwdPath $name]
        set img [$cat GetCurrentImage]
        set imgH [$img GetHandle]
        ::RMS::LogMsg INFO "using $imgH."
        ::RMS::LogMsg INFO "saving $outPath."
        set iceExpr "$imgH SetMetaDataItem(\"JPEG_QUALITY\", 100);"
        append iceExpr "$imgH Save(\"$outPath\", IceOutputType Jpeg)"
        it IceExpr $iceExpr
        }
    incr count
    }


Creating a Stereo Anaglyph

Listing 4 provides a script that reads two tif files and combines them into a anaglyph (figure 6).



Figure 6


It is assumed the tifs were rendered using Maya's dual cameras. The script expects to read and combine tifs contained in directories named left and right. For example, suppose the name of the Maya project is "stereo" and the name of the scene is "jack". If frame 1 has been rendered we should find, within the renderman directory, the following.

    /stereo
          |_ renderman
                     |_ jack
                           |_ images
                                   |_ left
                                   |      |_ jack.0001.tif
                                   |
                                   |_ right
                                          |_ jack.0001.tif
                                         

Renaming the shape nodes of the Maya's dual camera, figure 7, will ensure the "left" and "right" directories will be created within the renderman/images folder.



Figure 7


Before using the script check the PWD is pointing at the project directory. Enter the following command in the console,

 % mayaStereo jack 1

The number following the command tells the script which frame you wish to read. To combine a sequence of tifs use the following command,

 % mayaStereo jack -1

Since -1 is not a valid frame number the script "knows" you wish to read all the tifs from the "left" and "right" directories.


Listing 4 (mayaStereo.tcl)


# M.Kesson Sept 2011
# 1    Rename the camera shape nodes to "left" and "right".
# 2    Ensure padding in Render Setting is set to 4.
# 3    Use the pwd command to check you are in your Maya project directory.
# 4    If your maya scene is named "test" the proc would be used as follows,
#            % mayaStereo test
#        or
#            % mayaStereo test 2
#        or 
#            % mayaStereo test -1
#   If a frame number is not provided the proc will use the image from
#   frame 1. A negative frame number will cause the script to read all
#   the images from the "left" and "right" folders.
set count 0
  
proc mayaStereo { sceneName { frameNum 1 } } {
    set pwdPath [pwd]
    set rendermanDir [file join $pwdPath "renderman"]
    set sceneDir     [file join $rendermanDir $sceneName]
    set imagesDir    [file join $sceneDir "images"]
    set leftDir   [file join $imagesDir "left"]
    set rightDir  [file join $imagesDir "right"]
    if { [file exists $leftDir] == 0 || [file exists $rightDir] == 0 } {
        set msg    "The stereo camera shape nodes must be named \"left\" and \"right\".\n"
        append msg "The error may be caused by the \"present working director\" of the\n"
        append msg "console not \"pointing\" to your Maya project directory. Use the\n"
        append msg "pwd command in the console to check your directory."
        ::RMS::LogMsg ERROR $msg
        return
        }
    # We are dealing with one pair of images so the paths to  
    # the images are constructed "manually" and then converted.    
    if { $frameNum >= 0 } {
        set padding [format "%04d" $frameNum]
        set imageName "$sceneName.$padding.tif"
        set leftPath  [file join $leftDir  $imageName]
        set rightPath [file join $rightDir $imageName]
    
        # Final checks
        if { [checkFilePaths $leftPath $rightPath] == 0 } {
            return
            }
        convertToAnaglyph $leftPath    $rightPath
        cleanupIt
        return
        }
  
    # We are dealing with a sequence of images. It is assumed
    # the user wants ALL the tiff files in the "left" and "right"
    # directories to be processed as anaglyphs.
    set leftTiffs [glob -directory $leftDir *.tif]
    set rightTiffs [glob -directory $rightDir *.tif]
    set numLeftTiffs  [llength $leftTiffs]
    set numRightTiffs [llength $rightTiffs]
    # There might be more tiffs in one of the directories.
    set num $numLeftTiffs
    if { $numRightTiffs < $num } {
        set num $numRightTiffs
        }
    for {set n 0} {$n < $num} {incr n} {
        set leftPath [lindex  $leftTiffs $n]
        set rightPath [lindex $rightTiffs $n]
        convertToAnaglyph $leftPath $rightPath
        }
    cleanupIt
    }
    
#=====================================
# Local utility procs
#=====================================
proc checkFilePaths { left right } {
    if { [file exists $left] == 0 } {
        ::RMS::LogMsg ERROR "Cannot find the left image:\n\"$left\"."
        return 0
        }
    if { [file exists $right] == 0 } {
        ::RMS::LogMsg ERROR "Cannot find the right image:\n\"$right\"."
        return 0
        }    
    return 1
    }
proc convertToAnaglyph { leftPath rightPath } {
    global count
    [ice::load $leftPath  -h left_raw]
    [ice::load $rightPath -h right_raw]
    
    # Grab the rgb channels
    it IceExpr "left_rgb := left_raw Shuffle(list(0,1,2))"
    it IceExpr "right_rgb := right_raw Shuffle(list(0,1,2))"
    it IceExpr "m := list(1,0,0,0,   0,0,0,0,   0,0,0,0) ; right_tinted := right_rgb Cha(m, 3, 4)"
    it IceExpr "m := list(0,0,0,0,   0,1,0,0,   0,0,1,0) ; left_tinted  := left_rgb  Cha(m, 3, 4)"
    
    # Ensure the final output image has a unique (handle) name
    # then combine the two images.
    set imgname "stereo_$count"    
    it IceExpr "$imgname := left_tinted Add(right_tinted)"
    incr count
    }
proc cleanupIt { } {
    set cat [it GetCurrentCatalog]
    set imgs [$cat GetImageList]
    foreach item $imgs {
        set h [$item GetHandle]
        if { [string equal $h "left_rgb"]  } {
            $cat DeleteImage $item
        } elseif { [string equal $h "right_rgb"] } {
            $cat DeleteImage $item
        } elseif { [string equal $h "left_tinted"] } {
            $cat DeleteImage $item
        } elseif { [string equal $h "right_tinted"] } {
            $cat DeleteImage $item
            }
        }
    }






© 2002- Malcolm Kesson. All rights reserved.