Photoshop Automated Texture Exporting

Python Texture Monkey
Requires the Win32 Extensions: http://python.net/crew/mhammond/win32/

So the script has progressed far enough to be usable, but still has several crude elements, such as the way it exports the TGAs into each separate folder.  

Currently the script works like so:
  •  Using python grabs whatever doc is currently active in Photoshop and looks through it for specified group names
  • Exports each of these groups as a TGA in specified directories with a specific suffix depending on the original group name- eg the diffuse 'd' group becomes 'sourceTextureName_d'
  • Saves original doc and reverts control to user
  • Can export:
    • 'd' - Diffuse as 'fileName_d.tga'
    • 'n' - Normal as 'fileName_n.tga'
    • 's' - Spec as 'fileName_s.tga'
    • 'i' - Illuminance as 'fileName_s.tga'
    • 'a' - Texture with alpha as 'fileName_a.tga'
    • 'g' - Gloss as 'fileName_g.tga'
This script is based on a recursive layer export script by Adam Pletcher. The key differences between my script and Adam's are:
  • My new script exports TGA files rather than PNGs 
  • The script runs on the currently active Photoshop doc rather than recursively scanning through a folder. This is handy as it can be integrated directly into a user's workflow for rapidly updating work. 
  • Due to my current test project setup, TGA files are exported to two different folders- a Maya 'asset' location and an engine 'export' location. This can be easily modified by the savvy end user.
Intended future refinements:
  • Adding a button in Photoshop. Most artists don't like working from the command prompt! :-)
  • Optimizing the TGA export. As the export and asset TGA files are essentially the same thing, it might work out quicker to export it once to the asset folder and then copy the output over to the export folder.
  • Easily changed options for different export formats 

##############################################################################
#
# Photoshop texture exporter
# Author: Pete Hanshaw, 2012
# http://peterhanshawart.blogspot.com.au/
# Inspired by recursive Photoshop layer export script by
# Adam Pletcher
# http://techarttiki.blogspot.com.au/
#
##############################################################################
#
# Checks to see if a PSD file is open.
# For the currently active file, exports various 24-bit TGA textures based on
# layer groups found in the PSD.
#
# Requires the Win32 Extensions:
# http://python.net/crew/mhammond/win32/
#
##############################################################################

#Import required modules
from win32com.client.dynamic import Dispatch
import os
from sys import exit
import pythoncom

pythoncom.OleInitialize()

#Define our target directories for each of our exports
#Change this for whatever project you are working on
sourceTarget = r'c:\textureWork\source'
assetTarget = r'c:\textureWork\asset'
exportTarget = r'c:\textureWork\export'

#map layer group names to export names. Currently includes:
#Diffuse, Normal, Specular, Illuminance, Gloss, alpha
exportTypes = {'d': '_d', 'n': '_n', 's': '_s', 'i' : '_i', 'g': '_g', 'a':'_a'}

if (__name__ == '__main__'):

    #COM dispatch for Photoshop
    try:
        psApp = Dispatch('Photoshop.Application')

    except:
        print "OOPS! Something went wrong..."
        print "The dispatch to Photoshop did not work"

    # Define 24bit Targa save options
    options = Dispatch('Photoshop.TargaSaveOptions')
    PsTargaBitsPerPixels = 24
    options.Resolution = PsTargaBitsPerPixels
    options.AlphaChannels = False
    options.RLECompression = False

    # Define 32bit Targa save options
    optionsAlpha = Dispatch('Photoshop.TargaSaveOptions')
    PsTargaBitsPerPixels = 32
    optionsAlpha.Resolution = PsTargaBitsPerPixels
    optionsAlpha.AlphaChannels = True
    optionsAlpha.RLECompression = False

    # Define PSD save options
    psdOptions = Dispatch('Photoshop.PhotoshopSaveOptions')
    psdOptions.annotations = False
    psdOptions.alphaChannels = True
    psdOptions.layers = True
    psdOptions.spotColors = True
    psdOptions.embedColorProfile = True

    #Get the currently active document
    try:
        doc = psApp.activeDocument

    #Gracefully end if a document is not open
    except:
        print "OOPS! Something went wrong..."
        print "You need to have an active Photoshop Doc to use this script."
        print "Goodbye!"
        exit(0)

    #Get the document name and strip it's extension
    sourceFile = sourceTarget + '\\' + doc.name
    doc_name = os.path.splitext(doc.name)[0]
    print "Operating on ", sourceFile

    #Get our layer sets from the currently open doc
    layerSets = doc.LayerSets

    #Check if there are any layerSets in the current doc
    if (len(layerSets) > 0):
        # first hide all root-level layers
        for layer in doc.Layers:
            layer.Visible = False

        # ... and layerSets
        for layerSet in layerSets:
            layerSet.Visible = False

        # Loop through each LayerSet (aka Group)
        for layerSet in layerSets:
            lsName = layerSet.Name.lower()

            #save the current setup
            saved_state = doc.activeHistoryState

            if (lsName in exportTypes):
                layerSet.Visible = True # Make the group visible

                #make the asset and export file names
                exportFile = exportTarget + '\\' + doc_name + exportTypes[lsName] + '.tga'
                assetFile = assetTarget + '\\' + doc_name + exportTypes[lsName] + '.tga'
 
                #If the file exists, delete it
                #This is somewhat clumsy, but does the job
                if (os.path.exists(exportFile)):
                    os.remove(exportFile)

                if (os.path.exists(assetFile)):
                    os.remove(assetFile)

                #Since the export file is just a copy of the asset file, it
                #would be faster to just copy it using the o.s. rather than save
                #it all over again!

                #Flatten the image temporarily to allow TGA export
                doc.flatten

                #Check to see if the export requires alpha options
                if lsName == "a":
                    #Do our exports
                    doc.SaveAs(exportFile, optionsAlpha)
                    doc.SaveAs(assetFile, optionsAlpha)
                    print 'exporting: ', exportFile
                    print 'exporting: ', assetFile

                else:
                    #Do our exports
                    doc.SaveAs(exportFile, options)
                    doc.SaveAs(assetFile, options)
                    print 'exporting: ', exportFile
                    print 'exporting: ', assetFile

                #Go back to the previous history state
                doc.ActiveHistoryState = saved_state 

                #Hide the layer to make way for the others...
                layerSet.Visible = False

        #now that its all done, make the layer sets visible again
        for layerSet in layerSets:
            layerSet.Visible = True

        #Save the PSD to retain any changes and return control to the humans.
        doc.SaveAs(sourceFile, psdOptions)
        print "Saving original document as ", sourceFile
        print "Reverting control to humans!"
        print "All done!" 

    # If there are no layer sets present, gracefully end the script.
    else:
        print "OOPS! Something went wrong..."
        print "The file has no groups to export!"
        print "Goodbye!"
        exit(0)