Copy link to clipboard
Copied
Hey guys. I found myself in a trouble. Here's a screenshot.
I need to get Group size, however, Levels effect seems to brake it:/
app.activeDocument.activeLayer.boundsNoEffects;
If Groups is selected, it returns 0 px,0 px,500 px,500 px
If LAYER is selected, it returns 125 px,200 px,375 px,300 px
So my question is - is it possible to ignore Levels Size? Because they brake my calculations, and I need to get a result 125 px,200 px,375 px,300 px if Group is selected. Is this somehow doable?
Here is code without Lexicon library. I can't share library because is experimental and not done yet.
It takes 500ms per 1018 layers. And 77ms per 179 layers on my old PC 🙂
JJMack: you are wrong. This is "or" condition. I am skiping clipped layer and/or adjustment. Not clipped adjustment.
...var groupIndex = app.activeDocument.activeLayer.itemIndex;
function calculateGroupSize(index){
var maxBounds = {
left : null,
top : null,
right : null,
bottom
Copy link to clipboard
Copied
The only way I think you can get around this is a clumsy workaround. Get the code to dupe the layer group, merge the copy of the group, get your layer bounds, then delete the duped group.
Copy link to clipboard
Copied
Faster approach would be traverse all layers inside group with AM code get layer bounds and exclude some kind of layers. And then merge your bound with mathematica. (find maximum and minimum value in arrays)
This could be 10-50× faster. Reading descriptors with AM code is pretty fast. Duplicating merging and removing could take 30ms per each action. Properly written AM could do this in less than 5ms.
I will likely write this code in next days for UnSmart 2.0 script 🙂
Copy link to clipboard
Copied
Maybe action manager code could return different values.
Copy link to clipboard
Copied
Descriptor for the Group has "bounds", "boundsNoEffects" and "boundsNoMask", but each one of them sports the full bound (so in Tomas case 0,0,500,500).
No luck!
Davide
Copy link to clipboard
Copied
In your group you have clipped the levels adjustment layer levels 1 to the shape or smart object layer LAYER. LAYER has a bounds less than canvas size. The levels adjustment does not effect the any layers below that layer LAYER because it is clipped to the layer LAYER. An alternate method would be instead of clipping the adjustment layer levels 1 you could mask the adjustment layer to the layer LAYER transparency. You could do the same to the clipped Adjustment levels 1 even. Either way the bounds of the adjustment layer levels 1 would have the same bounds as layer LAYER. So would the group.
Copy link to clipboard
Copied
JJMack​ I am having real trouble understanding what you wrote.
And Davide Barranca​ is right, those methods still return same size as the canvas.
Jarda Bereza​ might be on a track of making it work. I thought of traversing all the layers and collecting their bounding box size and then calculating the overall size, but it smells as a hacky way to do so. If it could be done with AM logic, that would be great. However, I am rather new to PSD scripting and I find AM to be rather tricky t get a grasp on.
Jarda Bereza​ if you figure out the way to do that with AM, would you be willing to share your workflow?
Thanks.
Copy link to clipboard
Copied
Let me try a different way to explain way I wrote and include some screen captures.
An adjustment layer bounds is the same as the document canvas size unless masked and applies to all lower layer. You constrain an adjustment to fewer layer be segregating it within a layer group and clipping it to a particular layer. You can also constrain the adjustment to a selection via a layer mask. Transparency can change a layer bounds. The layer bounds will be the bounds of pixels in the layer mask.
To me it looks like you only want the levels adjustment layer to apply to the layer named LAYER. There are many ways to do that....
Here is a little script that show the active layer size bounds and position relative to the canvas. I will use it on layer Group see the differences,
// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher
// bring application forward for double-click events
app.bringToFront();
// Save the current preferences
var startRulerUnits = app.preferences.rulerUnits;
// Set Photoshop to use pixels
app.preferences.rulerUnits = Units.PIXELS;
try{
var LB = activeDocument.activeLayer.bounds;
var LWidth = (LB[2].value) - (LB[0].value);
var LHeight = (LB[3].value) - (LB[1].value);
MarkX((LB[0].value + LWidth/2));
MarkX(LB[0].value);
MarkX(LB[2].value);
MarkY((LB[1].value + LHeight/2));
MarkY(LB[1].value)
MarkY(LB[3].value)
alert("'" + activeDocument.activeLayer.name + "' Layer Bounds\nTop Left " + LB[0].value + "X," + LB[1].value + "Y Bottom Right " + LB[2].value + "X," + LB[3].value
+ "Y\nWidth " + LWidth + "px Height " + LHeight +"px"
+ "\nLayer center relative to canvas " + (LB[0].value + LWidth/2) + "X," + (LB[1].value + LHeight/2) +"Y"
);
}
catch(e){alert("Requires a layer targered");}
// Return the app preferences
app.preferences.rulerUnits = startRulerUnits;
function MarkX(x) {
// =======================================================
var idMk = charIDToTypeID( "Mk " );
var desc61 = new ActionDescriptor();
var idNw = charIDToTypeID( "Nw " );
var desc62 = new ActionDescriptor();
var idPstn = charIDToTypeID( "Pstn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc62.putUnitDouble( idPstn, idPxl, x);
var idOrnt = charIDToTypeID( "Ornt" );
var idOrnt = charIDToTypeID( "Ornt" );
var idVrtc = charIDToTypeID( "Vrtc" );
desc62.putEnumerated( idOrnt, idOrnt, idVrtc );
var idGd = charIDToTypeID( "Gd " );
desc61.putObject( idNw, idGd, desc62 );
executeAction( idMk, desc61, DialogModes.NO );
}
function MarkY(y) {
// =======================================================
var idMk = charIDToTypeID( "Mk " );
var desc63 = new ActionDescriptor();
var idNw = charIDToTypeID( "Nw " );
var desc64 = new ActionDescriptor();
var idPstn = charIDToTypeID( "Pstn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc64.putUnitDouble( idPstn, idPxl, y );
var idOrnt = charIDToTypeID( "Ornt" );
var idOrnt = charIDToTypeID( "Ornt" );
var idHrzn = charIDToTypeID( "Hrzn" );
desc64.putEnumerated( idOrnt, idOrnt, idHrzn );
var idGd = charIDToTypeID( "Gd " );
desc63.putObject( idNw, idGd, desc64 );
executeAction( idMk, desc63, DialogModes.NO );
}
Copy link to clipboard
Copied
Try this:
Seems to work for me. You will need replace some function from lx. library with your own. But is obvious what it should do.
And it should be very very fast. It uses linear layers traversing.
#include A:\programovani\PSDmagic\[Lx]\Lexicon-0.1.jsxinc
var layerID = lx.getSelectedLayersId();
calculateGroupSize(layerID);
function calculateGroupSize(layerID){
var maxBounds = {
left : null,
top : null,
right : null,
bottom : null
}
var index = lx.convertLayerIdToIndex(layerID);
for(var i = index-1, level=0; level >= 0 ; i--){
var desc = lx.getLayerDescriptor(i); // i = index
var clipped = desc.getBoolean(stringIDToTypeID('group'));
var isAdjustmentLayer = desc.getInteger(stringIDToTypeID('layerKind')) === 2;
if(clipped || isAdjustmentLayer){continue;} //skip this layer
var layerSection = typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection')));
if(layerSection==="layerSectionStart"){
level++
}
else if(layerSection==="layerSectionEnd"){
level--
}
else{
var bounds = desc.getObjectValue(stringIDToTypeID('bounds'));
if(maxBounds.left === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('left'));}
if(maxBounds.top === null) {maxBounds.top = bounds.getUnitDoubleValue(stringIDToTypeID('top'));}
if(maxBounds.right === null) {maxBounds.right = bounds.getUnitDoubleValue(stringIDToTypeID('right'));}
if(maxBounds.bottom === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('bottom'));}
maxBounds.left = Math.min(maxBounds.left, bounds.getUnitDoubleValue(stringIDToTypeID('left')));
maxBounds.top = Math.min(maxBounds.top, bounds.getUnitDoubleValue(stringIDToTypeID('top')));
maxBounds.right = Math.max(maxBounds.right, bounds.getUnitDoubleValue(stringIDToTypeID('right')));
maxBounds.bottom = Math.max(maxBounds.bottom, bounds.getUnitDoubleValue(stringIDToTypeID('bottom')));
}
}
return maxBounds;
}
Copy link to clipboard
Copied
I do not have your script library files so I can not test that code, It look like it skips adjustment layers if clipped. In his layered document it does not look like the levels 1 adjustment layer is clipped its an adjustment layer above layer LAYER in layer group Group.
not
Copy link to clipboard
Copied
That looks interesting, but hard to test without your lx library. Any chance you could share that?
Copy link to clipboard
Copied
Here is code without Lexicon library. I can't share library because is experimental and not done yet.
It takes 500ms per 1018 layers. And 77ms per 179 layers on my old PC 🙂
JJMack: you are wrong. This is "or" condition. I am skiping clipped layer and/or adjustment. Not clipped adjustment.
var groupIndex = app.activeDocument.activeLayer.itemIndex;
function calculateGroupSize(index){
var maxBounds = {
left : null,
top : null,
right : null,
bottom : null
}
for(var i = index-1, level=0; level >= 0 ; i--){
var desc = getLayerDescriptor(i); // i = index
var clipped = desc.getBoolean(stringIDToTypeID('group'));
var isAdjustmentLayer = desc.getInteger(stringIDToTypeID('layerKind')) === 2;
if(clipped || isAdjustmentLayer){continue;} //skip this layer
var layerSection = typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection')));
if(layerSection==="layerSectionStart"){
level++
}
else if(layerSection==="layerSectionEnd"){
level--
}
else{
var bounds = desc.getObjectValue(stringIDToTypeID('bounds'));
if(maxBounds.left === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('left'));}
if(maxBounds.top === null) {maxBounds.top = bounds.getUnitDoubleValue(stringIDToTypeID('top'));}
if(maxBounds.right === null) {maxBounds.right = bounds.getUnitDoubleValue(stringIDToTypeID('right'));}
if(maxBounds.bottom === null) {maxBounds.left = bounds.getUnitDoubleValue(stringIDToTypeID('bottom'));}
maxBounds.left = Math.min(maxBounds.left, bounds.getUnitDoubleValue(stringIDToTypeID('left')));
maxBounds.top = Math.min(maxBounds.top, bounds.getUnitDoubleValue(stringIDToTypeID('top')));
maxBounds.right = Math.max(maxBounds.right, bounds.getUnitDoubleValue(stringIDToTypeID('right')));
maxBounds.bottom = Math.max(maxBounds.bottom, bounds.getUnitDoubleValue(stringIDToTypeID('bottom')));
}
}
return maxBounds;
}
var getLayerDescriptor = function (index) { //todo reference param
var ref = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
ref.putIndex( idLyr, index );
var desc = executeActionGet(ref);
return desc;
}
var bounds = calculateGroupSize(groupIndex);
alert("\n left: " + bounds.left +"\n top: " + bounds.top +"\n right: " + bounds.right +"\n bottom: " + bounds.bottom);
.
Copy link to clipboard
Copied
Yes I do not know javascript so much of the code I do not understand. I jumped to the wrong conclusion. Most of the javascript code where I see .getxxx(yyyy) i have to take on faith or guess. Can't guess right all the time.
Copy link to clipboard
Copied
Appologies for taking long time to reply Jarda Bereza​
I jumped to conclusion too fast. Script has crashing if I had Background layer in the document. Once I removed it, it seems to work.
Will give more testing to it.
Thanks man.
Unfortunately, script crashes on var desc = executeActionGet(ref); with error Error 8800: General Photoshop error occurred. This functionality may not be available in this version of Photoshop. However, I have layerSet "Group" selected in the dome before executing the script.
Script seems to run fine if I have shape layer selected, but, unfortunately, crashes with layerSet selected.
Any chance you know why?
Copy link to clipboard
Copied
maybe background layer issue
increment index by +1 at row 53 if background layer exists.
Copy link to clipboard
Copied
yeap, seems as if background layer was messing it up.