

// scale speechbubbles in group »bubble« to type layers in group »Speech«;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
// set to pixels;
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var myDocument = activeDocument;
var theTypeLayers = collectLayersFromGroupsOfName("Speech");
var theSpeechBubbles = collectLayersFromGroupsOfName("bubble");
var theValue = 30;
// get matching text to bubble;
for (var m = 0; m < theSpeechBubbles.length;m++) {
var thisBubble = theSpeechBubbles[m];
for (var n = 0; n < theTypeLayers.length; n++) {
var thisText = theTypeLayers[n];
var theX = thisText[3][0] + thisText[4]/2;
var theY = thisText[3][1] + thisText[5]/2;
// if match found transform;
if (thisBubble[3][0] <= theX && thisBubble[3][1] <= theY && thisBubble[3][2] >= theX && thisBubble[3][3] >= theY) {
selectLayerByID(thisBubble[2], false);
hideOthers();
loadTransparencyAsSelection(thisBubble[2], false);
var theNewId = smartify();
contractSelection (theValue);
expandSelection (theValue);
loadChannelAsSelection("green", true, "subtract");
var theBounds = myDocument.selection.bounds;
myDocument.selection.deselect();
var selW = (Number(theBounds[2]-Number(theBounds[0])));
var selH = (Number(theBounds[3]-Number(theBounds[1])));
var theScaleX = thisText[4] / selW * 100;
var theScaleY = thisText[5] / selH * 100;
scaleRotateLayer (theScaleX, theScaleY, 0, 0, 0);
loadTransparencyAsSelection(theNewId, false);
contractSelection (theValue);
expandSelection (theValue);
loadChannelAsSelection("green", true, "subtract");
var theBounds = myDocument.selection.bounds;
myDocument.selection.deselect();
var selW = (Number(theBounds[2]-Number(theBounds[0])));
var selH = (Number(theBounds[3]-Number(theBounds[1])));
var offsetX = ((theBounds[0] + selW/2) - (thisText[3][0] + thisText[4]/2)) * (-1);
var offsetY = ((theBounds[1] + selH/2) - (thisText[3][1] + thisText[5]/2)) * (-1);
scaleRotateLayer (100, 100, 0, offsetX, offsetY);
//alert (theScaleX+"\n"+theScaleY+"\n"+offsetX+"\n"+offsetY);
hideOthers();
}
}
};
// reset;
app.preferences.rulerUnits = originalRulerUnits;
};
//////////////////
////// collect layers and their parents if the top level group has a specific name //////
function collectLayersFromGroupsOfName (folderName) {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// anumber is intended to keep track of layerset depth;
var aNumber = 0;
var theArray = new Array;
//var theGroups = new Array;
// work through layers;
for (var m = theNumber; m >= 0; m--) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theseBounds = [theBounds.getUnitDoubleValue(stringIDToTypeID("left")), theBounds.getUnitDoubleValue(stringIDToTypeID("top")), theBounds.getUnitDoubleValue(stringIDToTypeID("right")), theBounds.getUnitDoubleValue(stringIDToTypeID("bottom"))];
var theWidth = theseBounds[2]-theseBounds[0];
var theHeight = theseBounds[3]-theseBounds[1];
//var hasLayerMask = layerDesc.hasKey(charIDToTypeID("Usrs"));
var thisArray = [[theName, m, theID, theseBounds, theWidth, theHeight]];
////////////////////////////////////
// if group start:
if (layerSet == "layerSectionStart" && isBackground != true) {
if (aNumber == 0) {var setArray = [[theName, m, theID]]}
else {
// include groups in array;
for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
// set array;
setArray.push([theName, m, theID])
};
// add to mark group;
aNumber++
};
// if group end;
if (layerSet == "layerSectionEnd" && isBackground != true) {
// subtract to mark end of group;
aNumber--;
if (aNumber == 0) {var setArray = []}
else {setArray.pop()}
};
// if neither group start or end;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
// if anumber is 0 layer is top level;
if (aNumber != 0) {
for (var o = setArray.length - 1; o >= 0; o--) {thisArray.push(setArray[o])};
// check the to level folder name;
var theCheck = false;
for (var a = thisArray.length-1; a > 0; a--) {
if (thisArray[a][0] == folderName) {theCheck = true}
};
if (theCheck == true) {
theArray.push(thisArray[0])
}
};
};
////////////////////////////////////
} catch (e) {};
};
// the results;
return theArray
};
////// based on code by mike hale, via paul riggott //////
function selectLayerByID(id,add){
try {
add = undefined ? add = false:add
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), id);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message);
}
} catch (e) {}
};
////// scale active layer to canvas dimensions //////
function scaleRotateLayer (theScaleX, theScaleY, theAngle, offsetX, offsetY) {
try {
// scale layer:
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// transform;
var desc23 = new ActionDescriptor();
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc23.putReference( charIDToTypeID( "null" ), ref2 );
var idOfst = charIDToTypeID( "Ofst" );
var desc24 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( charIDToTypeID( "Hrzn" ), idPxl, offsetX );
desc24.putUnitDouble( charIDToTypeID( "Vrtc" ), idPxl, offsetY );
desc23.putObject( idOfst, idOfst, desc24 );
var idPrc = charIDToTypeID( "#Prc" );
desc23.putUnitDouble( charIDToTypeID( "Wdth" ), idPrc, theScaleX );
desc23.putUnitDouble( charIDToTypeID( "Hght" ), idPrc, theScaleY );
desc23.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), theAngle );
desc23.putEnumerated( charIDToTypeID( "Intr" ), charIDToTypeID( "Intp" ), stringIDToTypeID( "bicubicAutomatic" ) );
desc23.putEnumerated( stringIDToTypeID( "freeTransformCenterState" ), stringIDToTypeID( "quadCenterState" ), stringIDToTypeID( "QCSAverage" ) );
// desc23.putBoolean( charIDToTypeID( "Cpy " ), true );
executeAction( charIDToTypeID( "Trnf" ), desc23, DialogModes.NO );
app.preferences.rulerUnits = originalRulerUnits;
} catch (e) {alert ("NONONO")}
};
////// load transparency //////
function loadTransparencyAsSelection (theID, theInvert) {
var idchannel = stringIDToTypeID( "channel" );
var desc7 = new ActionDescriptor();
var ref3 = new ActionReference();
ref3.putProperty( idchannel, stringIDToTypeID( "selection" ) );
desc7.putReference( stringIDToTypeID( "null" ), ref3 );
var ref4 = new ActionReference();
ref4.putEnumerated( idchannel, idchannel, stringIDToTypeID( "transparencyEnum" ) );
ref4.putIdentifier( stringIDToTypeID( "layer" ), theID );
desc7.putReference( stringIDToTypeID( "to" ), ref4 );
desc7.putBoolean(charIDToTypeID("Invr"), theInvert);
executeAction( stringIDToTypeID( "set" ), desc7, DialogModes.NO );
};
////// expand selection //////
function expandSelection (theValue) {
var idExpn = charIDToTypeID( "Expn" );
var desc5 = new ActionDescriptor();
var idBy = charIDToTypeID( "By " );
var idPxl = charIDToTypeID( "#Pxl" );
desc5.putUnitDouble( idBy, idPxl, theValue );
executeAction( idExpn, desc5, DialogModes.NO );
};
////// contract selection //////
function contractSelection (theValue) {
try {
// =======================================================
var idCntc = charIDToTypeID( "Cntc" );
var desc14 = new ActionDescriptor();
var idBy = charIDToTypeID( "By " );
var idPxl = charIDToTypeID( "#Pxl" );
desc14.putUnitDouble( idBy, idPxl, theValue );
executeAction( idCntc, desc14, DialogModes.NO );
} catch (e) {}
};
////// load channel as selection //////
function loadChannelAsSelection(theName, theInvert, theAdd) {
try {
var idchannel = stringIDToTypeID( "channel" );
if (theAdd == false || theAdd == undefined) {
var desc70 = new ActionDescriptor();
var ref9 = new ActionReference();
ref9.putProperty( idchannel, stringIDToTypeID( "selection" ) );
desc70.putReference( stringIDToTypeID( "null" ), ref9 );
var ref10 = new ActionReference();
ref10.putEnumerated( idchannel, idchannel, stringIDToTypeID( theName ) );
desc70.putReference( stringIDToTypeID( "to" ), ref10 );
desc70.putBoolean(charIDToTypeID("Invr"), theInvert);
executeAction( stringIDToTypeID( "set" ), desc70, DialogModes.NO );
} else {
var desc221 = new ActionDescriptor();
var ref5 = new ActionReference();
ref5.putEnumerated( idchannel, idchannel, stringIDToTypeID(theName) );
desc221.putReference( stringIDToTypeID( "null" ), ref5 );
desc221.putBoolean(charIDToTypeID("Invr"), theInvert);
var ref6 = new ActionReference();
ref6.putProperty( idchannel, stringIDToTypeID( "selection" ) );
desc221.putReference( stringIDToTypeID( "to" ), ref6 );
executeAction( stringIDToTypeID( theAdd ), desc221, DialogModes.NO );
}
} catch (_error) {alert (_error)}
};
////// load channel as selection //////
function intersectChannelWithSelection(theName) {
try {
var idchannel = stringIDToTypeID( "channel" );
var desc5 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated( idchannel, idchannel, stringIDToTypeID(theName) );
desc5.putReference( stringIDToTypeID( "null" ), ref1 );
var ref2 = new ActionReference();
ref2.putProperty( idchannel, stringIDToTypeID( "selection" ) );
desc5.putReference( stringIDToTypeID( "with" ), ref2 );
executeAction( stringIDToTypeID( "interfaceIconFrameDimmed" ), desc5, DialogModes.NO );
} catch (_error) {alert (_error)}
};
////// toggle visibility of others //////
function hideOthers () {
// =======================================================
var idShw = charIDToTypeID( "Shw " );
var desc10 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var list4 = new ActionList();
var ref7 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref7.putEnumerated( idLyr, idOrdn, idTrgt );
list4.putReference( ref7 );
desc10.putList( idnull, list4 );
var idTglO = charIDToTypeID( "TglO" );
desc10.putBoolean( idTglO, true );
executeAction( idShw, desc10, DialogModes.NO );
};
////// function to smartify if not //////
function smartify () {
// make layers smart objects if they are not already;
if (activeDocument.activeLayer.kind != LayerKind.SMARTOBJECT) {
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 activeDocument.activeLayer
};
//return theLayer
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var layerDesc = executeActionGet(ref);
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
return theID
};
edited