Skip to main content
Known Participant
January 18, 2024
Answered

Script to find and replace text layers and ignore missing fonts text layers.

  • January 18, 2024
  • 4 replies
  • 1896 views

I want to search and replace content inside text layers (e.g. X -> x). I found this code but it throws an error if there is a text layer in the file that uses the missing font. Is there any way to skip such layers?

 

 

 

 

Correct answer c.pfaffenbichler

Thank you very much for this script. But, it won't work if I don't select the text layers first.
Btw, I'm really interested in these, where can I find tutorials on photoshop scripts?


Did you try the Script @Davide_Barranca12040269 posted? 

 

Edit: An ESTK-code-version: 

// 2024, use it at your own risk;
if (app.documents.length > 0) {
replaceLetterInTypeLayers ("x", "8");
};
////////////////////////////////////
function replaceLetterInTypeLayers (searchText, replaceWith) {
// 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 theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
try {
var actionDes1 = new ActionDescriptor();
var actionRef = new ActionReference();
selectLayerByID(theID, false);
actionRef.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID("replace") );
actionRef.putEnumerated( charIDToTypeID( "TxLr" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
actionDes1.putReference( charIDToTypeID( "null" ), actionRef );
var actionDes2 = new ActionDescriptor();
actionDes2.putString( stringIDToTypeID( "find" ), searchText );
actionDes2.putString( stringIDToTypeID("replace"), replaceWith );
actionDes2.putBoolean( stringIDToTypeID( "checkAll" ), false );
actionDes2.putBoolean( charIDToTypeID( "Fwd " ), true );
actionDes2.putBoolean( stringIDToTypeID( "caseSensitive" ), false );
actionDes2.putBoolean( stringIDToTypeID( "wholeWord" ), false );
actionDes2.putBoolean( stringIDToTypeID( "ignoreAccents" ), true );
actionDes1.putObject( charIDToTypeID( "Usng" ), stringIDToTypeID( "findReplace" ), actionDes2 );
executeAction( stringIDToTypeID("replace"), actionDes1, DialogModes.NO );
theLayers.push([theName, theID])
} catch (e) {};
};
}
catch (e) {};
};
return theLayers
};
////////////////////////////////////
// based on code by mike hale, via paul riggott;
function selectLayerByID(id,add){ 
add = undefined ? add = false:add 
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), id);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
}
};

 

4 replies

Davide_Barranca12040269
Community Expert
Community Expert
January 19, 2024

Put the following in a file with a `.psjs` extension.

 

const { app, constants } = require("photoshop");
const doc = app.activeDocument;
for (const lay of doc.layers) {
  if (lay.kind === constants.LayerKind.TEXT) {
    lay.textItem.contents = lay.textItem.contents.replace(/x/g, "y");
  }
}

 

It won't work if you have nested text layers; otherwise, it should be OK. It runs a RegExp to replace instances of "x" with "y" .

 

 

Davide Barranca - PS developer and authorwww.ps-scripting.com
c.pfaffenbichler
Community Expert
Community Expert
January 19, 2024

Dang, I suppose it is time to specify jsx or psjs when posting Scripts … 

Davide_Barranca12040269
Community Expert
Community Expert
January 19, 2024

LOL it's about time 😁

Davide Barranca - PS developer and authorwww.ps-scripting.com
Legend
January 18, 2024
layerUpdate();

function layerUpdate(){
    if(documents.length > 0){
        var originalDialogMode = app.displayDialogs;
        app.displayDialogs = DialogModes.ERROR;
        var originalRulerUnits = preferences.rulerUnits;
        try{
            var docRef = activeDocument;
            preferences.rulerUnits = Units.POINTS;
            for(var i = 0; i < docRef.artLayers.length; i++){
                var LayerRef = docRef.artLayers[i];
                if(LayerRef.kind == LayerKind.TEXT){
                    var TextRef = LayerRef.textItem;
                    var layerText = TextRef.contents;
                    var newText = layerText.replace('x', 'y');
                    TextRef.contents= newText;
                    }
                }
            preferences.rulerUnits = originalRulerUnits;
            app.displayDialogs = originalDialogMode;
            }
        catch(e){
            }
        }
    }
NahidkuAuthor
Known Participant
January 19, 2024

thank you, but it's not working 😞

c.pfaffenbichler
Community Expert
Community Expert
January 18, 2024

If that does not work please provide the Script and the file for testing. 

c.pfaffenbichler
Community Expert
Community Expert
January 18, 2024

Have you tried wrapping the operation in a try-clause? 

NahidkuAuthor
Known Participant
January 19, 2024

oh... i'm not a programmer so i don't know what you're talking about. Currently the script only works on layers selected before running the script. Here is my script and psd file:

function replaceText (searchText, replaceWith)

{

    var actionDes1 = new ActionDescriptor();

    var actionRef = new ActionReference();

    actionRef.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID("replace") );

    actionRef.putEnumerated( charIDToTypeID( "TxLr" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );

    actionDes1.putReference( charIDToTypeID( "null" ), actionRef );

    var actionDes2 = new ActionDescriptor();

    actionDes2.putString( stringIDToTypeID( "find" ), searchText );

    actionDes2.putString( stringIDToTypeID("replace"), replaceWith );

    actionDes2.putBoolean( stringIDToTypeID( "checkAll" ), false );

    actionDes2.putBoolean( charIDToTypeID( "Fwd " ), true );

    actionDes2.putBoolean( stringIDToTypeID( "caseSensitive" ), false );

    actionDes2.putBoolean( stringIDToTypeID( "wholeWord" ), false );

    actionDes2.putBoolean( stringIDToTypeID( "ignoreAccents" ), true );

    actionDes1.putObject( charIDToTypeID( "Usng" ), stringIDToTypeID( "findReplace" ), actionDes2 );

    executeAction( stringIDToTypeID("replace"), actionDes1, DialogModes.NO );

};

replaceText ("I", "i")

 

c.pfaffenbichler
Community Expert
c.pfaffenbichlerCommunity ExpertCorrect answer
Community Expert
January 21, 2024

Thank you very much for this script. But, it won't work if I don't select the text layers first.
Btw, I'm really interested in these, where can I find tutorials on photoshop scripts?


Did you try the Script @Davide_Barranca12040269 posted? 

 

Edit: An ESTK-code-version: 

// 2024, use it at your own risk;
if (app.documents.length > 0) {
replaceLetterInTypeLayers ("x", "8");
};
////////////////////////////////////
function replaceLetterInTypeLayers (searchText, replaceWith) {
// 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 theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
try {
var actionDes1 = new ActionDescriptor();
var actionRef = new ActionReference();
selectLayerByID(theID, false);
actionRef.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID("replace") );
actionRef.putEnumerated( charIDToTypeID( "TxLr" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
actionDes1.putReference( charIDToTypeID( "null" ), actionRef );
var actionDes2 = new ActionDescriptor();
actionDes2.putString( stringIDToTypeID( "find" ), searchText );
actionDes2.putString( stringIDToTypeID("replace"), replaceWith );
actionDes2.putBoolean( stringIDToTypeID( "checkAll" ), false );
actionDes2.putBoolean( charIDToTypeID( "Fwd " ), true );
actionDes2.putBoolean( stringIDToTypeID( "caseSensitive" ), false );
actionDes2.putBoolean( stringIDToTypeID( "wholeWord" ), false );
actionDes2.putBoolean( stringIDToTypeID( "ignoreAccents" ), true );
actionDes1.putObject( charIDToTypeID( "Usng" ), stringIDToTypeID( "findReplace" ), actionDes2 );
executeAction( stringIDToTypeID("replace"), actionDes1, DialogModes.NO );
theLayers.push([theName, theID])
} catch (e) {};
};
}
catch (e) {};
};
return theLayers
};
////////////////////////////////////
// based on code by mike hale, via paul riggott;
function selectLayerByID(id,add){ 
add = undefined ? add = false:add 
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), id);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
}
};