Copy link to clipboard
Copied
Anyone can help me with the script for measuring the distance between two elements (layers) in Photoshop.
I know that there are smart guides . I need this funcionality as a script to apply correct margins/paddings in CSS
Layers should be selected by shift. It's works very similar in Adobe Dreamweaver Extract and Assets Extract.
OK.
The following script gives you this result. But it seems to me this is complete nonsense. ))
...// version no CS6 or no effects
var old_units = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
try { app.activeDocument.suspendHistory("Get Text Bounds", "var bounds = get_selected_layers_bounds()") } catch(e) { alert(e); }
try { executeAction( charIDToTypeID( "undo" ), undefined, DialogModes.NO ); } catch(e) { alert(e); }
app.preferences.rulerUnits = old_units;
Copy link to clipboard
Copied
I'm not sure if it's accurate with text, but you can use bounds to find the location of various layers, then do some math using the bounds:
var doc = activeDocument;
var layerBounds doc.activeLayer.bounds
//layerBounds[0] = left edge
//layerBounds[1] = top edge
//layerBounds[2] = right edge
//layerBounds[3] = bottom edge
I've found that it's best to convert these results to a number using parseFloat(), as sometime if you do math without converting, you get odd results.
Copy link to clipboard
Copied
Also do not forget about the property boundsNoEffects )
Copy link to clipboard
Copied
Chuck, can I get an array of active layers? Seems like if I select two layers with shift, Photoshop treats them as a single layer for defining bounds.
And... Where can I see all properties, subelements of doc, actieveLayer briefly - I'm newbie in PS scripting
Copy link to clipboard
Copied
A Photoshop document can have many element in different layer kinds and layers can be masked and effect added which effects layers visibility and effects can extend outside the layer with the effects. How would the script know which elements you are interested in measuring.
You show text layers. They can be mask and have effects all of the a layer's content may not be visible and effect can be rendered outside a layers bounds for the layer's composite view.
Copy link to clipboard
Copied
How would the script know which elements you are interested in measuring.
Layers should be selected by shift.
Copy link to clipboard
Copied
The active layer can be only one. If the layers are selected with Shift - this is called targetLayers. This is a list of indexes of the layer. Using it you can get any information about each of the selected layers. Just do not understand what and with what you are going to compare to determine the distance. What do you think is the distance between layers and which ones?
Copy link to clipboard
Copied
Two layers should be selected with shift key.
The distance is the distance - veritcal distance - between bottom border of top layer and top border of bottom layer.
30px on screenshot (from Adobe Assets Extract).... Could U provide script example with targetLayers?
Copy link to clipboard
Copied
OK. A simple example )
var old_units = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var bounds = get_selected_layers_bounds();
app.preferences.rulerUnits = old_units;
if (bounds)
{
if (bounds.length == 2)
{
if (bounds[0].bottom <= bounds[1].top)
alert("verilal distance: " + (bounds[1].top - bounds[0].bottom))
else if (bounds[1].bottom <= bounds[0].top)
alert("verilal distance: " + (bounds[0].top - bounds[1].bottom))
else
alert("intersected layers")
}
else
alert("More then 2 selected layers")
}
else
alert("There is no selected layers")
/////////////////////////////////////////////////////////////////////////////////////////////////
function get_selected_layers_bounds()
{
try {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID( "targetLayers" ) );
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if (!desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ) return null;
var selectedLayers = new Array;
var n = 0;
try { activeDocument.backgroundLayer } catch (e) { n = 1; }
desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
var len = desc.count;
var selected_bounds = new Array();
var d = new ActionDescriptor();
for (var i = 0; i < len; i++)
{
try
{
d.clear();
var r = new ActionReference();
r.putIndex( charIDToTypeID( "Lyr " ), desc.getReference(i).getIndex() + n);
d.putReference( charIDToTypeID( "null" ), r );
var ret = executeAction( charIDToTypeID( "getd" ), d, DialogModes.NO );
//var bounds = ret.getObjectValue(stringIDToTypeID("bounds")); // use this in CS6 or when you want to take into account the effects
var bounds = ret.getObjectValue(stringIDToTypeID("boundsNoEffects")); // in CS6 does not work
var obj = { left: bounds.getUnitDoubleValue(stringIDToTypeID("left")),
top: bounds.getUnitDoubleValue(stringIDToTypeID("top")),
right: bounds.getUnitDoubleValue(stringIDToTypeID("right")),
bottom: bounds.getUnitDoubleValue(stringIDToTypeID("bottom"))};
selected_bounds.push(obj);
}
catch (e)
{
alert(e);
return null;
}
}
return selected_bounds;
}
catch (e) { alert(e); return null; }
}
Copy link to clipboard
Copied
Didn't yeah.not want to measure from baseline of the top text-layer to the cap-line of the bottom-layer?
Copy link to clipboard
Copied
If you use Point text plus without letters protruding down, for example "Foobar", then this will be the required distance. I think, it is not possible to calculate the distance from the baseline (of the bottom line of the top text), although ...
r-bin, Tom If it will be possible to calculate this way - it will be excellent!!!
Copy link to clipboard
Copied
If you want to measure the distance between the baselines of the text, then it's very simple. The position of the baseline is specified in Layer.textItem.position or, in our case, in textClickPoint. If this is what you need, then it's easy. The truth is still no time. I'll do it later.
P.S. Just specify, is this what you need?
Copy link to clipboard
Copied
Temporarily replace all the symbols with the â–ˆ (SolidBlock symbol).
It was really cool idea! Full (solid) block covers 120% of font-size = PS leading auto or CSS line-height 120%. So the last thing.. really))... Should be applied updated and simplified formula
CSS = PS - (line-height_1 - 1.2 * font-size_1) / 2
- (line-height_2 - 1.2
* font-size_2) / 2
or in Photoshop Script syntax it should look something like this:
distance_in_css = distance - (Layer1.textItem.leading - 1.2 * Layer1.textItem.size) / 2
- (Layer2.textItem.leading - 1.2 * Layer2.textItem.size) / 2;
But I still do not understand how exactly this can be applied in the script. It's too hard for me
Copy link to clipboard
Copied
Here is the version with the text replaced with a symbol with the maximum height.
Check the distance that gives out the scrit with what you expect to get.
You can also get the position of the baseline, and for the paragraph text you can get the size of the bounding box.
But I do not know what to do with this, since I do not know what font parameters mean and I do not even understand CSS.
I have nothing more to offer you.(
var old_units = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
try { app.activeDocument.suspendHistory("Get Text Bounds", "var bounds = get_selected_layers_bounds()") } catch(e) { alert(e); }
try { executeAction( charIDToTypeID( "undo" ), undefined, DialogModes.NO ); } catch(e) { alert(e); }
app.preferences.rulerUnits = old_units;
if (bounds)
{
if (bounds.length == 2)
{
if (bounds[0].bottom <= bounds[1].top)
alert("Vertical distance: " + (bounds[1].top - bounds[0].bottom))
else if (bounds[1].bottom <= bounds[0].top)
alert("Vertical distance: " + (bounds[0].top - bounds[1].bottom))
else
alert("Intersecting layers")
}
else
alert("More then 2 selected layers")
}
else
alert("There is no selected layers")
/////////////////////////////////////////////////////////////////////////////////////////////////
function get_selected_layers_bounds()
{
try {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID( "Prpr" ), stringIDToTypeID( "targetLayers" ) );
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if (!desc.hasKey( stringIDToTypeID("targetLayers") ) ) return null;
var n = 0;
try { activeDocument.backgroundLayer } catch (e) { n = 1; }
desc = desc.getList( stringIDToTypeID("targetLayers"));
var len = desc.count;
var selected_bounds = new Array();
for (var i = 0; i < len; i++)
{
try
{
var r = new ActionReference();
r.putIndex( charIDToTypeID( "Lyr " ), desc.getReference(i).getIndex() + n);
var ret = executeActionGet(r);
if (ret.hasKey(stringIDToTypeID("textKey")))
{
var s = ret.getObjectValue(stringIDToTypeID("textKey")).getString(charIDToTypeID("Txt " ));
s = s.replace(/^./gm, String.fromCharCode(0x2588));
var d1 = new ActionDescriptor();
d1.putReference( charIDToTypeID( "null" ), r );
var d2 = new ActionDescriptor();
d2.putString( charIDToTypeID( "Txt " ), s);
d1.putObject( charIDToTypeID( "T " ), charIDToTypeID( "TxLr" ), d2 );
executeAction( charIDToTypeID( "setd" ), d1, DialogModes.NO );
ret = executeActionGet(r);
}
//var bounds = ret.getObjectValue(stringIDToTypeID("bounds")); // use this in CS6 or when you want to take into account the effects
var bounds = ret.getObjectValue(stringIDToTypeID("boundsNoEffects")); // in CS6 does not work
var obj = { left : bounds.getUnitDoubleValue(stringIDToTypeID("left")),
top : bounds.getUnitDoubleValue(stringIDToTypeID("top")),
right : bounds.getUnitDoubleValue(stringIDToTypeID("right")),
bottom: bounds.getUnitDoubleValue(stringIDToTypeID("bottom"))};
selected_bounds.push(obj);
}
catch (e)
{
alert(e);
return null;
}
}
return selected_bounds;
}
catch (e) { alert(e); return null; }
}
Copy link to clipboard
Copied
You have done a great job! It seems this is what I need and I will only have to take into account the line-height. Not the height of the text, as you might think, but what is called "leading" in Photoshop.
I'll try your script and to update the code. Let me do something by myself!)) Given that I forgot the mouse, this may take some time))).
Thank you again and Happy New Year!
Copy link to clipboard
Copied
r-bin​,
Hi, happy New Year!
Сan we finish the script? It remains to do a little bit.
Sorry if I'm distracting you from the holidays
Copy link to clipboard
Copied
It's not quite clear what's wrong with the script and what do not you get? Could you more precisely formulate the problem?
P.S. Happy New Year, too!
Copy link to clipboard
Copied
Hi there! The script is good, but not complete .
In CSS, the height of a single-line text block is equal to the line-height (leading), for a multi-line block the height = line-height * n, where n - number of lines.
In Photoshop, the height of a single-line text layer (pointed text) is determined by the boundaries of the letters in the line. Leading affects only the distance between lines in a multi-line text layer, but not the height of a single-line layer. The height will be determined by the letter boundaries - the upper bound of the first line and the lower bound of the last line.
I noticed that the height of a single-line text layer using a solid block in Photoshop corresponds to a line height 120% (auto). And the script, if I understand correctly, calculates the distance between two such lines. But what happens if the line height, for example, is 200% or 100%?
I hope I explained it normally...
So we obtain the formula (where distance is distance calculated by script):
distance_in_css
= distance
- (line-height_1 - 1.2 * font-size_1) / 2
- (line-height_2 - 1.2
* font-size_2) / 2
or in Photoshop Script syntax it should look something like this:
distance_in_css = distance - (Layer1.textItem.leading - 1.2 * Layer1.textItem.size) / 2
- (Layer2.textItem.leading - 1.2 * Layer2.textItem.size) / 2;
But I still do not understand how exactly this can be applied in the script. It's too hard for me
Copy link to clipboard
Copied
(Auto-)Leading is changable by script / user. There is no need to use 1.2 value as you can read current percent of autoleading by activeDocument.activeLayer.textItem.autoLeadingAmount / 100 on the condition auto leading was enabled by command activeDocument.activeLayer.textItem.useAutoLeading = true. That means you can change it to any other available value, so to not doing complex calculation set it back to 100 by activeDocument.activeLayer.textItem.autoLeadingAmount = 100
Copy link to clipboard
Copied
Ok, but leading still doesn't affect single-line text height - that is the problem.
Copy link to clipboard
Copied
In your image example what would be border of bottom layer if there was "y" letter in "Welcome" word like "Welcomey". Was that still actual bottom line (like it's now), or the line on the level of lowest "y" letter pixel?
If there was polish letter "Ó" (what is higher than any english letter in your second text layer) what should be top border of that layer, current one for regular letters or for the highest pixel in "Ó" letter?.
Or other example (Arial Regular, 12, leading 100%, 72 px/in resolution):
Welcome to...
(27 pixels)
ÓÓÓÓÓÓÓÓÓ
Welcome to...
(28 pixels)
jjjjjjjjjjjj
Welcome to...
(30 pixels)
AAAAAAAAA
Welcome to...
(32 pixels)
aaaaaaaaa
Would you like the distance between 'Welcome to' and another text layer was physical distance so like in example above, or 'text' distance where it measures height to letter top (of next layer) what gives always 30px (incl some pixels of empty space unfilled for certain letter, which are over that letter) ?
Copy link to clipboard
Copied
Honestly, I did not understand anything ). For me, the font parameters are similar to the Chinese grammar.
Could you draw two different text strings with a designation, roughly like in this figure, and indicate from which point and to what point do you want to measure the distance?
Copy link to clipboard
Copied
r-bin​, sorry for the delay - I was sick.
I still need a vertical distance between the two text layers, but given the line-height (leading). The script calculates the distance correctly for text with a line height of 120% (auto) - the â–ˆ (SolidBlock symbol) takes exactly this height. If it is less than or greater than 120% - in CSS the height will change, therefore the distance needs to be changed. Look at the screenshot, how it works in the browser (css) at different line-heights:
Copy link to clipboard
Copied
I do not know how to help you, because I do not understand where you get the line height of 70%, 120%, etc. and call it still leading. I do not find this in photoshop. There the concept of leading sets, as I understand it, the distance between the baselines of the lines.
In addition, it depends on the resolution of the document. See the screenshot.
Copy link to clipboard
Copied
You can not find it in Photoshop, because it's in the CSS . This was a screenshot from Chrome. In CSS there is a line-height and it can be set as a percentage of the font size or in pixels. In Photoshop, there is leading and it can be set to AUTO (corresponds to the line height of 120% of the font size) or in pixels, points, etc.
The the line-height in CSS determines the actual height of the text block (even 1 line of text!) AND the distance between the lines of text. The leading in PS determines ONLY the distance between lines of text. That's the problem.
Example - 2 single-line text layers.
1st - font size 100px, leading 120px (auto);
2nd - font size 100px, leading 200px.
The vertical distance between the boundaries of the layers is 50px.
The browser shows that the visual vertical distance between the blocks is somewhere around 100px because of the 200px line-height of the 2nd layer.