transform multiple layers individually in one go

Use this Forum for Beta-Testing your Photoshop Scripts

Moderators: Tom, Kukurykus

pfaffenbichler

transform multiple layers individually in one go

Post by pfaffenbichler »

In the Photoshop Feature Request Forum the ability to free transform multiple objects has been requested a while back.
http://forums.adobe.com/thread/768368?tstart=0
The best I could come up with so far is a dialog with sliders as that seems to allow a preview for all affected layers.

I’d appreciate it if any one of you could give the Script a look to see if any Scripting-atrocities are contained.

Happy New Year,
C.Pfaffenbichler

Code: Select all// scale and/or rotate multiple selected layers and groups with dialog;
// selected pixel-layers and groups are converted to smart objects if not such already;
// groups take precedent over contained layers and naturally adjustment layers situated in a selected group will subsequently only affect that;
// adjustment layers are edited only if masked;
// thanks to xbytor, jeffrey tranberry, mike hale and paul riggott;
// 2010, pfaffenbichler; use it at your own risk;
#target photoshop
// check and get back array of selected layers;
var checksOut = true;
checksOut = checkPhotoshop(checksOut);
if (checksOut[0] == true) {
// define document;
var myDocument = app.activeDocument;
myDocument.selection.deselect();
// set the history states;
var histStates = historyStates();
var memUsage = memoryUsage();
if (histStates < checksOut[1].length * 2 + 1) {
   setHistoryStates (checksOut[1].length * 2 + 1, memUsage)
   };
var theFirstState = myDocument.activeHistoryState;
// smartify the layers;
var theLayers = getSelectedLayersAndSmartify(myDocument);
var thisState = myDocument.activeHistoryState;
////////////////////////////////////
// the dialog;
var dlg = new Window("dialog", "scale the selected layers", [500,300,840,500]);   
// scale;
dlg.scale = dlg.add('panel', [15,15,325,65], 'scale');
dlg.scale.slider = dlg.scale.add('slider', [12,12,300,32], 500);
dlg.scale.slider.value = 20;
dlg.scale.slider.onChange = scaleTheLayers;
// rotate;
dlg.rotate = dlg.add('panel', [15,75,325,125], 'rotate');
dlg.rotate.slider = dlg.rotate.add('slider', [12,12,300,32], 360);
dlg.rotate.slider.value = 50;
dlg.rotate.slider.onChange = scaleTheLayers;
// buttons for ok and cancel;
dlg.buttons = dlg.add('panel', [15,135,325,185], '');
dlg.buttons.buildBtn = dlg.buttons.add('button', [13,12,145,34], 'OK', {name:'ok'});
dlg.buttons.cancelBtn = dlg.buttons.add('button', [155,12,290,34], 'Cancel', {name:'cancel'});
// show the dialog;
dlg.center();
var myReturn = dlg.show ();
////////////////////////////////////
if (myReturn == 1) {
// select the layers;
   reselectLayers (myDocument, theLayers);
   }
else {
// go back in history and select the layers;
   myDocument.activeHistoryState = theFirstState;
   reselectLayers (myDocument, checksOut[1]);
   };
// reset the history states;
setHistoryStates (histStates, memUsage);
};
////////////////////////////////////
////// scale the layers //////
function scaleTheLayers () {
   app.activeDocument.suspendHistory("scale__"+(String(dlg.scale.slider.value * 5).slice(0,7))+"%_rotate_"+(String(dlg.rotate.slider.value * 3.6 - 180).slice(0,7))+"˚", "main()");   
function main () {
   app.activeDocument.activeHistoryState = thisState;
   var theScale = dlg.scale.slider.value * 5;
   var theRotate = dlg.rotate.slider.value * 3.6 - 180;
   for (var m = 0; m < theLayers.length; m++) {
      try {
         myDocument.activeLayer = theLayers[m];
// =======================================================
var idTrnf = charIDToTypeID( "Trnf" );
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref2 = new ActionReference();
        var idLyr = charIDToTypeID( "Lyr " );
        var idOrdn = charIDToTypeID( "Ordn" );
        var idTrgt = charIDToTypeID( "Trgt" );
        ref2.putEnumerated( idLyr, idOrdn, idTrgt );
    desc3.putReference( idnull, ref2 );
    var idFTcs = charIDToTypeID( "FTcs" );
    var idQCSt = charIDToTypeID( "QCSt" );
    var idQcsa = charIDToTypeID( "Qcsa" );
    desc3.putEnumerated( idFTcs, idQCSt, idQcsa );
    var idOfst = charIDToTypeID( "Ofst" );
        var desc4 = new ActionDescriptor();
        var idHrzn = charIDToTypeID( "Hrzn" );
        var idPxl = charIDToTypeID( "#Pxl" );
        desc4.putUnitDouble( idHrzn, idPxl, 0.000000 );
        var idVrtc = charIDToTypeID( "Vrtc" );
        var idPxl = charIDToTypeID( "#Pxl" );
        desc4.putUnitDouble( idVrtc, idPxl, -0.000000 );
    var idOfst = charIDToTypeID( "Ofst" );
    desc3.putObject( idOfst, idOfst, desc4 );
    var idWdth = charIDToTypeID( "Wdth" );
    var idPrc = charIDToTypeID( "#Prc" );
    desc3.putUnitDouble( idWdth, idPrc, theScale );
    var idHght = charIDToTypeID( "Hght" );
    var idPrc = charIDToTypeID( "#Prc" );
    desc3.putUnitDouble( idHght, idPrc, theScale );
    var idAngl = charIDToTypeID( "Angl" );
    var idAng = charIDToTypeID( "#Ang" );
    desc3.putUnitDouble( idAngl, idAng, theRotate );
    var idLnkd = charIDToTypeID( "Lnkd" );
    desc3.putBoolean( idLnkd, true );
executeAction( idTrnf, desc3, DialogModes.NO );
         }
         catch (e) {}
      };
   app.refresh()
   }
};
////// check if file is eligible for this script //////
function checkPhotoshop(checksOut) {
if (app.documents.length == 0) {
   alert("no documents are open\nplease open a document and try again");
   checksOut = false
   }
else {
   if (app.activeDocument.mode == DocumentMode.BITMAP || app.activeDocument.mode == DocumentMode.INDEXEDCOLOR || app.activeDocument.mode == DocumentMode.MULTICHANNEL) {
      alert("the current document cannot have layers");
      checksOut = false
      }
   else {
      var theLayers = getSelectedLayers(app.activeDocument);
      if (theLayers.length < 2) {
         alert("the current document does not have more than one layer selected");
         checksOut = false
         }
      };
   };
return [checksOut, theLayers]
};
////// function collect all layers //////
function collectLayers (theParent) {
   if (!allLayers) {
      var allLayers = new Array}
   else {};
   for (var m = theParent.layers.length - 1; m >= 0;m--) {
      var theLayer = theParent.layers[m];
// apply the function to layersets;
      if (theLayer.typename == "ArtLayer") {
         allLayers.push(theLayer)
         }
      else {
         allLayers = allLayers.concat(collectLayers(theLayer))
// this line includes the layer groups;
         allLayers.push(theLayer);
         }
      }
   return allLayers
   };
////// adapted from an xbytor script, thanks to xbytor //////
function getSelectedLayers (doc) {
   var layers = collectLayers(doc);
   var visible = [];
   var selLayers = [];
   for (var i = 0; i < layers.length; i++) {
      var l = layers;
      visible = l.visible;
      l.visible = true;
      };
////// hide selected;
   var id807 = charIDToTypeID( "Hd  " );
   var desc161 = new ActionDescriptor();
   var id808 = charIDToTypeID( "null" );
   var ref116 = new ActionReference();
   var id809 = charIDToTypeID( "Lyr " );
   var id810 = charIDToTypeID( "Ordn" );
   var id811 = charIDToTypeID( "Trgt" );
   ref116.putEnumerated( id809, id810, id811 );
   desc161.putReference( id808, ref116 );
   executeAction( id807, desc161, DialogModes.NO );
////// collect invisibles;
   for (var i = 0; i < layers.length; i++) {
      var l = layers;
      if (!l.visible) {
         selLayers.push(l);         
         };
      l.visible = visible;
      };
   return selLayers;
   };
////// adapted from an xbytor script, thanks to xbytor //////
function getSelectedLayersAndSmartify (doc) {
   var layers = collectLayers(doc);
   var visible = [];
   var selLayers = [];
   for (var i = 0; i < layers.length; i++) {
      var l = layers;
      visible = l.visible;
      l.visible = true;
      };
////// hide selected;
   var id807 = charIDToTypeID( "Hd  " );
   var desc161 = new ActionDescriptor();
   var id808 = charIDToTypeID( "null" );
   var ref116 = new ActionReference();
   var id809 = charIDToTypeID( "Lyr " );
   var id810 = charIDToTypeID( "Ordn" );
   var id811 = charIDToTypeID( "Trgt" );
   ref116.putEnumerated( id809, id810, id811 );
   desc161.putReference( id808, ref116 );
   executeAction( id807, desc161, DialogModes.NO );
////// collect invisibles;
   for (var i = 0; i < layers.length; i++) {
      var l = layers;
      if (!l.visible) {
         selLayers.push(l);
         };
      l.visible = visible;
      };
// filter out layers within selected groups and smartify pixel layers and groups;
var theLayers = new Array;
for (var m = 0; m < selLayers.length; m++) {
   var thisLayer = selLayers[m];
   var check = true;
   for (var n = 0; n < selLayers.length; n++) {
      var theCheckLayer = selLayers[n];
      var theParent = thisLayer.parent;
      while (theParent != app.activeDocument) {
         if (theParent == theCheckLayer) {
            check = false;
            };
         theParent = theParent.parent
         }
      };
   if (check == true) {theLayers.push(thisLayer)}
   };
// smartify;
var theFinalLayers = new Array;
for (var n = 0; n < theLayers.length; n++) {
   var thisLayer = smartify2010(theLayers[n]);
   if (thisLayer != false) {theFinalLayers.push(thisLayer)}
   };
   return theFinalLayers;
   };
////// function to smartify if not //////
function smartify2010 (theLayer) {
// make layers smart objects if they are not already;
   app.activeDocument.activeLayer = theLayer;
// process pixel-layers and groups;
   if (theLayer.kind == "LayerKind.GRADIENTFILL" || theLayer.kind == "LayerKind.LAYER3D" || theLayer.kind == "LayerKind.NORMAL" || 
   theLayer.kind == "LayerKind.PATTERNFILL" || theLayer.kind == "LayerKind.SOLIDFILL" || theLayer.kind == "LayerKind.TEXT" || 
   theLayer.typename == "LayerSet") {
      var id557 = charIDToTypeID( "slct" );
      var desc108 = new ActionDescriptor();
      var id558 = charIDToTypeID( "null" );
      var ref77 = new ActionReference();
      var id559 = charIDToTypeID( "Mn  " );
      var id560 = charIDToTypeID( "MnIt" );
      var id561 = stringIDToTypeID( "newPlacedLayer" );
      ref77.putEnumerated( id559, id560, id561 );
      desc108.putReference( id558, ref77 );
      executeAction( id557, desc108, DialogModes.NO );
      return app.activeDocument.activeLayer
      };
// return smart objects;
   if (theLayer.kind == LayerKind.SMARTOBJECT || theLayer.kind == "LayerKind.VIDEO") {return theLayer};
// if neither pixel-layer, group nor smart object return only masked adjustment layers;
   if (theLayer.kind == "LayerKind.BLACKANDWHITE" || theLayer.kind == "LayerKind.BRIGHTNESSCONTRAST" || 
   theLayer.kind == "LayerKind.CHANNELMIXER" || theLayer.kind == "LayerKind.COLORBALANCE" || theLayer.kind == "LayerKind.CURVES" || 
   theLayer.kind == "LayerKind.EXPOSURE" || theLayer.kind == "LayerKind.GRADIENTMAP" || theLayer.kind == "LayerKind.HUESATURATION" || 
   theLayer.kind == "LayerKind.INVERSION" || theLayer.kind == "LayerKind.LAYER3D" || theLayer.kind == "LayerKind.LEVELS" || 
   theLayer.kind == "LayerKind.PHOTOFILTER" || theLayer.kind == "LayerKind.POSTERIZE" || theLayer.kind == "LayerKind.SELECTIVECOLOR" || 
   theLayer.kind == "LayerKind.THRESHOLD" || theLayer.kind == "LayerKind.VIBRANCE") {
      if (hasLayerMask() == true || hasVectorMask() == true) {
         return theLayer
         }
      else {return false}
      }
   };
// from »Flatten All Masks.jsx« by jeffrey tranberry;
///////////////////////////////////////////////////////////////////////////////
// Function: hasLayerMask
// Usage: see if there is a raster layer mask
// Input: <none> Must have an open document
// Return: true if there is a vector mask
///////////////////////////////////////////////////////////////////////////////
function hasLayerMask() {
   var hasLayerMask = false;
   try {
      var ref = new ActionReference();
      var keyUserMaskEnabled = app.charIDToTypeID( 'UsrM' );
      ref.putProperty( app.charIDToTypeID( 'Prpr' ), keyUserMaskEnabled );
      ref.putEnumerated( app.charIDToTypeID( 'Lyr ' ), app.charIDToTypeID( 'Ordn' ), app.charIDToTypeID( 'Trgt' ) );
      var desc = executeActionGet( ref );
      if ( desc.hasKey( keyUserMaskEnabled ) ) {
         hasLayerMask = true;
      }
   }catch(e) {
      hasLayerMask = false;
   }
   return hasLayerMask;
};
///////////////////////////////////////////////////////////////////////////////
// Function: hasVectorMask
// Usage: see if there is a vector layer mask
// Input: <none> Must have an open document
// Return: true if there is a vector mask
///////////////////////////////////////////////////////////////////////////////
function hasVectorMask() {
   var hasVectorMask = false;
   try {
      var ref = new ActionReference();
      var keyVectorMaskEnabled = app.stringIDToTypeID( 'vectorMask' );
      var keyKind = app.charIDToTypeID( 'Knd ' );
      ref.putEnumerated( app.charIDToTypeID( 'Path' ), app.charIDToTypeID( 'Ordn' ), keyVectorMaskEnabled );
      var desc = executeActionGet( ref );
      if ( desc.hasKey( keyKind ) ) {
         var kindValue = desc.getEnumerationValue( keyKind );
         if (kindValue == keyVectorMaskEnabled) {
            hasVectorMask = true;
         }
      }
   }catch(e) {
      hasVectorMask = false;
   }
   return hasVectorMask;
};
////// get number of history states //////
function historyStates () {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("capp"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var appDesc = executeActionGet(ref);
var prefDesc = appDesc.getObjectValue(charIDToTypeID( "CchP" ));
var theHistoryStates = prefDesc.getInteger(charIDToTypeID( "HsSt" ));
return theHistoryStates
};
////// get memory usage percentage //////
function memoryUsage () {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("capp"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var appDesc = executeActionGet(ref);
var prefDesc = appDesc.getObjectValue(charIDToTypeID( "CchP" ));
var theHistoryStates = prefDesc.getInteger(charIDToTypeID( "MmrU" ));
return theHistoryStates
};
////// set number of history states //////
function setHistoryStates (histStates, memUsage) {
// =======================================================
var idsetd = charIDToTypeID( "setd" );
    var desc2 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var idPrpr = charIDToTypeID( "Prpr" );
        var idCchP = charIDToTypeID( "CchP" );
        ref1.putProperty( idPrpr, idCchP );
        var idcapp = charIDToTypeID( "capp" );
        var idOrdn = charIDToTypeID( "Ordn" );
        var idTrgt = charIDToTypeID( "Trgt" );
        ref1.putEnumerated( idcapp, idOrdn, idTrgt );
    desc2.putReference( idnull, ref1 );
    var idT = charIDToTypeID( "T   " );
        var desc3 = new ActionDescriptor();
        var idHsSt = charIDToTypeID( "HsSt" );
        desc3.putInteger( idHsSt, histStates );
        var idMmrU = charIDToTypeID( "MmrU" );
        var idPrc = charIDToTypeID( "#Prc" );
        desc3.putUnitDouble( idMmrU, idPrc, memUsage );
    var idCchP = charIDToTypeID( "CchP" );
    desc2.putObject( idT, idCchP, desc3 );
executeAction( idsetd, desc2, DialogModes.NO );
};
////// select layer additionally to selected layers //////
function addToSelectedLayers (layerIndex) {
// =======================================================
var idslct = charIDToTypeID( "slct" );
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref7 = new ActionReference();
        var idLyr = charIDToTypeID( "Lyr " );
        ref7.putIndex( idLyr, layerIndex - 1 );
    desc8.putReference( idnull, ref7 );
    var idselectionModifier = stringIDToTypeID( "selectionModifier" );
    var idselectionModifierType = stringIDToTypeID( "selectionModifierType" );
    var idaddToSelection = stringIDToTypeID( "addToSelection" );
    desc8.putEnumerated( idselectionModifier, idselectionModifierType, idaddToSelection );
    var idMkVs = charIDToTypeID( "MkVs" );
    desc8.putBoolean( idMkVs, false );
try {executeAction( idslct, desc8, DialogModes.NO )}
catch (e) {};
};
////// based on a getLayerId and getLayerItemIndexByLayerID by mike hale //////
function getLayerItemIndex(layer) {
app.activeDocument.activeLayer = layer;
//Assumes activeDocument and activeLayer
    var ref = new ActionReference();
    ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    d = executeActionGet(ref);
var id = d.getInteger(charIDToTypeID('LyrI'));
// get index;
    var ref = new ActionReference();
    ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
    ref.putIdentifier( charIDToTypeID( "Lyr " ), id );
try{var itemIndex = executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))}
catch(e){var itemIndex = true};
//
return itemIndex
};
////// re-select layers //////
function reselectLayers (myDocument, theLayers) {
   var layerIndices = new Array;
   for (var m = 0; m < theLayers.length; m++) {
      layerIndices.push(getLayerItemIndex(theLayers[m]));
      };
   myDocument.activeLayer = theLayers[0];
   for (var n = 1; n < theLayers.length; n++) {
      addToSelectedLayers (layerIndices[n])
      };
   };