Illustrator - Select layer by explicit name only - adobe-illustrator

This script selects every layer that contains the word "shadow" but it also picks up any layer that has that word.
How do I explicitly only select "shadow" and "shadow-7" for example so it ignores "shadow-4", "shadow-5" etc?
var aDoc = app.activeDocument;
var pI = aDoc.pageItems;
aDoc.selection = null;
for (i=pI.length-1; i>=0; i--) {
if (pI[i].name.match(/shadow/i) != null) {
pI[i].selected = true;
}
}

You need to change your regex /shadow/i to /^shadow$/i

Related

How to parse subfolders for find specific files?

I Would like to create a script for photoshop who allow me to search some files with a specific name (for example : 300x250_F1.jpg, 300x250_F2.jpg, 300x600_F1.jpg, etc... ) in differents subfolders (all in the same parent folder) and after load them in my active document. The problem is names of subfolders will be everytime differents.
I definitely need some help :)
i found a code which almost do what i want (thank you).
I'm almost good but i have a problem: if the variable "mask" have only one value, it works. But with few values, it doesn't work anymore.
I think it's because i made an array with the mask variable and i have to update the script...
var topFolder = Folder.selectDialog("");
//var topFolder = new Folder('~/Desktop/PS_TEST');
var fileandfolderAr = scanSubFolders(topFolder, /\.(jpg)$/i);
//var fileandfolderAr = scanSubFolders(topFolder, /\.(jpg|tif|psd|bmp|gif|png|)$/i);
var fileList = fileandfolderAr[0];
var nom = decodeURI(fileList);
//all file paths found and amount of files found
//alert("fileList: " + nom + "\n\nFile Amount: " + fileList.length);
//alert(allFiles);
for (var a = 0; a < fileList.length; a++) {
var docRef = open(fileList[a]);
//do things here
}
function scanSubFolders(tFolder, mask) { // folder object, RegExp or string
var sFolders = [];
var allFiles = [];
var mask = ["300x250_F1", "300x250_F2"];
sFolders[0] = tFolder;
for (var j = 0; j < sFolders.length; j++) { // loop through folders
var procFiles = sFolders[j].getFiles();
for (var i = 0; i < procFiles.length; i++) { // loop through this folder contents
if (procFiles[i] instanceof File) {
if (mask == undefined) {
allFiles.push(procFiles); // if no search mask collect all files
}
if (procFiles[i].fullName.search(mask) != -1) {
allFiles.push(procFiles[i]); // otherwise only those that match mask
}
}
else if (procFiles[i] instanceof Folder) {
sFolders.push(procFiles[i]); // store the subfolder
scanSubFolders(procFiles[i], mask); // search the subfolder
}
}
}
return [allFiles, sFolders];
}
There are several ways you can accomplish this without reassigning mask within the scanSubFolders function.
Solution 1: use a regex
The function is already set up to accept a regex or string as a mask. You just need to use one that would match the pattern of the files you're targeting.
var fileandfolderAr = scanSubFolders(topFolder, /300x250_F(1|2)/gi);
Solution 2: call the function within a loop
If regex isn't your thing, you could still utilize an array of strings, but do it outside the function. Loop the array of masks and call the function with each one, then execute your primary logic on the results of each call.
var topFolder = Folder.selectDialog("");
var myMasks = ["300x250_F1", "300x250_F2"];
for (var index in myMasks) {
var mask = myMasks[index]
var fileandfolderAr = scanSubFolders(topFolder, mask);
var fileList = fileandfolderAr[0];
for (var a = 0; a < fileList.length; a++) {
var docRef = open(fileList[a]);
//do things here
}
}
Don't forget to remove var mask = ["300x250_F1", "300x250_F2"]; from within the scanSubFolders function or else these won't work.

Photoshop Scripting: Relink Smart Object

I'm working on a script that should go through a photoshop document and relink all visible linked objects to a new specified file. I've gotten the loop working so that it cycles through every layer and collects only the visible layers, but for the life of me I can't find if there's a method available to relink a smart object. The closest I've found is this script:
https://gist.github.com/laryn/0a1f6bf0dab5b713395a835f9bfa805c
but when it gets to desc3.putPath(idnull, new File(newFile));, it spits out an error indicating that the functionality may not be present in the current Photoshop version. The script itself is 4 years old so it may be out of date.
Any help would be appreciated!
MY script as it stands is below:
// SELECT FILE //
var files = File.openDialog("Please select new linked file");
var selectedFile = files[0];
// GET ALL LAYERS //
var doc = app.activeDocument;
var allLayers = [];
var allLayers = collectAllLayers(doc, allLayers);
function collectAllLayers (doc, allLayers)
{
for (var m = 0; m < doc.layers.length; m++)
{
var theLayer = doc.layers[m];
if (theLayer.typename === "ArtLayer")
{
allLayers.push(theLayer);
}
else
{
collectAllLayers(theLayer, allLayers);
}
}
return allLayers;
}
// GET VISIBLE LAYERS //
var visibleLayers = [];
for (i = 0; i < allLayers.length; i++)
{
var layer = allLayers[i];
if (layer.visible && layer.kind == LayerKind.SMARTOBJECT)
{
visibleLayers.push(layer);
}
}
// REPLACE LAYERS
for (i = 0; i < visibleLayers.length; i++)
{
var layer = visibleLayers[i];
//--> REPLACE THE FILE HERE
}
Note: I am aware that this script currently may be error-prone if you don't know exactly how it works; I'm not intending to publish it at this time so I'm not super concerned with that at the moment. Mostly I just need the core functionality to work.
I used an AM function for getting visible smart objects — it works much faster. But if you want you can use yours. The important bit is relinkSO(path);: it'll also work in your script (just don't forget to select a layer: activeDocument.activeLayer = visibleLayers[i];)
Note that it works similar to Photoshop Relink to File command — if used on one instance of Smart Object all the instances are going to be relinked. If you want to relink only specific layers you'll have to break instancing first (probably using the New Smart Object via Copy command)
function main() {
var myFile = Folder.myDocuments.openDlg('Load file', undefined, false);
if (myFile == null) return false;
// gets IDs of all smart objects
var lyrs = getLyrs();
for (var i = 0; i < lyrs.length; i++) {
// for each SO id...
// select it
selectById(lyrs[i]);
// relink SO to file
relinkSO(myFile);
// embed linked if you want
embedLinked()
}
function getLyrs() {
var ids = [];
var layers, desc, vis, type, id;
try
{
activeDocument.backgroundLayer;
layers = 0;
}
catch (e)
{
layers = 1;
}
while (true)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), layers);
try
{
desc = executeActionGet(ref);
}
catch (err)
{
break;
}
vis = desc.getBoolean(charIDToTypeID("Vsbl"));
type = desc.getInteger(stringIDToTypeID("layerKind"));
id = desc.getInteger(stringIDToTypeID("layerID"));
if (type == 5 && vis) ids.push(id);
layers++;
}
return ids;
} // end of getLyrs()
function selectById(id) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), id);
desc.putReference(charIDToTypeID('null'), ref);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
} // end of selectById()
function relinkSO(path) {
var desc = new ActionDescriptor();
desc.putPath( charIDToTypeID('null'), new File( path ) );
executeAction( stringIDToTypeID('placedLayerRelinkToFile'), desc, DialogModes.NO );
} // end of relinkSO()
function embedLinked() {
executeAction( stringIDToTypeID('placedLayerConvertToEmbedded'), undefined, DialogModes.NO );
} // end of embedLinked()
}
app.activeDocument.suspendHistory("relink SOs", "main()");

Run last Photoshop script (again)

This seems like a trivial issue but I'm not sure Photoshop supports this type of functionality:
Is it possible to implement use last script functionality?
That is without having to add a function on each and every script that writes it's filename to a text file.
Well... It's a bit klunky, but I suppose you could read in the scriptlistener in reverse order and find the first mention of a script file:
// Switch off any dialog boxes
displayDialogs = DialogModes.NO; // OFF
var scripts_folder = "D:\\PS_scripts";
var js = "C:\\Users\\GhoulFool\\Desktop\\ScriptingListenerJS.log";
var jsLog = read_file(js);
var lastScript = process_file(jsLog);
// use function to call scripts
callScript(lastScript)
// Set Display Dialogs back to normal
displayDialogs = DialogModes.ALL; // NORMAL
function callScript (ascript)
{
eval('//#include "' + ascript + '";\r');
}
function process_file(afile)
{
var needle = ".jsx";
var msg = "";
// Let's do this backwards
for (var i = afile.length-1; i>=0; i--)
{
var str = afile[i];
if(str.indexOf(needle) > 0)
{
var regEx = str.replace(/(.+new\sFile\(\s")(.+\.jsx)(.+)/gim, "$2");
if (regEx != null)
{
return regEx;
}
}
}
}
function read_file(inFile)
{
var theFile = new File(inFile);
//read in file
var lines = new Array();
var l = 0;
var txtFile = new File(theFile);
txtFile.open('r');
var str = "";
while(!txtFile.eof)
{
var line = txtFile.readln();
if (line != null && line.length >0)
{
lines[l++] = line;
}
}
txtFile.close();
return lines;
}

Replacing smart objects in bulk with Photoshop

Just facing this issue: I have a mockup in Photoshop with two smart-objects: Rectangle 14.psb and Place your logo.psb
I have 100+ images in png that should be applied to create mockups.
For this reason, I would like your help to create a script that:
Let me select the png file that I would like to use
Open the smart objects (Rectangle 14.psb and Place your logo.psb)
Re-Link the same png to the layers "place your logo" of both the smart objects.
Finally, the script should save the file as png with the same file name of the selected png file adding just _new after its name.
So far I have tried this code without any luck:
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theName = myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var theLayer = myDocument.activeLayer;
// PSD Options;
psdOpts = new PhotoshopSaveOptions();
psdOpts.embedColorProfile = true;
psdOpts.alphaChannels = true;
psdOpts.layers = true;
psdOpts.spotColors = true;
// Check if layer is SmartObject;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {
alert("selected layer is not a smart object")
} else {
// Select Files;
if ($.os.search(/windows/i) != -1) {
var theFiles = File.openDialog("please select files",
"*.psd;*.tif;*.jpg;*.png", true)
} else {
var theFiles = File.openDialog("please select files", getFiles,
true)
};
if (theFiles) {
for (var m = 0; m < theFiles.length; m++) {
// Replace SmartObject
theLayer = replaceContents(theFiles[m], theLayer);
var theNewName = theFiles[m].name.match(/(.*)\.[^\.]+$/)[1];
// Save JPG
myDocument.saveAs((new File(thePath + "/" + theName + "_" +
theNewName + ".psd")), psdOpts, true);
}
}
}
};
// Get PSDs, TIFs and JPGs from files
function getFiles(theFile) {
if (theFile.name.match(/\.(psd|png|jpg)$/i) != null ||
theFile.constructor.name == "Folder") {
return true
};
};
// Replace SmartObject Contents
function replaceContents(newFile, theSO) {
app.activeDocument.activeLayer = theSO;
// =======================================================
var idplacedLayerReplaceContents =
stringIDToTypeID("placedLayerReplaceContents");
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc3.putPath(idnull, new File(newFile));
var idPgNm = charIDToTypeID("PgNm");
desc3.putInteger(idPgNm, 1);
executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);
return app.activeDocument.activeLayer
};
The above code substitute the smart object but I would like just to re-link the layer withing the smartobject to a new image and save the file. Any help would be much appreciated!
Are you familiar with Scriptlistener? You can use it to get all the functions you need and then modify the output to run within your loop of 100 pngs, it should be straightforward.

Make OCG layer visible when field isn't empty?

Is it possible to check when a field is not empty and if not, make an ocg layer visible?
var ocg = FindOCG("Item 1 Arrow");
if (+event.value === '') {
ocg.state = !ocg.state;
} else {
ocg.state = !ocg.state;
}
Something like this (which doesn't work)!
Put this in the custom format script of the field in question. Replace "Square" with the name of your layer. You can see an example of it working here.
function getOCGByName(cName, nPage) {
var ocg = null;
var ocgArray = this.getOCGs(nPage);
for (var i=0; i < ocgArray.length; i++) {
if (ocgArray[i].name == cName) {
ocg = ocgArray[i];
}
}
return ocg;
}
var field = event.target;
var ocg = getOCGByName("Square", this.pageNum);
if (field.value.length > 0) {
ocg.state = true;
}
else {
ocg.state = false;
}
Note: This will only work in Adobe Acrobat and Reader and a few other viewers that are JavaScript capable.