Copy link to clipboard
Copied
Hi fellow Photoshop users.
I start by saying that I'm quite a newbie about PS scripting, even if I'm a professional designer and PS user since 1999.
The subject says almost all.
This is the situation:
- I have PSD with 4 artboards;
- all artboards have a the same smart layer containing only one text level with a number (let's say it's "01");
- the same smart layer is also floating outside all artboards so I can just easily find it everytime I need to update the number on alla layers at once;
Every day I need to
- export all artboards in PNG
- export one specific artboard (let's call it "landscape") in JPG and rename all of them using some constant text + the number contained into the smart layer mentioned above + the name of the arboard
i.e.
MyConstantText-01-portrait.png
MyConstantText-01-landscape.png
MyConstantText-01-banner.png
MyConstantText-01-landscape.jpg
As I need to do this several times a day every week from different PSD source file I was asking myself if there's any way to do this with an action or scripting function that I can use on whatever source file.
I've seen different posts on this board about naming a file using a text layer but this seems to be a bit more complicated and I could'nt figure out how to put all the things I learnt here togegher to make the script I need.
Thanks in advance to anyone who can help.
Alessandro
// save png for each artboard and jpg for "Artboard 1";
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var myDocument = app.activeDocument;
var docName = myDocument.name;
try {
var basename = docName.match(/(.*)\.[^\.]+$/)[1];
var origDocPath = myDocument.fullName;
var docPath = myDocument.path;
}
catch (e) {
var basename = myDocument.name;
var docPath = "~/Desktop"
};
//////
...
Copy link to clipboard
Copied
That’s 3 pngs and one jpg, but you stated 4 Artboards.
I think it would be best to provide the sample file or at the very least meaningful screenshots (including all pertinent Panels) to illustrate the whole Layer and File structure.
Copy link to clipboard
Copied
Good point. I'll try to be more specific and if it doesn't sound comprehensive, I'll follow your advise.
There's artboards A, B, C, D.
I need to export all of them as PNGs AND one of them, let's say artboard A, as a JPG.
I hope it's more clear 🙂
And thanks for your answer.
Copy link to clipboard
Copied
If a picture is worth a thousand words, please post a screenshot of the layers panel and preferably a sample file so that those freely offering their time are not spending extra time creating test assets.
Or put another way, help others to help you.
Copy link to clipboard
Copied
// save png for each artboard and jpg for "Artboard 1";
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var myDocument = app.activeDocument;
var docName = myDocument.name;
try {
var basename = docName.match(/(.*)\.[^\.]+$/)[1];
var origDocPath = myDocument.fullName;
var docPath = myDocument.path;
}
catch (e) {
var basename = myDocument.name;
var docPath = "~/Desktop"
};
////////////////////////////////////
var theSO = openSmartObject(myDocument.layers.getByName("NUM"));
if (theSO == false) {alert ("please select the smart object")} else {
var theTypeLayers = collectTypeLayers ();
theSO.close(SaveOptions.DONOTSAVECHANGES);
if (theTypeLayers.length == 1) {
////////////////////////////////////
var theLayerSets = collectArtBoards ();
for (var m = 0; m < theLayerSets.length; m++) {
var theCopy = myDocument.duplicate("copy", true);
cropImageTo (theLayerSets[m][3]);
savePNG (myDocument, docPath, basename, theLayerSets[m][0]+"_"+theTypeLayers[0][3]);
if (theLayerSets[m][0] == "landscape <- PNG & JPG (Web, 1280x720, compr 90)") {
theCopy.bitsPerChannel = BitsPerChannelType.EIGHT;
saveJPG (activeDocument, docPath, basename, theLayerSets[m][0]+"_"+theTypeLayers[0][3])
};
theCopy.close(SaveOptions.DONOTSAVECHANGES)
};
} else {alert ("more than one type layer in the smart object")};
};
app.preferences.rulerUnits = originalRulerUnits;
};
////// collect artboards //////
function collectArtBoards () {
// get number of layers;
var ref = new ActionReference();
ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var artboardEn = layerDesc.getBoolean(stringIDToTypeID("artboardEnabled"));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if group collect values;
if (layerSet != "layerSectionEnd" && layerSet == "layerSectionStart" && isBackground != true && artboardEn == true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
//var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theArtboard = layerDesc.getObjectValue(stringIDToTypeID("artboard")).getObjectValue(stringIDToTypeID("artboardRect"));
//checkDesc2(theArtboard, true);
var theseBounds = [theArtboard.getUnitDoubleValue(stringIDToTypeID("left")), theArtboard.getUnitDoubleValue(stringIDToTypeID("top")), theArtboard.getUnitDoubleValue(stringIDToTypeID("right")), theArtboard.getUnitDoubleValue(stringIDToTypeID("bottom"))];
theLayers.push([theName, theIndex, theID, theseBounds])
};
}
catch (e) {};
};
return theLayers
};
////// function to png //////
function savePNG (myDocument, docPath, basename, theSuffix) {
var desc10 = new ActionDescriptor();
var desc11 = new ActionDescriptor();
desc11.putEnumerated( stringIDToTypeID( "method" ), stringIDToTypeID( "PNGMethod" ), stringIDToTypeID( "quick" ) );
desc11.putEnumerated( stringIDToTypeID( "PNGInterlaceType" ), stringIDToTypeID( "PNGInterlaceType" ), stringIDToTypeID( "PNGInterlaceNone" ) );
desc11.putEnumerated( stringIDToTypeID( "PNGFilter" ), stringIDToTypeID( "PNGFilter" ), stringIDToTypeID( "PNGFilterAdaptive" ) );
desc11.putInteger( stringIDToTypeID( "compression" ), 6 );
desc11.putEnumerated( stringIDToTypeID( "embedIccProfileLastState" ), stringIDToTypeID( "embedOff" ), stringIDToTypeID( "embedOff" ) );
var idPNGFormat = stringIDToTypeID( "PNGFormat" );
desc10.putObject( stringIDToTypeID( "as" ), idPNGFormat, desc11 );
desc10.putPath( stringIDToTypeID( "in" ), new File( docPath+"/"+basename+"_"+theSuffix+".png" ) );
desc10.putBoolean( stringIDToTypeID( "copy" ), true );
desc10.putBoolean( stringIDToTypeID( "lowerCase" ), true );
desc10.putBoolean( stringIDToTypeID( "embedProfiles" ), true );
desc10.putEnumerated( stringIDToTypeID( "saveStage" ), stringIDToTypeID( "saveStageType" ), stringIDToTypeID( "saveSucceeded" ) );
executeAction( stringIDToTypeID( "save" ), desc10, DialogModes.NO );
};
////// function to jpg //////
function saveJPG (myDocument, docPath, basename, theSuffix) {
myDocument = myDocument.duplicate("copy", true);
myDocument.flatten();
var jpgopts = new JPEGSaveOptions();
jpgopts.embedProfile = true;
jpgopts.formatOptions = FormatOptions.STANDARDBASELINE;
jpgopts.matte = MatteType.NONE;
jpgopts.quality = 12;
myDocument.saveAs((new File(docPath+"/"+basename+"_"+theSuffix+".jpg")),jpgopts,false);
myDocument.close()
};
////// crop //////
function cropImageTo (theBounds) {
var desc7 = new ActionDescriptor();
var desc8 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc8.putUnitDouble( charIDToTypeID( "Top " ), idPxl, theBounds[1] );
desc8.putUnitDouble( charIDToTypeID( "Left" ), idPxl, theBounds[0] );
desc8.putUnitDouble( charIDToTypeID( "Btom" ), idPxl, theBounds[3] );
desc8.putUnitDouble( charIDToTypeID( "Rght" ), idPxl, theBounds[2] );
var idRctn = charIDToTypeID( "Rctn" );
desc7.putObject( charIDToTypeID( "T " ), idRctn, desc8 );
desc7.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), 0.000000 );
desc7.putBoolean( charIDToTypeID( "Dlt " ), false );
desc7.putEnumerated( stringIDToTypeID( "cropAspectRatioModeKey" ), stringIDToTypeID( "cropAspectRatioModeClass" ), stringIDToTypeID( "pureAspectRatio" ) );
desc7.putBoolean( charIDToTypeID( "CnsP" ), false );
executeAction( charIDToTypeID( "Crop" ), desc7, DialogModes.NO );
};
////// open smart object //////
function openSmartObject (theLayer) {
try {
activeDocument.activeLayer = theLayer;
// =======================================================
var idplacedLayerEditContents = stringIDToTypeID( "placedLayerEditContents" );
var desc2 = new ActionDescriptor();
executeAction( idplacedLayerEditContents, desc2, DialogModes.NO );
return app.activeDocument
} catch (e) {return false}
};
////// collect type layers //////
function collectTypeLayers () {
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true && layerDesc.hasKey(stringIDToTypeID("textKey")) == true) {
var visible = layerDesc.getBoolean(stringIDToTypeID("visible"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theText = textDesc.getString(stringIDToTypeID('textKey'));
theLayers.push([theName, theID, visible, theText])
};
}
catch (e) {};
};
return theLayers
};
edited again 2024-02-28
Copy link to clipboard
Copied
My dear @c.pfaffenbichler.
Finally I had the chance to analyze and test your script.
I'm quite sure I need to study a little more to understand everything, but I got the most of it. 😉
Unfortunately there something going wrong.
Cycle looks good for PNGs but when it gets to export the JPG I get a "Save As" dialog asking me to manually save a file with the correct JPG filename BUT with PSD extension.
IF: I do click "save" as asked, it saves the file as PSD and closes the JPG "copy" file but asks me is I wanna save it or not, then it closes the PNG copy file and the cycle ends with no errors. But with a PSD instead of a JPG.
ELSE IF: I discard the save request, the two "copy" files created by the script stay opened and I get this error message at Line 107
myDocument.saveAs((new File(docPath+"/"+basename+"_"+theSuffix+".jpg")),jpgopts,false);
I can't figure out how to solve this, so I'm asking you for help.
Beside this, I only have a couple of request to add (I forgot to specify them at the beginning):
1. is it possible to export the JPG "for web" with a specified resizing (maintaining proportions) and compression? I need it to be under 2 MB.
2. can we just set in the script the Smart Object layer name for the text to use, instead of having to manually select it before running the script?
Thanks for all you've done.
Cheers
Alessandro
Copy link to clipboard
Copied
Can you please provide the psd-file (feel free to remove any sensitive content) for testing?
Copy link to clipboard
Copied
Here's a clean version of the PSD file: https://we.tl/t-Dg61n8NKqa
I will use this script on other files too with more artboards, but all of them are similar very to this (I will adapt the other files structure to the script).
Thanks for your help.
Copy link to clipboard
Copied
I edited the code, please try that.
Copy link to clipboard
Copied
Tried the new code (with the same file I sent you), but I got the PNGs and no JPG in my folder.
Copy link to clipboard
Copied
Could it be you renamed the Artboard?
Because here it seems to work fine.
Copy link to clipboard
Copied
Sorry my friend, I must have done that, but not in purpose.
Now it works just fine 🙂
Many thanks for your help.
Cheers
Copy link to clipboard
Copied
You can change the name for the jpg-Artboard in the line:
if (theLayerSets[m][0] == "landscape <- PNG & JPG (Web, 1280x720, compr 90)") {
You could also change the clause not to check for an exact name but to »look for« some element in the name.
Copy link to clipboard
Copied
Thanks for the explanation mate. I will take some time during the weekend and go through the whole code to fully understand it, even If I've seen you already commented it which is really helpful.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Maybe I should have explained for the OP’s sake that the line
if (theLayerSets[m][0] == "Artboard 1") {saveJPG (activeDocument, docPath, basename, theLayerSets[m][0]+"_"+theTypeLayers[0][3])};
determines whether a jpg will be produced for an Artboard – in this case if its name is exactly »Artboard 1«.
So changing that part to the intended name should work out.
Copy link to clipboard
Copied
Sorry guys. Been quite busy 🙂
I'll try @c.pfaffenbichler solution ASAP. Thanks, btw!
But it really looks like you got the point.
Copy link to clipboard
Copied
To use text layer content inside a smart layer to name the export file in Adobe Photoshop, you can follow these steps:
1. **Set Up Your Document**: Open your Photoshop document (.PSD) containing the text layer and smart object you want to use for naming the export file.
2. **Create a Text Layer**: If you haven't already, create a text layer with the desired content that you want to use for naming the export file. This text layer should be inside the smart object you're using.
3. **Convert Text Layer to Smart Object (Optional)**: If the text layer is not already part of the smart object, you can convert it into one. Right-click on the text layer and choose "Convert to Smart Object" from the context menu.
4. **Edit Smart Object Contents**: Double-click on the smart object's thumbnail in the Layers panel to open its contents. This will open a new tab with the contents of the smart object.
5. **Link Layer Names to Text Layer**: Inside the smart object's contents, create a new layer and use the Text tool to create a text box. Right-click on the text layer and choose "Convert to Smart Object" from the context menu.
6. **Set up Layer Name**: Double-click on the layer name to make it editable. Then, type in the desired name or use the Type tool to link it to the text layer in the smart object.
7. **Save and Close Smart Object**: Once you've set up the text layer content to name the export file, save the changes to the smart object and close its tab.
8. **Export Your File**: Back in the main document, go to File > Export > Export As or Save for Web (Legacy) to export your file. The export file name will now reflect the content of the linked text layer within the smart object.
By following these steps, you can use text layer content inside a smart layer to name the export file in Adobe Photoshop. This allows for dynamic file naming based on the content of the text layer within the smart object.