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

ADBE Text Document boxTextSize attribute

Guest
Nov 27, 2013 Nov 27, 2013

Hello,

I am trying to determine the size and position of a text box in a text layer.

the attribute "boxTextSize" works as expected, I am able to retrive the size of the text box with a call like this :

myLayer.property(\"ADBE Text Properties\").property(\"ADBE Text Document\").value.boxTextSize;

But how can I determine the origin of the text box relative to the anchor point (or vice-versa) ? Strangely, when I create the text box in After Effects (CC), the anchor point is automatically placed in the center of the box (visually), even though the reported numerical values for the anchor point for that layer are (0, 0, 0). Am I misinterpreting something ?

Thanks !

Steph

TOPICS
Scripting
6.3K
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
Advocate ,
Dec 04, 2013 Dec 04, 2013

You would need to do some math to track down it's location. I know there is something to this, but it isn't fleshed out yet and my brain isn't working too clearly at the moment, but...

var myLayer = app.project.item(1).layer(1);     //Your text layer

var myTextBox = myLayer.property("ADBE Text Properties").property("ADBE Text Document");     //The text box

var myTextBoxSizeX = myTextBox.value.boxTextSize[0];     //The text box X size

var myTextBoxSizeY = myTextBox.value.boxTextSize[1];     //The text box Y size

var myLayerPX = myLayer.property("Position").value[0];     //Layer position X

var myLayerPY = myLayer.property("Position").value[1];     //Layer position Y

var myLayerAPX = myLayer.property("Anchor Point").value[0];     //Layer anchor point X

var myLayerAPY = myLayer.property("Anchor Point").value[1];     //Layer anchor point Y

var myTextBoxCompLocationX = myLayerPX - myLayerAPX;     //Should be the center X location of the text box within the comp space

var myTextBoxCompLocationY = myLayerPY - myLayerAPY;     //Should be the center Y location of the text box within the comp space

/*

     Should be able to subtract the anchor from the position to find center of box then offset by the box X or Y divided by 2 to get a boundry line of the box. I may be over thinking this too.

*/

var myTextBoxCompLocationRightBoundryLineMaybe = (myTextBoxSizeY/2) - myTextBoxCompLocationY;

alert(myTextBoxCompLocationRightBoundryLineMaybe);

Maybe someone else can figure the math out better on this. I'll keep thinking on it. I know it should be doable though, just not natively in ExtendScript from what I know.

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
Guest
Dec 05, 2013 Dec 05, 2013

Thanks David, but my problem is that the Anchor Point is returned as (0, 0, 0) even though in AE it appears to be at the center of the text box. The Position property gives me correct values for the position of the Anchor Point.

It seems to be a bug with the way AE reports the Anchor Point for a text layer defined as box text : numerical value is zero, which is inconsistent with where the crosshair appears visually, at the center of the box.

Thanks anyway !

Steph

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
Advocate ,
Dec 05, 2013 Dec 05, 2013

The Position property gives me correct values for the position of the Anchor Point.

It seems to be a bug with the way AE reports the Anchor Point for a text layer defined as box text :

I do believe this is correct though. The Anchor Point coordinates of a layer is always based relative to the layer size. So if you have a 300 x 200 text box in a 1920 x 1080 composition and the Anchor Point on the text box is centered. It's Anchor Point would be [0, 0]. If you moved the Anchor Point to the top left corner of that text box, it should be [-150, -100].

I think the confusion happens with how AE handles it's composition layers. A composition starts it's X, Y coordinates from the top left corner as 0, 0 and works out from there.

0, 0-------------------------->

|

|

|

|

|

|

\/

versus

                   /\

                    |

                    |

                    |

                    |

<----------- 0, 0 ----------->

                    |

                    |

                    |

                    |

                   \/

My guess is that Adobe made the text box center the 0, 0 point intentionally.

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
Guest
Dec 06, 2013 Dec 06, 2013

Hi David,

OK, try this :

- On a 600x600 composition, create a 300x300 text box

- Change the position of that box to the center of the composition (300, 300)

- Now the box is perfectly centered

How can I now calculate the position of the top-left corner of that box ? The box is at (300, 300), and anchor point is at (0, 0) acording to the layer transform properties. So what math would give me the position (150,150) that represents the coordinates of the top left corner of the text box ?

If you are not convinced something is missing, try to select part of the text in the box using the text tool, and when the box handles appear, move the top-left handle around. Now the box is no longer 300x300 in size, its anchor point is no longer in its center, yet AE still reports (300, 300) and (0,0) for position and anchor point of that layer. Obviously there is a key piece of information we're missing.

Thanks,

Steph

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
Advocate ,
Dec 06, 2013 Dec 06, 2013

- Change the position of that box to the center of the composition (300, 300)

- Now the box is perfectly centered

For the record, if you are using AECC, and you create a text box via the addBoxText() method, it will automatically place it centered in the composition. No need to reposition.

var myComp = app.project.activeItem;

if(myComp instanceof CompItem){

     myComp.layers.addBoxText([300, 300], "Write this text in the box for me.");     //Two arguments: addBoxText([width, height], "String of text")

}

How can I now calculate the position of the top-left corner of that box ? The box is at (300, 300), and anchor point is at (0, 0) acording to the layer transform properties. So what math would give me the position (150,150) that represents the coordinates of the top left corner of the text box ?

That is what I was working on before, but my results were slightly off from the real location within the comp space. I believe it would be this, but again maybe someone can correct me on the math:

Top left:

var x = PositionX - AnchorX - (Box width ÷ 2);

var y = PositionY - AnchorY - (Box height ÷ 2);

var result = [x, y];

Top right:

var x = PositionX - AnchorX + (Box width ÷ 2);

var y = PositionY - AnchorY - (Box height ÷ 2);

var result = [x, y];

Bottom left:

var x = PositionX - AnchorX - (Box width ÷ 2);

var y = PositionY - AnchorY + (Box height ÷ 2);

var result = [x, y];

Bottom right:

var x = PositionX - AnchorX + (Box width ÷ 2);

var y = PositionY - AnchorY + (Box height ÷ 2);

var result = [x, y];

If you are not convinced something is missing, try to select part of the text in the box using the text tool, and when the box handles appear, move the top-left handle around. Now the box is no longer 300x300 in size, its anchor point is no longer in its center, yet AE still reports (300, 300) and (0,0) for position and anchor point of that layer. Obviously there is a key piece of information we're missing.

You are correct. That doesn't make sense. It should now have a new total box size with the Anchor Point updating it's value. Yet it doesn't. That's throws a big monkey wrench in the works.

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
Advocate ,
Dec 06, 2013 Dec 06, 2013

Hi,

First, for ANY layer, position and anchorPoint always refer to the SAME point, the point that is represented graphically by a crosshair in the viewer.

  •     position is the coordinates of the crosshair in the parent coordinates system (if no parent: comp, or parent group in shapes).
  •     anchorPoint is the coordinates of the crosshair in the layer's own system.

So if you want to know where in your layer is the origin (point[0,0]), simply set the anchorPoint to [0,0] and see where the crosshair is.

  •     for a comp or a layer with source (solid, footage, etc), the rule is that it is always the topLeft corner.
  •     for a layer without a source (Text, ShapeLayer) : depends...

In a ShapeLayer, the origin [0,0] is represented graphically by a small (full) square, and in an empty text layer too.

For a non empty text layer, it is not represented, but by setting anchorPoint to [0,0] one can see how it behaves:

  •     for non boxed text : somewhere near the [left edge, baseline] of the 1st caracter (left aligned text), or [right edge, baseline] of the last character (right aligned text), or ??? for a centered text, hard to know, seems to depend on the caracters, the font type...
  •     for a boxed text: middle of the text box.

So for a boxed text, the top Left corner of the box is ALWAYS [-w/2, -h/2], the botRight corner at [w/2, h/2], etc etc,  in LAYER COORDINATES (where w and h are the width/ height of the boxTextSize).

To know the position of these points in comp coordinates, you have to work out layer-to-parent coordinates transformations until you reach the comp (requires a bit of maths..).

If no parent and if the scale is at default, rotation same, and same pixelAspect ratios, it is:

topLeft(comp) =  position + topLeft(layer) - anchorPoint;

This gives the topLeft corner of the ALLOCATED text box. If you want the ACTUAL box occupied by the text, don't use boxTextSize but layer.sourceRectAtTime(time, false), which is an object with properties top, left, width, height,

and gives the actual bounds of the text in the LAYER COORDINATES system.

So if you set rect = layer.sourceRectAtTime(time, false); actualTopLeft(layer) = [rect.left, rect.top]; you get likewise actualTopLeft(comp) = position + actualTopLeft(layer) - anchorPoint; in default setup, and requires some more maths if the layer is rotated, scaled etc.

Note that it is consistent with how anchorPoints and positions work in After Effects, there is no misbehaviour or bug, but it is true that it is hard to set up a text very precisely by script.

One way to do is to write it in a random position (e.g. [0,0]), read the sourceRectAtTime, then translate to the desired position:

var myDesiredPosition = [300,500];

layer.transform.position.setValue([0,0]);

var rect = layer.sourceRectAtTime(time, false);

layer.transform.position.setValue(layer.transform.position + myDesiredPosition - [rect.left, rect.top]);

Xavier.

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
Advocate ,
Dec 06, 2013 Dec 06, 2013

Nicely explained Xavier. I appreciate the clarity on that.

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
Advocate ,
Dec 07, 2013 Dec 07, 2013

Hi David,

I'm actually not 100% sure of what i say since it is from observation only. It is hopefully correct.

I just wrote a script that displays (masks) the sourceRect, text box and origin of a layer.

Can't test the textBox part ... i don't have CS6!

Xavier.

//==================================================================== ==

//

//    $.source - Xavier Gomez (dec. 7, 2013)

//

//    Helps visualise(*) sourceRectAtTime, textBox and origin of a layer without a source

//    ScriptUI Panel only

//

//     (*) draws masks...

//

//==================================================================== ==

if (this instanceof Panel)

(function(ooo)

{

    // tweaks

    var

            sourceRectName = "$.sourceRect",

            sourceRectColor = [0,1,1],

               

            textBoxName = "$.textBox",

            textBoxColor = [0,1,0],

           

            originName = "$.origin",

            originColor = [1,0,0],

           

            emptyValue = "-";    // ""

    ooo.margins = 5;

    ooo.content = ooo.add("group{orientation: 'column', alignment: ['left', 'top'], \

                                            header: Group{orientation: 'row', alignment: ['center', 'top'], alignChildren: ['center', 'top'], spacing: 10,\

                                                                info: Checkbox{text: 'info', value: true},\

                                                                option: Checkbox{text: 'show extents'},\

                                                                btn: Button{text: '\u2192', maximumSize: [25,18], helpTip:'Draw sourceRect (teal), textBox (green) and origin (red).'}\

                                                                },\

                                            info: Group{orientation: 'row', alignment: ['left', 'top'], alignChildren: ['left', 'top'],\

                                                            sourceRect: Panel{text: 'Source Rect', orientation: 'column', left: StaticText{characters: 10}, top: StaticText{characters: 10}, w: StaticText{characters: 10}, h: StaticText{characters: 10}},\

                                                            textBox:  Panel{text: 'Text Box', orientation: 'column',  left: StaticText{characters: 10}, top: StaticText{characters: 10}, w: StaticText{characters: 10}, h: StaticText{characters: 10}}\

                                                            }\

                                            }");

    with(ooo.content.header)

    {

        option.maximumSize.height = 18;

        info.onClick = function()

        {

            this.parent.parent.info.maximumSize.height = (this.value) ? 1000 : 0;

            ooo.layout.layout(1);

            };

        btn.onClick = function()

        {

            var 

                    comp, layer,

                   

                    rect, left, right, top, bot, w, h,

                   

                    shape, mask, path;

           

            var getMaskByName = function(name, color)

            {

                var m, M=layer.Masks.numProperties, mask;

                for (m=1; m<=M; m++) if (layer.mask(m).name === name) return layer.mask(m);

                       

                mask = layer.Masks.addProperty("ADBE Mask Atom");

                mask.name = name;

                mask.maskMode = MaskMode.NONE;

                mask.color = color;

                return mask;

                };

           

            var setMaskShape = function(mask, vertices)

            {

                var path = mask.property(1), shape = new Shape();

                shape.vertices = vertices;

                (path.numKeys) ? path.setValueAtTime(comp.time, shape) : path.setValue(shape);

                return;

                };

            var setValues = function(g, top, left, w, h)

            {

                g.left.text = "Left: " + ((typeof left === 'number') ? left.toFixed(1) : emptyValue);

                g.top.text = "Top: " + ((typeof top === 'number') ? top.toFixed(1) : emptyValue);

                g.w.text = "W: " + ((typeof w === 'number') ? w.toFixed(1) : emptyValue);

                g.h.text = "H: " + ((typeof h === 'number') ? h.toFixed(1) : emptyValue);

                };

           

            if (app.project && app.project.activeItem instanceof CompItem && app.project.activeItem.selectedLayers.length==1 && app.project.activeItem.selectedLayers[0].mask)

            {

                 comp = app.project.activeItem;

                 layer = comp.selectedLayers[0];

                

                // draw source rect, clockwise from topLeft

                rect = layer.sourceRectAtTime(comp.time, this.parent.option.value);

                left = rect.left; right = rect.left+rect.width; top = rect.top; bot = rect.top+rect.height;

               

                setValues(this.parent.parent.info.sourceRect, top, left, rect.width, rect.height);

                mask = getMaskByName(sourceRectName, sourceRectColor);

                setMaskShape(mask, [ [left, top], [right, top], [right, bot], [left, bot] ]);

                // repeat the same thing, this time for textBox

                if (layer instanceof TextLayer && app.version >=11 && layer.property("ADBE Text Properties").property("ADBE Text Document").value.boxText)

                {

                    rect = layer.property("ADBE Text Properties").property("ADBE Text Document").value.boxTextSize;

                    w = rect[0]*0.5;

                    h = rect[1]*0.5;

                    setValues(this.parent.parent.info.textBox, -w, -h, rect[0], rect[1]);

                    mask = getMaskByName(textBoxName, textBoxColor);

                    setMaskShape(mask, [ [-w,-h], [w, -h], [w, h], [-w, h] ]);

                    }

                else setValues(this.parent.parent.info.textBox);

               

                // Draw the origin;

                mask = getMaskByName(originName, originColor);

                setMaskShape(mask, [ [0,0] ]);

                }

            else

            {

                setValues(this.parent.parent.info.sourceRect);

                setValues(this.parent.parent.info.textBox);

                };

            getMaskByName = null;

            setValues = null;

            setMaskShape = null;

            return;

            };

        btn.notify();

        };

    ooo.onClose = function()

    {

        if (Object.isValid(this.content))

        {

            this.remove(this.content);

            sourceRectColor = textBoxColor = originColor = null;

            $.gc(); $.gc();

            };

        };

           

    ooo.layout.layout(1);

    return;

    })(this);

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
Guest
Dec 07, 2013 Dec 07, 2013

Hi Xavier,

Thanks for the detailed explanation. I did not know the actual text box could be retrieved (vs allocated), that could be very helpful, thanks for that.

My usecase however requires me to find the position of the allocated text box. You say that its top left corner is always at -w/2, -h/2; I have to disagree though : while this is true originally when the text box is drawn, if we subsequently move the top left handle of that box, the anchor point of the layer is no longer in its center, so the top left corner is no longer at -w/2, -h/2. You can try be yourself.

In these circumstances, the only way to find the position of the top-left corner of the allocated text box would be through a property, but I still don't know is such a property exists.

Steph

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
Advocate ,
Dec 07, 2013 Dec 07, 2013

I just ran your code in CS6. The $.sourceRect mask encapsulates the physical text only (blue box) and not the actual textBox container (red box). See Fig. 1 Still useful though.

The $.origin works only if the Anchor Point isn't changed. Fig. 1 shows the red mask just over the "n" in the last line of text. This is the 0,0 point of the text box. Fig. 2 shows the red mask still applying to the same location even though the Anchor Point has now been offset to just below the "jdb" in the first line of text.

Fig. 1 (Anchor Point left at 0,0 location)

Screen Shot 2013-12-07 at 12.11.28 PM.png

Fig. 2 (Anchor Point moved via Pan Behind tool)

Screen Shot 2013-12-07 at 12.12.37 PM.png

I still think there is a math problem somewhere in this that could be used to determine the Anchor Point location in relation to the text box with a bit of work. I'm just not finding it though.

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
Advocate ,
Dec 07, 2013 Dec 07, 2013

Hi,

normally the script draws a third mask in green for the textBox if it has one. This textBox information is available to scripting only from CS6 and i don't have it so i couldnt test if it works.

It is the part done after " if (layer instanceof TextLayer && app.version >=11 && layer.property("ADBE Text Properties").property("ADBE Text Document").value.boxText) ".

Since you have CS6 it should be true for you and display that third mask... which should normally be the textBox (the red rectangle in your first image).

Apparently my condition is wrong. Try changing it (or remove it) so that the textBox mask is drawn. Basically it should be true for a text layer with a boxed text and false otherwise...

Now i think you are confused between origin, position and anchorPoint... everything is where it should be. Moving around the anchorPoint with the pan behind tool doesnt change any value since everything is expressed in layer's coordinates.

Only when you want to express coordinates in comp system things might change.

Xavier.

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
Advocate ,
Dec 09, 2013 Dec 09, 2013

Removing the if statement forced it to work. Keeping the "layer instanceof TextLayer && app.version" part still didn't create the green mask though. On a great note, the grren mask perfectly hits the mark of the text box boundry.

Screen Shot 2013-12-09 at 11.34.17 AM.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
Advocate ,
Dec 09, 2013 Dec 09, 2013

Cool, thanks David for checking.

I agree these coordinate thingies can be very confusing, espacially for texts

When using real time interface (slider, mouse...) it's quite natural but when one wants to set things up by script it is another story.

Xavier.

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
Enthusiast ,
Jun 03, 2018 Jun 03, 2018
LATEST

Xavier,

This is a very old thread, and am not certain you will get this very new reply , but I thought I would try anyways.  I'm not sure if I am seeing things correctly, but it appears that the internals of the BoxText object might be different in the latest update — that is 15.1.1.  In my own scripts, I'm unable to get the width / height extents of the actual text paragraph within the BoxText object.  I can now only retrieve the width and height of the BoxText "cage" so to speak.  I ran the ScriptUI panel you pasted into this thread, and I'm not seeing it return a distinction between the BoxText's cage extents and the internal paragraph extents.  It appears that the SourceRect and the TextBox are one in the same now.  Do you know if that's the case?

Thanks,

Arie

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