Copy link to clipboard
Copied
Copy link to clipboard
Copied
Hi!
In searching out the answer to your question, I came across the following website (link directly below) and it gave the link to a website with scripts that seem to do what you are looking for. (second link below!) I havent tried either of these, but I am sending the information as one option. I am sure others will chime in with scripts that will accomplish it too.
Scripts website:
https://morris-photographics.com/photoshop/scripts/index.html
Let us know if that helps!
Michelle
Copy link to clipboard
Copied
Thanks. I'll have to look into scripts. It seems like Distribute Vertically/Horizontally should just have an input option.
Copy link to clipboard
Copied
Theoretically I agree. In Illustrator, the input option is only available if you make a Key Object first. Photoshop does not have Key objects.
Jane
Copy link to clipboard
Copied
You can distribute vertically, but you cannot distribute a fixed amount in Photoshop, at least not out of the box.
Illustrator lets you choose an amount for the distribution when you have a key object and lets you choose 1 inch. Photoshop does not.
A script might work. Try the ones from mglush. I've also edited your post to include the Scripting topic.
Jane
Copy link to clipboard
Copied
If Michelle's scripts don't work, then could you use a New Guide layout? You'd have to know the width of the objects of course.
Copy link to clipboard
Copied
I've been using guides, but I am resizing text to fit in a box, like in the preview image, and each time the height of the text changes, it throws them all off.
Copy link to clipboard
Copied
As the others have responded, it's all manual without a script.
1. Original spacing
2. Remove all existing spacing
3. Move the right-hand layer 2 inches over:
4. Distribute the space equally horizontally using the move tool options bar:
5. The final result – 2 x 1 inch spaces between the 3 distributed objects:
So yes, it would be easier if it "just worked like Illustrator"! :]
Copy link to clipboard
Copied
Are you trying to get equal spacing between the one-two-three that have different type sizes or are you trying to get equal spacing between the two (or more) text frames?
Are you using point text or paragraph text?
Did you press Return or Shift+Return after each word?
Jane
Copy link to clipboard
Copied
Jane, I wonder if Chuck would have any thoughts about it. I used his Space Equal Extension before Photoshop added its similar feature.
https://exchange.adobe.com/apps/cc/2578/space-equal
Copy link to clipboard
Copied
Does Chuck's script use objects or text?
I was waiting to hear back from Brian, but have been wondering if leading or paragraph spacing settings might work.
Jane
Copy link to clipboard
Copied
My script used objects. so text might cause some issues, as trying to determin the actual text boundries can be an issue. Other than that, it should be fairly easy to change the script to space by a known amount. The other issue would be which direction you would want the expansion or contracton of the blocks to go: from the center of them all, the top or the bottom?
Copy link to clipboard
Copied
...Other than that, it should be fairly easy to change the script to space by a known amount. The other issue would be which direction you would want the expansion or contracton of the blocks to go: from the center of them all, the top or the bottom?
By @Chuck Uebele
As this is a legacy CEP panel, would it be possible to also post standard script code for the horizontal and vertical without the panel GUI? That would make it more accessible to a wider audience. I imagine that recreating this via a UXP panel would be quite an undertaking.
Copy link to clipboard
Copied
I just have the normal script for this. I stopped doing CEP and haven't gotten into UXP panels.
Copy link to clipboard
Copied
You can resize the bounding box to fit your text by converting to point type and then back to paragraph type. I have an action that does this, part of my automation for adding text overlays to images.
Copy link to clipboard
Copied
I modified my equal space scripts. Here it is that will set the space between the objects. It doesn't seem to be too accurate with text, but it's close. you need to set the distance in the text box in the UI in the units in which your ruler is set. So if you want to work in inches, set your ruler to inches. This will only work on vertical spacing.
#target photoshop
app.displayDialogs = DialogModes.NO;
if (app.documents.length>0){
var dlg = new Window('dialog','Space Objects');
var docRef = activeDocument
var shapeSizeTotal = 0
var selLay = getSelectedLayersIdx()
var docLayers = new Array()
var amt
if (selLay.length>2){runProg()}
else{alert('There needs to be 3 or more layers selected')}
}
else{alert('There are no open Documents')};
function runProg(){
var run = true;
dlg.infoGp = dlg.add('group');
dlg.sTxt = dlg.infoGp.add('statictext',undefined,'Enter distance between object. distance will be in current ruler units.');
dlg.eTxt = dlg.infoGp.add('edittext',undefined, '');
dlg.eTxt.size = [100,20]
dlg.buttonGp = dlg.add('group');
dlg.buttonGp.okay = dlg.buttonGp.add('button',undefined,'Okay');
dlg.buttonGp.okay.onClick = function(){
dlg.close();
amt = Number (dlg.eTxt.text)
}
dlg.buttonGp.cancel = dlg.buttonGp.add('button',undefined,'cancel');
dlg.buttonGp.cancel.onClick = function(){
dlg.close();
run = false;
}
dlg.show()
if(run){
makeActiveByIndex(selLay, true)
docLayers.sort(compare)
makeSingleActiveByIndex(selLay[0], true);//select only one layer to make the translations
//docRef.activeLayer = docRef.layers[docRef.layers.length-1]
for (var i=0;i<docLayers.length-1;i++){
var deltaM = amt-(docLayers[i+1][1].bounds[1].value-docLayers[i][1].bounds[3].value)
docLayers[i+1][1].translate (0, deltaM)
};
makeActiveByIndex(selLay, true);//reset selection to all layers
}//end if to run
};//end function runProg
function compare(a,b){return a-b}
function getSelectedLayersIdx() {
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var desc = executeActionGet(ref);
if (desc.hasKey(stringIDToTypeID("targetLayers"))) {
desc = desc.getList(stringIDToTypeID("targetLayers"));
var c = desc.count
var selectedLayers = new Array();
for (var i = 0; i < c; i++) {
try {
docRef.backgroundLayer;
selectedLayers.push(desc.getReference(i).getIndex());
} catch (e) {
selectedLayers.push(desc.getReference(i).getIndex() + 1);
}
}
} else {
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("ItmI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
try {
docRef.backgroundLayer;
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID("ItmI")) - 1);
} catch (e) {
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID("ItmI")));
}
}
return selectedLayers;
}
function makeActiveByIndex(idx, visible) {
for (var i = 0; i < idx.length; i++) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), idx[i])
desc.putReference(charIDToTypeID("null"), ref);
if (i > 0) {
var idselectionModifier = stringIDToTypeID("selectionModifier");
var idselectionModifierType = stringIDToTypeID("selectionModifierType");
var idaddToSelection = stringIDToTypeID("addToSelection");
desc.putEnumerated(idselectionModifier, idselectionModifierType, idaddToSelection);
}
desc.putBoolean(charIDToTypeID("MkVs"), visible);
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
if(checkLayerKind(docRef.activeLayer)){
var layerLeft = new Array(docRef.activeLayer.bounds[1],docRef.activeLayer)
docLayers.push(layerLeft)
}
}
};// end makeActiveByIndex
function makeSingleActiveByIndex(idx, visible) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), idx)
desc.putReference(charIDToTypeID("null"), ref);
desc.putBoolean(charIDToTypeID("MkVs"), visible);
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
};//end makeSingleActiveByIndex
function checkLayerKind(lay){
if(lay.kind == LayerKind.NORMAL || lay.kind == LayerKind.TEXT || lay.kind == LayerKind.SOLIDFILL){return true}
else{return false}
};//end checkLayerKind
Copy link to clipboard
Copied
@Chuck Uebele – Thanks for sharing! What is simple for you is much harder for me!
Do you have the horizontal version? If not, I'll look at changing this one.
A few of cosmetic alterations:
One can change the following line 21 from:
dlg.eTxt = dlg.infoGp.add('edittext',undefined, '');
To:
dlg.eTxt = dlg.infoGp.add('editnumber',undefined, '');
To enforce the entry of digits/numbers only, that way the script will not fail if somebody enters letters such as 50px into the prompt. This simple change from edittext to editnumber is much simpler than using the more complicated keydown event to enforce the entry of digits.
One can also add a new line after line 23:
dlg.eTxt.size = [100,20]
Adding the following new line of code:
dlg.eTxt.active = true;
To default the entry field to be active, so that one doesn't need to press the tab key or click in the field to give it focus.
EDIT:
One could also change line 20 from:
dlg.sTxt = dlg.infoGp.add('statictext',undefined,'Enter distance between object. distance will be in current ruler units.');
To:
dlg.sTxt = dlg.infoGp.add('statictext',undefined,'Enter the distance between the objects (' + app.preferences.rulerUnits.toString().replace(/Units\./, '') + '):');
To indicate what the current unit of measure is for the rulers.
Copy link to clipboard
Copied
Thanks for the tips! I didn't realize that there was an editnumber. That's nice!
I don't have a horizontal version, but it would be easy to modify it, by just changing the bounds references.
Copy link to clipboard
Copied
I have made minor progress, as in I have changed the bounds and reversed the translate deltaM order... But now the layers are changing position.
Before (green, pink, brown):
After (pink, green, brown):
Does the for loop need reversing or is this something else?
EDIT: I don't think that it's the for loop...
Copy link to clipboard
Copied
Editnumber is undocumented, of course. But yes I use it in some scripts.
Copy link to clipboard
Copied
Yea, I would have liked to have known about editnumber a long time ago. I have error checking routines for edittext that I really didn't need. Oh well.
Copy link to clipboard
Copied
@Stephen Marsh I think the reason you got reversed order is that I had taken out the sort order for the layer for the horizontal. Here's a script that will do both vertical and horizontal. I also added your suggestions.
#target photoshop
app.displayDialogs = DialogModes.NO;
if (app.documents.length>0){
var dlg = new Window('dialog','Space Objects');
var docRef = activeDocument
var shapeSizeTotal = 0
var selLay = getSelectedLayersIdx()
var docLayers = new Array()
var isHor = true;
var amt;
if (selLay.length>2){runProg()}
else{alert('There needs to be 3 or more layers selected')}
}
else{alert('There are no open Documents')};
function runProg(){
var run = true;
dlg.hor = dlg.add('radiobutton',undefined,'Space Horizontal');
dlg.hor.value = true;
dlg.vert = dlg.add('radiobutton',undefined,'Space Vertical');
dlg.infoGp = dlg.add('group');
dlg.sTxt = dlg.infoGp.add('statictext',undefined,'Enter the distance between the objects (' + app.preferences.rulerUnits.toString().replace(/Units\./, '') + '):');
dlg.eTxt = dlg.infoGp.add('editnumber',undefined, '');
dlg.eTxt.size = [100,20]
dlg.buttonGp = dlg.add('group');
dlg.buttonGp.okay = dlg.buttonGp.add('button',undefined,'Okay');
dlg.buttonGp.okay.onClick = function(){
dlg.close();
if(dlg.hor.value){isHor = true}
else {isHor = false};
amt = dlg.eTxt.value
}
dlg.buttonGp.cancel = dlg.buttonGp.add('button',undefined,'cancel');
dlg.buttonGp.cancel.onClick = function(){
dlg.close();
run = false;
}
dlg.eTxt.active = true;
dlg.show()
if(run){
makeActiveByIndex(selLay, true)
docLayers.sort(compare)
for (var i=0;i<docLayers.length-1;i++){
if(isHor){
var deltaM = amt-(docLayers[i+1][1].bounds[0].value-docLayers[i][1].bounds[2].value)
docLayers[i+1][1].translate (deltaM, 0)
$.writeln(deltaM)
}
else{
var deltaM = amt-(docLayers[i+1][1].bounds[1].value-docLayers[i][1].bounds[3].value)
docLayers[i+1][1].translate (0, deltaM)
}
};
makeSingleActiveByIndex(selLay[0], true);//select only one layer to make the translations
//docRef.activeLayer = docRef.layers[docRef.layers.length-1]
makeActiveByIndex(selLay, true);//reset selection to all layers
}//end if to run
};//end function runProg
function compare(a,b){return a-b}
function getSelectedLayersIdx() {
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var desc = executeActionGet(ref);
if (desc.hasKey(stringIDToTypeID("targetLayers"))) {
desc = desc.getList(stringIDToTypeID("targetLayers"));
var c = desc.count
var selectedLayers = new Array();
for (var i = 0; i < c; i++) {
try {
docRef.backgroundLayer;
selectedLayers.push(desc.getReference(i).getIndex());
} catch (e) {
selectedLayers.push(desc.getReference(i).getIndex() + 1);
}
}
} else {
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("ItmI"));
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
try {
docRef.backgroundLayer;
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID("ItmI")) - 1);
} catch (e) {
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID("ItmI")));
}
}
return selectedLayers;
}
function makeActiveByIndex(idx, visible) {
for (var i = 0; i < idx.length; i++) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), idx[i])
desc.putReference(charIDToTypeID("null"), ref);
if (i > 0) {
var idselectionModifier = stringIDToTypeID("selectionModifier");
var idselectionModifierType = stringIDToTypeID("selectionModifierType");
var idaddToSelection = stringIDToTypeID("addToSelection");
desc.putEnumerated(idselectionModifier, idselectionModifierType, idaddToSelection);
}
desc.putBoolean(charIDToTypeID("MkVs"), visible);
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
if(checkLayerKind(docRef.activeLayer)){
if(isHor){var layerLeft = new Array(docRef.activeLayer.bounds[0],docRef.activeLayer)}
else{var layerLeft = new Array(docRef.activeLayer.bounds[1],docRef.activeLayer)}
docLayers.push(layerLeft)
}
}
};// end makeActiveByIndex
function makeSingleActiveByIndex(idx, visible) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), idx)
desc.putReference(charIDToTypeID("null"), ref);
/*if (i > 0) {
var idselectionModifier = stringIDToTypeID("selectionModifier");
var idselectionModifierType = stringIDToTypeID("selectionModifierType");
var idaddToSelection = stringIDToTypeID("addToSelection");
desc.putEnumerated(idselectionModifier, idselectionModifierType, idaddToSelection);
}*/
desc.putBoolean(charIDToTypeID("MkVs"), visible);
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
};//end makeSingleActiveByIndex
function checkLayerKind(lay){
if(lay.kind == LayerKind.NORMAL || lay.kind == LayerKind.TEXT || lay.kind == LayerKind.SOLIDFILL){return true}
else{return false}
};//end checkLayerKind
Copy link to clipboard
Copied
@Chuck Uebele – great work, thank you for sharing!
@Brian32453879u67v – looks like this latest script from Chuck is the correct answer.