Photoshop Scripting JavaScript loop through layers problem - javascript

I have a script that does the following:
loops through layers,
saves each layer in a separate folder (name of folder same as layer name)
saved layer images have names "nameofthedocument, nameofthelayer.png"
Now I wanted to add text item on top of those layers while they are saving as separate pngs so that for gods sake you don't have to always look at the file name but instead there would be text in the PNG image rasterized and says "nameofthelayer" variable.
So for each layer of course different text should be inserted in the image.
i encountered weird problems once I tried to do that what seamigly looked easy.
HEre is the link with a video and an explanation of the code as well as what I did and why it messed up the script.
https://drive.google.com/drive/folders/1h2KAiEuruLY_PQ2JVhQAwINDYPvk9xHS?usp=sharing
Thank you folks, please help me out
Code, image and video explanation is all available in the link
CODE:
// NAME:
// SaveLayers
// DESCRIPTION:
// Saves each layer in the active document to a PNG or JPG file named after the layer.
// These files will be created in the current document folder.
// REQUIRES:
// Adobe Photoshop CS2 or higher
// VERSIONS:
// 27 March 2013 by Robin Parmar (robin#robinparmar.com)
// preferences stored in object
// auto-increment file names to prevent collisions
// properly handles layer groups
// header added
// code comments added
// main() now has error catcher
// counts number of layers
// many little code improvements
// 26 Sept 2012 by Johannes on stackexchange
// original version
// enable double-clicking from Finder/Explorer (CS2 and higher)
#target photoshop
app.bringToFront();
//alert(activeDocument.name);
function main() {
// two quick checks
if(!okDocument()) {
alert("Document must be saved and be a layered PSD.");
return;
}
var len = activeDocument.layers.length;
// user preferences
prefs = new Object();
prefs.fileType = "";
prefs.fileQuality = 0;
prefs.filePath = app.activeDocument.path;
prefs.count = 0;
saveLayers(activeDocument);
//toggleVisibility(activeDocument);
}
function saveLayers(ref) {
var len = ref.layers.length;
// rename layers top to bottom
for (var i = 0; i < len; i++) {
var layer = ref.layers[i];
if (layer.typename == 'LayerSet') {
// recurse if current layer is a group
saveLayers(layer);
} else {
// otherwise make sure the layer is visible and save it
layer.visible = true;
saveImage(layer.name);
layer.visible = false;
}
}
}
function getNameWithoutExtension(nameWithExt) {
var nameWithoutExtension = nameWithExt;
return nameWithoutExtension.split(".")[0];
}
function saveImage(layerName) {
var f = new Folder("D:/Process/0/"+layerName);
f.create();
//////////////// BROKEN PART I ADDED
#target photoshop
// Current layer name as text layer
var myDoc = app.activeDocument;
var myRulers = app.preferences.rulerUnits
app.preferences.rulerUnits = Units.PIXELS;
var OriginalLayerName = myDoc.activeLayer.name
var myLayerName = myDoc.activeLayer.name + "text";
var myLayerText = myDoc.artLayers.add()
myLayerText.kind = LayerKind.TEXT
var myText = myLayerText.textItem
myColor = new SolidColor
myColor.rgb.red = 255
myColor.rgb.green = 0
myColor.rgb.blue = 0
myLayerText.textItem.color = myColor
myText.position = [0,20] // Upper Left
myText.justification = Justification.LEFT
myText.size = 12
myText.contents = myLayerName
myLayerText.name = myLayerName // Or add a fixed string in quotes i.e. 'My Great Layer Name!'
app.preferences.rulerUnits = myRulers
//////////////////////////////END OF THE BROKN PART
//var handle = generateName(f.path + "/",layerName, ".png");
//alert(handle);
var handle = getUniqueName(prefs.filePath + "/"+ layerName +"/"+ getNameWithoutExtension(activeDocument.name) + ", " + layerName);
//alert(handle);
prefs.count++;
if(prefs.fileType=="PNG") {
SavePNG(handle);
} else {
SaveJPEG(handle);
}
}
function getUniqueName(fileroot) {
// form a full file name
// if the file name exists, a numeric suffix will be added to disambiguate
var filename = fileroot;
for (var i=1; i<100; i++) {
var handle = File(filename + "." + prefs.fileType);
if(handle.exists) {
filename = fileroot + "-" + padder(i, 3);
} else {
return handle;
}
}
}
function padder(input, padLength) {
// pad the input with zeroes up to indicated length
var result = (new Array(padLength + 1 - input.toString().length)).join('0') + input;
return result;
}
function SavePNG(saveFile) {
pngSaveOptions = new PNGSaveOptions();
activeDocument.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
}
function SaveJPEG(saveFile) {
pngSaveOptions = new PNGSaveOptions();
activeDocument.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
}
// file type
var saveOpt = [];
saveOpt[0] = "PNG";
saveOpt[1] = "PNG";
// png type
var pngtypeOpt = [1];
pngtypeOpt[0]=24;
pngtypeOpt[1]=24;
function okDocument() {
// check that we have a valid document
if (!documents.length) return false;
var thisDoc = app.activeDocument;
var fileExt = decodeURI(thisDoc.name).replace(/^.*\./,'');
return fileExt.toLowerCase() == 'psd'
}
function wrapper() {
function showError(err) {
alert(err + ': on line ' + err.line, 'Script Error', true);
}
try {
// suspend history for CS3 or higher
if (parseInt(version, 10) >= 10) {
activeDocument.suspendHistory('Save Layers', 'main()');
} else {
main();
}
} catch(e) {
// report errors unless the user cancelled
if (e.number != 8007) showError(e);
}
}
function generateName(filePath, layerName, ext) {
var generatedName = app.activeDocument.name;
var generatedName = generatedName.split(".")[0];
generatedName = generatedName + ", " + layerName;
return filePath + generatedName + ext;
}
wrapper();

Related

Script works in IE but not Chromium

I have a script I am using in a html file my program accesses. it has been using IE as the browser, but the new version no longer uses IE, it uses Chromium. some of the script works, but it gets to a point that it does nothing. no errors just stops. I am guessing there is a difference in the way Chromium handles the script. The script is one I got online and modified. I will include the code below. I use the update option the most "AutomateExcel3" please ignore my code block outs and comments as I was trying to figure sometime else out.
thanks for the help
<script>
//*********************************************INTRODUCTION*****************************************
//When using Web.Link the first thing to do is initialize what's called a handle to Pro/Engineer
// Get Session, Model.
var mGlob = pfcCreate("MpfcCOMGlobal");
var oSession = mGlob.GetProESession();
var CurDwg = oSession.CurrentModel;
var CurWind = oSession.CurrentWindow;
var Base = "P:\ENGINEERING FILES\TPS PRE-PROD ENG\MV-22\excel_file.xls";
function UpdateControls(Opt)
{
bottom.innerHTML = "";
var Cntls="";
if (Opt==1)
{
Cntls = "<H2>To Export:</H2>"+
"<LI>Enter target Excel Files path</LI><LI>Pick \"Dwg Table\"</LI><LI>Pick Drawing Table</LI><P><INPUT id=FileName type=file size=80 value=\""+Base+"\"><BR>"+
"<INPUT id=button1 type=button value=\"Dwg Table\" onclick=\"AutomateExcel1()\">";
}
else if (Opt==2)
{
Cntls = "<H2>To Import:</H2>"+
"<LI>Enter the Excel Files path</LI><LI>Pick \"Next>>>\"</LI><LI>Pick Drawing To Place</LI><P><INPUT id=FileName type=file size=80 value=\""+Base+"\"><BR>"+
"<INPUT id=button1 type=button value=\"Next>>>\" onclick=\"AutomateExcel2()\">";
}
else if (Opt ==3)
{
Cntls = "<H2>To Update:</H2>"+
"<LI>Enter the Excel Files path</LI><LI>Pick \"Dwg Table\"</LI><LI>Pick Drawing Table</LI><P><INPUT id=FileName type=file size=80 value=\""+Base+"\"><BR>"+
"<INPUT id=button1 type=button value=\"Dwg Table\" onclick=\"AutomateExcel3()\">";
}
middle.innerHTML = Cntls;
}
function AutomateExcel1()
{
var MultipleLinesInCells = false;
//Have the user pick a table to export
var SelOptions = pfcCreate("pfcSelectionOptions").Create ("dwg_table");
SelOptions.MaxNumSels = 1;
var Selections = oSession.Select(SelOptions, null);
var Table = Selections.Item(0).SelItem;
//Build a matrix containing the values for the table
var nTableRows = Table.GetRowCount();
var nTableCols = Table.GetColumnCount();
//Start a new Excel Spreadsheet
var oXL;
oXL = new ActiveXObject("Excel.Application");
var oWB = oXL.Workbooks.Add();
var oSheet = oWB.ActiveSheet;
//Loop around the table and dump information to excel
for (i=0;i<nTableRows;i++)
{
for (j=0;j<nTableCols;j++)
{
var Cell = pfcCreate("pfcTableCell").Create(i+1, j+1);
var Mode = pfcCreate("pfcParamMode").DWGTABLE_NORMAL;
try
{
var Val = Table.GetText (Cell,Mode);
var Out="";
if (Val.Count>1)
MultipleLinesInCells = true;
for (k=0;k<Val.Count;k++)
{
if (k>0)
{
if (k<Val.Count)
{
Out = Out + " ";
}
}
Out = Out + Val.Item(k);
}
oSheet.Cells(i+1, j+1).Value = Out;
}
catch(er)
{
//Failure occurs when cells are merged, pro/e doesn't recognize cells that are now merged into another
}
}
}
//Bring up Excel for user to do with what they want.
//oXL.Visible = true;
oXL.UserControl = false;
if (FileName.value==null)
File = Base
else
File = FileName.value;
try
{
oWB.Close(true, File,null);
oXL.Workbooks.Close();
oXL.Quit();
Base = FileName.value;
var Out = "<H2>Success:</H2>Pick here for created document";
if (MultipleLinesInCells)
Out = Out + "<H2>Warning:</H2>The export resulted in some Multi-line cells being concatenated";
bottom.innerHTML = Out;
}
catch(er)
{
var Out = "<H2>Error:</H2>Could Not Write Specified File, please edit path and try again. If not Chuck Norris Might Get Angry!";
bottom.innerHTML = Out;
}
}
function AutomateExcel2()
{
//Have the user pick somewhere
var mousePick = oSession.UIGetNextMousePick ( pfcCreate("pfcMouseButton").MOUSE_BTN_LEFT);
var Orig = mousePick.Position;
//Start Excel
var oXL = new ActiveXObject("Excel.Application");
try
{
var oWB = oXL.Workbooks.Open(FileName.value);
var oSheet = oWB.ActiveSheet;
Base = FileName.value;
}
catch (er)
{
bottom.innerHTML = "<H2>Error:</H2>Could Not Open Specified File, \""+FileName.value+"\" for Import, please edit path and try again";
return;
}
//Start the table instructions
var TableInsts = pfcCreate("pfcTableCreateInstructions").Create (Orig);
var TableSizeType = pfcCreate("pfcTableSizeType").TABLESIZE_BY_NUM_CHARS;
TableInsts.SizeType = TableSizeType;
var columnInfo = pfcCreate ("pfcColumnCreateOptions");
//Look for headers in top row
var nCols=0;
var Val = oSheet.Cells(1,nCols+1).Value;
while (Val!=null)
{
nCols=nCols+1;
Val = oSheet.Cells(1,nCols+1).Value;
var column = pfcCreate ("pfcColumnCreateOption").Create (pfcCreate ("pfcColumnJustification").COL_JUSTIFY_LEFT,Math.round(oSheet.Cells(1,nCols).ColumnWidth+1));
columnInfo.Append (column);
}
//Push column information into Table Instructions
TableInsts.ColumnData = columnInfo;
//Push in the Header row
var rowInfo = pfcCreate ("realseq");
rowInfo.Append (2.0); //title line
TableInsts.RowHeights = rowInfo;
//Now create the table in proe
var CurTable = CurDwg.CreateTable(TableInsts);
//Populate the header information
for (var i=1;i<=nCols;i++)
{
var Val = oSheet.Cells(1,i).Value;
writeTextInCell (CurTable, 1, i, Val);
}
//Populate the rest of the table
var i=2;
var Row = oSheet.Cells(i,1).Value;
while (Row!=null)
{
CurTable.InsertRow (1.0, i-1, false);
for (var j=1;j<=nCols;j++)
{
var Val = oSheet.Cells(i,j).Value;
writeTextInCell (CurTable, i, j, Val);
}
i=i+1;
Row = oSheet.Cells(i,1).Value;
}
//Close down Excel.
oXL.UserControl = false;
oWB.Close(true);
oXL.Workbooks.Close();
oXL.Quit();
Excel.Application.Quit(); // added this to try to close excel
var Out = "<H2>Success:</H2>Excel sheet imported as Pro/E Drawing Table";
bottom.innerHTML = Out;
}
function AutomateExcel3()
{
//Have the user pick a table to update
var SelOptions = pfcCreate("pfcSelectionOptions").Create ("dwg_table");
SelOptions.MaxNumSels = 1;
var Selections = oSession.Select(SelOptions, null);
var Table = Selections.Item(0).SelItem;
//Start Excel
var oXL = new ActiveXObject("Excel.Application");
try
{
var oWB = oXL.Workbooks.Open(FileName.value);
var oSheet = oWB.ActiveSheet;
Base = FileName.value;
}
catch(er)
{
bottom.innerHTML = "<H2>Error:</H2>Could Not Open Specified File, \""+FileName.value+"\" for Update, please edit path and try again.";
return;
}
//Look for headers in top row and check them against the already existing headers
var nProCols = Table.GetColumnCount ();
var nCols=0;
var Val = oSheet.Cells(1,nCols+1).Value;
while (Val!=null)
{
nCols=nCols+2; // default was 1 changed to 2 now it doesn't delete the column if nothing in the first row.
//Check to see if we need to add another column
if (nCols>nProCols)
{
Table.InsertColumn (Math.round(oSheet.Cells(1,nCols).ColumnWidth+1), nCols-1, false);
nProCols=nProCols+1;
}
//Get current XL value
var ValXL = oSheet.Cells(1,nCols).Value;
//Get current ProE value
var cell = pfcCreate ("pfcTableCell").Create (1, nCols);
var mode = pfcCreate("pfcParamMode").DWGTABLE_NORMAL;
try
{
var ValProE = Table.GetText (cell, mode).Item(0);
}
catch(er)
{
var ValProE = "";
}
//Overwrite ProE value with XL value if they are not equal
if (ValProE!=ValXL)
{
ModifyCellText(Table, cell, ValXL);
}
Val = oSheet.Cells(1,nCols+1).Value;
}
//Check to see if any columns are left that need deleting off
//removed code and it appears to work without setting column to 15 above
while (nCols<nProCols)
{
Table.DeleteColumn (nProCols, false);
nProCols=nProCols-1; //default was -1 (changed to -0 and crashed creo)
}
//Populate the rest of the table
var nProRows = Table.GetRowCount();
var nRows = 0;
var Val = oSheet.Cells(nRows+1,1).Value;
while (Val!=null)
{
nRows = nRows + 1;
//Check to see if we need to add another row
if (nRows>nProRows)
{
Table.InsertRow (1, nRows-1, false);
nProRows=nProRows+1;
}
//Loop around all columns for each row
for (i=1;i<=nCols;i++)
{
//Get current XL value
var ValXL = oSheet.Cells(nRows,i).Value;
//Get current ProE value
var cell = pfcCreate ("pfcTableCell").Create (nRows, i);
var mode = pfcCreate("pfcParamMode").DWGTABLE_NORMAL;
try
{
var ValProE = Table.GetText (cell, mode).Item(0);
}
catch(er)
{
var ValProE = "";
}
//Overwrite ProE value with XL value if they are not equal
if (ValProE!=ValXL)
{
ModifyCellText(Table, cell, ValXL);
}
}
Val = oSheet.Cells(nRows+1,1).Value;
}
//Check to see if any rows are left that need deleting off
while (nRows<nProRows)
{
Table.DeleteRow (nProRows, false);
nProRows=nProRows-1;
}
CurDwg.Regenerate ();
//Close down Excel.
oXL.DisplayAlerts = false;
oXL.UserControl = false;
oWB.Close(true);
oXL.Workbooks.Close();
oXL.Quit();
// below code seams to stop excel instance created by from task manager while leaving other instances of excel alone
excel = null;
excelfile = null;
excelsheet = null;
CollectGarbage();
setTimeout("CollectGarbage()",1);
oSheet = null;
oWB = null;
oXL = null;
// below code kills excel from taskmanager but all excel is closed.
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("taskkill /F /IM EXCEL.exe");
CurDwg.UpdateTables ();
var Out = "<H2>Success:</H2>Excel sheet used as basis to update a Pro/E Drawing Table"+
"<p>Note:"+
"<LI>Cell Font and Alignment is Maintained for existing cells</LI>"+
"<LI>Rows can be added and removed - this is likely to require extra formatting</LI>"+
"<LI>There may be problems involving updating tables with merged cells</LI>"+
"<LI>Ensure you check the table for correct format after an update</LI>"+
"<LI>Congratulations Chuck Norris Approves!</LI>"+
"</p>";
bottom.innerHTML = Out;
}
function ModifyCellText(Table, cell, ValXL)
{
try
{
var CellNote = Table.GetCellNote (cell);
var CellNoteInsts = CellNote.GetInstructions (true);
var CellNoteTextLines = CellNoteInsts.TextLines;
var CellNoteTextLine1 = CellNoteInsts.TextLines.Item(0);
var CellNoteTextLine1Texts = CellNoteTextLine1.Texts;
var CellNoteTextLine1Text1 = CellNoteTextLine1Texts.Item(0);
var FontName = CellNoteTextLine1Text1.FontName;
}
catch(er)
{
var FontName = "ariallight.TTF";
}
var lines = pfcCreate("stringseq");
lines.Append (ValXL);
Table.SetText(cell, lines);
var CellNote = Table.GetCellNote (cell);
var CellNoteInsts = CellNote.GetInstructions (true);
var CellNoteTextLines = CellNoteInsts.TextLines;
var CellNoteTextLine1 = CellNoteInsts.TextLines.Item(0);
var CellNoteTextLine1Texts = CellNoteTextLine1.Texts;
var CellNoteTextLine1Text1 = CellNoteTextLine1Texts.Item(0);
//Switch Font
CellNoteTextLine1Text1.FontName = FontName;
CellNote.Modify (CellNoteInsts);
}
function writeTextInCell(table /* pfcTable */, row /* integer */,
col /* integer */, text /* string */)
{
var cell = pfcCreate ("pfcTableCell").Create (row, col);
var lines = pfcCreate ("stringseq");
lines.Append (text);
try{
table.SetText (cell, lines);
}
catch(er)
{
alert (row+" "+col);
}
}
// Function to create the activeX objects that are the interface to Web.Link.
function pfcCreate (className)
{
if (!pfcIsWindows())
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (pfcIsWindows())
return new ActiveXObject ("pfc."+className);
else
{
ret = Components.classes ["#ptc.com/pfc/" + className + ";1"].createInstance();
return ret;
}
}
//Checks what OS is being operated
//IE11 requires more indepth browser testing...
function get_browser_info(){
var ua=navigator.userAgent,tem,M=ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem=/\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1]||'')};
}
if(M[1]==='Chrome'){
tem=ua.match(/\bOPR\/(\d+)/)
if(tem!=null) {return {name:'Opera', version:tem[1]};}
}
M=M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem=ua.match(/version\/(\d+)/i))!=null) {M.splice(1,1,tem[1]);}
return {
name: M[0],
version: M[1]
};
}
function pfcIsWindows ()
{
var browser = get_browser_info();
if (browser.name.indexOf ("IE") != -1)
return true;
else
return false;
}
</script>
code worked perfectly in IE but not in the new browser I am forced to use

JS / JSX Script to generate unique PNGs from all permutations across all Photoshop Layer Groups and their Photoshop Layers

I'm looking into getting into generative art. My idea is to have Photoshop (CS5) generate a unique PNG for all permutations that exist while the script iterates through every LAYER across each LAYER GROUP (layerSets).
As an example, it would be similar to a character generator where:
PARENT layerSets consist of parts or locations across the face/body (A,B)
CHILD layers consist of accessories/styles (1,2,3)
Such that all generated PNG permutations would be: A1B1,A2B1,A3B1;A2B1,A2B2,A2B3;A3B1,A3B2,A3B3 only. (A1A2, A2A3, A1A3; B1B2, B2B3, B1B3 are not necessary; Standalone A1,A2,A3,B1,B2,B3 are not necessary).
I've found some code from #Mr.Online that generates random, and potentially redundant combinations from user-inputted quantity. His script requires that all layers be hidden by the user prior to running.
Thanks so much. Hopefully this'll help:
function Visible() {
var Grps = app.activeDocument.layerSets; // loops through all groups
for(var i = 0; i < Grps.length; i++){
var tmp = app.activeDocument.layerSets[i].layers.length;
app.activeDocument.layerSets[i].visible=true;
var groupChildArr = app.activeDocument.layerSets[i].layers;
var randLays = Math.floor(Math.random() * tmp);
groupChildArr[randLays].visible = true;
Save();
}
Revert();
}
function Save() {
var outFolder = app.activeDocument; // psd name
var outPath = outFolder.path;
var fName = "PNG"; // define folder name
var f = new Folder(outPath + "/" + fName);
if ( ! f.exists ) {
f.create()
}
var saveFile = new File(outPath + "/" + fName +"/" + "Pattern_" + num + ".png");
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.interlaced = false;
app.activeDocument.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
}
// Original code - revert function does not work
// for some users
//function Revert(){
// var idslct = charIDToTypeID( "slct" );
// var desc300 = new ActionDescriptor();
// var idnull = charIDToTypeID( "null" );
// var ref163 = new ActionReference();
// var idSnpS = charIDToTypeID( "SnpS" );
// ref163.putName( idSnpS, "test.psd" );
// desc300.putReference( idnull, ref163 );
// executeAction( idslct, desc300, DialogModes.NO );
//}
function Revert(){
var idRvrt = charIDToTypeID( "Rvrt" );
executeAction( idRvrt, undefined, DialogModes.NO );
}
var count = prompt("How many patterns you want","");
for (var x=0 ; x<count;x++){
var num = x+1;
Visible();
}
As you say, you need to ignore the random layers. However, if you know the number of layers & groups it's quite straight forward:
show_layers("A", "1");
show_layers("B", "1");
function show_layers(g, n)
{
// g is the name of the group (layerset)
// n is the name of the layer (artlayer)
srcDoc.activeLayer = srcDoc.layerSets.getByName(g).artLayers.getByName(n);
srcDoc.activeLayer.visible = true;
}
So, assuming all layers are switched off, you can get the layers by name and then make them visible.
Switching off all the layers is a bit more involved. You have to loop over all groups and then loop over its sublayers. Working with groups is a bit of a learning curve.
function switch_off_all_layers(bool)
{
var numLayers = app.activeDocument.layers.length;
// want to hide the background as well?
// default: background = visible
if (bool == undefined) bool = false;
if (bool == false)
{
numLayers -=1; // -1 for background
}
for(var i = 0 ; i < numLayers; i++)
{
if (app.activeDocument.layers[i].typename == "LayerSet")
{
app.activeDocument.layers[i].visible = true;
var subDoc = app.activeDocument.layers[i];
var numOfSubLayers = subDoc.layers.length;
for (var j = numOfSubLayers -1; j >= 0; j--)
{
var tempSubLayer = subDoc.layers[j];
tempSubLayer.visible = false;
}
}
}
}
Further to my explanation, if you can't supply the group layers & names then you fill want to loop over all groups and all layers.
var groupLayers = [];
var artLayers = [];
var theLayers = collectAllLayers(app.activeDocument, 0);
alert("Group layers\n" + groupLayers);
alert("Art layers\n" + artLayers);
// function collect all layers
function collectAllLayers (theParent, level)
{
for (var m = theParent.layers.length - 1; m >= 0; m--)
{
var theLayer = theParent.layers[m];
// apply the function to layersets;
if (theLayer.typename == "ArtLayer")
{
if (theLayer.isBackgroundLayer == true)
{
// add background layer (if needed)
// artLayers.push(theLayer.name);
}
else
{
// find the art layers
artLayers.push(theLayer.name);
}
}
else
{
// find the group layers
groupLayers.push(theLayer.name);
collectAllLayers(theLayer, level + 1)
}
}
}

Script to copy Layer Names to text box in Photoshop

I'm trying to create a script out of 2 working scripts
Goal:
We need a script that will go through all the layers in the current document, find each layer marked in certain color (Red for example), copy the names of only the layers marked in red, then put all names in a text layer one after another (attached example image).
Resources:
I found 2 scripts that each do half of what we need, so how to we put them together?
1) "Select by red" goes through the document and finds how many layers marked in "red" are in the document:
#target photoshop
if (app.documents.length > 0) {
// 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;
var theOthers = 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) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var visible = layerDesc.getBoolean(stringIDToTypeID("visible"));
var theColor = layerDesc.getEnumerationValue(stringIDToTypeID("color"));
if (typeIDToStringID(theColor) == "red") {theLayers.push([theName, theID])}
else {theOthers.push([theName, theID])}
};
}
catch (e) {};
};
// if layers are red;
if (theLayers.length > 0) {alert ("there are " + theLayers.length + " Red layers")}
else {alert ("no red layers")}
};
2) "Text box from layer name" takes the name of the currently selected layer, and pastes it into a new text layer called "Comp".
if (app.documents.length > 0) mainScript();
function mainScript() {
try{
var myLayerName = activeDocument.activeLayer.name;
var myLayerText = activeDocument.artLayers.add();
myLayerText.name = "Comp";
myLayerText.kind = LayerKind.TEXT;
var textProperty = myLayerText.textItem;
textProperty.size = 10;
textProperty.font = "Arial";
myLayerText.textItem.contents = myLayerName;
}catch (errStr){
alert(errStr);
}
}
Plan:
From my understanding, we need to start with a loop that's as long as our document size i.e. total number of layers for (var i = 0; i < doc.layers.length; i++).
Then layer by layer the script will check for color ID if (typeIDToStringID(theColor) == "red") . When it finds layer marked in red, it copies the layer name - then either stores it in array (to output later all at once), or creates a new text box and pastes the layer name myLayerText.textItem.contents = myLayerName.
Then for each time it finds another layer marked in red , it copies the layer name, and pastes it in the same text box just a line above/below previous layer name.
Any help is much appreciated!
The only thing you needed to do was to join the names of your theLayers array using the line-break symbol \r:
if (app.documents.length > 0)
{
// 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)
{
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theColor = layerDesc.getEnumerationValue(stringIDToTypeID("color"));
if (typeIDToStringID(theColor) == "red")
{
theLayers.push(theName); // we only need names here
}
};
}
catch (e)
{};
};
// got our red layers in theLayers
var myLayerText = activeDocument.artLayers.add();
myLayerText.name = "Result";
myLayerText.kind = LayerKind.TEXT;
var textProperty = myLayerText.textItem;
textProperty.size = 10;
textProperty.font = "Arial";
myLayerText.textItem.contents = theLayers.join('\r'); // joining layers with a line-break: this is going to be textItem text
};
Here's the result:
I'd suggest you to take a course on JS on any learning website (code academy, etc): this won't take you more than an hour or two but you'll get the basic concepts: this will make your life much easier in terms of dealing with questions like this.

Problem with counter in script Photoshop CS6 ver 13 64 bit

I have script that
PSD (activeDocument) in "3.Working folder saves jpg in draft folders in directory "../UserNameJobName/4.WIP/"
The problem is that everything works fine until I want to to create third draft folder (draft003). Then it saved again activeDocument in the same jpg file in draft002, instead of creating new folder draft003 and saving there respectivly. It seams that var draftCounter can't be higher than 2 value. I'm not sure where is a bug. What I know in photoshop CC it works without any problems.
[Link to folder structure zip]
https://www.dropbox.com/s/kbalzsubs2477jy/191130_WARGAMES_LUKKAR.zip?dl=0
Main file directory pic
Draft directory pic
code
#target photoshop;
var wipCounter = 1;
var fileNotFound = true;
main();
function main(){
//Get file information
var doc = app.activeDocument;
var docName = doc.name;
var docPath = doc.path;
//Get the percentage to scale by
var scaleValue = prompt("Enter the WIP JPEG scale percentage", "100");
//Figure out the location of the WIP folder
var savePath = docPath.toString();
savePath = savePath.slice(0,-10);
savePath = savePath + "/4.WIP/";
var currDoc = docName.toString();
currDoc = currDoc.slice(0,-4);
//global variables are defined here
//Look at the WIP folder and run a search for anything containing the word "draft"
//Define the location of the WIP folder
var inWIPFolder = new Folder(savePath);
//Look in each folder and create an array containing all of the information
var fileList = inWIPFolder.getFiles();
// Look at each array and sort the info out
for(var a=0; a<fileList.length; a++) {
//Exclude anything that is not a folder
if(fileList[a] instanceof Folder) {
//convert each foldername to string for editing
var fileName = fileList[a].toString();
var draftSearch = fileName.search("draft");
if(draftSearch > -1) {
var draftCounter = fileName.slice(draftSearch);
if(fileNotFound == true) {
searchDraftFolder(draftCounter, savePath, currDoc);
}
}
}
}
//Formatting the numbers
if(wipCounter < 10){
wipCounter = "00" + wipCounter.toString();
}else if(wipCounter >= 10 && wipCounter < 100) {
wipCounter = "0" + wipCounter.toString();
}
//Define the path of the draft folders
savePath = Folder(savePath +"/draft" + wipCounter);
//Check to see if the draft folders exists. If not, make one
if(!savePath.exists){
savePath.create();
}
//Define the WIP file name with the incremental counter
var wipFileName =savePath + "/" + currDoc + "_WIP" + wipCounter + ".jpg";
//Resize the file
doc.selection.selectAll();
var blankLayer = doc.artLayers.add();
blankLayer.name = "blankLayer";
doc.selection.copy(true);
doc.layers.getByName("blankLayer").remove();
//Make new doc to paste into
app.preferences.rulerUnits = Units.PIXELS;
//arguments are: Width, Height, resolution, filename, colourspce, documentfill
app.documents.add(UnitValue(doc.width, "PX"), UnitValue(doc.height, "PX"), doc.resolution, wipFileName, NewDocumentMode.RGB, DocumentFill.TRANSPARENT,1);
app.activeDocument.paste();
app.activeDocument.resizeImage(UnitValue(scaleValue, "PERCENT"), null, null, ResampleMethod.BICUBICSHARPER);
//Save a RGBJpeg
jpegFileSaver(app.activeDocument, new File(wipFileName), 10);
//Close the new document down
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
//Deselect
doc.selection.deselect();
alert(currDoc + "WIP" + wipCounter + " saved.");
}
function searchDraftFolder(draftCounter, savePath, currDoc){
var fileSearch = -1;
//Define the location of each draft folder
var internalFolder = new Folder(savePath + "/" + draftCounter);
//Look in each folder and create an array containing all of the information
var internalFileList = internalFolder.getFiles();
// Look at each array and sort the info out
for(var a=0; a<internalFileList.length; a++) {
//Exclude anything that is not a file
if(internalFileList[a] instanceof File) {
// convert each filename to string for editing
var fileName = internalFileList[a].toString();
//Searching the current document name and replacing spaces with %20
var currDocStripped = currDoc.replace(/ /g, '%20');
//Checking files until a result greater than 0 appears
if(fileSearch === -1){
//search for the current file name
fileSearch = fileName.search(currDocStripped);
}
}
}
//if the filesearch does not return a result:
if(fileSearch === -1){
fileNotFound = true;
//if it does return a result:
} else {
//Slice the number off the draft folder
draftCounter = draftCounter.slice(-3);
//convert the string into an integer
draftCounter = parseInt(Number(draftCounter));
//increment the number up
wipCounter++;
//terminate the main loop
fileNotFound = false;
}
}
//A resuable JPEG save script
function jpegFileSaver(doc, saveFile, quality){
//define the save options
var saveOptions = new JPEGSaveOptions();
saveOptions.embedColorProfile = true;
saveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
saveOptions.quality = quality;
//save the files
doc.saveAs(saveFile, saveOptions, true);
}
Thanks in advance.
Additional credits to code author http://jamesmcdonald3d.com/
The issue is with searchDraftFolder(). When it finds the already saved Great Map_wip in draft001, fileNotFound is set to false and your loop on line 39 terminates. That's why wipCounter is stuck on 2: it increments ones and that's it.
Here I rewrote this function a little bit, trying to make it simpler: all necessary loops are inside the function and I think it's easier to understand.
p.s. there was also an issue at least on CC: app.documents.add() was showing interface. That's because you were using a full path as a new document name and you can't use \-symbol in it, so Photoshop was suggesting a different name and showing it. I added a separate variable for document name without a path (line 49) to use in .add()
main();
function main()
{
//Get file information
var doc = app.activeDocument;
var docName = doc.name;
var docPath = doc.path;
var wipCounter;
//Get the percentage to scale by
var scaleValue = prompt("Enter the WIP JPEG scale percentage", "100");
//Figure out the location of the WIP folder
var savePath = docPath.toString();
savePath = savePath.slice(0, -10);
savePath = savePath + "/4.WIP/";
var currDoc = docName.toString();
currDoc = currDoc.slice(0, -4);
//global variables are defined here
//Look at the WIP folder and run a search for anything containing the word "draft"
//Define the location of the WIP folder
var inWIPFolder = new Folder(savePath);
// !! modifications
wipCounter = searchDraftFolder(inWIPFolder, currDoc)
//Formatting the numbers
if (wipCounter < 10)
{
wipCounter = "00" + wipCounter.toString();
}
else if (wipCounter >= 10 && wipCounter < 100)
{
wipCounter = "0" + wipCounter.toString();
}
//Define the path of the draft folders
savePath = Folder(savePath + "/draft" + wipCounter);
//Check to see if the draft folders exists. If not, make one
if (!savePath.exists)
{
savePath.create();
}
//Define the WIP file name with the incremental counter
var wipFileName = currDoc + "_WIP" + wipCounter + ".jpg";
var wipFilePath = savePath + "/" + wipFileName;
//Resize the file
doc.selection.selectAll();
var blankLayer = doc.artLayers.add();
blankLayer.name = "blankLayer";
doc.selection.copy(true);
doc.layers.getByName("blankLayer").remove();
//Make new doc to paste into
app.preferences.rulerUnits = Units.PIXELS;
//arguments are: Width, Height, resolution, filename, colourspce, documentfill
app.documents.add(UnitValue(doc.width, "PX"), UnitValue(doc.height, "PX"), doc.resolution, wipFileName, NewDocumentMode.RGB, DocumentFill.TRANSPARENT, 1);
app.activeDocument.paste();
app.activeDocument.resizeImage(UnitValue(scaleValue, "PERCENT"), null, null, ResampleMethod.BICUBICSHARPER);
//Save a RGBJpeg
jpegFileSaver(app.activeDocument, new File(wipFilePath), 10);
//Close the new document down
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
//Deselect
doc.selection.deselect();
alert(currDoc + "_WIP" + wipCounter + " saved.");
}
// p is WIP path
// n is a name of the active doc without extension
function searchDraftFolder(p, n)
{
var fileList = p.getFiles(); // folders in wip folder
var counter = 1;
var drafts, fileName, i, k;
// for all the files found..
for (i = 0; i < fileList.length; i++)
{
//if a folder is found and its name has 'draft' in it
if (fileList[i] instanceof Folder && fileList[i].name.indexOf('draft') != -1)
{
//get files inside this draft folder
drafts = fileList[i].getFiles();
// for all files inside
for (k = 0; k < drafts.length; k++)
{
//'.name' gives us a URI-name, so replacing %20 with ' '. Probably should add more special symbols here if you use them
fileName = drafts[k].name.replace(/%20/g, ' ');
// if there's a file that starts with active doc name counter is incremented
if (fileName.indexOf(n) != -1)
{
counter++
}
}
}
}
return counter;
}
//A resuable JPEG save script
function jpegFileSaver(doc, saveFile, quality)
{
//define the save options
var saveOptions = new JPEGSaveOptions();
saveOptions.embedColorProfile = true;
saveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
saveOptions.quality = quality;
//save the files
doc.saveAs(saveFile, saveOptions, true);
}

Illustrator edit link filepath via javascript

Edit, original copy marked below:
I've managed to create a semi-functioning script. I realized, to much frustration, that the syntax errors were the '' marks of text edit. It semi-works in that it will relink some files and usually ends in an error, "placedArt does not exist" after a few loops through. I feel like the XML finds more "stRef:filePath"s than exist in the file. Example: file with two images finds a file path for each twice. Any tips?
var counter = 0;
var doc = app.activeDocument;
var x = new XML(doc.XMPString);
var m = x.xpath('//stRef:filePath');
if (m !== '') {
for (var i=0, len=m.length(); i < len ; i++) {
var link_path = m[i];
if ( File(link_path).exists === false ) {
link_path = link_path.split('/Projects').join('/Volumes/Projects')
link_path = link_path.split('O:').join('/Volumes/Projects');
link_path = link_path.split('P:').join('/Volumes/Projects');
link_path = link_path.split('\\SERVER').join('Volumes');
link_path = link_path.split("\\").join("/");
if ( File(link_path).exists === true ){
placedArt = app.activeDocument.placedItems[i];
placedArt.relink(new File (link_path));}
alert(File(link_path).fsName);
counter++;
}
};}
if ( counter > 0 ) {
alert("Attempted to relink " + counter + " links");}
else {
alert("No links replaced");}
orginal post
Okay, I'm very inexperienced XML, but I'm trying to edit parts of a link filepath in Adobe Illustrator using a script. Below is what I have so far:
var doc = app.activeDocument;
var x = new XML(doc.XMPString);
var m = x.xpath('//stRef:filePath');
if (m !== '') {
for (var i=0, len=m.length(); i < len ; i++) {
var link_path = m[i];
if ( File(link_path).exists === false ) {
var link_path2 = String(link_path)
link_path2 = link_path2.replace(‘%5C’, ‘/‘)
alert(File(link_path2));
}
};
}
This returns an error:8 syntax error. on the line link_path2 = link_path2.replace(‘%5C’, ‘/‘). So does any attempt to redefine link_path2, such as
link_path2 = 'cow';
I currently am changing, the link_path to link_path2 to convert it into a string, assuming that the fact that the var link_path returns typeof XML is an issue for redefining, or editing the value.
The end goal is to edit the filepath from a windows server path to a macOS filepath, to script fix broken links. I've searched for hours on this, and keep hitting dead ends.
I don't if XML/XMP data is the best way to do this. We had a similar issue with linked files at our firm in swapping linked images from one server to another. This opens each AI file, looks for placed items and relinks the images to the new path. I have only used this on a PC, so I am not sure if this will work without the Mac path being available, but figured you could try.
Are you always using the same two file paths, or would you like to select them uniquely each time? If you have a two set server paths that you just want to swap, you can use something like this (I have a similar one where you pick the initial location and the destination for the files):
// Select the source folder.
var destFolder, sourceFolder, files, fileType, doc, targetFile, pngExportOpts;
if (app.documents.length == 0 ){
sourceFolder = Folder.selectDialog( 'Select the folder with Illustrator files you want to relink', '~' );
// If a valid folder is selected
if ( sourceFolder != null ){
files = new Array();
// Get all files matching the filetype
files = sourceFolder.getFiles("*.ai");
if ( files.length > 0 ) {
for ( i = 0; i < files.length; i++ ){
doc = app.open(files[i]); // returns the document object
changeExt();
if (app.documents.length != 0){
doc.save();
doc.close();
}
}
}
}
}
else{
changeExt();
}
function changeExt(){
var i;
var doc = app.activeDocument;
if (doc.placedItems.length != 0){
for (i=0;i<doc.placedItems.length;i++) {
//gets the full path of the image
var imageName = doc.placedItems[i].file.fsName;
var imageURL = doc.placedItems[i].uRL;
var imagePath;
var newPath;
var i, in_file, out_file;
//if the scan is placed for the first time it uses the drive letter
//this swaps the drive letters to the server names so they can be replaced properly
if (imageName.match(/O:/)){
imagePath = imageName.replace("O:", "\\\\Serv01\\Projects1")
imageName = imagePath;
}
else (imageName.match(/P:/)){
imagePath = imageName.replace("P:", "\\\\Serv02\\Projects2")
imageName = imagePath;
}
if (imageName.match(/Serv02/)){
imagePath = imageName.replace("Serv02", "Serv01")
activePath = imagePath.replace("Projects2", "Projects1");
newPath = File(activePath);
if (newPath.exists){//copies scan over if it doesn't exist.
doc.placedItems[i].file = newPath;
}
else{
in_file = doc.placedItems[i].file;
out_file = File(activePath);
in_file.copy(out_file);
doc.placedItems[i].file = out_file;
}
}
else{
imagePath = imageName.replace("Serv01", "Serv02")
activePath = imagePath.replace("Projects1", "Projects2");
newPath = File(activePath);
if (newPath.exists){//copies scan over if it doesn't exist.
doc.placedItems[i].file = newPath;
}
else{
in_file = doc.placedItems[i].file;
out_file = File(activePath);
in_file.copy(out_file);
doc.placedItems[i].file = out_file;
}
}
}
}
else{
doc.close(SaveOptions.DONOTSAVECHANGES);
}
}
If that is the case and the starting point and ending point are different, we used a script like this for transferring files with links from one location to another, and allows you to pick the starting location and the destination. Again, can't promise it will work for a Mac, but maybe some of this can help you. In our setup we store graphics in one folder and scans in another, so you may need to adjust the file paths if you keep it all in one folder. So we have a root folder and within that folder a "Graphics" folder and a "Scans" folder.
This also has a try/catch for files missing scans and will spit them out in an error list at the end so you know which files have missing images.
Hope some of this helps!
// Select the source folder.
sourceFolder = Folder.selectDialog( 'Select the GRAPHICS folder with Illustrator files you want to move', '~' );
var export_folderSelect = Folder.selectDialog("Select the root folder (NOT GRAPHICS) to move the Illustrator files to");
var export_folder = export_folderSelect + "/Graphics";
var errorList = [];
var destFolder, sourceFolder, files, fileType, doc, targetFile, pngExportOpts;
var save_options = new IllustratorSaveOptions();
save_options.embedICCProfile = true;
save_options.pdfCompatible = true;
// If a valid folder is selected
if ( sourceFolder != null && export_folderSelect != null){
files = new Array();
// Get all files matching the pattern
files = sourceFolder.getFiles("*.ai");
if ( files.length > 0 ){
// Get the destination to save the files
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
for ( i = 0; i < files.length; i++ ){
//try to open the file and move it over, otherwise note it in the error list.
var docOpened = true;
try{
doc = app.open(files[i]); // returns the document object
}
catch(e){
errorList.push(files[i].name + " !!!CORRUPT - NOT COPIED!!!");
docOpened = false;
}
try{
moveFile();
}
catch(e){
if (docOpened == true){
doc.close();
}
}
}
}
if (errorList.length > 0){
alert("COPY THIS LIST TO WORD: " + errorList);
}
else{
alert("Woo hoo! No errors!");
}
app.userInteractionLevel = UserInteractionLevel.DISPLAYALERTS;
}
function moveFile(){
const FILE_SUFFIX = "";
const ASSET_SUFFIX = "";
var doc = app.activeDocument;
if (!doc.saved) doc.save();
var original_file = doc.fullName;
var extension = "";
var arr = doc.name.split(".");
if (arr.length>1) extension = "." + arr.pop();
var filename = arr.join(".");
var assets_folder = new Folder(export_folderSelect + "/Scans");
if (assets_folder.exists || assets_folder.create()) {
var f, in_file, out_file;
for (f=0;f<doc.placedItems.length;f++) {
try{
in_file = doc.placedItems[f].file;
out_file = File(assets_folder+"/"+in_file.name);
in_file.copy(out_file);
doc.placedItems[f].file = out_file;
}
catch(e){
errorList.push(files[i].name + " SCAN MISSING");
}
}
for (g=0;g<doc.rasterItems.length;g++) {
if (doc.rasterItems[g].embedded == false) {
try{
in_file = doc.rasterItems[g].file;
out_file = File(assets_folder+"/"+in_file.name);
in_file.copy(out_file);
doc.rasterItems[g].file = out_file;
}
catch(e){
errorList.push(files[i].name + " SCAN MISSING");
}
}
}
// save as new file
packaged_file = File(export_folder + "/" + filename + FILE_SUFFIX + extension);
doc.saveAs(packaged_file, save_options);
doc.close();
// re-open the original file
//app.open(File(original_file));
} else {
alert("Unable to create the assets folder.");
}
}
This doesn't answer your question directly but it may solve your problem or be helpful to others.
There is a totally different solution.
Illustrator always looks for missing artwork in a "Links" folder in the same folder as the document.
If you regularly need to move projects around, just keep the artwork in a "Links" folder with the AI file and you can open the AI file anywhere without breaking the links.
Why are using XMP Data for this? You can get all placedItems placed in the document and you can check whether links exist or not and if not exists you relink them to the new file. Here is the small script for this
var activeDocument = app.activeDocument;
var links = activeDocument.placedItems;
for (var i = 0; i < links.length; i++) {
try {
var file = links[i].file;
if (file && file.exists) {
// Do anything as oer your requirement if link exists.
}
} catch (e) {
// if link missing relink with new_File
links[i].relink(File(new_File));
}
}
When you relink links for missing links, it will automatically update in document XMP.

Categories

Resources