Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding the actual text height AS3

How can I get the actual height of a text in AS3 TextField? It appears that TextField.textHeight reports some fixed value that doesn't depend on the contents of a TextField.

The example code below produces the following:

text=o p g y d j
textWidth=120.8
textHeight=**96**

text=o
textWidth=15
textHeight=**96**

text=oW
textWidth=43.3
textHeight=**96**

Obviously, the height should be different for "o" and "p", etc.

The AS3 code:

import flash.text.TextField;

        var format : TextFormat = new TextFormat();
        format.font = "Times New Roman";
        format.size = 30;
        format.align = TextFormatAlign.CENTER;


        var textField1 : TextField = new TextField();       
        textField1.defaultTextFormat = format;      

        textField1.selectable = false;              
        textField1.sharpness = 0;   
        textField1.embedFonts = true;   
        textField1.multiline = false;

        textField1.height = 50;
        textField1.width = 200;
        textField1.x = 10;
        textField1.y = 10;

        addChild(textField1);

        textField1.text = "o p g y d j";    
        trace("text=" + textField1.text);
        trace("textWidth=" + textField1.textWidth);
        trace("textHeight=" + textField1.textHeight);       

        textField1.text = "o";      
        trace("\ntext=" + textField1.text);
        trace("textWidth=" + textField1.textWidth);
        trace("textHeight=" + textField1.textHeight);   

        textField1.text = "oW";     
        trace("\ntext=" + textField1.text);
        trace("textWidth=" + textField1.textWidth);
        trace("textHeight=" + textField1.textHeight);       

        stop();

I guess TextField.textHeight is not the right variable, but what should I use instead?

like image 815
user1566515 Avatar asked Aug 25 '13 21:08

user1566515


2 Answers

Mark Fox is right that textHeight doesn't represent the actual height of text - and that the classic TextField in Flash doesn't have any support for getting the actual pixel height of rendered text. What textHeight does represent is the line height - which is its ascent (font's height above baseline), descent (font's height below baseline) and leading (space between lines) combined. As implied, the height is constant, based on the font's ascent and descent, not the actual text's. (Bearing this in mind, see Adobe's overview of the terms here - and note that TextLineMetrics won't help you either).

The "new" Flash Text Engine (flash.text.engine) does include properties to get the actual height of text rendered using that technology (e.g. TextLine.totalHeight) - but then we're getting into low level text rendering. If you need to use "classic" TextFields, this won't help you measuring the text anyway, since the Flash Text Engine has its own renderer, which doesn't necessarily render text at the same height and width as "classic" text.

What you can do instead is render the TextField to BitmapData then measure the bounds of the text:

// Create a completely transparent BitmapData:
var bmd:BitmapData = new BitmapData(
                            textfield.width, 
                            textfield.height, 
                            true,
                            0x00ffffff);

// Note that some cases may require you to render a Sprite/MovieClip
// CONTAINING the TextField for anything to get drawn.
// For example, AntiAliasType.ADVANCED (antialias for readability) is known to 
// not be renderable in some cases - other settings may cause nothing to be
// rendered too. In that case, simply wrap add the TextField as a child of an 
// otherwise empty Sprite/MovieClip, and pass that to draw() instead:
bmd.draw(textfield);

// This gets the bounds of pixels that are not completely transparent.
// Param 1: mask  = specifies which color components to check (0xAARRGGBB)
// Param 2: color = is the color to check for.
// Param 3: findColor = whether to bound pixels OF the specified color (true),
//                      or NOT OF the specified color (false)
//
// In this case, we're interested in:
// 1: the alpha channel (0xff000000)
// 2: being 00 (0x00......)
// 3: and want the bounding box of pixels that DON'T meet that criterium (false)
var rect:Rectangle = bmd.getColorBoundsRect(0xff000000, 0x00000000, false);

// Do remember to dispose BitmapData when done with it:
bmd.dispose();

trace("text height = " + rect.height);
trace("text width = " + rect.width);

Note on accuracy

This may be completely irrelevant, depending on what you're going to use this for, but it's worth bearing in mind:

This method will obviously always return a result in whole pixels - the actual rendering of the glyphs, however, uses sub-pixels.

In other words, if you add the results of measuring the width of a "V" and an "o", and then compare that to the result of "Vo", they may not be the same. You might get "40 + 35 = 74". Ignoring that kerning etc. may push the letters closer together, the rendering of each letter (placement, anti-aliasing etc.) may also be different, depending on its context.

like image 172
JimmiTh Avatar answered Sep 17 '22 08:09

JimmiTh


Your question highlights a legacy of weak semantics in the Flash typographic APIs.

The textHeight property represents the relative size of the typeface in pixels, it doesn't account for the pixel representation of the particular glyphs (the individual letter shapes) in the TextField.

As far as I know there is no direct programatic way to measure a glyph with Flash. However, you could bitmap the textfield and use getPixel to guess:

var tf:TextField = …your textfield…
var wide:int = tf.width;
var tall:int = tf.height;
var bmpd:BitmapData = new BitmapData(wide, tall, true,0xFFFFFFFF);
bmpd.draw( tf );
var totalPixels:int = wide * tall;
var index:int = totalPixels + 1;
var useIndex:int;
var xPixel:int;
var yPixel:int;
while (--index > 0) {
    useIndex = index - 1;
    xPixel = useIndex % wide;
    yPixel = int(useIndex / wide);
    var pixelColor:uint = bmpd.getPixel(xPixel, yPixel);
    // write some logic to find the y extremes where the pixelColor values are not white (or whatever background color specified when you created the BitmapData)
}
like image 21
Mark Fox Avatar answered Sep 21 '22 08:09

Mark Fox