Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
2

Script to resize a layer to fit a text with stroke/ a smart object

Explorer ,
Mar 05, 2024 Mar 05, 2024

Hello everyone, 

I'm a comic editor, and i need to resize bubble to fit text with stroke.

Is there any script that can adjust/ resize layer bubble to fit with layer text? I'm trying to convert text into smart object, and i found a script tooo, but it's quite complicated. 
screenshot_1709704968.png

TOPICS
Actions and scripting
1.7K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Mar 11, 2024 Mar 11, 2024

Screenshot 2024-03-11 at 09.53.45.pngScreenshot 2024-03-11 at 09.53.59.png

 

 

 

 

// 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 < theSpee
...
Translate
Adobe
Community Expert ,
Mar 06, 2024 Mar 06, 2024

Didn’t we already cover this?

Maybe it was just something similar. 

 

Please provide the file or at least meaningful screenshots with the pertinent Panels (Toolbar, Layers, Options Bar, …) visible? 

What is the property that definitively establishes the connection of bubble and text (position, name, …)? 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 06, 2024 Mar 06, 2024

I know about you script to create a shape (ellipse, rectangle, custom shape) fit with stroke text, so magic, your script help me alot!

But my issue is: it's not a shape that you can create or custom, our customer don't allow us to draw it by shape. It just a pixel layer with a handraw speech bubble. I put all  that bubble in group "Bubble" like the image below, and text on group "Speech". Each bubble is an independent layer in "bubble group". I'm searching for a script that can resize each selected "bubble layer" to fit with each selected "text layer include stroke". 

Up until now, we would have had to use free transform to squeeze the speech bubble and adjust it little by little, which is very time consuming.

I'm trying to cut out the bubble text direction indicator, only the oval shape is left for easy applying the resizing script, but there is still no suitable script.screenshot_1709704968.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 06, 2024 Mar 06, 2024

This is the bubble layer inside the bubble group 

screenshot_1709704968.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 07, 2024 Mar 07, 2024

Please post more meaningful screenshots. 

What is the property that definitively establishes the connection of bubble and text (position, name, …)? 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 08, 2024 Mar 08, 2024

Please provide a sample file (feel free to remove the illustration) and a file representing the intended result for that file. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 08, 2024 Mar 08, 2024

Here is the PSD file before and after editing the speech bubble in one of the comics I'm working on. It would be much easier if I was allowed to redraw it as a shape, but the client doesn't allow that, they only allow us to distort the speech bubble using free transform.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Mar 08, 2024 Mar 08, 2024

Have you tried telling the client no?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 08, 2024 Mar 08, 2024
  1. Yes, already... The sample is just one of various comics I working on. Some of them are hand-draw bubbles, so client want to keep it. They just need 4 side of the bubble fit with the text
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Mar 08, 2024 Mar 08, 2024

If you are only allowed to use free transform than... just do that? You can't script a manual adjustment AFAIK.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 08, 2024 Mar 08, 2024

Customer didn't just allow us to use free transform, they just don't allow us to draw the hand-draw bubble... And free transform is the only way we think about. 

I used to try to make a script that covert text to smart object, and resize bubble to fit with that smart object, it works but quite complicated... 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Mar 09, 2024 Mar 09, 2024

Honestly I have no idea what you are doing. Can you walk us through this step by step and explain the actual problem you are having? What doesn't work?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 11, 2024 Mar 11, 2024

The Script I sposted (and edited) does not do an alignment. 

Because the handles cause the transformations not to center on the middle of the »main bodies« of the speech-bubbles this would probably best be done in a second step. 

 

Identifying the corresponding »Speech«-Layer for a »bubble«-Layer is done by adding some padding to the bubbles’s bounds and checking if there is a speech-Layer that fits into that area completely. 

Under certain circumstances that might result in multiple matches and cause issues. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 10, 2024 Mar 10, 2024
quote

Here is the PSD file before and after editing the speech bubble in one of the comics I'm working on. It would be much easier if I was allowed to redraw it as a shape, but the client doesn't allow that, they only allow us to distort the speech bubble using free transform.


By @KathyDang

Thanks. 

 

The speech-bubbles are irregular due to the »handles« or have black rays – those would all be included in the bounds. 

So one would need to »filter out« that stuff … 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 12, 2024 Mar 12, 2024

Thank you so much, you are very dedicated!

Can I ask if it is possible to adjust the script to only work on a specific speech bubble and text that I choose, instead of all the text and bubbles in 2 groups "Speech" and "Bubble" ?

Because if I run it on the entire group, there will cause many errors with some bubble have irregular shapes are hard to recognize (like the sample below). So, I think it's better to manually adjust these speech bubbles. The script should only be used for speech bubbles that can be easily automated to save time.

It would be a great help to me if you could make this happen. Thank you for your help regardless!screenshot_1709622560.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 12, 2024 Mar 12, 2024

Screenshot 2024-03-12 at 11.59.51.pngScreenshot 2024-03-12 at 11.59.59.png

 

// scale selected speech-bubble-layer to type; 
// 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;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
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 thisBubble = [theName, theIndex, theID, theseBounds, theWidth, theHeight];
// get matching text to bubble;
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);
        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
};

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 15, 2024 Mar 15, 2024

I don't know why...the script works very well on the sample file I gave you, I also tested it, but when I use it for the official comic page, it doesn't work, nothing happens at all... I don't know where the problem is. Is it possible to make the test simpler by just recognizing 1 text and 1 speech bubble that I choose, instead of searching by group? Thank you,  T.T

I'm so sorry to bother you so much. If it's not possible, that's okay too. You've helped me a lot already

screenshot_1709622560.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 16, 2024 Mar 16, 2024
LATEST

Two issues: 

• You applied the Stroke to the Group, not the Type Layers. 

• Most of the Type Layer exceed the Bounds of the bubbles. 

 

I edited the code in the previous post to change the check for corresponding Type Layers, but you need to apply the Stroke to the individual Type Layers. 

Screenshot 2024-03-16 at 12.24.57.pngScreenshot 2024-03-16 at 12.25.26.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Mar 06, 2024 Mar 06, 2024

Record an action to convert your text to point and then back to paragraph. That will fit the text bounding box to the text. Then you can get the dimensions with a script and resize from there.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 08, 2024 Mar 08, 2024

Sorry, I'm not really understand what you mean. Can you describe it more detail?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Mar 11, 2024 Mar 11, 2024

Screenshot 2024-03-11 at 09.53.45.pngScreenshot 2024-03-11 at 09.53.59.png

 

 

 

 

// 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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines