Copy link to clipboard
Copied
Is there a script to be able to remove extra spaces (and soft returns) within a text block in photoshop?
And if so, how would I load the script again? I remember there's a folders somewhere I need to put the script file into? Then it shows up under the fle menu, under automations, right.
@NDL_DH – Yes, as I previously wrote I don't know why the formatting is lost or how to avoid that. More accomplished scripters may be able to answer.
You can use the Edit > Find and Replace Text command. ScriptingListener can also capture the use of this as well and it doesn't remove the formatting in my simple tests.
The issue is that it uses strings as input/output, I can't work out how to "inject" variables or regular expressions. Therefore it would need repetition with hard-coded values:
...Copy link to clipboard
Copied
..I have a InDesign script that use to remove extra spacces, posted below.
Making a photoshop version of the below would be a good start..?
//reset GREP preferences
app.findGrepPreferences=app.changeGrepPreferences=null;
app.findGrepPreferences.findWhat="[~m~>~f~|~S~s~<~/~.~3~4~% ]{2,}";
app.changeGrepPreferences.changeTo="\\s";
var sel = app.selection;
for(var n=0;n<sel.length;n++)
{
sel[n].changeGrep();
};
//reset GREP preferences
//app.findGrepPreferences=app.changeGrepPreferences=null;
Copy link to clipboard
Copied
EDIT:
..I have an InDesign script that I use to remove extra spacces, posted below.
Making a photoshop version of the below script would be a good start..?
//reset GREP preferences
app.findGrepPreferences=app.changeGrepPreferences=null;
app.findGrepPreferences.findWhat="[~m~>~f~|~S~s~<~/~.~3~4~% ]{2,}";
app.changeGrepPreferences.changeTo="\\s";
var sel = app.selection;
for(var n=0;n<sel.length;n++)
{
sel[n].changeGrep();
};
//reset GREP preferences
//app.findGrepPreferences=app.changeGrepPreferences=null;
Copy link to clipboard
Copied
The following script will replace 1 or more word spaces with a single word space in the active document:
var doc = app.activeDocument;
for (var j = 0; j < doc.layers.length; j++) {
try {
doc.activeLayer = doc.layers[j];
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
}
} catch (e) {}
}
I am not sure if Photoshop has the same level of support as one would find in InDesign, I can't get a soft return (shift + return) to work:
.replace(/\u2029/g, '')
Edit: Instructions for saving and installing script code here –
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
Copy link to clipboard
Copied
Wow, thanks so much for this.
Just waiting for my admin at work to place it in the scripts folder.
Will report back results and mark correct hopefully by tomorrow.
Just to be clear though, this script I can run while having a text box selected (or the actual text selected, i.e., with the type tool) and it will only effect what I have selected, right?
Just want to make sure it's not going to effect everything within the PSD, regardless if it's selected or not. That would be bad.
Copy link to clipboard
Copied
It edits alll text layers in the open doc.
Remove the for loop to only edit the active layer.
The script can also be browsed without installation.
Copy link to clipboard
Copied
@Stephen_A_Marsh wrote:It edits alll text layers in the open doc.
Remove the for loop to only edit the active layer.
The script can also be browsed without installation.
...So would something like the below work, where I commmented out the "for" line, and the closing "}" also?
var doc = app.activeDocument;
/* for (var j = 0; j < doc.layers.length; j++) { */
try {
doc.activeLayer = doc.layers[j];
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
}
} catch (e) {}
/* } */
Copy link to clipboard
Copied
@Stephen_A_Marsh wrote:It edits alll text layers in the open doc.
Remove the for loop to only edit the active layer.
The script can also be browsed without installation.
...Oh, duh, it can be browsed, let me see if I can test it now. 🤦🏾:male_sign:
Copy link to clipboard
Copied
I tried removing the "for" loop, and the"try" line also, cause that's a part of the loop also, right. Both resulted in errors.
Then it was throwing errors because of the "j" inside of doc.layers[j];, so I deleted the "j" from there, and still nothing, just more errors.
var doc = app.activeDocument;
// for (var j = 0; j < doc.layers.length; j++) {
// try {
doc.activeLayer = doc.layers[];
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
}
// } catch (e) {}
//}
Copy link to clipboard
Copied
2 things:
1. I went back to the original script, and nothing happens when I run that also, but it doesn't give an errors either.
2. I ran the below, and it didn't remove the spaces, but it removed all the formatting on the box I had selected, defaulting it to the fontsize and color, etc, of the top most line, i.e., the headline. But it also threw no errors.
var doc = app.activeDocument;
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
}
Copy link to clipboard
Copied
That's alright, in re to the soft return.
I'll be more than happy if this word space script works.
Copy link to clipboard
Copied
And if so, how would I load the script again? I remember there's a folders somewhere I need to put the script file into?
Presets > Scripts
In the program they are listed under File > Scripts
Copy link to clipboard
Copied
Yes, thanks for showing me the location, found it.
Cheers.
Copy link to clipboard
Copied
@Stephen_A_Marsh This script below, removes the spaces from the selected text layer, but it also removes all the formating, and defaults to the headline styling (font weight, size, color, etc).
Is there a way to retain the existing styling?
var doc = app.activeDocument;
app.activeDocument.activeLayer.kind == LayerKind.TEXT ;
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
Copy link to clipboard
Copied
That is unexpected, I didn't intend for the formatting to be removed, however, you are indeed correct.
This is what I was referring to with regards to removing the for loop:
var doc = app.activeDocument;
try {
if (doc.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
}
} catch (e) {}
I'm not sure why this would affect the formatting, however, I don't have a great deal of experience with scripting text layer changes so it may be something basic.
Copy link to clipboard
Copied
This removes the spaces, but defaults the styling to whatever the top most style is, like previously mentioned.
It's so close I can taste it.
Monday I'll try to look for something that retains styling, that maybe I can place at the end of this script, IDK...?
Copy link to clipboard
Copied
@Stephen_A_Marsh Also, sorry for all these messages, but is there a way to remove a space and an adjoining return or soft return..?
Along with the multiple space, or a separate jsx to deal with occurances of space followed by a return or soft return..?
Copy link to clipboard
Copied
@NDL_DH wrote:
@Stephen_A_Marsh Also, sorry for all these messages, but is there a way to remove a space and an adjoining return or soft return..?
Along with the multiple space, or a separate jsx to deal with occurances of space followed by a return or soft return..?
As I wrote earlier, I can't see a way to change a soft-return.
Multiple spaces and or multiple spaces and a line ending to be replaced with a space would be:
var doc = app.activeDocument;
try {
if (doc.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +\r/g, ' ');
}
} catch (e) {}
I'm not sure why this would affect the formatting, however, I don't have a great deal of experience with scripting text layer changes so it may be something basic.
Copy link to clipboard
Copied
I'll test this out tomorrow and post results.
Thanks again.
Copy link to clipboard
Copied
This works too, but removes the styling also, defaulting to the topmost style on the text layer.
Copy link to clipboard
Copied
@Stephen_A_Marsh I wonder if anything on this thread will work, to retain styling after script runs?
https://community.adobe.com/t5/photoshop-ecosystem-discussions/setting-a-font-on-a-psd-text-item-in-...
Copy link to clipboard
Copied
@Stephen_A_Marsh
@c.pfaffenbichler
I get the same results using this, below.
Removes extra spaces but the styling still defaults.
/*
var doc = app.activeDocument;
try {
if (doc.activeLayer.kind == LayerKind.TEXT) {
doc.activeLayer.textItem.contents = doc.activeLayer.textItem.contents.replace(/ +/g, ' ');
}
} catch (e) {}
*/
var aLay = app.activeDocument.activeLayer;
try{
if(aLay.textItem && aLay.textItem.contents != "") {
var changedText= aLay.textItem.contents.replace (/ +/g, ' ');
aLay.textItem.contents = changedText;
}
} catch (e) {}
Copy link to clipboard
Copied
@NDL_DH – Yes, as I previously wrote I don't know why the formatting is lost or how to avoid that. More accomplished scripters may be able to answer.
You can use the Edit > Find and Replace Text command. ScriptingListener can also capture the use of this as well and it doesn't remove the formatting in my simple tests.
The issue is that it uses strings as input/output, I can't work out how to "inject" variables or regular expressions. Therefore it would need repetition with hard-coded values: find/replace two spaces with one space. Repeat again for three spaces and replace with one space etc. Not the end of the world, but it could be better...
Edit:
findReplaceText(" ", " ", true, false, false, false, false); // 2 spaces
findReplaceText(" ", " ", true, false, false, false, false); // 3 spaces
findReplaceText(" ", " ", true, false, false, false, false); // 4 spaces
findReplaceText(" ", " ", true, false, false, false, false); // 5 spaces
function findReplaceText(find, replace, checkAll, forward, caseSensitive, wholeWord, ignoreAccents) {
function s2t(s) {
return app.stringIDToTypeID(s);
}
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putProperty( s2t( "property" ), s2t( "replace" ));
reference.putEnumerated( s2t( "textLayer" ), s2t( "ordinal" ), s2t( "allEnum" ));
descriptor.putReference( s2t( "null" ), reference );
descriptor2.putString( s2t( "find" ), find );
descriptor2.putString( s2t( "replace" ), replace );
descriptor2.putBoolean( s2t( "checkAll" ), checkAll );
descriptor2.putBoolean( s2t( "forward" ), forward );
descriptor2.putBoolean( s2t( "caseSensitive" ), caseSensitive );
descriptor2.putBoolean( s2t( "wholeWord" ), wholeWord );
descriptor2.putBoolean( s2t( "ignoreAccents" ), ignoreAccents );
descriptor.putObject( s2t( "using" ), s2t( "findReplace" ), descriptor2 );
executeAction( s2t( "replace" ), descriptor, DialogModes.NO );
}
Copy link to clipboard
Copied
I guess repeating the replacement of double-spaces until there are none would suffice.
DOM-support for Type Layers is not great unfortunately and, as you are probably aware, editing them via AM-code is a bit »peculiar«. Not impossible but, for me at least, not exactly comfortable.
Copy link to clipboard
Copied
Something peculiar seems to prevent this Script from running meaningfully in specific situations, but try it anyway:
(edited 2022-08-07)
// 2022, use it at your own risk;
if (app.documents.length > 0) {
var theTypeLayers = collectTypeLayersTexts();
selectLayerByID(theTypeLayers[0][2]);
var theCheck = false;
for (var n = 0; n < theTypeLayers.length; n ++) {
if (theTypeLayers[n][4].indexOf(" ") != -1) {theCheck = true}
};
while (theCheck == true) {
replaceText (" ", " ");
var theTypeLayers = collectTypeLayersTexts();
var theCheck = false;
for (var m = 0; m < theTypeLayers.length; m ++) {
if (theTypeLayers[m][4].indexOf(" ") != -1) {theCheck = true}
};
};
};
////// reoplace text //////
function replaceText (replaceThis, replaceWith) {
try {
// =======================================================
var idreplace = stringIDToTypeID( "replace" );
var desc22 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref3 = new ActionReference();
var idPrpr = charIDToTypeID( "Prpr" );
var idreplace = stringIDToTypeID( "replace" );
ref3.putProperty( idPrpr, idreplace );
var idTxLr = charIDToTypeID( "TxLr" );
var idOrdn = charIDToTypeID( "Ordn" );
var idAl = charIDToTypeID( "Al " );
ref3.putEnumerated( idTxLr, idOrdn, idAl );
desc22.putReference( idnull, ref3 );
var idUsng = charIDToTypeID( "Usng" );
var desc23 = new ActionDescriptor();
var idfind = stringIDToTypeID( "find" );
desc23.putString( idfind, replaceThis );
var idreplace = stringIDToTypeID( "replace" );
desc23.putString( idreplace, replaceWith );
var idcheckAll = stringIDToTypeID( "checkAll" );
desc23.putBoolean( idcheckAll, true );
var idFwd = charIDToTypeID( "Fwd " );
desc23.putBoolean( idFwd, true );
var idcaseSensitive = stringIDToTypeID( "caseSensitive" );
desc23.putBoolean( idcaseSensitive, false );
var idwholeWord = stringIDToTypeID( "wholeWord" );
desc23.putBoolean( idwholeWord, false );
var idignoreAccents = stringIDToTypeID( "ignoreAccents" );
desc23.putBoolean( idignoreAccents, true );
var idfindReplace = stringIDToTypeID( "findReplace" );
desc22.putObject( idUsng, idfindReplace, desc23 );
executeAction( idreplace, desc22, DialogModes.NO );
} catch (e) {}
};
////// collect layers //////
function collectTypeLayersTexts () {
// get number of layers;
var ref = new ActionReference();
ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
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 type layer 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'));
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theseBounds = [theBounds.getUnitDoubleValue(stringIDToTypeID("left")), theBounds.getUnitDoubleValue(stringIDToTypeID("top")), theBounds.getUnitDoubleValue(stringIDToTypeID("right")), theBounds.getUnitDoubleValue(stringIDToTypeID("bottom"))];
var textDesc = layerDesc.getObjectValue(stringIDToTypeID('textKey'));
var theText = textDesc.getString(stringIDToTypeID("textKey"));
theLayers.push([theName, theIndex, theID, theseBounds, theText])
};
}
catch (e) {};
};
return theLayers
};
////// based on code by mike hale and paul riggott //////
function selectLayerByID(index,add){
add = undefined ? add = false:add
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), index);
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);
}
};