Is there a way to get the bounds of, for example, 3 linked layers? My script needs to change the position of the linked layers but, unfortunately, I am not able to extract the anchor point (x,y) of them (it only returns the x,y position of the layer selected in the Layers panel).
Any help will be more than appreciated.
Thanks a lot,
Alex
Getting bounds of a linked layer selection
-
Mike Hale
Getting bounds of a linked layer selection
Here is one way
Code: Select allgetLinkedLayersBounds();
function getLinkedLayersBounds(){
var linkedIDs = getLinkedLayersIDs();
var bounds = [];
for(var l =0; l<linkedIDs.length;l++){
bounds.push(boundsDescriptorToLayerBounds( getLayerBoundsLayerID(linkedIDs[l])));
}
var totalBounds = bounds[0];
for(var b = 1;b<bounds.length;b++){
if(bounds[0]<totalBounds[0]) totalBounds[0] = bounds[0];
if(bounds[1]<totalBounds[1]) totalBounds[1] = bounds[1];
if(bounds[2]>totalBounds[2]) totalBounds[2] = bounds[2];
if(bounds[3]>totalBounds[3]) totalBounds[3] = bounds[3];
}
return totalBounds;
};
function getLinkedLayersIDs(){
var idList = getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LnkL"));
if(idList == undefined) return;
var idArray = [];
idArray.push(getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LyrI")));
for(var l = 0;l<idList.count;l++){
idArray.push(idList.getInteger(l));
}
return idArray;
};
function getProperty( psClass, psKey, index ){// integer:Class, integer:key
var ref = new ActionReference();
if( psKey != undefined ) ref.putProperty( charIDToTypeID( "Prpr" ), psKey );
if(index != undefined ){
ref.putIndex( psClass, index );
}else{
ref.putEnumerated( psClass , charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
}
try{
var desc = executeActionGet(ref);
}catch(e){ return; }// return on error
if(desc.count == 0) return;// return undefined if property doesn't exists
var dataType = desc.getType(psKey);
switch(dataType){// not all types supported - returns undefined if not supported
case DescValueType.INTEGERTYPE:
return desc.getInteger(psKey);
break;
case DescValueType.ALIASTYPE:
return desc.getPath(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.UNITDOUBLE:
return desc.getUnitDoubleValue(psKey);
break;
case DescValueType.STRINGTYPE:
return desc.getString(psKey);
break;
case DescValueType.OBJECTTYPE:
return desc.getObjectValue(psKey);
break;
case DescValueType.LISTTYPE:
return desc.getList(psKey);
break;
case DescValueType.ENUMERATEDTYPE:
return desc.getEnumerationValue(psKey);
break;
}
};
function getLayerBoundsLayerID(id) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID("bounds"));
ref.putIdentifier( charIDToTypeID( "Lyr " ), id );
return executeActionGet(ref).getObjectValue(stringIDToTypeID("bounds"))
};
function boundsDescriptorToLayerBounds( desc ){
var bounds = [];
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Left")),'px'));
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Top ")),'px'));
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Rght")),'px'));
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Btom")),'px'));
return bounds;
};
Code: Select allgetLinkedLayersBounds();
function getLinkedLayersBounds(){
var linkedIDs = getLinkedLayersIDs();
var bounds = [];
for(var l =0; l<linkedIDs.length;l++){
bounds.push(boundsDescriptorToLayerBounds( getLayerBoundsLayerID(linkedIDs[l])));
}
var totalBounds = bounds[0];
for(var b = 1;b<bounds.length;b++){
if(bounds[0]<totalBounds[0]) totalBounds[0] = bounds[0];
if(bounds[1]<totalBounds[1]) totalBounds[1] = bounds[1];
if(bounds[2]>totalBounds[2]) totalBounds[2] = bounds[2];
if(bounds[3]>totalBounds[3]) totalBounds[3] = bounds[3];
}
return totalBounds;
};
function getLinkedLayersIDs(){
var idList = getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LnkL"));
if(idList == undefined) return;
var idArray = [];
idArray.push(getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LyrI")));
for(var l = 0;l<idList.count;l++){
idArray.push(idList.getInteger(l));
}
return idArray;
};
function getProperty( psClass, psKey, index ){// integer:Class, integer:key
var ref = new ActionReference();
if( psKey != undefined ) ref.putProperty( charIDToTypeID( "Prpr" ), psKey );
if(index != undefined ){
ref.putIndex( psClass, index );
}else{
ref.putEnumerated( psClass , charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
}
try{
var desc = executeActionGet(ref);
}catch(e){ return; }// return on error
if(desc.count == 0) return;// return undefined if property doesn't exists
var dataType = desc.getType(psKey);
switch(dataType){// not all types supported - returns undefined if not supported
case DescValueType.INTEGERTYPE:
return desc.getInteger(psKey);
break;
case DescValueType.ALIASTYPE:
return desc.getPath(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.UNITDOUBLE:
return desc.getUnitDoubleValue(psKey);
break;
case DescValueType.STRINGTYPE:
return desc.getString(psKey);
break;
case DescValueType.OBJECTTYPE:
return desc.getObjectValue(psKey);
break;
case DescValueType.LISTTYPE:
return desc.getList(psKey);
break;
case DescValueType.ENUMERATEDTYPE:
return desc.getEnumerationValue(psKey);
break;
}
};
function getLayerBoundsLayerID(id) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID("bounds"));
ref.putIdentifier( charIDToTypeID( "Lyr " ), id );
return executeActionGet(ref).getObjectValue(stringIDToTypeID("bounds"))
};
function boundsDescriptorToLayerBounds( desc ){
var bounds = [];
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Left")),'px'));
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Top ")),'px'));
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Rght")),'px'));
bounds.push(new UnitValue( desc.getUnitDoubleValue(charIDToTypeID("Btom")),'px'));
return bounds;
};
-
d3mac123
Getting bounds of a linked layer selection
Mike, sorry to bother you again. The script was working fine in almost all scenarios until I face this situation:
- I check manually the size of one of my selections and the Info panel says its size is 1046x714 positioned at 6,26;
- however your script returns 1052x768 positioned at 0,0
After extensive trial and error, I figured out that when I add a layer with "advanced blending options" (particularly disabling checkbox Transparency Shapes Layer), the calculations gets the discrepancy, which obviously this is "killing" my script auto positioning. Any idea on how to solve this issue with the blending mode?
Thanks a lot!
- I check manually the size of one of my selections and the Info panel says its size is 1046x714 positioned at 6,26;
- however your script returns 1052x768 positioned at 0,0
After extensive trial and error, I figured out that when I add a layer with "advanced blending options" (particularly disabling checkbox Transparency Shapes Layer), the calculations gets the discrepancy, which obviously this is "killing" my script auto positioning. Any idea on how to solve this issue with the blending mode?
Thanks a lot!
-
Mike Hale
Getting bounds of a linked layer selection
Well I threw that together just to see if I could get the bounds using only Action Manger and not using any historyStates. I didn't know that the Action Manger bounds would be different than the DOM bounds if there were blending settings.
I can think of other ways to do this but would use several historyStates. Let me throw something together and I will post it later. But let me make sure I am clear. If you manually load each linked layer as a selection the combined selection is correct? That is how I tested that the results of the first script was accurate but of course didn't test with blending options.
I can think of other ways to do this but would use several historyStates. Let me throw something together and I will post it later. But let me make sure I am clear. If you manually load each linked layer as a selection the combined selection is correct? That is how I tested that the results of the first script was accurate but of course didn't test with blending options.
-
d3mac123
Getting bounds of a linked layer selection
Without the "advanced blending options" the results are correct.
Thanks a lot for your support here.
Thanks a lot for your support here.
-
Mike Hale
Getting bounds of a linked layer selection
It seems that even the DOM layer bounds are wrong if the layer has Transparency Shapes Layer off. This seem to work by using the selection bounds of all the linked layers. Assumes the activeLayer has linked layers.
Code: Select allapp.activeDocument.selection.deselect();
var linkedIDs = getLinkedLayersIDs();
makeLayerActiveByID( linkedIDs[0] );
loadLayerTransparencyToSelection(linkedIDs[0]);
for(var l =1;l<linkedIDs.length;l++){
makeLayerActiveByID( linkedIDs[l] );
addLayerTransparencyToSelection(linkedIDs[l]);
}
var bounds = app.activeDocument.selection.bounds;
// app.activeDocument.selection.deselect();
alert(bounds);
function getLinkedLayersIDs(){
var idList = getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LnkL"));
if(idList == undefined) return;
var idArray = [];
idArray.push(getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LyrI")));
for(var l = 0;l<idList.count;l++){
idArray.push(idList.getInteger(l));
}
return idArray;
};
function getProperty( psClass, psKey, index ){// integer:Class, integer:key
var ref = new ActionReference();
if( psKey != undefined ) ref.putProperty( charIDToTypeID( "Prpr" ), psKey );
if(index != undefined ){
ref.putIndex( psClass, index );
}else{
ref.putEnumerated( psClass , charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
}
try{
var desc = executeActionGet(ref);
}catch(e){ return; }// return on error
if(desc.count == 0) return;// return undefined if property doesn't exists
var dataType = desc.getType(psKey);
switch(dataType){// not all types supported - returns undefined if not supported
case DescValueType.INTEGERTYPE:
return desc.getInteger(psKey);
break;
case DescValueType.ALIASTYPE:
return desc.getPath(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.UNITDOUBLE:
return desc.getUnitDoubleValue(psKey);
break;
case DescValueType.STRINGTYPE:
return desc.getString(psKey);
break;
case DescValueType.OBJECTTYPE:
return desc.getObjectValue(psKey);
break;
case DescValueType.LISTTYPE:
return desc.getList(psKey);
break;
case DescValueType.ENUMERATEDTYPE:
return desc.getEnumerationValue(psKey);
break;
}
};
function addLayerTransparencyToSelection() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('null'), ref );
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('T '), ref );
executeAction( charIDToTypeID('Add '), desc, DialogModes.NO );
};
function loadLayerTransparencyToSelection() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function makeLayerActiveByID( amID ){
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier( charIDToTypeID( "Lyr " ), amID );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
return activeDocument.activeLayer;
}catch(e){}
};
Code: Select allapp.activeDocument.selection.deselect();
var linkedIDs = getLinkedLayersIDs();
makeLayerActiveByID( linkedIDs[0] );
loadLayerTransparencyToSelection(linkedIDs[0]);
for(var l =1;l<linkedIDs.length;l++){
makeLayerActiveByID( linkedIDs[l] );
addLayerTransparencyToSelection(linkedIDs[l]);
}
var bounds = app.activeDocument.selection.bounds;
// app.activeDocument.selection.deselect();
alert(bounds);
function getLinkedLayersIDs(){
var idList = getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LnkL"));
if(idList == undefined) return;
var idArray = [];
idArray.push(getProperty(charIDToTypeID("Lyr "), charIDToTypeID("LyrI")));
for(var l = 0;l<idList.count;l++){
idArray.push(idList.getInteger(l));
}
return idArray;
};
function getProperty( psClass, psKey, index ){// integer:Class, integer:key
var ref = new ActionReference();
if( psKey != undefined ) ref.putProperty( charIDToTypeID( "Prpr" ), psKey );
if(index != undefined ){
ref.putIndex( psClass, index );
}else{
ref.putEnumerated( psClass , charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
}
try{
var desc = executeActionGet(ref);
}catch(e){ return; }// return on error
if(desc.count == 0) return;// return undefined if property doesn't exists
var dataType = desc.getType(psKey);
switch(dataType){// not all types supported - returns undefined if not supported
case DescValueType.INTEGERTYPE:
return desc.getInteger(psKey);
break;
case DescValueType.ALIASTYPE:
return desc.getPath(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.BOOLEANTYPE:
return desc.getBoolean(psKey);
break;
case DescValueType.UNITDOUBLE:
return desc.getUnitDoubleValue(psKey);
break;
case DescValueType.STRINGTYPE:
return desc.getString(psKey);
break;
case DescValueType.OBJECTTYPE:
return desc.getObjectValue(psKey);
break;
case DescValueType.LISTTYPE:
return desc.getList(psKey);
break;
case DescValueType.ENUMERATEDTYPE:
return desc.getEnumerationValue(psKey);
break;
}
};
function addLayerTransparencyToSelection() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('null'), ref );
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('T '), ref );
executeAction( charIDToTypeID('Add '), desc, DialogModes.NO );
};
function loadLayerTransparencyToSelection() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Chnl'), charIDToTypeID('fsel') );
desc.putReference( charIDToTypeID('null'), ref );
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Trsp') );
desc.putReference( charIDToTypeID('T '), ref );
executeAction( charIDToTypeID('setd'), desc, DialogModes.NO );
};
function makeLayerActiveByID( amID ){
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier( charIDToTypeID( "Lyr " ), amID );
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
return activeDocument.activeLayer;
}catch(e){}
};
-
d3mac123
Getting bounds of a linked layer selection
The selection works perfectly, unfortunately I am having hard time to returning it to its original position. My current script does that:
- gets all linked layers and get the boundaries
- using the original selected layer, gets its position
- user input the new position of the layer (to be used later)
- app.refresh() shows where the linked layer will be with the entered input
- clicking OK (or cancel), saves the future position and returns to original position. I do that with the following code:
Code: Select allvar a = parseInt(layerX) - parseInt(activeDocument.activeLayer.bounds[0].value)
var b = parseInt(layerY) - parseInt(activeDocument.activeLayer.bounds[1].value)
translateActiveLayer(a,b);
function translateActiveLayer( deltaX, deltaY ) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var coords = new ActionDescriptor();
coords.putUnitDouble( charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), deltaX );
coords.putUnitDouble( charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), deltaY );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Ofst'), coords );
executeAction( charIDToTypeID('move'), desc, DialogModes.NO );
};
layerX and layerY holds the original activeLayer position before all the input
With the you new code:
- gets all linked layers and get the boundaries
- using the original selected layer, gets its position
- user input the new position of the layer (to be used later)
- app.refresh() shows where the linked layer will be with the entered input
Till here every thing is fine.
- clicking OK (or cancel), saves the future position and returns to original position.
Here the issue happens because, now the selection does not match the original position anymore so, instead of returning to the original position, the selection goes to a different place.
In my current example, the "manual" selection shows x,y: 6,26 and w/h: 1046,714
Your script boundaries shows: x,y: 6,26 and w/h: 1046,714 (the same)
If I leave my input fields as 6 and 26 (same as original position, meaning NO movements). When I hit cancel, the selection goes to x,y: 644,189
Let me know if you want me to send you my sample file (too big to be uploaded here).
- gets all linked layers and get the boundaries
- using the original selected layer, gets its position
- user input the new position of the layer (to be used later)
- app.refresh() shows where the linked layer will be with the entered input
- clicking OK (or cancel), saves the future position and returns to original position. I do that with the following code:
Code: Select allvar a = parseInt(layerX) - parseInt(activeDocument.activeLayer.bounds[0].value)
var b = parseInt(layerY) - parseInt(activeDocument.activeLayer.bounds[1].value)
translateActiveLayer(a,b);
function translateActiveLayer( deltaX, deltaY ) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
var coords = new ActionDescriptor();
coords.putUnitDouble( charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), deltaX );
coords.putUnitDouble( charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), deltaY );
desc.putObject( charIDToTypeID('T '), charIDToTypeID('Ofst'), coords );
executeAction( charIDToTypeID('move'), desc, DialogModes.NO );
};
layerX and layerY holds the original activeLayer position before all the input
With the you new code:
- gets all linked layers and get the boundaries
- using the original selected layer, gets its position
- user input the new position of the layer (to be used later)
- app.refresh() shows where the linked layer will be with the entered input
Till here every thing is fine.
- clicking OK (or cancel), saves the future position and returns to original position.
Here the issue happens because, now the selection does not match the original position anymore so, instead of returning to the original position, the selection goes to a different place.
In my current example, the "manual" selection shows x,y: 6,26 and w/h: 1046,714
Your script boundaries shows: x,y: 6,26 and w/h: 1046,714 (the same)
If I leave my input fields as 6 and 26 (same as original position, meaning NO movements). When I hit cancel, the selection goes to x,y: 644,189
Let me know if you want me to send you my sample file (too big to be uploaded here).
-
Mike Hale
Getting bounds of a linked layer selection
Sorry, I don't understand.
If your original script works why not use that.
The x,y position of all the linked layer may be different that the activeLayer. Even if it's not different activeLayer.bounds returns the wrong values if that layer has the blend setting.
You might try to undo the first translate to restore the original position instead of trying to move it back with another translate step. Or store the values used in the first translate and invert those for the move back.
Your original question was about how to get the total bounds of all the linked layers. And you haven't posted enough of your script for me to understand what it is doing. BTW translate() is a layer method, you don't need Action Manager
app.activeDocument.activeLayer.translate( deltaX, deltaY);
And app.activeDocument.activeLayer.bounds[0].value property returns a number, you don't need the parseInt().
If your original script works why not use that.
The x,y position of all the linked layer may be different that the activeLayer. Even if it's not different activeLayer.bounds returns the wrong values if that layer has the blend setting.
You might try to undo the first translate to restore the original position instead of trying to move it back with another translate step. Or store the values used in the first translate and invert those for the move back.
Your original question was about how to get the total bounds of all the linked layers. And you haven't posted enough of your script for me to understand what it is doing. BTW translate() is a layer method, you don't need Action Manager
app.activeDocument.activeLayer.translate( deltaX, deltaY);
And app.activeDocument.activeLayer.bounds[0].value property returns a number, you don't need the parseInt().
-
d3mac123
Getting bounds of a linked layer selection
I'll review my code (thanks for the tips) as soon as I return from a trip starting tomorrow.
Thanks again!
Thanks again!