• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
3

Can you automatically set the distance between objects?

Explorer ,
Dec 30, 2023 Dec 30, 2023

Copy link to clipboard

Copied

If I have 3 objects stacked one above the other and I want a  1" gap between them is there a way I can do this automatically? Say by selecting all 3 objects and then setting the verticle distance between them to 1" somewhere?

 

janee_0-1704024044907.png

 

TOPICS
Actions and scripting , macOS

Views

571

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe
Community Expert ,
Dec 30, 2023 Dec 30, 2023

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.

https://graphicdesign.stackexchange.com/questions/16152/how-to-distribute-an-equal-amount-of-space-b...

Scripts website:

https://morris-photographics.com/photoshop/scripts/index.html

Let us know if that helps!

Michelle

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 30, 2023 Dec 30, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 30, 2023 Dec 30, 2023

Copy link to clipboard

Copied

@Brian32453879u67v 

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 30, 2023 Dec 30, 2023

Copy link to clipboard

Copied

@Brian32453879u67v 

 

You can distribute vertically, but you cannot distribute a fixed amount in Photoshop, at least not out of the box.

janee_0-1703983994366.png

 

Illustrator lets you choose an amount for the distribution when you have a key object and lets you choose 1 inch. Photoshop does not.

janee_1-1703984335147.png

A script might work. Try the ones from mglush. I've also edited your post to include the Scripting topic.

 

Jane

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 30, 2023 Dec 30, 2023

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.

image.png

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 30, 2023 Dec 30, 2023

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 30, 2023 Dec 30, 2023

Copy link to clipboard

Copied

As the others have responded, it's all manual without a script.

 

1. Original spacing

2023-12-31_14-57-29.png

 

2. Remove all existing spacing

2023-12-31_14-57-38.png

 

3. Move the right-hand layer 2 inches over:2023-12-31_14-58-19.png

2023-12-31_14-58-41.png

 

4. Distribute the space equally horizontally using the move tool options bar:

2023-12-31_14-59-03.png

 

5. The final result – 2 x 1 inch spaces between the 3 distributed objects:

2023-12-31_15-01-01.png

 

So yes, it would be easier if it "just worked like Illustrator"!  :]

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 31, 2023 Dec 31, 2023

Copy link to clipboard

Copied

 

 

@Brian32453879u67v 

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 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

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

 

@Chuck Uebele 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

Copy link to clipboard

Copied

@Trevor.Dennis 

 

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 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

Copy link to clipboard

Copied

quote

...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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

Copy link to clipboard

Copied

I just have the normal script for this. I stopped doing CEP and haven't gotten into UXP panels.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jan 02, 2024 Jan 02, 2024

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

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. 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

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. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 01, 2024 Jan 01, 2024

Copy link to clipboard

Copied

@Chuck Uebele 

 

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):

2024-01-02_16-47-52.png

After (pink, green, brown):

2024-01-02_16-48-27.png

 

Does the for loop need reversing or is this something else?

 

EDIT: I don't think that it's the for loop...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jan 02, 2024 Jan 02, 2024

Copy link to clipboard

Copied

Editnumber is undocumented, of course. But yes I use it in some scripts.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 02, 2024 Jan 02, 2024

Copy link to clipboard

Copied

LATEST

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 02, 2024 Jan 02, 2024

Copy link to clipboard

Copied

@Stephen_A_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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 02, 2024 Jan 02, 2024

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines