Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save UserUnknownFactor/296edae2a3b3cad3730699ed6a230a4d to your computer and use it in GitHub Desktop.
Save UserUnknownFactor/296edae2a3b3cad3730699ed6a230a4d to your computer and use it in GitHub Desktop.
Photoshop JS script to duplicate a group of layers to all files
// This script duplicates the current selected text layer to every open document
// and replaces text in the each of those layers to the one specified in arrow
// separated CSV file in format: `{filename without extension}→Added text`
// it can automatically save modified files as PSDs and additionally
// hides the only image layer in each document if present.
if (app.documents.length > 0) {
var csvFile = File.openDialog("Select CSV file", "Arrow Separated Values:*.csv", false);
if (csvFile) {
var csvData = readCSV(csvFile);
if (csvData) {
var saveAsPSD = confirm("Would you like to save the other files as PSDs?");
duplicateAndReplaceText(csvData, saveAsPSD, true);
} else {
alert("Could not read or parse the CSV file.");
}
}
} else {
alert("No documents are open.");
}
/*
function cTID(s) { return app.charIDToTypeID(s); };
function sTID(s) { return app.stringIDToTypeID(s); };
function exportPngManual(fileName, optionsNative) {
// Metadata:
// "MDAl" All metadata; "MDNn" No metadata;
// "MDCp" Copyright; "MDCC" Copyright and contact;
// "MDAx" All except camera info;
// Profile:
// "CHsR" sRGB Profile; "CHDc" Use document profile
metadata = "MDNn";//!!optionsNative.metadata ? optionsNative.metadata : "MDNn";
progressive = !!optionsNative.progressive ? optionsNative.progressive : 1;
var options = new ActionDescriptor();
options.putEnumerated(cTID("Op "), cTID("SWOp"), cTID("OpSa"));
options.putEnumerated(cTID("Fmt "), cTID("IRFm"), cTID(!!optionsNative.PNG8 ? "PNG8" : "PN24"));
options.putBoolean(cTID("Intr"), optionsNative.interlaced);
options.putInteger(cTID("Qlty"), optionsNative.quality);
options.putBoolean(cTID("Trns"), optionsNative.transparency);
options.putInteger(cTID("QChS"), 0);
options.putInteger(cTID("QCUI"), 0);
options.putBoolean(cTID("QChT"), false);
options.putBoolean(cTID("QChV"), false);
options.putBoolean(cTID("Optm"), optionsNative.optimized);
options.putInteger(cTID("Pass"), progressive); // 1 = optimized; 3 = progressive
options.putDouble(cTID("blur"), 0.000000);
options.putBoolean(cTID("EICC"), !!optionsNative.includeProfile); //Embed Color Profile, Bool
options.putBoolean(cTID("Mtt "), !!optionsNative.matteColor);
options.putInteger(cTID("MttR"), optionsNative.matteColor.red);
options.putInteger(cTID("MttG"), optionsNative.matteColor.green);
options.putInteger(cTID("MttB"), optionsNative.matteColor.blue);
options.putBoolean(cTID("SHTM"), false);
options.putBoolean(cTID("SImg"), true);
options.putEnumerated(cTID("SWch"), cTID("STch"), cTID(!!optionsNative.includeProfile ? "CHDc" : "CHsR"));
options.putEnumerated(cTID("SWmd"), cTID("STmd"), cTID(metadata));
options.putBoolean(cTID("SSSO"), false);
options.putList(cTID("SSLt"), new ActionList());
options.putBoolean(cTID("DIDr"), false);
options.putPath(cTID("In "), new File(fileName));
var save_for_web_dlg = new ActionDescriptor();
save_for_web_dlg.putObject(cTID('Usng'), sTID('SaveForWeb'), options);
executeAction(cTID('Expr'), save_for_web_dlg, DialogModes.NO);
};
*/
function saveAsPSDFile(doc, openNewTab, exportFolderPath) {
var filename = doc.name.replace(/\.[^\/.]+$/, "");
var psdFile = new File(doc.path + "/" + filename + ".psd");
var options = new PhotoshopSaveOptions();
options.layers = true;
options.alphaChannels = true;
options.annotations = true;
options.embedColorProfile = true;
options.spotColors = true;
doc.saveAs(psdFile, options, openNewTab, Extension.LOWERCASE);
// Replace the current document with the new PSD document
if (openNewTab) {
doc.close(SaveOptions.DONOTSAVECHANGES);
app.open(psdFile);
}
if (exportFolderPath) {
// Create the export folder relative to the PSD file's directory
var exportFolder = new Folder(psdFile.path + "/" + exportFolderPath);
if (!exportFolder.exists)
exportFolder.create();
// Export the PSD file as PNG to the specified directory
var pngFile = new File(psdFile.path + "/" + exportFolderPath + "/" + filename + ".png");
var pngOptions = new ExportOptionsSaveForWeb();
pngOptions.format = SaveDocumentType.PNG;
pngOptions.PNG8 = false; // export as 8-bit PNG
pngOptions.quality = 100;
pngOptions.interlaced = false;
pngOptions.optimized = true; // optimize for web use
pngOptions.dither = Dither.NONE; // not use dithering
pngOptions.transparencyDither = Dither.NONE; // not use transparency dithering
//pngOptions.colorReduction = ColorReductionType.SELECTIVE; // use selective color reduction
//pngOptions.colors = 256; // use 256 colors
pngOptions.includeProfile = false; // include color profile
pngOptions.matteColor = new RGBColor(); //255, 255, 255); // White matte color
//pngOptions.metadata = null;
//pngOptions.progressive = null;
//exportPngManual(pngFile, pngOptions);
activeDocument.exportDocument(pngFile, ExportType.SAVEFORWEB, pngOptions);
//activeDocument.save();
}
}
function hideSingleImageLayer(doc) {
var imageLayerCount = 0;
var imageLayer;
// Count image layers and identify the single image layer
for (var i = 0; i < doc.layers.length; i++) {
var layer = doc.layers[i];
if (layer.kind == LayerKind.NORMAL) {
imageLayerCount++;
imageLayer = layer;
}
}
// If there's only one image layer, hide it
if (imageLayerCount == 1) {
imageLayer.visible = false;
}
}
function duplicateAndReplaceText(csvData, saveAsPSD, hideSingleImage) {
if (!csvData) {
alert("CSV file is empty.");
return;
}
var curDoc = app.activeDocument;
var textLayer = curDoc.activeLayer;
if (!textLayer.kind || textLayer.kind != LayerKind.TEXT) {
alert("Please select a text layer.");
return;
}
var currentDocs = [];
for (var i = 0; i < app.documents.length; i++)
currentDocs.push(app.documents[i]);
for (var i = 0; i < currentDocs.length; i++) {
var doc = currentDocs[i];
if (doc != curDoc) {
var filename = doc.name.replace(/\.[^.]+$/, "");
var replacement = getReplacementText(csvData, filename);
if (replacement) {
var copiedLayer = textLayer.duplicate(doc, ElementPlacement.PLACEATBEGINNING);
app.activeDocument = doc;
hideSingleImageLayer(doc);
copiedLayer.textItem.contents = replacement;
copiedLayer.name = replacement;
var docWidth = doc.width.as("px");
//var docHeight = doc.height.as("px");
var textWidth = copiedLayer.bounds[2].as("px") - copiedLayer.bounds[0].as("px");
var textHeight = copiedLayer.bounds[3].as("px") - copiedLayer.bounds[1].as("px");
var verticalScaleFactor = 1.0;
var isReducedTrackingAndSize = false;
// Adjust tracking until the text fits within the document width
if (copiedLayer.textItem.contents.length > 8 && textWidth > docWidth) {
copiedLayer.textItem.capitalization = TextCase.NORMAL;
var newTextHeight = copiedLayer.bounds[3].as("px") - copiedLayer.bounds[1].as("px");
verticalScaleFactor = textHeight / newTextHeight;
}
// Adjust tracking and font size until the text fits within the document width
while (textWidth > docWidth) {
if (copiedLayer.textItem.tracking > -150) {
copiedLayer.textItem.tracking -= 10;
} else {
isReducedTrackingAndSize = true;
var currentFontSize = copiedLayer.textItem.size.as("pt");
copiedLayer.textItem.size = (currentFontSize - 1) + " pt";
// Adjust vertical scale to maintain constant text height
var newTextHeight = copiedLayer.bounds[3].as("px") - copiedLayer.bounds[1].as("px");
var verticalScale = textHeight * verticalScaleFactor * 110 / newTextHeight;
copiedLayer.textItem.verticalScale = verticalScale;
}
copiedLayer.textItem.size = copiedLayer.textItem.size; // Force Photoshop to recalculate the text size
textWidth = copiedLayer.bounds[2].as("px") - copiedLayer.bounds[0].as("px");
}
// Try to stretch text back if its size was reduced
while (isReducedTrackingAndSize && textWidth < docWidth) {
if (copiedLayer.textItem.tracking < 0)
copiedLayer.textItem.tracking += 10;
else
break;
copiedLayer.textItem.size = copiedLayer.textItem.size;
textWidth = copiedLayer.bounds[2].as("px") - copiedLayer.bounds[0].as("px");
}
if (hideSingleImage)
hideSingleImageLayer(doc);
if (saveAsPSD)
saveAsPSDFile(doc, false, "export");
app.activeDocument = curDoc;
}
}
}
alert("Text duplication complete.");
}
function readCSV(file) {
var csvData = [];
file.encoding = "UTF-8";
file.open("r");
while (!file.eof) {
var line = file.readln();
var values = line.split(/\u2192/); // '\u{2192}' or →
csvData.push(values);
}
file.close();
return csvData;
}
function getReplacementText(csvData, filename) {
for (var i = 0; i < csvData.length; i++) {
if (csvData[i][0] == filename)
return csvData[i][1];
}
return null;
}
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, "");
};
/*
function trim(str, chars) {
chars = chars || '\\s'; // Default to removing whitespace characters
var regex = new RegExp('^[' + chars + ']+|[' + chars + ']+$', 'g');
return str.replace(regex, '');
}
*/
// This script duplicates the current group of layers to every open document
if( app.documents.length > 0 ){
duplicateToAll();
}
function duplicateToAll(){
docs = app.documents;
curDoc = app.activeDocument;
groupLayerset();
for(var i = 0; i < docs.length; i++){
if(curDoc != docs[i]){
var curLayer;
try { curLayer = docs[i].activeLayer; } catch(e) {}
curDoc.activeLayer.duplicate(docs[i],ElementPlacement.PLACEATBEGINNING);
app.activeDocument = docs[i];
app.activeDocument.activeLayer.name = 'Duplicated Group';
if(curLayer){docs[i].activeLayer.move(curLayer, ElementPlacement.PLACEBEFORE);}
ungroupLayerset();
}
app.activeDocument = curDoc;
}
ungroupLayerset();
alert("Completed duplicating layer to all");
}
function cTID(s){return charIDToTypeID(s)}
function sTID(s){return stringIDToTypeID(s)}
function ungroupLayerset(){
var m_Dsc01 = new ActionDescriptor();
var m_Ref01 = new ActionReference();
m_Ref01.putEnumerated( cTID( "Lyr " ), cTID( "Ordn" ), cTID( "Trgt" ) );
m_Dsc01.putReference( cTID( "null" ), m_Ref01 );
executeAction( sTID( "ungroupLayersEvent" ), m_Dsc01, DialogModes.NO );
}
function groupLayerset(){
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putClass( sTID('layerSection') );
desc.putReference( cTID('null'), ref );
var ref = new ActionReference();
ref.putEnumerated( cTID('Lyr '), cTID('Ordn'), cTID('Trgt') );
desc.putReference( cTID('From'), ref );
executeAction( cTID('Mk '), desc, DialogModes.NO );
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment