Replacing smart objects in bulk with Photoshop - 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.

Related

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;
}

Saving multiple files with group name Photoshop

My PSD structure
Group myname
layer -> Visible
Layer -> Hidden
Group 2randomname
layer -> Visible
Layer -> Hidden
and goes on ...
I am trying to save export groups as png, it works file when using file -> Exports -> Layers to File but my problem is its not using the group name, I want to include group name for each file, this is working when selecting all the groups and right click -> export as then selecting PNG the layers have the group names but the problem is its automatically trimming the canvas and there is no option to avoid trimming.
Is there any code or script that can do this ? any directions or help appreciated.
I guess something like this?
Result:
function main()
{
var topLayers = activeDocument.layers, // will export all top level layers (groups, backgorund layer, etc)
exportFolder = Folder.selectDialog();
if (exportFolder == null) return false;;
for (var i = 0; i < topLayers.length; i++)
{
activeDocument.activeLayer = topLayers[i];
toggleVisibility();
savePng24(topLayers[i].name);
toggleVisibility();
}
function savePng24(fileName)
{
var pngOpts = new ExportOptionsSaveForWeb;
pngOpts.format = SaveDocumentType.PNG
pngOpts.PNG8 = false;
pngOpts.transparency = true;
activeDocument.exportDocument(new File(exportFolder + "/" + fileName + ".png"), ExportType.SAVEFORWEB, pngOpts);
}; // end of savePng24()
function toggleVisibility()
{
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt'));
list.putReference(ref);
desc.putList(cTID('null'), list);
desc.putBoolean(cTID('TglO'), true);
executeAction(cTID('Shw '), desc, DialogModes.NO);
}; // end of toggleVisibility()
function cTID(s)
{
return app.charIDToTypeID(s);
};
function sTID(s)
{
return app.stringIDToTypeID(s);
};
}
app.activeDocument.suspendHistory("temp", "main()");

Extendscript with Photoshop: Importing an image

I'm trying to select some image files via a prompt, then add those files to the active document. Here's what I have so far:
#target photoshop
doc = app.activeDocument;
// choose image files
var files = File.openDialog(undefined,undefined,true);
// for each image, add to new layer and insert into doc
for (var file in files) {
var layer = doc.artLayers.add();
layer.image = file; // this doesn't work.
}
What's layer.image? ArtLayer doesn't have this property. Maybe placing will work better in your case:
doc = app.activeDocument;
// choose image files
var files = File.openDialog(undefined, undefined, true);
// for each image, add to new layer and insert into doc
for (var i = 0; i < files.length; i++)
{
var layer = placeImage(files[i]);
}
function placeImage(imageFile)
{
var desc554 = new ActionDescriptor();
desc554.putPath(cTID('null'), imageFile);
desc554.putEnumerated(cTID('FTcs'), cTID('QCSt'), cTID('Qcsa'));
var desc555 = new ActionDescriptor();
desc555.putUnitDouble(cTID('Hrzn'), cTID('#Pxl'), 0.000000);
desc555.putUnitDouble(cTID('Vrtc'), cTID('#Pxl'), 0.000000);
desc554.putObject(cTID('Ofst'), cTID('Ofst'), desc555);
executeAction(cTID('Plc '), desc554, DialogModes.NO);
return activeDocument.activeLayer
};
function cTID(s)
{
return app.charIDToTypeID(s);
};
function sTID(s)
{
return app.stringIDToTypeID(s);
};
Also Photoshop doesn't like when for...in loops are used on Array (sometimes it works, sometimes it doesn't: in case of File object it doesn't work)

How to write a script that does "Save for web" for mutiple resolutions in Adobe Illustrator?

It's tedious to have to click to "Save for web" and change the resolution each time I want to create the image as a different resolution. Is there a way to write a script to automatically achieve this, for multiple resolutions as one?
For that i myself use this function
function saveDocumentAsPng(d, width, height) {
var fileName = d.fullName.toString();
if(fileName.lastIndexOf(".") >= 0) { fileName = fileName.substr(0, fileName.lastIndexOf("."));}
fileName += "_wxh.png".replace("w", width).replace("h", height);
var exportOptions = new ExportOptionsPNG24();
exportOptions.horizontalScale = exportOptions.verticalScale = 100 * Math.max(width/d.width, height/d.height);
var file = new File(fileName);
app.activeDocument = d;
d.exportFile(file, ExportType.PNG24, exportOptions);
}
Note that it names a resulting png's with “_[width]x[height]” suffix.
I wrote my function based on a sample from adobe's javascript reference http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/illustrator/scripting/illustrator_scripting_reference_javascript_cs5.pdf (page 59).
This is an old post, but it inspired me to create a different version for my Android project that I'd like to share.
Just create a 144x144 pixels document and run this:
var doc = app.activeDocument;
// This is the scale factor that you can see in "Percent" textbox of
// the "Save for Web..." dialog box while changing the size of the image
var scale = [100, 66.67, 50, 33.33]
// This is the image size for the PNGs files names
var size = [144, 96, 72, 48]
for(var i = 0; i<4; i++)
{
var fileName = doc.fullName.toString();
if (fileName.lastIndexOf(".") >= 0) {
// Get the file name without the extension
fileName = fileName.substr(0, fileName.lastIndexOf("."));
}
// Name each file with yours size to avoid overwrite
fileName += "_wxh.png".replace("w", size[i]).replace("h", size[i]);
var exportOptions = new ExportOptionsPNG24();
exportOptions.horizontalScale = exportOptions.verticalScale = scale[i];
exportOptions.artBoardClipping = true;
var file = new File(fileName);
doc.exportFile(file, ExportType.PNG24, exportOptions);
}
Window.alert ("Successfully exported!", "Success");
Thank you!
Here is the script that will export all files of the selected folder into PNG. You can specify resolution in this code and image quality will be good. In this code by default resolution is 600
var folder = Folder.selectDialog();
if (folder) {
var files = folder.getFiles("*.ai");
for (var i = 0; i < files.length; i++) {
var currentFile = files[i];
app.open(currentFile);
var activeDocument = app.activeDocument;
var pngFolder = Folder(currentFile.path + "/PNG");
if (!pngFolder.exists)
pngFolder.create();
var fileName = activeDocument.name.split('.')[0] + ".png";
var destinationFile = File(pngFolder + "/" + fileName);
// Export Artboard where you can set resolution for an image. Set to 600 by default in code.
var opts = new ImageCaptureOptions();
opts.resolution = 600;
opts.antiAliasing = true;
opts.transparency = true;
try {
activeDocument.imageCapture(new File(destinationFile), activeDocument.geometricBounds, opts);
} catch (e) {
}
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
currentFile = null;
}
}
If you want to export in jpg format, just change extension of the file in the code in the following line
var fileName = activeDocument.name.split('.')[0] + ".png";
change to
var fileName = activeDocument.name.split('.')[0] + ".jpg"; // For jpg
Also, you can change the name of the file and where the exported file will be stored according to your requirement.
Hope my answer will help you.