There's a plugin for Photoshop called ScriptingListener: after it's installed, it starts to write a log of most of the actions you do in Photoshop as code (basically everything you can save as an Action can be written as code). The code (Javascript) it gives you is quite difficult to read and can be confusing but! This allows you to put much more different conditions. It's like Actions 2.0.
Here's an example of code generated from running Save For Web command. I save a file as JPG with 33% scale and 92 quality:
// =======================================================
var idExpr = charIDToTypeID( "Expr" );
var desc21 = new ActionDescriptor();
var idUsng = charIDToTypeID( "Usng" );
var desc22 = new ActionDescriptor();
var idOp = charIDToTypeID( "Op " );
var idSWOp = charIDToTypeID( "SWOp" );
var idOpSa = charIDToTypeID( "OpSa" );
desc22.putEnumerated( idOp, idSWOp, idOpSa );
var idDIDr = charIDToTypeID( "DIDr" );
desc22.putBoolean( idDIDr, true );
var idIn = charIDToTypeID( "In " );
desc22.putPath( idIn, new File( "E:\\temp\\del" ) );
var idovFN = charIDToTypeID( "ovFN" );
desc22.putString( idovFN, """Untitled-3-033.jpg""" );
var idFmt = charIDToTypeID( "Fmt " );
var idIRFm = charIDToTypeID( "IRFm" );
var idJPEG = charIDToTypeID( "JPEG" );
desc22.putEnumerated( idFmt, idIRFm, idJPEG );
var idIntr = charIDToTypeID( "Intr" );
desc22.putBoolean( idIntr, false );
var idQlty = charIDToTypeID( "Qlty" );
desc22.putInteger( idQlty, 92 );
var idQChS = charIDToTypeID( "QChS" );
desc22.putInteger( idQChS, 0 );
var idQCUI = charIDToTypeID( "QCUI" );
desc22.putInteger( idQCUI, 0 );
var idQChT = charIDToTypeID( "QChT" );
desc22.putBoolean( idQChT, false );
var idQChV = charIDToTypeID( "QChV" );
desc22.putBoolean( idQChV, false );
var idOptm = charIDToTypeID( "Optm" );
desc22.putBoolean( idOptm, true );
var idPass = charIDToTypeID( "Pass" );
desc22.putInteger( idPass, 1 );
var idblur = charIDToTypeID( "blur" );
desc22.putDouble( idblur, 0.000000 );
var idMtt = charIDToTypeID( "Mtt " );
desc22.putBoolean( idMtt, false );
var idEICC = charIDToTypeID( "EICC" );
desc22.putBoolean( idEICC, false );
var idMttR = charIDToTypeID( "MttR" );
desc22.putInteger( idMttR, 255 );
var idMttG = charIDToTypeID( "MttG" );
desc22.putInteger( idMttG, 255 );
var idMttB = charIDToTypeID( "MttB" );
desc22.putInteger( idMttB, 255 );
var idHScl = charIDToTypeID( "HScl" );
var idPrc = charIDToTypeID( "#Prc" );
desc22.putUnitDouble( idHScl, idPrc, 33.333333 );
var idVScl = charIDToTypeID( "VScl" );
var idPrc = charIDToTypeID( "#Prc" );
desc22.putUnitDouble( idVScl, idPrc, 33.333333 );
var idSHTM = charIDToTypeID( "SHTM" );
desc22.putBoolean( idSHTM, false );
var idSImg = charIDToTypeID( "SImg" );
desc22.putBoolean( idSImg, true );
var idSWsl = charIDToTypeID( "SWsl" );
var idSTsl = charIDToTypeID( "STsl" );
var idSLAl = charIDToTypeID( "SLAl" );
desc22.putEnumerated( idSWsl, idSTsl, idSLAl );
var idSWch = charIDToTypeID( "SWch" );
var idSTch = charIDToTypeID( "STch" );
var idCHsR = charIDToTypeID( "CHsR" );
desc22.putEnumerated( idSWch, idSTch, idCHsR );
var idSWmd = charIDToTypeID( "SWmd" );
var idSTmd = charIDToTypeID( "STmd" );
var idMDCC = charIDToTypeID( "MDCC" );
desc22.putEnumerated( idSWmd, idSTmd, idMDCC );
var idohXH = charIDToTypeID( "ohXH" );
desc22.putBoolean( idohXH, false );
var idohIC = charIDToTypeID( "ohIC" );
desc22.putBoolean( idohIC, true );
var idohAA = charIDToTypeID( "ohAA" );
desc22.putBoolean( idohAA, true );
var idohQA = charIDToTypeID( "ohQA" );
desc22.putBoolean( idohQA, true );
var idohCA = charIDToTypeID( "ohCA" );
desc22.putBoolean( idohCA, false );
var idohIZ = charIDToTypeID( "ohIZ" );
desc22.putBoolean( idohIZ, true );
var idohTC = charIDToTypeID( "ohTC" );
var idSToc = charIDToTypeID( "SToc" );
var idOCzerothree = charIDToTypeID( "OC03" );
desc22.putEnumerated( idohTC, idSToc, idOCzerothree );
var idohAC = charIDToTypeID( "ohAC" );
var idSToc = charIDToTypeID( "SToc" );
var idOCzerothree = charIDToTypeID( "OC03" );
desc22.putEnumerated( idohAC, idSToc, idOCzerothree );
var idohIn = charIDToTypeID( "ohIn" );
desc22.putInteger( idohIn, -1 );
var idohLE = charIDToTypeID( "ohLE" );
var idSTle = charIDToTypeID( "STle" );
var idLEzerothree = charIDToTypeID( "LE03" );
desc22.putEnumerated( idohLE, idSTle, idLEzerothree );
var idohEn = charIDToTypeID( "ohEn" );
var idSTen = charIDToTypeID( "STen" );
var idENzerozero = charIDToTypeID( "EN00" );
desc22.putEnumerated( idohEn, idSTen, idENzerozero );
var idolCS = charIDToTypeID( "olCS" );
desc22.putBoolean( idolCS, false );
var idolEC = charIDToTypeID( "olEC" );
var idSTst = charIDToTypeID( "STst" );
var idSTzerozero = charIDToTypeID( "ST00" );
desc22.putEnumerated( idolEC, idSTst, idSTzerozero );
var idolWH = charIDToTypeID( "olWH" );
var idSTwh = charIDToTypeID( "STwh" );
var idWHzeroone = charIDToTypeID( "WH01" );
desc22.putEnumerated( idolWH, idSTwh, idWHzeroone );
var idolSV = charIDToTypeID( "olSV" );
var idSTsp = charIDToTypeID( "STsp" );
var idSPzerofour = charIDToTypeID( "SP04" );
desc22.putEnumerated( idolSV, idSTsp, idSPzerofour );
var idolSH = charIDToTypeID( "olSH" );
var idSTsp = charIDToTypeID( "STsp" );
var idSPzerofour = charIDToTypeID( "SP04" );
desc22.putEnumerated( idolSH, idSTsp, idSPzerofour );
var idolNC = charIDToTypeID( "olNC" );
var list3 = new ActionList();
var desc23 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCzerozero = charIDToTypeID( "NC00" );
desc23.putEnumerated( idncTp, idSTnc, idNCzerozero );
var idSCnc = charIDToTypeID( "SCnc" );
list3.putObject( idSCnc, desc23 );
var desc24 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNConenine = charIDToTypeID( "NC19" );
desc24.putEnumerated( idncTp, idSTnc, idNConenine );
var idSCnc = charIDToTypeID( "SCnc" );
list3.putObject( idSCnc, desc24 );
var desc25 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwoeight = charIDToTypeID( "NC28" );
desc25.putEnumerated( idncTp, idSTnc, idNCtwoeight );
var idSCnc = charIDToTypeID( "SCnc" );
list3.putObject( idSCnc, desc25 );
var desc26 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwofour = charIDToTypeID( "NC24" );
desc26.putEnumerated( idncTp, idSTnc, idNCtwofour );
var idSCnc = charIDToTypeID( "SCnc" );
list3.putObject( idSCnc, desc26 );
var desc27 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwofour = charIDToTypeID( "NC24" );
desc27.putEnumerated( idncTp, idSTnc, idNCtwofour );
var idSCnc = charIDToTypeID( "SCnc" );
list3.putObject( idSCnc, desc27 );
var desc28 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwofour = charIDToTypeID( "NC24" );
desc28.putEnumerated( idncTp, idSTnc, idNCtwofour );
var idSCnc = charIDToTypeID( "SCnc" );
list3.putObject( idSCnc, desc28 );
desc22.putList( idolNC, list3 );
var idobIA = charIDToTypeID( "obIA" );
desc22.putBoolean( idobIA, false );
var idobIP = charIDToTypeID( "obIP" );
desc22.putString( idobIP, """""" );
var idobCS = charIDToTypeID( "obCS" );
var idSTcs = charIDToTypeID( "STcs" );
var idCSzeroone = charIDToTypeID( "CS01" );
desc22.putEnumerated( idobCS, idSTcs, idCSzeroone );
var idovNC = charIDToTypeID( "ovNC" );
var list4 = new ActionList();
var desc29 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCzeroone = charIDToTypeID( "NC01" );
desc29.putEnumerated( idncTp, idSTnc, idNCzeroone );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc29 );
var desc30 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwozero = charIDToTypeID( "NC20" );
desc30.putEnumerated( idncTp, idSTnc, idNCtwozero );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc30 );
var desc31 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCzerotwo = charIDToTypeID( "NC02" );
desc31.putEnumerated( idncTp, idSTnc, idNCzerotwo );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc31 );
var desc32 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNConenine = charIDToTypeID( "NC19" );
desc32.putEnumerated( idncTp, idSTnc, idNConenine );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc32 );
var desc33 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCzerosix = charIDToTypeID( "NC06" );
desc33.putEnumerated( idncTp, idSTnc, idNCzerosix );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc33 );
var desc34 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwofour = charIDToTypeID( "NC24" );
desc34.putEnumerated( idncTp, idSTnc, idNCtwofour );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc34 );
var desc35 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwofour = charIDToTypeID( "NC24" );
desc35.putEnumerated( idncTp, idSTnc, idNCtwofour );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc35 );
var desc36 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwofour = charIDToTypeID( "NC24" );
desc36.putEnumerated( idncTp, idSTnc, idNCtwofour );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc36 );
var desc37 = new ActionDescriptor();
var idncTp = charIDToTypeID( "ncTp" );
var idSTnc = charIDToTypeID( "STnc" );
var idNCtwotwo = charIDToTypeID( "NC22" );
desc37.putEnumerated( idncTp, idSTnc, idNCtwotwo );
var idSCnc = charIDToTypeID( "SCnc" );
list4.putObject( idSCnc, desc37 );
desc22.putList( idovNC, list4 );
var idovCM = charIDToTypeID( "ovCM" );
desc22.putBoolean( idovCM, false );
var idovCW = charIDToTypeID( "ovCW" );
desc22.putBoolean( idovCW, true );
var idovCU = charIDToTypeID( "ovCU" );
desc22.putBoolean( idovCU, true );
var idovSF = charIDToTypeID( "ovSF" );
desc22.putBoolean( idovSF, true );
var idovCB = charIDToTypeID( "ovCB" );
desc22.putBoolean( idovCB, true );
var idovSN = charIDToTypeID( "ovSN" );
desc22.putString( idovSN, """images""" );
var idSaveForWeb = stringIDToTypeID( "SaveForWeb" );
desc21.putObject( idUsng, idSaveForWeb, desc22 );
executeAction( idExpr, desc21, DialogModes.NO );
It's huge and terrifying, however it's easy to identify several lines that I'd want to change to get different results. There's a line with file path, file name, quality (desc22.putInteger( idQlty, 92 );
), and scale (desc22.putUnitDouble( idHScl, idPrc, 33.333333 );
for horizontal and another similar for vertical scale).
So basically what we need is to be able to use this huge command with a name we want and a scale we want. And we don't want to repeat these chunks of code for each export. Also if it could look at least a little more pretty it'd be amazing.
Ok, so
- to get active document name and path we can use
activeDocument.name
and activeDocument.path
;
- to reuse the code we can use functions and we can pass argumens to these functions;
- to make the code a bit more readable amazing xbytorx made a a script ScriptListener Code Cleaner that's a part of his xtools library;
here's the final version of the script:
var filePath = activeDocument.path; // this can be changed to something like "/E/MyPhotos/JPEGs";
var fileName = activeDocument.name.replace(/\.[^.]+$/g, ""); // activeDocument.name will give a name with its extension, I want only a name
saveForWeb(fileName + "[email protected]", filePath, 90, 100); // I'm running my saveForWeb function and give it some arguments: a name I want, a path, quality and scale
saveForWeb(fileName + "[email protected]", filePath, 90, 33);
function saveForWeb(fileName, filePath, quality, scale)
{
function cTID(s)
{
return app.charIDToTypeID(s);
};
function sTID(s)
{
return app.stringIDToTypeID(s);
};
var desc21 = new ActionDescriptor();
var desc22 = new ActionDescriptor();
desc22.putEnumerated(cTID('Op '), cTID('SWOp'), cTID('OpSa'));
desc22.putBoolean(cTID('DIDr'), true);
desc22.putPath(cTID('In '), new File(filePath)); // file path
desc22.putString(cTID('ovFN'), fileName); // file name
desc22.putEnumerated(cTID('Fmt '), cTID('IRFm'), cTID('JPEG'));
desc22.putBoolean(cTID('Intr'), false);
desc22.putInteger(cTID('Qlty'), quality); // quality
desc22.putInteger(cTID('QChS'), 0);
desc22.putInteger(cTID('QCUI'), 0);
desc22.putBoolean(cTID('QChT'), false);
desc22.putBoolean(cTID('QChV'), false);
desc22.putBoolean(cTID('Optm'), true);
desc22.putInteger(cTID('Pass'), 1);
desc22.putDouble(cTID('blur'), 0.000000);
desc22.putBoolean(cTID('Mtt '), false);
desc22.putBoolean(cTID('EICC'), false);
desc22.putInteger(cTID('MttR'), 255);
desc22.putInteger(cTID('MttG'), 255);
desc22.putInteger(cTID('MttB'), 255);
desc22.putUnitDouble(cTID('HScl'), cTID('#Prc'), scale); // scale
desc22.putUnitDouble(cTID('VScl'), cTID('#Prc'), scale); // scale
desc22.putBoolean(cTID('SHTM'), false);
desc22.putBoolean(cTID('SImg'), true);
desc22.putEnumerated(cTID('SWsl'), cTID('STsl'), cTID('SLAl'));
desc22.putEnumerated(cTID('SWch'), cTID('STch'), cTID('CHsR'));
desc22.putEnumerated(cTID('SWmd'), cTID('STmd'), cTID('MDCC'));
desc22.putBoolean(cTID('ohXH'), false);
desc22.putBoolean(cTID('ohIC'), true);
desc22.putBoolean(cTID('ohAA'), true);
desc22.putBoolean(cTID('ohQA'), true);
desc22.putBoolean(cTID('ohCA'), false);
desc22.putBoolean(cTID('ohIZ'), true);
desc22.putEnumerated(cTID('ohTC'), cTID('SToc'), cTID('OC03'));
desc22.putEnumerated(cTID('ohAC'), cTID('SToc'), cTID('OC03'));
desc22.putInteger(cTID('ohIn'), -1);
desc22.putEnumerated(cTID('ohLE'), cTID('STle'), cTID('LE03'));
desc22.putEnumerated(cTID('ohEn'), cTID('STen'), cTID('EN00'));
desc22.putBoolean(cTID('olCS'), false);
desc22.putEnumerated(cTID('olEC'), cTID('STst'), cTID('ST00'));
desc22.putEnumerated(cTID('olWH'), cTID('STwh'), cTID('WH01'));
desc22.putEnumerated(cTID('olSV'), cTID('STsp'), cTID('SP04'));
desc22.putEnumerated(cTID('olSH'), cTID('STsp'), cTID('SP04'));
var list3 = new ActionList();
var desc23 = new ActionDescriptor();
desc23.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC00'));
list3.putObject(cTID('SCnc'), desc23);
var desc24 = new ActionDescriptor();
desc24.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC19'));
list3.putObject(cTID('SCnc'), desc24);
var desc25 = new ActionDescriptor();
desc25.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC28'));
list3.putObject(cTID('SCnc'), desc25);
var desc26 = new ActionDescriptor();
desc26.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC24'));
list3.putObject(cTID('SCnc'), desc26);
var desc27 = new ActionDescriptor();
desc27.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC24'));
list3.putObject(cTID('SCnc'), desc27);
var desc28 = new ActionDescriptor();
desc28.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC24'));
list3.putObject(cTID('SCnc'), desc28);
desc22.putList(cTID('olNC'), list3);
desc22.putBoolean(cTID('obIA'), false);
desc22.putString(cTID('obIP'), "");
desc22.putEnumerated(cTID('obCS'), cTID('STcs'), cTID('CS01'));
var list4 = new ActionList();
var desc29 = new ActionDescriptor();
desc29.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC01'));
list4.putObject(cTID('SCnc'), desc29);
var desc30 = new ActionDescriptor();
desc30.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC20'));
list4.putObject(cTID('SCnc'), desc30);
var desc31 = new ActionDescriptor();
desc31.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC02'));
list4.putObject(cTID('SCnc'), desc31);
var desc32 = new ActionDescriptor();
desc32.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC19'));
list4.putObject(cTID('SCnc'), desc32);
var desc33 = new ActionDescriptor();
desc33.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC06'));
list4.putObject(cTID('SCnc'), desc33);
var desc34 = new ActionDescriptor();
desc34.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC24'));
list4.putObject(cTID('SCnc'), desc34);
var desc35 = new ActionDescriptor();
desc35.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC24'));
list4.putObject(cTID('SCnc'), desc35);
var desc36 = new ActionDescriptor();
desc36.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC24'));
list4.putObject(cTID('SCnc'), desc36);
var desc37 = new ActionDescriptor();
desc37.putEnumerated(cTID('ncTp'), cTID('STnc'), cTID('NC22'));
list4.putObject(cTID('SCnc'), desc37);
desc22.putList(cTID('ovNC'), list4);
desc22.putBoolean(cTID('ovCM'), false);
desc22.putBoolean(cTID('ovCW'), true);
desc22.putBoolean(cTID('ovCU'), true);
desc22.putBoolean(cTID('ovSF'), true);
desc22.putBoolean(cTID('ovCB'), true);
desc22.putString(cTID('ovSN'), "images");
desc21.putObject(cTID('Usng'), sTID('SaveForWeb'), desc22);
executeAction(cTID('Expr'), desc21, DialogModes.NO);
}
The script can be a part of an action used for batch of course. So you can open your .psd with an action, maybe do some modifications and then use a script as a last step instead of Save for Web
. Also it can be rewritten in a more sophisticated way but who cares.
The result: two jpegs saved in the same folder as my original psd with correct names and sizes:
Update:
To use a script in an action you can first save it as a .jsx
file in YourPhotoshop/Presets/Scripts
folder, restart PS and add it with Insert Menu Item...
command from the flyout menu (the script will be located in File > Scripts
menu), then it'll appear as a usual step: