views:

519

answers:

4

I'm learning ActionScript/Flash. I love to play with text, and have done a lot of that kind of thing with the superb Java2D API.

One of the things I like to know is "where, exactly, are you drawing that glyph?" The TextField class provides the methods getBounds and getCharBoundaries, but these methods return rectangles that extend far beyond the actual bounds of the whole text object or the individual character, respectively.

var b:Sprite = new Sprite();
b.graphics.lineStyle(1,0xFF0000);
var r:Rectangle = text.getCharBoundaries(4);
r.offset(text.x, text.y);
b.graphics.drawRect(r.x,r.y,r.width,r.height);
addChild(b);

b = new Sprite();
b.graphics.lineStyle(1,0x00FF00);
r = text.getBounds(this);
b.graphics.drawRect(r.x,r.y,r.width,r.height);
addChild(b);

some bounds

Is there any way to get more precise information about the actual visual bounds of text glyphs in ActionScript?

+2  A: 

I'm afraid all the methods that are available on TextField are supposed to do what you have already found them to do. Unless performance is key in your application (i.e. unless you intend to do this very often) maybe one option would be to draw the text field to a BitmapData, and find the topmost, leftmost, et c colored pixels within the bounding box retrieved by getCharBoundaries()?

var i : int;
var rect : Rectangle;
var top_left : Point;
var btm_right : Point;

var bmp : BitmapData = new BitmapData(tf.width, tf.height, false, 0xffffff);
bmp.draw(tf);

rect = tf.getCharBoundaries(4);
top_left = new Point(Infinity, Infinity);
btm_right = new Point(-Infinity, -Infinity);

for (i=rect.x; i<rect.right; i++) {
  var j : int;

  for (j=rect.y; j<rect.bottom; i++) {
    var px : uint = bmp.getPixel(i, j);

    // Check if pixel is black, i.e. belongs to glyph, and if so, whether it
    // extends the previous bounds
    if (px == 0) {
      top_left.x = Math.min(top_left.x, i);
      top_left.y = Math.min(top_left.y, j);
      btm_right.x = Math.max(btm_right.x, i);
      btm_right.y = Math.max(btm_right.y, j);
    }
  }
}

var actualRect : Rectangle = new Rectangle(top_left.x, top_left.y);
actualRect.width = btm_right.x - top_left.x;
actualRect.height = btm_right.y - top_left.y;

This code should loop through all the pixels that were deemed part of the glyph rectangle by getCharBoundaries(). If a pixel is not black, it gets discarded. If black, the code checks whether the pixels extends further up, down, right or left than any pixel that has previuosly been checked in the loop.

Obviously, this is not optimal code, with nested loops and unnecessary point objects. Hopefully though, the code is readable enough, and you are able to make out the parts that can most easily be optimized.

You might also want to introduce some threshold value instead of ignoring any pixel that is not pitch black.

richardolsson
Upvote for your pragmatic and detailed answer, and for nice discussion of pitfalls. I appreciate it.
Jonathan Feinberg
+2  A: 

Not reasonably possible in Flash 9 -- Richard's answer is a clever work-around, though probably completely unsuitable for production code (as he mentions) :)

If you have access to Flash 10, check out the new text engine classes, particularly TextLine.

Cory Petosky
That's just the ticket. The question is now "Why does Flex Builder come only with a debug player for Flash 9, and not Flash 10?"
Jonathan Feinberg
http://www.adobe.com/support/flashplayer/downloads.html
Cory Petosky
I'm in business. Thanks very much.
Jonathan Feinberg
Sadly, the Text Engine provides no better introspection than the Flash 9 stuff. The best you can get is the broad rectangular bounding box of the TextLine, which you can partition horizontally using atom bounds. But there's no way to get the actual bounds of an individual glyph. Too bad!
Jonathan Feinberg
+2  A: 

Richard is on the right track, but BitmapData.getColorBounds() is much faster and accurate... I've used it a couple of times, and optimized for your specific needs its not as slow as one might think.

Cory's suggestion of using flash.text.engine is probably the "correct" way to go, but I warn you that flash.text.engine is VERY (very!) hard to use compared to TextField.

Cay
On the contrary, it's just what I was looking for! +1 for your helpful comment.
Jonathan Feinberg
A: 

Hello did you find a good solution for that problem using the text layout framework?

Romeo Copaciu
No. As far as I know, it's impossible.
Jonathan Feinberg
I found some actionscript font parsers in my quest for glyph rendering. It might be a solution for what you needed.http://blog.byteface.com/?p=96http://www.sephiroth.it/file_detail.php?id=159
Romeo Copaciu