Tech Art Photoshop work

Hey guys, I just wanted to see how often you write tools for photoshop, script or plugin? Or how often you get requests from artists?

I’ve written a few tools here, as well as some one-off scripts to help batch through certain tedious tasks.

The tools primarily involve initial setup of master textures with layer groups (Diffuse, Normal, Specular, etc), based on the asset type (different shaders, different needs), as well as an exporter to spit out the various TGAs needed (our specular, emissive, etc are fed into each channel of the mask textures, so helps with artist workflow, and cuts down human error).

Other than that, I’ve got a couple of batch exporters, and some time savers for when I find myself needing to fix assets.

I’ve dealt with it a little.

I’m not a big fan of the infrastructure Photoshop provides for scripting, it’s a lot like old-style maxscript where you feel like your just automating button pushes instead of actually writing real code. For the applications I’ve dealt with it’s been adequate, but hardly pleasant.

Apart from lightweight Javascripts, the only big thing I’ve attempted was an external C# app that talked to an open photoshop via COM. That worked OK, but it was ugly under the hood and in retrospect it was extra work I did mostly to to avoid dealing with Javascript, which I cordially loathe. If I had it to do over again I’d probably bite the bullet and learn JS, the producivity loss from working in the ‘native’ language of photoshop can’t be much worse than the productivity loss of writing lots of stupid wrapper classes and long lists of bizarre constants. Plus the latest Pshops include something called ‘panels’ which allows you to do Flash based UI with JS, I don’t think that’s accessible any other way. My feelings for flash echo my feelings for JS, but what can you do - it’s adobe’s baby. At least it isn’t Mel!

It’s a shame because bringing Photoshop in from the cold and making it a full fledged part of the pipeline is a Good Idea – it’s amazing that we lavish so much attention on model data and then when it comes to textures we expect artists to do things like pack different maps into different color channels (or worse, into high and low bits of the same channel!) by hand with no help and no data tracking.

Yeah, the scripting environment isn’t great. While it’s nice that you actually can set breakpoints (unlike with maxscript), the code completion isn’t stellar, and the help documentation structure is pretty abysmal.

That said, there’s quite a lot you can do, even if it involves rolling a lot of your own functions to deal with the inadequacies of some of the built-in methods (lack of case-insensitive layer searching, searching not drilling down the layer hierarchy, etc).

I did a couple of small scripts to make a composition of images into a psd file for marketing and approval. Was a bit painful, but could have been worse …

I do not get a lot of requests for photoshop tools though … And in all honesty, I have not put too much time in it yet as the artist are already quite fast/flexible with the software.

I’ve created a few JavaScript-based tools for Photoshop (a DDS Exporter for 64-bit versions of Photoshop, a simple image-matching tool etc.). The advantage of JS in Photoshop is that tools created with JS should work both with the PC version and the Mac version of PS (and who wants to learn AppleScript?). My experience has been that some operations (even basic operations like sampling the color of a pixel) can be painfully slow. In fairness, it’s been a release or two since I’ve messed with the scripting API. Perhaps things have improved.

I hear a lot of HATE! lol.

Sure it’s not python or c#, but when did we get so language dependent? I mean I can agree that photoshop scripting isn’t on level with maya or the likes, but damn. Most of the stuff you need to do for photoshop automation is there, and yes it can be slow at times, but it also beats having no scripting interface. Ryan Turney and I got pretty deep into the scripting for ps at my last job. (considering it was like 90% of our pipeline) I think it’s worthwhile, I mean just go watch your artist work in photoshop for a few hours, and you’ll get some ideas to save hours.

[QUOTE=UncCheezy;18305]I hear a lot of HATE! lol.

Sure it’s not python or c#, but when did we get so language dependent? I mean I can agree that photoshop scripting isn’t on level with maya or the likes, but damn. Most of the stuff you need to do for photoshop automation is there, and yes it can be slow at times, but it also beats having no scripting interface. Ryan Turney and I got pretty deep into the scripting for ps at my last job. (considering it was like 90% of our pipeline) I think it’s worthwhile, I mean just go watch your artist work in photoshop for a few hours, and you’ll get some ideas to save hours.[/QUOTE]

Agreed to some extent. That does not mean there aint a LOT of room for improvement tho. And while not language “dependent” it would sure be nice not to maintain the same type of code in different languages for different tools, no? :D:

Regards,
Thorsten

P.S. My hate is also more of a general hate towards Photoshop, not only the scripting interface :cool:

The lower level of scripting power puts a cap on how much you can do. It’s be a pain in the butt, for example, to set up a JS system that could update your asset database with good image metadata when a user exports a file to the game, or that listens for a network connection to do some piece of complex processing in response to a remote request.

If you’re stuck inside the JS sandbox you’re doomed to be a second class citizen. The ickiness of the language is just aesthetic for the most part (if you don’t mind all those goddam global variable related bugs) but the inherent (and by-design) limitations of JS as a ‘safe client language’ mean it’s never going to be competitive for a lot of things. Hell, you can’t even write a blankety-blank TXT file !

It’s possible to create external libraries (using C++) for Adobe apps and to call into them from JavaScript. Check out chapter seven of the JavaScript Tools Guide. It’s obviously more work, but you can extend the JavaScript DOM to do all sorts of things, including writing text files.

you can extend the JavaScript DOM to do all sorts of things, including writing text files.

In fairness, you can already do that without extending the DOM, with the standard file io stuff (unless I’m misunderstanding what you and Theodox are saying?). I occasionally abuse it to spit out audit logs and batch files for our texture assets, for example.

I was griping broadly about JS as it shows up in most places. Technically its up to the Javascript engine – Node.js, for example, runs on a ‘server’ js engine not a browser, so it it has a file io library and lots of other things that typical JS doesn’t. ExtendScript has File(), so you could write out a text file from photoshop. There’s even the old trick using ActiveX in IE. The sandbox limits only browsers – but that’s the usual place we see JS so I kind of conflated those things.

What I was really griping about the fact that unlike Python or C# there’s no Javascript standard library for bread and butter tasks – you can’t easily just ‘import csv’ and start reading a csv file, or ‘using System.Net’ and whip up an FTP client. No pickle or [Serializable]. That sort of thing.

<edit>

I did come across CoffeeScripttonight, which might make me somewhat less anti-JS. Python has rendered me permanently averse to curly-brackets, but this:


CreditCard =
  cleanNumber: (number) -> number.replace /[- ]/g, ""
  
  validNumber: (number) ->
    total = 0
    number = @cleanNumber(number)
    for i in [(number.length-1)..0]
      n = +number[i]
      if (i+number.length) % 2 == 0
        n = if n*2 > 9 then n*2 - 9 else n*2
      total += n
    total % 10 == 0

Is more than tolerable. Next time I have to do JS, I’ll do this once I finish rolling my eyes and making faces.

There’s also Python to Javascript compilers like PyJs or Java to Javascript like the Google Web Toolkit. I haven’t played with those much, but the idea is appealing - treat JS like bytecode so you don’t have to deal with it too much directly but can deploy it to browsers, etc.

That’s what we did to make Photoshop talk to Python, via an external library written in C++ (further via JSON-RPC via ZMQ). Was easier than I though - much easier than writing a C++ plugin for Max :(. For UIs we use Flash panels and for the business logic Extendscript itself, because it’s easier to code vs ActionScript.

Named dropped, so I feel compelled to reply :stuck_out_tongue:

While its true Shawn and I got pretty deep into JS for Adobe products, its actually no longer the case. Our larger tools now use COM as we have massive amounts of C# libs already in use throughout many aspects of the company that we’re now able to tie in pretty easily. There are a few downsides to this approach however the power of .NET and existing company libs save a lot of time and grant us a lot of power we didn’t see when using JS directly.

If I’m writing anything in javascript, currently, its for new effects in After Effects or aiding an artist in expression writing.

New requests tend to be quite frequent.

For the haterz : http://www.artima.com/weblogs/viewpost.jsp?thread=329840 The book he mentions - JavaScript: The Good Parts (how’s that for conceding up front!?!?) is really useful if you do have to do serious JS.

Awesome, i didn’t know there was that much use. No one i’ve ever talked to even thought of doing it.

I’ve written a bunch of automation and PSD setup type things as mentioned before. I wrote a couple things for it like a proper module loader compliant with CommonJS Module 1.1. It makes importing things as theodox mentioned a lot easier. I still dont get the hate for JS. It’s a simple language that’s very forgiving. It has some quirkiness, but so does python (trinary operator?).

I also had the tcp connection going with cs5.1. So maya could subscribe to save events in PS and trigger scripts and reload materials as needed. All in python. I’d like to get something more advanced with zmq or celery, but comtypes always wins due to < CS5.

It still seems like PS is the ugly stepchild of our work.

@lotekk, What functions do you have that index layers? That’s by far the slowest thing i’ve run into

Funny thing is, I quite like working with Photoshop - must be this “boldly go where no-one has gone before…” type of thing. I especially like Flash panels - good excuse to finally check out Flex and AS3 after ignoring AS for the last 10 years. It’s pretty neat for UIs. The other cool thing is that you don’t just script for Photoshop - the basics hold true for all CS applications such as Illustrator, Flash, PS, etc.

Eventually I hope we can make some useful tools for our 2D teams who work on Flash games. … btw, did you guys know there’s a whole new bones and IK system in Flash? That alone makes me really interested to get deeper into it.

TheMaxx: Yeah, hunting through layers is pretty slow. I don’t have anything that speeds the process up any, though; just a couple functions that recursively search layer hierarchy (and aren’t case-sensitive).
The functions could probably be nicer, but they work for what I typically need them for.

[edit]
Oops. Actually, it appears that my GetLayerByName is getting into an infinite loop/recursion if it doesn’t find the named layer in the first layerset of the document… :frowning: I’ve generally only used GetLayerSetByName with recursion, while GetLayerByName tends to get used on top-level stuff, which seems to be why I’ve never hit that bug. Not completely sure where it’s infinite-looping though -_-
[/edit]

[edit2]
Stepping through it, for some reason at some point the top-level for loop seems to be botching the counter (I’ve now seen it keep looping at l=4, other times it oscillates between l=3 and l=4… Am I doing the recursion incorrectly?
[/edit2]


function GetLayerSetByName(searchString, parent)		//(string, layer/doc)
{
	if(parent == undefined)
		parent = app.activeDocument;
	searchString = searchString.replace(/[\s_-]/g, "").toLowerCase();
	for(l = 0; l < parent.layerSets.length; l++)
	{
		var childName = parent.layerSets[l].name;
		childName = childName.replace(/[\s_-]/g, "").toLowerCase();
		if(childName == searchString)
		{
			//this is here in case you need to merge the returned layerset
			//(photoshop's dom breaks if you merge with a containing layer selected prior)
			parent.activeLayer = parent.layerSets[l];
			return parent.layerSets[l];
		}
		if(parent.layerSets[l].layerSets.length > 0)
		{
			child = GetLayerSetByName(searchString, parent.layerSets[l]);
			childName = child.name.replace(/[\s_-]/g, "").toLowerCase();	//strip whitespace
			if(childName == searchString)
			{
				parent.activeLayer = child;
				return child;
			}
		}
	}
	return parent;
}

function GetLayerByName(searchString, parent)		//(string, layer/doc)
{
	if(parent == undefined)
		parent = app.activeDocument;
	searchString = searchString.replace(/[\s_-]/g, "").toLowerCase();
	for(l = 0; l < parent.layers.length; l++)
	{
		var childName = parent.layers[l].name;
		childName = childName.replace(/[\s_-]/g, "").toLowerCase();
		if(childName == searchString)
		{
			return parent.layers[l];
		}
		if(parent.layers[l].layers != undefined)
		{
			child = GetLayerByName(searchString, parent.layers[l]);
			childName = child.name.replace(/[\s_-]/g, "").toLowerCase();	//strip whitespace
			if(childName == searchString)
			{
				return child;
			}
		}
	}
	return parent;
}

I haven’t tried it myself yet but you can do all that from ActionScript via flash panel vs doing it in JSX. I wonder if this offers any speed advantage, because sorting through layers is just too damn slow.

If you’re looking for speed look into using ActionManager code. It’s an absolute pain to learn and work with, but the ScriptListener can help. Basically all this is, is writing a Photoshop action. Actions perform much faster than the DOM and when we’ve needed speed we’ve turned to the ActionManager. We’ve gotten around layer recursing speed issues with this.

Also, I’ve found some speed increases when you remove anything within the Application (app) object from a loop, this includes just getting a length as we’re still dinkin’ around with the app object:


#target Photoshop

/** Slow Loop Times:
* 1st - 7.476
* 2nd - 7.487
* 3rd - 7.426
* Avg - 7.463
**/

/** Fast Loop Times:
* 1st - 4.450
* 2nd - 4.479
* 3rd - 4.516
* Avg - 4.481
**/

var startTime = new Date().getTime();
//SlowLoop();
FastLoop();
var endTime = new Date().getTime();

alert((endTime - startTime) / 1000);

function SlowLoop()
{
    for(i = 0; i < app.activeDocument.layers.length; i++)
    {
        $.writeln(app.activeDocument.layers[i].name);
    }
}

function FastLoop()
{
    var appLayers = app.activeDocument.layers;
    var appLayersCount = appLayers.length;
    
    for(i = 0; i < appLayersCount; i++)
    {
        $.writeln(appLayers[i].name);
    }
}

By removing your reference to the application layers from the loop construct you’re removing multiple calls for that info. Being that JS is interpreted we don’t get the benefit here of a smart compiler doing similar work for us. I would imagine refactoring your recursive layer methods to take this info into account, LoTekK, you’ll see some speed increase. Probably not a huge amount, but I would imagine it would be noticeable.

This probably isn’t the best way to determine run times, so hopefully it gets the point across. :slight_smile: