Creating a new photoshop doc with Python, Part Two

Just a quick update on my previous post about adding a new document to photoshop with python.

It seems that Cs2 uses pixels as it's default assumed unit. Due to this, my script previously did not bother to define a unit type for the document and it all worked fine.

I am running some tests of the script on Cs5 and coming up with some unexpected results- namely really massive documents, which are no fun. This is because the document is being made in CM by default rather than pixels. 

To fix this, I added in this wee bit o'code:
psApp.Preferences.RulerUnits = 1

Which defines the ruler units as pixels. The lesson... assume nothing! If it needs it, define it.

Learn Python the Hard Way

For anyone who is interested, I've found this book really helpful in picking up the python language.

Learn Python The Hard Way contains a heap of useful programming advice delivered in a clear and very readable way.

It progresses from very simple examples to more complex concepts with a learning curve that will always challenge, but doesn't ever put you in water too deep to fathom. Highly recommended to anyone aspiring to learn the basics of Python.

Python- Updating alpha from a group

I've tied the alpha updating to an action inside photoshop, and the results are pretty pleasing. Within the script there is a bit of juggling between active layers and active channels in order to get the action working properly.

I also like to leave the user off in a place that makes sense- in this case, the alpha group, since its the one being updated.  

The basics of this script:
Checks for an 'alpha' group in the active PSD file. If present, copies it's merged contents to the alpha channel.
##############################################################################
#
# Photoshop alpha updater
# (C) Pete Hanshaw, 2012
# http://peterhanshawart.blogspot.com.au/
#
##############################################################################
#
# Checks for an 'alpha' group in the active PSD file. If present, copies it's 
# contents to the alpha channel. 
#
# Requires the Win32 Extensions:
# http://python.net/crew/mhammond/win32/
#
##############################################################################
 
#Import required modules
from win32com.client.dynamic import Dispatch
from stat import *
import os
from sys import exit
import pythoncom

#Define the name of the Alpha group here
alpha_group = 'alpha'

#Begin the script
if (__name__ == '__main__'):

    #COM dispatch for Photoshop
    try:
        psApp = Dispatch('Photoshop.Application')
 
    except:
        os.system("color 0c")
        print "Photoshop dispatch failed"
        os.system("PAUSE")
        exit(0)

    #Get the currently active document
    try:
        doc = psApp.activeDocument
 
    #Gracefully end if a document is not open
    except:
        os.system("color 0c")
        print "You need to have an active Photoshop Doc to use this script."
        os.system("PAUSE")
        exit(0)

    #Get information about our current doc
    activeChannels = doc.ActiveChannels
    layerSets = doc.LayerSets
    channelRef = doc.Channels
    
    #Check if there are any layerSets in the current doc
    if (len(layerSets) > 0):

        #Assume there is no alpha
        alphaExists = False

        #Check for an alpha channel
        for channel in channelRef:
            if channel.name == "Alpha 1":
                alphaExists = True
                break

        if alphaExists == False:
            #add a blank alpha channel
            doc.Channels.Add()

        #save the current setup
        saved_state = doc.activeHistoryState

        #Prepare the alpha group for duplication
        doc.activeChannels = activeChannels
        doc.activeLayer = (doc.layerSets[alpha_group])
        doc.activeLayer.Visible = True
        doc.activeLayer.Merge()
        doc.activeLayer.Copy()

        #Now that we have a merged copy, revert the merging
        doc.activeHistoryState = saved_state

        #Now paste the merged alpha source into the alpha channel
        doc.activeLayer = (doc.artLayers['Background'])
        doc.activeChannels = [doc.Channels[5]]
        doc.Paste()

        #Restore control to the user
        doc.selection.deselect
        doc.activeChannels = activeChannels
        doc.activeLayer = (doc.layerSets[alpha_group])

        print "All done!"
        
    else:
        os.system("color 0c")
        print "Doc has no groups."
        os.system("PAUSE")
        exit(0)

Exporting texture Alpha from a group

While looking for a good Maya PitsNPeaks alternative, I have been tinkering with further scripts to improve artist texture workflow.

One of the things I am working on is a neat little script that allows an artist to work on an image's alpha in a group named 'alpha' in the source PSD document, which is automatically copied over to the output file's alpha channel when it is exported, provided it is a texture that requires it (eg, an 'a' or 't' texture).

The intention is that an artist will be able to edit and update the alpha channel as fluidly as any other texture map a material requires.

Creating a new photoshop doc with Python

In the spirit of saving time (and also because I think its cool) I wrote a quick little script to create a new Photoshop document, set up with groups and layers. It ties quite nicely in with Texture monkey, as it uses the same group names etc when it creates the doc, and it just saves a lot of clicking.

When you run the script, which only takes a couple of seconds, you end up with a neat little document ready to edit:


I added a part at the end of the script to make sure the diffuse
layer was active. It's a little touch, but makes it nice to know the
script leaves off somewhere useful rather than some random layer.


The script is pretty straightforward, but has a couple of interesting little bits, like how it moves groups. I had to trawl around for a while to get that one working. I'm also becoming a big fan of minimizing console feedback. As long as it's all working I don't think it should spit too many "I'm doing this!" messages out at you. It's annoying. 

##############################################################################
#
# ps_newdoc.py
#
# Photoshop doc setup
# (C) Pete Hanshaw, 2012
# http://peterhanshawart.blogspot.com.au/
#
##############################################################################
#
# Creates a new PSD document and sets up placeholder groups and layers 
# ready for texture work.
#
# Creates:
# -'n' group for normal map
# -'s' group for specular map
# -'d' group for diffuse map
#
#
# Requires the Win32 Extensions:
# http://python.net/crew/mhammond/win32/
#
##############################################################################

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

#Set up the document. More groups can be added easily by creating more dict keys
group_names = {}
group_names['d'] = 'dif_base'
group_names['s'] = 'spec_base'
group_names['n'] = 'nrm_base'

#Begin the script            
if (__name__ == '__main__'):
    #COM dispatch for Photoshop
    try:
        psApp = Dispatch('Photoshop.Application')

    except:
        os.system("color 0c")
        print "The dispatch to Photoshop did not work"
        os.system("PAUSE")
        exit(0)

    #Define the fill colors
    #Normal base
    nrm_SolidColor = Dispatch('Photoshop.SolidColor')
    nrm_SolidColor.rgb.red = 128
    nrm_SolidColor.rgb.green = 128
    nrm_SolidColor.rgb.blue = 255

    #Define the fill colors
    #Spec base
    spec_SolidColor = Dispatch('Photoshop.SolidColor')
    spec_SolidColor.rgb.red = 0
    spec_SolidColor.rgb.green = 0
    spec_SolidColor.rgb.blue = 0
    
    #Define the fill colors
    #Diffuse base
    dif_SolidColor = Dispatch('Photoshop.SolidColor')
    dif_SolidColor.rgb.red = 128
    dif_SolidColor.rgb.green = 128
    dif_SolidColor.rgb.blue = 128
    

    #w, h, res, name, mode, initial-fill, asp-ratio, Bits-P/Ch, ColProfile
    new_doc = psApp.Documents.Add(1024, 1024, 72, "new_source_texture", 2, 1, 1)

    print "Setting up a", new_doc.name
    
    for group, layer in group_names.items():
        new_layerSet = new_doc.LayerSets.Add()
        new_layerSet.name = group

        if group == 'n':
            new_art_layer = new_layerSet.ArtLayers.Add()
            new_art_layer.name = layer

            #Fill the layer with appropriate color
            psApp.activeDocument.selection.selectAll
            psApp.activeDocument.selection.Fill(nrm_SolidColor)
            new_layerSet.Visible = False

        elif group == 's':
            new_art_layer = new_layerSet.ArtLayers.Add()
            new_art_layer.name = layer

            #Fill the layer with appropriate color
            psApp.activeDocument.selection.selectAll
            psApp.activeDocument.selection.Fill(spec_SolidColor)
            new_layerSet.Visible = False

        elif group == 'd':
            new_art_layer = new_layerSet.ArtLayers.Add()
            new_art_layer.name = layer
            #Fill the layer with appropriate color
            psApp.activeDocument.selection.selectAll
            psApp.activeDocument.selection.Fill(dif_SolidColor)

        else:
            new_art_layer = new_layerSet.ArtLayers.Add()
            new_art_layer.name = layer
   
            #Fill the layer with appropriate color
            psApp.activeDocument.selection.selectAll
            psApp.activeDocument.selection.Fill(dif_SolidColor)

    #Reorder the photoshop layers so that it reads from top down:
    #normal, spec, diffuse
    dGroup = psApp.activeDocument.layerSets['d']

    #See Adobe's photoshop_cs4_vbscript_ref.pdf to make sense of this-
    dGroup.Move(new_doc, 2)

    #Deselect the fill area
    psApp.activeDocument.selection.deselect

    #Set the active layer to the diffuse
    psApp.activeDocument.activeLayer = (psApp.activeDocument.layerSets['d'].
                                        artLayers['dif_base'])
    
    print "All done!"
    exit(1)