Copy link to clipboard
Copied
I'm trying to write an AppleScript that will create a bunch of PNG files from:
1) A list of hex colors
2) A CS4 Photoshop file that consists of a single shape layer which uses a logo as a vector mask.
I want to end up with different colored versions of the logo--a red one, a sea foam one, a burnt sienna one, etc. etc.
So far I've got this:
set colorlist to every word of "002266 005566 006611 . . ."
set destinationFolder to "HD:Logos:"
tell application "Adobe Photoshop CS4"
activate
repeat with theCurrentValue in colorlist
--set color of current shape layer of current document to theCurrentValue
set currentFilepath to destinationFolder & theCurrentValue & ".png"
save current document in file currentFilepath as PNG with options {interlaced:false}
end repeat
end tell
So, how do I change the color of a shape layer?
How do I specify the color as a hex value?
Are these things even possible?
----------------
Finally, is it just me, or is the Adobe documentation incredibly obtuse? Well, maybe that's not the right word. How about "useless." E.g., I searched the script reference for hex, but all I found was this:
RGB hex color
A hexadecimal specification of an RGB color. The RGB hex color class inherits properties from the color
value class.
Properties:
Property Value Type What it is
hex value Unicode text The hex representation of an RGB color
Well, thanks a lot. Sorry to be churlish, but that's a bit like "The copy command copies the selected object.
This is what I knocked together but Im not sure what Mike recorded as this is not working for me.
I get the saved files but no colour change to the shape layer.
Can't really check until on my work mac where I've got X's tool kit installed.
set Dest_folder to (path to startup disk as text) & "logos:"
set Color_List to {"990000", "005566", "006611"} -- a list
--
tell application "Adobe Photoshop CS2"
activate
set Doc_Ref to the current document
tell Doc_Ref
repeat with This_Value in Color_List
set This_
...Copy link to clipboard
Copied
I don't use Applescript but I think the guide it trying to note that the returned value of that property is a String. Some expect it to be a Number.
I know that with javascript and VB the only way to change solidfill layer is with scriptlistner. I expect it's the same with Applescript.
Copy link to clipboard
Copied
Thanks, I didn't know about Script Listener. I installed it, recorded a color change, opened the Listener log, turned the contents into a javascript function (change all double quotes to single quotes; add vars, function name and curly brackets; pass AS vars to JS with concatenation), and inserted it into my script (thanks in part to http://forums.adobe.com/thread/433329).
It's ugly, but it works. See below. The only thing left to do is convert a hex color to an RGB color.
I tried:
set currentRGB to convert color theCurrentValue to RGB
but that doesn't work.
Any ideas?
-----------------------
Scripting Listener plug in is located here:
Adobe Photoshop CS4:Scripting:Utilities
To install, move here:
Adobe Photoshop CS4:Plug-Ins:Automate
Also useful: Adobe Intro to Scripting which is buried here:
Applications:Utilities:Adobe Utilities:ExtendScript Toolkit CS4:SDK:English:Adobe Intro to Scripting
--------------------
set colorlist to every word of "002266 005566 006611 . . ."
set destinationfolder to "HD:logos:"
tell application "Adobe Photoshop CS4"
activate
repeat with theCurrentValue in colorlist
set currentRGB to convert color theCurrentValue to RGB --THIS LINE DOESN'T WORK
set currentRed to red of currentRGB
set currentGreen to green of currentRGB
set currentBlue to blue of currentRGB
do javascript "ChangeShapeColor(" & currentRed & "," & currentGreen & "," & currentBlue & ");
// =======================================================
function ChangeShapeColor(NewRed, NewGreen, NewBlue)
{
var idsetd = charIDToTypeID( 'setd' );
var desc5 = new ActionDescriptor();
var idnull = charIDToTypeID( 'null' );
var ref2 = new ActionReference();
var idcontentLayer = stringIDToTypeID( 'contentLayer' );
var idOrdn = charIDToTypeID( 'Ordn' );
var idTrgt = charIDToTypeID( 'Trgt' );
ref2.putEnumerated( idcontentLayer, idOrdn, idTrgt );
desc5.putReference( idnull, ref2 );
var idT = charIDToTypeID( 'T ' );
var desc6 = new ActionDescriptor();
var idClr = charIDToTypeID( 'Clr ' );
var desc7 = new ActionDescriptor();
var idRd = charIDToTypeID( 'Rd ' );
desc7.putDouble( idRd, NewRed );
var idGrn = charIDToTypeID( 'Grn ' );
desc7.putDouble( idGrn, NewGreen );
var idBl = charIDToTypeID( 'Bl ' );
desc7.putDouble( idBl, NewBlue );
var idRGBC = charIDToTypeID( 'RGBC' );
desc6.putObject( idClr, idRGBC, desc7 );
var idsolidColorLayer = stringIDToTypeID( 'solidColorLayer' );
desc5.putObject( idT, idsolidColorLayer, desc6 );
executeAction( idsetd, desc5, DialogModes.NO );
};" show debugger on runtime error
set currentFilepath to destinationfolder & theCurrentValue & "png"
save current document in file theCurrentValue as PNG with options {interlaced:false}
end repeat
end tel
Copy link to clipboard
Copied
Send the javascript the hex value you want as a string. The function below will accept a string.
///////////////////////////////////////////////////////////////////////////////
// Function: colorToSolidColorLayer
// Description: Sets color of active layer solidColor
// Usage: colorToSolidColorLayer( [ 72, 50.6, 45.45 ] );
// Input: Color as one of String, Array, or SolidColor
// Return: -1 if fails
// Notes: Use Array for 16bit color. Both String and
// SolidColor are 8bit.
///////////////////////////////////////////////////////////////////////////////
function colorToSolidColorLayer( color ){
var arg = arguments[0].constructor;
switch( arg ){
case Array:
var c = color;
break;
case SolidColor:
var c = new Array();
c.push( color.rgb.red );
c.push( color.rgb.green );
c.push( color.rgb.blue );
break;
case String:
var c = new Array();
var sc = new SolidColor();
sc.rgb.hexValue = color;
c.push( sc.rgb.red );
c.push( sc.rgb.green );
c.push( sc.rgb.blue );
break;
default:
return -1;
}
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( stringIDToTypeID( "contentLayer" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc.putReference( charIDToTypeID( "null" ), ref );
var modeDesc = new ActionDescriptor();
var colorDesc = new ActionDescriptor();
colorDesc.putDouble( charIDToTypeID( "Rd " ), c[ 0 ] );
colorDesc.putDouble( charIDToTypeID( "Grn " ), c[ 1 ] );
colorDesc.putDouble( charIDToTypeID( "Bl " ), c[ 2 ] );
modeDesc.putObject( charIDToTypeID( "Clr " ), charIDToTypeID( "RGBC" ), colorDesc );
desc.putObject( charIDToTypeID( "T " ), stringIDToTypeID( "solidColorLayer" ), modeDesc );
executeAction( charIDToTypeID( "setd" ), desc, DialogModes.NO );
}catch(e){ return -1; }
}
EIther that or convert the 3 hex pairs to 3 decimal numbers if that is possible in Applescript.
Edit: I hate the way this forum mangles code. Remove all the & ndsp;
Copy link to clipboard
Copied
I couldn't get the script you posted to work with anything but RGB arrays, so I converted the hex to decimal (modified a subroutine I found here: http://osdir.com/ml/editors.bbedit.general/2006-06/msg00020.html).
I haven't analyzed the subroutine to make sure it gives the correct values, but that can be adjusted later.
For now, the only remaining problem is that the save statements at the end of the script don't work. Instead, Photoshop's save dialogs pop up. What am I doing wrong?
set colorlist to every word of "990000 005566 006611"
set destinationfolder to "HD:logos:"
on fromHex(hexstring, channel)
set charactarlist to every character of hexstring
if channel = "red" then
set firstdigit to item 1 of charactarlist
set seconddigit to item 2 of charactarlist
else if channel = "green" then
set firstdigit to item 3 of charactarlist
set seconddigit to item 4 of charactarlist
else if channel = "blue" then
set firstdigit to item 5 of charactarlist
set seconddigit to item 6 of charactarlist
end if
set str to firstdigit & seconddigit
set n to 0
set i to 1
repeat with a in reverse of every text item of str
if a is greater than 9 or a is less than 0 then
set a to ASCII number of a
if a is greater than 70 then
set a to a - 87
else
set a to a - 55
end if
end if
set n to n + a * i
set i to i * 16
end repeat
return n
end fromHex
tell application "Adobe Photoshop CS4"
activate
repeat with theCurrentValue in colorlist
set currentRed to my fromHex(theCurrentValue, "red")
set currentGreen to my fromHex(theCurrentValue, "green")
set currentBlue to my fromHex(theCurrentValue, "blue")
do javascript "ChangeShapeColor(" & currentRed & "," & currentGreen & "," & currentBlue & ");
function ChangeShapeColor(NewRed, NewGreen, NewBlue)
{
var idsetd = charIDToTypeID( 'setd' );
var desc5 = new ActionDescriptor();
var idnull = charIDToTypeID( 'null' );
var ref2 = new ActionReference();
var idcontentLayer = stringIDToTypeID( 'contentLayer' );
var idOrdn = charIDToTypeID( 'Ordn' );
var idTrgt = charIDToTypeID( 'Trgt' );
ref2.putEnumerated( idcontentLayer, idOrdn, idTrgt );
desc5.putReference( idnull, ref2 );
var idT = charIDToTypeID( 'T ' );
var desc6 = new ActionDescriptor();
var idClr = charIDToTypeID( 'Clr ' );
var desc7 = new ActionDescriptor();
var idRd = charIDToTypeID( 'Rd ' );
desc7.putDouble( idRd, NewRed );
var idGrn = charIDToTypeID( 'Grn ' );
desc7.putDouble( idGrn, NewGreen );
var idBl = charIDToTypeID( 'Bl ' );
desc7.putDouble( idBl, NewBlue );
var idRGBC = charIDToTypeID( 'RGBC' );
desc6.putObject( idClr, idRGBC, desc7 );
var idsolidColorLayer = stringIDToTypeID( 'solidColorLayer' );
desc5.putObject( idT, idsolidColorLayer, desc6 );
executeAction( idsetd, desc5, DialogModes.NO );
};" show debugger on runtime error
set currentFilepath to destinationfolder & theCurrentValue & "png"
set saveOptions to {class:PNG save options, interlaced:false}
save current document in file currentFilepath as PNG with options saveOptions appending no extension with copying
end repeat
end tell
Copy link to clipboard
Copied
Sorry, as I said I don't know Applescript so I did not know that my function would not work for you. I would guess that it has something to do with the way arguments are passed. But I'm glad you got that part working.
Hopefully someone will post a fix for you save problem soon.
Copy link to clipboard
Copied
If it helps both the applescript guide and the save sample script have a 'tell finder' line that I don't see in your code.
Copy link to clipboard
Copied
Turns out it was working fine. I just made a stupid mistake and had the destination folder on the desktop instead of the hard drive. Again, thanks for your help on this.
Copy link to clipboard
Copied
Joe, you were passing Photoshop a 6 character string and it wants a little more info than that does this work for you?
tell application "Adobe Photoshop CS2"
activate
set This_RGB to convert color {class:RGB hex color, hex value:"006611"} to RGB
end tell
This_RGB
Copy link to clipboard
Copied
That's much prettier. The script is now:
. . .
repeat with theCurrentValue in colorlist
set currentRGB to convert color {class:RGB hex color, hex value:theCurrentValue} to RGB
set currentRed to red of currentRGB
set currentGreen to green of currentRGB
set currentBlue to blue of currentRGB
do javascript "ChangeShapeColor(" & currentRed & "," & currentGreen & "," & currentBlue & ");
. . .
Now that I see it the syntax, the entry in the reference make sense. I suppose a better understanding of OOP would have led me to that solution in the first place, but it wouldn't kill the writers of the reference to put a single example after each section to make it a bit easier for non-programmers. I mean, it's AppleSCRIPT, not C.
Copy link to clipboard
Copied
This is what I knocked together but Im not sure what Mike recorded as this is not working for me.
I get the saved files but no colour change to the shape layer.
Can't really check until on my work mac where I've got X's tool kit installed.
set Dest_folder to (path to startup disk as text) & "logos:"
set Color_List to {"990000", "005566", "006611"} -- a list
--
tell application "Adobe Photoshop CS2"
activate
set Doc_Ref to the current document
tell Doc_Ref
repeat with This_Value in Color_List
set This_RGB to convert color {class:RGB hex color, hex value:This_Value} to RGB
set {R, G, B} to {red of This_RGB, green of This_RGB, blue of This_RGB}
do javascript "colorToSolidColorLayer( " & R & ", " & G & ", " & B & " );
function colorToSolidColorLayer( color ){
var arg = arguments[0].constructor;
switch( arg ){
case Array:
var c = color;
break;
case SolidColor:
var c = new Array();
c.push( color.rgb.red );
c.push( color.rgb.green );
c.push( color.rgb.blue );
break;
case String:
var c = new Array();
var sc = new SolidColor();
sc.rgb.hexValue = color;
c.push( sc.rgb.red );
c.push( sc.rgb.green );
c.push( sc.rgb.blue );
break;
default:
return -1;
}
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( stringIDToTypeID( 'contentLayer' ), charIDToTypeID( 'Ordn' ), charIDToTypeID( 'Trgt' ) );
desc.putReference( charIDToTypeID( 'null' ), ref );
var modeDesc = new ActionDescriptor();
var colorDesc = new ActionDescriptor();
colorDesc.putDouble( charIDToTypeID( 'Rd ' ), c[ 0 ] );
colorDesc.putDouble( charIDToTypeID( 'Grn ' ), c[ 1 ] );
colorDesc.putDouble( charIDToTypeID( 'Bl ' ), c[ 2 ] );
modeDesc.putObject( charIDToTypeID( 'Clr ' ), charIDToTypeID( 'RGBC' ), colorDesc );
desc.putObject( charIDToTypeID( 'T ' ), stringIDToTypeID( 'solidColorLayer' ), modeDesc );
executeAction( charIDToTypeID( 'setd' ), desc, DialogModes.NO );
}catch(e){ return -1; }
}" show debugger on runtime error
set File_Path to Dest_folder & This_Value & ".png"
save in file File_Path as PNG with options ¬
{class:PNG save options, interlaced:false} ¬
appending no extension with copying
end repeat
end tell
end tell
Copy link to clipboard
Copied
MM--What I have is working, so no need to go further with this unless you just want to clean up the script for the heck of it and for any future users .
Copy link to clipboard
Copied
Well I had a look at script listeners output and it was exactly the same as Mikes. When I cut down the code to this it works just fine.
set Dest_folder to (path to startup disk as text) & "logos:"
set Color_List to {"990000", "005566", "006611"} -- a list
--
tell application "Adobe Photoshop CS2"
activate
set Doc_Ref to the current document
tell Doc_Ref
repeat with This_Value in Color_List
set This_RGB to convert color {class:RGB hex color, hex value:This_Value} to RGB
set {R, G, B} to {red of This_RGB, green of This_RGB, blue of This_RGB}
do javascript "colorToSolidColorLayer();
function colorToSolidColorLayer( color ){
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( stringIDToTypeID( 'contentLayer' ), charIDToTypeID( 'Ordn' ), charIDToTypeID( 'Trgt' ) );
desc.putReference( charIDToTypeID( 'null' ), ref );
var modeDesc = new ActionDescriptor();
var colorDesc = new ActionDescriptor();
colorDesc.putDouble( charIDToTypeID( 'Rd ' )," & R & ");
colorDesc.putDouble( charIDToTypeID( 'Grn ' )," & G & ");
colorDesc.putDouble( charIDToTypeID( 'Bl ' )," & B & ");
modeDesc.putObject( charIDToTypeID( 'Clr ' ), charIDToTypeID( 'RGBC' ), colorDesc );
desc.putObject( charIDToTypeID( 'T ' ), stringIDToTypeID( 'solidColorLayer' ), modeDesc );
executeAction( charIDToTypeID( 'setd' ), desc, DialogModes.NO );}" show debugger on runtime error
set File_Path to Dest_folder & This_Value & ".png"
save in file File_Path as PNG with options ¬
{class:PNG save options, interlaced:false} ¬
appending no extension with copying
end repeat
end tell
end tell
Copy link to clipboard
Copied
Hi Mark, if it's not too much trouble would you mind doing a test for me to see why my function doesn't work with Applescript?
It takes only one argument. That can be a string or an array or a solidColor object. I wouldn't expect solidColor to work, the Applescript guide doesn't seem to list solidColor.
With javascript the function would be called like this
colorToSolidColorLayer( [255,255,255] );
or
colorToSolidColorLayer( "a10000" );
For the test I would like you to add the following to the top of the function
alert("The number of argument(s): " + arguments.length + "\rFirst
argument: " + arguments[0] + "\rArgument class : " +
arguments[0].constructor );
Thanks,
Mike
Copy link to clipboard
Copied
Mike, I will go back and run a check. From a quick glance though it looks like I've forgot the JS array [] from the function call. (thats why I've got the muppet handle)
Copy link to clipboard
Copied
Yep the typo was my doing… doh! When breaking up the call to pass the AppleScript variables into the function I forgot the array brackets…
I had…
colorToSolidColorLayer( " & R & ", " & G & ", " & B & " );
should have been…
colorToSolidColorLayer( [" & R & ", " & G & ", " & B & "] );
It does work with the string too. But then I knew it would
Copy link to clipboard
Copied
Thanks for the testing. I knew it worked with javascript but I was worried that when Applescript passed the argument my constructor switch fails for some reason.
Looking back over this thread maybe I should have been clearer on how to call the function when I first posted it.
Thanks again,
Mike
Find more inspiration, events, and resources on the new Adobe Community
Explore Now