Copy link to clipboard
Copied
Is it possible to script CS4 Photoshop's palette menus? Specifically, the "Save Curves Preset ..." and "Load Curves Preset" ... of the Adjustments Palette.
I have 600 images, some of which have layer>new adjustment layer>curves applied.
I want to save the curves using the image name. Later, I want to be able to load the appropriate curve.
E.g., for image001.tif, the curve would be image001.acv
(I already have a loop set up to iterate through the files and get the file names.)
I can't help with Applescript( or even know if it is possible to do this with Applescript alone ). And to my knowledge you can't script things in dialogs like load or save curve directly. But here is code in javascript that will load and save the settings.
First the easy part, setting an adjustment layer from a file.
...function loadCurves( file ) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "AdjL" ), charIDToTypeID( "Ordn"
Copy link to clipboard
Copied
Hi Joesick,
For this kind of work where you need different adjustments I advise you to create an action.
First you open an image of the 600 taht you have to work then you open the Actions panel and click on the small icon at the bottom right (similar to new level) and it open a wizard that invites you to nominate future action then click records ... Run the workings of levels curves, contrast and so on and when you are done, hit stop.
You can use the same action for all pics with freedom to make new adjustments if and where you need!
Copy link to clipboard
Copied
The curves are different for each image, and have to be named differently for each image.
I want to be able to batch through 600 images and save each existing curve with a name based on the image name. Actions cannot do that.
Copy link to clipboard
Copied
I did not understand.
want you to save a series of curves with different adjustments and name them with an appropriate name for each type so as to be able to load the curve more right for each type of image ?
If is it so I don't think that there is a scripit to create what you want, but maybe someone else knows things that I don't know
Copy link to clipboard
Copied
I am experimenting with ScriptListener, which will probably work eventually, but I was hoping there was a more straightforward way.
Copy link to clipboard
Copied
To rephrase your question, you want to save the curve settings from an existing adjustment layer to an .acv file and then later set an adjustment layer from an .acv file?
If so I have code that does that. It's not that straightforward because of the way Photoshop stores the settings in the adjustment layer but it does work.
Let me know if I understood your question correctly and I will post the code.
Copy link to clipboard
Copied
Yes, but the code has to be able to use a variable (the current file name) when saving or retrieving the .acv file.
Here's what I have so far:
tell application "Finder"
set TheFolder to choose folder
set FileList to every file of entire contents of TheFolder as alias list
end tell
repeat with theFile in FileList
set thefilename to theFile as string
set text item delimiters to ":"
set thefilename to last text item of thefilename --remove path
set text item delimiters to "."
set thefilename to first text item of thefilename --remove extension
tell application "Adobe Photoshop CS4"
open theFile
-- CODE HERE to save or load thefilename.acv --
end tell
end repeat
I've been using ScriptListener to generate Javascripts that are then inserted in the above Applescript. Some stuff works, but so far I haven't been able to get "Save Curves Preset" and "Load Curves Preset" to work.
A purely Applescript script would be preferable, but Applescript can pass variables (e.g., thefilename) to Javascript functions and then execute them.
Copy link to clipboard
Copied
I can't help with Applescript( or even know if it is possible to do this with Applescript alone ). And to my knowledge you can't script things in dialogs like load or save curve directly. But here is code in javascript that will load and save the settings.
First the easy part, setting an adjustment layer from a file.
function loadCurves( file ) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "AdjL" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc.putReference( charIDToTypeID( "null" ), ref );
var desc1 = new ActionDescriptor();
desc1.putPath( charIDToTypeID( "Usng" ), new File( file ) );
desc.putObject( charIDToTypeID( "T " ), charIDToTypeID( "Crvs" ), desc1 );
executeAction( charIDToTypeID( "setd" ), desc, DialogModes.NO );
};
The code to write the .acv file from an adjustment layer is bit more involved and doesn't work with all color modes
// Works with RGB or CMYK images.
// Does not work at all with greyscale, or indexColor
// Does not work correctly with Lab
File.prototype.writeByte = function(b) {
this.write(String.fromCharCode(b));
};
File.prototype.writeShort = function(ET,s) {
var self = this;
if(ET == "BE"){
self.writeByte(s & 0xFF);
self.writeByte((s >> 8) & 0xFF);
}else{
self.writeByte((s >> 8) & 0xFF);
self.writeByte(s & 0xFF);
}
return self;
};
function convertBCD( num ){
var res = new Array;
if(num > 16 ){
res.unshift(1);
num = num - 16;
}else{
res.unshift(0);
}
if(num > 8 ){
res.unshift(1);
num = num - 8;
}else{
res.unshift(0);
}
if(num > 4 ){
res.unshift(1);
num = num - 4;
}else{
res.unshift(0);
}
if(num > 2 ){
res.unshift(1);
num = num - 2;
}else{
res.unshift(0);
}
if(num == 1 ){
res.unshift(1);
}else{
res.unshift(0);
}
return res;
};
function getCurve( numberOfPoints ){
this.getPoints = function(){
this.tempArray = new Array;
this.tempArray.push( rawDesc.charCodeAt( pointer ) );
pointer = pointer + 2;// set pointer to next point
this.tempArray.push( rawDesc.charCodeAt( pointer ) );
return this.tempArray;
}
this.pointsArray = new Array;
for( var i = 0; i < numberOfPoints; i++ ){
pointer = pointer + 2;// next point
this.pointsArray.push( this.getPoints() );
}
pointer = pointer + 2;// next curve
return this.pointsArray;
};
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( 'Lyr ' ), charIDToTypeID( 'Ordn' ), charIDToTypeID( 'Trgt' ) );
var rawDesc = executeActionGet( ref ).getList( stringIDToTypeID( 'adjustment' ) ).getObjectValue( 0 ).getData( stringIDToTypeID( 'legacyContentData' ) );
var pointer = 2;// used to read rawData similar to reading a file
var flag = rawDesc.charCodeAt( pointer );// char at offset 2 always == 1 so use to validate data
if( flag != 1 ) forceError;// unknown problem with rawData
pointer = 6;// update pointer to BCD byte
var bcd = rawDesc.charCodeAt( pointer );
if( bcd < 0 || bcd > 31 ) forceError;// check for valid value
if( bcd == 0 ) forceError;// an empty adjustment - no curves to process
var bcdArray = convertBCD( bcd );
var numberOfCurves = bcdArray.toString().match(/(1)/g).length;
var curvesArray = new Array;
pointer = 8;// set pointer to start of curve data
for(var i = 0; i < numberOfCurves; i++ ){
var numberOfPoints = rawDesc.charCodeAt( pointer );
curvesArray.push( getCurve( numberOfPoints ) );
}
// now need to map rawData curves in curvesArray to known channel curves
var acvArray = new Array;
if( bcdArray[0] == 1 ) {
acvArray.push( curvesArray.shift() );
} else {
acvArray.push( [ [0,0],[255,255] ] );
}
if( bcdArray[1] == 1 ) {
acvArray.push( curvesArray.shift() );
} else {
acvArray.push( [ [0,0],[255,255] ] );
}
if( bcdArray[2] == 1 ) {
acvArray.push( curvesArray.shift() );
} else {
acvArray.push( [ [0,0],[255,255] ] );
}
if( bcdArray[3] == 1 ) {
acvArray.push( curvesArray.shift() );
} else {
acvArray.push( [ [0,0],[255,255] ] );
}
if( bcdArray[4] == 1 ) {
acvArray.push( curvesArray.shift() );
} else {
acvArray.push( [ [0,0],[255,255] ] );
}
var myACV = new File('~/desktop/myCurve.acv');
myACV.open('w');
myACV.writeShort( 'LE','4' );// acv header
myACV.writeShort( 'LE','5' );// acv header
for( var i = 0; i< 5; i++ ) {
var numberOfPoints = acvArray.length;
myACV.writeShort( 'LE', numberOfPoints.toString() );
for( var p = 0; p < numberOfPoints; p++ ){
myACV.writeShort( 'LE', acvArray
[0].toString() );
myACV.writeShort( 'LE', acvArray
[1].toString() );
}
}
myACV.close();
I wrote this a while back. It might be possible to just write the acv header then add the raw data from the descriptor to work with other modes.
Also neither checks that the selected layer is a curves adjustment layer and will fail if it is not.
Copy link to clipboard
Copied
Thank you.
I got both scripts working without JS or AS errors, but, when trying to load .acv files generated by the second script, CS4 Photoshop gave an error:
"Could not load the curves because the file is not compatible with this version of Photoshop"
(The loading script works fine when loading .acv files created directly from Photoshop.)
The only change I made to your Save Curves code was:
FROM: var myACV = new File('~/desktop/myCurve.acv')
TO: var myACV = new File(file);
and made the code a function:
saveCurves(file)
{
YOUR CODE HERE
}
so that I could incorporate it into the Applescript.
Maybe that was naive (I'm not very knowledgeable about JS).
-------------
Here are the scripts I'm using:
SAVE CURVES:
set gammaFolder to "/Users/me/Desktop/myproject/gamma/"
tell application "Finder"
set TheFolder to choose folder
set FileList to every file of entire contents of TheFolder as alias list
end tell
repeat with theFile in FileList
set thefilename to theFile as string
set text item delimiters to ":"
set thefilename to last text item of thefilename --remove path
set text item delimiters to "."
set thefilename to first text item of thefilename --remove extension
tell application "Adobe Photoshop CS4"
activate
open theFile
tell current document
if exists layer "Curves 1" then
set current layer to layer "Curves 1"
do javascript "saveCurves('" & gammaFolder & thefilename & ".acv');
function saveCurves(file) {
-- SAVE CURVES JAVASCRIPT HERE
};" --show debugger on runtime error
end if
end tell
end tell
end repeat
-------------
LOAD CURVES:
set gammaFolder to "/Users/me/Desktop/myproject/gamma/"
tell application "Finder"
set TheFolder to choose folder
set FileList to every file of entire contents of TheFolder as alias list
end tell
repeat with theFile in FileList
set thefilename to theFile as string
set text item delimiters to ":"
set thefilename to last text item of thefilename --remove path
set text item delimiters to "."
set thefilename to first text item of thefilename --remove extension
set acvFile to gammaFolder & thefilename & ".acv"
tell application "Finder" to set acvExists to exists my POSIX file acvFile
if acvExists then
tell application "Adobe Photoshop CS4"
activate
open theFile
tell current document
if not (exists layer "Curves 1") then
do action "Create Curve Layer" from "MyActions"
end if
set current layer to layer "Curves 1"
do javascript "loadCurves('" & gammaFolder & thefilename & ".acv');
function loadCurves(file) {
-- LOAD CURVES JAVASCRIPT HERE
};" --show debugger on runtime error
end tell
end tell
end if
end repeat
Copy link to clipboard
Copied
I don't have CS4 installed to test but from the date of the file I got this code from it was written during CS4. And I also have never tested this on Mac. Just a guess but maybe on Mac you have to set the file type or creator as well as the extension. Can you use finder to set the type as a test to see if it loads then. If it does we can add code to set the type.
I thought the byte order in the Adobe support files like acv is the same on Windows or Mac but that may be another reason it doesn't work.
Or it is writting a binary file but doesn't explicitly set the file encoding. It works on Windows without setting the encoding but maybe Mac needs the encoding set. You can try adding the following line
// new line to set encoding
myACV.encoding = 'BINARY';
// existing line to open file to write
myACV.open('w');
Copy link to clipboard
Copied
Adding the BINARY line worked. Thank you for your help.