Copy link to clipboard
Copied
Hi there,
I have been trying to write a script that finds and replaces certain text files in photoshop.
For example: There was a large man called (Name) with a big burly beard.
I have created an action using find and replace text to achieve this, but in the process of trying to automate this process by converting it to javascript using Xtools it no longer works.
Any help pointing me in the right direction would be super useful.
Cheers,
Marty
#target photoshop
//
// Action1.jsx
//
//
// Generated Fri Jan 10 2020 12:56:37 GMT+1100
//
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
//
//==================== Action 1 ==============
//
function Action1() {
// Replace All
function step1(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty(cTID('Prpr'), sTID("replace"));
ref1.putEnumerated(cTID('TxLr'), cTID('Ordn'), cTID('Al '));
desc1.putReference(cTID('null'), ref1);
var desc2 = new ActionDescriptor();
desc2.putString(cTID('find'), "(Name)");
desc2.putString(sTID("replace"), "John");
desc2.putBoolean(sTID("checkAll"), true);
desc2.putBoolean(cTID('Fwd '), true);
desc2.putBoolean(sTID("caseSensitive"), false);
desc2.putBoolean(sTID("wholeWord"), false);
desc2.putBoolean(sTID("ignoreAccents"), true);
desc1.putObject(cTID('Usng'), sTID("findReplace"), desc2);
executeAction(sTID('replace'), desc1, dialogMode);
};
step1(); // Replace All
};
//=========================================
// Action1.main
//=========================================
//
Action1.main = function () {
Action1();
};
Action1.main();
// EOF
"Action1.jsx"
// EOF
Copy link to clipboard
Copied
Yes the action conversion to Javascript by xtool does not work where the action does.
The Scriptlistener Code works and the cleaned up code by Clean SL works. Here is Dog to Cat
#target photoshop
//
// DoToCat.jsx
//
// =======================================================
// =======================================================
replace("Dog", "Cat", true, true, false, false, false);
function replace(find, replace, checkAll, forward, caseSensitive, wholeWord, ignoreAccents) {
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putProperty( stringIDToTypeID( "property" ), stringIDToTypeID( "replace" ));
reference.putEnumerated( stringIDToTypeID( "textLayer" ), stringIDToTypeID( "ordinal" ), stringIDToTypeID( "allEnum" ));
descriptor.putReference( charIDToTypeID( "null" ), reference );
descriptor2.putString( stringIDToTypeID( "find" ), find );
descriptor2.putString( stringIDToTypeID( "replace" ), replace );
descriptor2.putBoolean( stringIDToTypeID( "checkAll" ), checkAll );
descriptor2.putBoolean( stringIDToTypeID( "forward" ), forward );
descriptor2.putBoolean( stringIDToTypeID( "caseSensitive" ), caseSensitive );
descriptor2.putBoolean( stringIDToTypeID( "wholeWord" ), wholeWord );
descriptor2.putBoolean( stringIDToTypeID( "ignoreAccents" ), ignoreAccents );
descriptor.putObject( stringIDToTypeID( "using" ), stringIDToTypeID( "findReplace" ), descriptor2 );
executeAction( stringIDToTypeID( "replace" ), descriptor, DialogModes.NO );
}
Copy link to clipboard
Copied
Thanks JJMack!
In case it was not obvious, the code in the previous post works on an active (text) layer.
Adding some extra code, all text layers that contain Dog can be replaced with Cat – this is just a quick hack, I have not used a conditional to only process text layers:
var doc = app.activeDocument;
for(var i=0;i<doc.layers.length;i++){
try{
doc.activeLayer = doc.layers[i];
// Find = Dog, Replace = Cat
replace("Dog", "Cat", true, true, false, false, false); // Change the 3rd boolean to true for case sensitive match
}
catch(e){}
}
function replace(find, replace, checkAll, forward, caseSensitive, wholeWord, ignoreAccents) {
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putProperty( stringIDToTypeID( "property" ), stringIDToTypeID( "replace" ));
reference.putEnumerated( stringIDToTypeID( "textLayer" ), stringIDToTypeID( "ordinal" ), stringIDToTypeID( "allEnum" ));
descriptor.putReference( charIDToTypeID( "null" ), reference );
descriptor2.putString( stringIDToTypeID( "find" ), find );
descriptor2.putString( stringIDToTypeID( "replace" ), replace );
descriptor2.putBoolean( stringIDToTypeID( "checkAll" ), checkAll ); // Boolean #1
descriptor2.putBoolean( stringIDToTypeID( "forward" ), forward ); // Boolean #2
descriptor2.putBoolean( stringIDToTypeID( "caseSensitive" ), caseSensitive ); // Boolean #3
descriptor2.putBoolean( stringIDToTypeID( "wholeWord" ), wholeWord ); // Boolean #4
descriptor2.putBoolean( stringIDToTypeID( "ignoreAccents" ), ignoreAccents ); // Boolean #5
descriptor.putObject( stringIDToTypeID( "using" ), stringIDToTypeID( "findReplace" ), descriptor2 );
executeAction( stringIDToTypeID( "replace" ), descriptor, DialogModes.NO );
}
Copy link to clipboard
Copied
Here is the DOM code instead of AM code:
app.activeDocument.activeLayer.textItem.contents = app.activeDocument.activeLayer.textItem.contents.replace(/Dog/gi, 'Cat'); // g = global, i = case insensitve
While this version will change all text layers:
var doc = app.activeDocument;
for (var i = 0; i < doc.layers.length; i++) {
try {
doc.activeLayer = doc.layers[i];
// Find = Dog, Replace = Cat
// g = global, i = case insensitve
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/\bDog\b/gi, 'Cat');
}
} catch (e) {}
}
EDIT: I forgot to add, if you wish to isolate the word Dog by itself as a "whole word" and not have it included within another word such as doggedly, then use the following modification, adding a \b either side of the target word:
.replace(/\bDog\b/gi, 'Cat');
Copy link to clipboard
Copied
Hi, here's a stupid non-coder question: is it hard to create a panel, with input fields that would do this job?
That sort of panels exists in a rich ecosystem for After Effects (Aescripts and others) but I find it rare for Photoshop, is it harder to create a panel? the market is bigger...
Copy link to clipboard
Copied
It depends on the use/expectation for the script...
As part of an automation project, a GUI would get in the way, so either the text strings or a variable would be hard coded into a broader script so that no human interaction was required, so no GUI in this case.
However, anything GUI related is harder. It is simple enough to use a couple of built-in prompts to ask for user input, although one may then need to add error checking. Next level up is to write scriptUI for a "runtime" window and buttons, input fields etc. This takes more work... The code would probably be at least double or greater, here is an example... 49 lines of code without a "simple" scriptUI window and 92 lines of code with the GUI:
Then if you wish to have a constantly "floating panel" just like a native panel/window, then you need to do a whole lot more work with proper "extensions/panels", which is a lot of extra work.
But it is not so much the number of lines or amount of code, it is how long does all of this take to build and debug/test. As these scripts are offered freely without any payment for services rendered, they are often built to get the job done with the least amount of time/work. You get more than what you pay for, but payment would perhaps get you more!
Copy link to clipboard
Copied
If you want a Panel you do not even need a script. Just record an Action and make the Find and replace interactive. Find and Replace has a dialog. However, An interactive Step is not appropriate for a Batch Script. A Batch Find and replace Script would be possible. But would require a Script Dialog or and HTML photoshop extension panel. These require a lot more Script coding. And also require coding to make the script a batch process. I also do not know why the Xtool converted script does not work. The Action I converted does a Global Dog to Cat change. The Action Works the Xtool conversion does not. If the Xtool conversion changes an Active Text Layer the conversion does not work like the action that converted all text Layer the have Dog to Cat. No searching for text layer to make them active should be required. The Action Manager Code recorder by Adobe Scriptlistener Plug-in for the global Find and Replace step works.
An interactive action would shoe this the Text used recording in the action would be displayed in the dialog and would have toe be changed by the user. So record something like A to B not Dog to Cat the options can also be changed. A script dialog would need to be more complex if you want to support all the Find Replace Text tool options.
Copy link to clipboard
Copied
Hello!,
.replace(/\bDog\b/gi, 'Cat');
is an amazing code, thank you very much!, this is awesome and very usuable, I have one question,
is there any way it replace text after a word, I mean for example in series like:
Photo_01
Photo_02
Photo_BB
Image_03940
to remove the end in the 4 of them for example, I mean something like " _* "
I have an script to make a new text layer from the file name and I just want now to trim the text
after some character or series of words to keep only the important file as I must have names like
For sale _ Design 023.psd and I want the layers to be like "FOR SALE" only
I hope my question make sense, thank you guys for your help in advance, blessings.
Copy link to clipboard
Copied
'Image_03940'.split(/(?:_.*)/)[0]
Copy link to clipboard
Copied
Wow thank you very much, sorry non-coder guy here, I do some basic scripts
but I am not a savy person sorry, so I must replace the
\bDog\b
with
'Image_03940'.split(/(?:_.*)/)[0]
something like:
.replace(/\b'Image_03940'.split(/(?:_.*)/)[0]\b/gi, 'Cat');
I guess the code is like RegExp or something right?
just a guy who learn by himself online sorry, I apreciate your help
have a blessed day.
Copy link to clipboard
Copied
That you wrote is big chaos, I don't understand what you want to replace with what.
Copy link to clipboard
Copied
Sorry I am stupid, Not coding guy,
just tried to follow your instructions,
what I want is just a kind of wildcard if possible to replace anything after "_",
please apologize, God bless you day.
Copy link to clipboard
Copied
From previous post it looked like you wanted to remove the part after _, including this char. Now I understand you want to keep it while replace following part with something else? Then finish my code with:
+ '_Cat'
Copy link to clipboard
Copied
Is to much to ask for an example ?
Copy link to clipboard
Copied
I gave you one code, then second, to combine together with that first.
Isn't 'Image_Cat' result that you expected to have with that code?
Copy link to clipboard
Copied
Sorry, I was not able to understand your instructions,
the answer from Stephen_A_Marsh was was I was looking for and I was able to use his example
I apreciate your help and time anyway,blessings
Copy link to clipboard
Copied
You didn't answer to make me sure of your goal, basing on given example. So once again, is 'Image_Cat' a result you wanted to be created from 'Image_03940'?
Copy link to clipboard
Copied
AlexPrint was looking to change:
For sale _ Design 023.psd
to:
For sale
Perhaps taking this a step further with .toUpperCase() – which I didn't go into at the time, as I didn't wish to complicate this further than just the regex:
FOR SALE
Copy link to clipboard
Copied
That was the other, probably final goal. I was referring part of post where he described something different my code was fit to.
Copy link to clipboard
Copied
@Kukurykus sorry I was not able to explain myself better before, Stephen_A_Marsh is correct, that was what I was looking for, I did the change to upercase in the photoshop action using the "all caps" option in fonts panel but yes, the .toUpperCase() fucntion is more elegant answer, I am just dealing with extra or double spaces now but thank you very much for your time guys, this community is awesome. have a blessed day.
Copy link to clipboard
Copied
Okay, but can you finally answer to me despite what is your final goal. Basing on your example did you want 'Image_03940' be turned into 'Image_Cat'?
Copy link to clipboard
Copied
Oh!, sorry for my late answer, the final goal was for a a filename like:
For rent_Design025.psd To remove everything after the first underscore _ character, including the underscore as described by Stephen_A_Marsh below, thank you for your time and help. blessings
Copy link to clipboard
Copied
I did not ask what is your final goal, but what should be result for Image_03940. I asked it already 3 times and you still can't answer. Anyway reading your next sentence I understand the result should be: 'Image'. If so the code I shared does exactly what you asked for: Jan 19, 2022, additionally later one adds another part to result in place of removed part: Jan 19, 2022
Copy link to clipboard
Copied
Sorry I am tottally confused, I must be stupid, but I do not get it sorry, I do not really understand regex yet,
the "image" part can be any word, just wanted to remove any text after "_" from any other text (image, design, dog, tigger) I guess I replied to your code by mistake, and my question may not apply to your code at the end, not sure, please apologize if I wasted your time, I am learning here sorry.
Copy link to clipboard
Copied
It's okay - we finally solved it 🙂