Wrapping text around an image or movieclip in Flash

textwrapping01

Text has always been a bit of a pain in the ass in Flash (luckily, Flash CS5 will include the new Text Layout Framework) – apart from the fact that rich text and custom typography isn’t a problem, it’s really one of those areas where plain old HTML takes the win. Still, I just discovered something that makes life a little easier if you’re going to design a text heavy website in Flash – the ability to wrap text around images (and MovieClips) in a fairly easy way – without multiple text fields, split up strings and whatnot.

So how is it done? Well, it turns out that Flash actually has the ability to embed an image directly into a dynamic text field, using HTML markup. I for one wasn’t aware of this at all, and the documentation was really thin in regards to embedded TextField media, so I hope this little walk-through will be helpful to someone.

textfield.htmlText = "<img src='monkey.jpg' />";

And that’s it. The image loads (without having to assign a Loader object, an URLRequest or anything) and is placed into the textfield, with any text wrapped neatly around it. Great! You can even specify the alignment of the image (align=”left”) to make the text wrap to the left or right of the photo. Additional properties can be set, such as vspace and hspace to control padding – but it’s all quite limited. For example, you have no way of adding a preloader, you can’t control the left/right/bottom/top padding individually, you can’t add a background/frame, tinker with the alpha channel etc. Actually, right now, you’ve no way of manipulating that image through AS at all. To do that, you need to store a reference to the embedded bitmap in a variable. To do this, the embedded image’s id property needs to be set:

textfield.htmlText = "<img src='monkey.jpg' id='myImage' />";

Then, you store the reference by refererring to that id:

var _image:Bitmap = textfield.getImageReference('myImage') as Bitmap;

Now, you get access to all of the properties of the Bitmap class, and can do stuff like tweening the alpha channel, copying the image, change the colors etc. But you still have no way of adding a preloader or any graphics to the image – to do that, you need to not embed a bitmap file, but a movieclip.

Fortunately, this method works just as well for any kind of DisplayObject. Instead of passing an URL to the text field, you pass the AS identifier (which means the object needs to exist in your library). For example, if I’ve created a MovieClip with the identifier “ImageContainer”:

textfield.htmlText = "<img src='ImageContainer' id='myImageContainer' />";

Notice that you still need the id property, and you still need to call the getImageReference method of the TextField to manipulate your embedded MovieClip. For example:

var _imageContainer:MovieClip = textfield.getImageReference('myImageContainer') as MovieClip;

Then, you can easily load the bitmap using a regular loader, adding it to the _imageContainer MovieClip upon completion – which means total control over preloading, error handling etc.

There’s only one problem. When you embed a DisplayObject in a TextField, Flash automatically pulls the dimensions of the object and uses that to wrap the text. This is fine when you add an image directly, but to use a container MovieClip you obviously need to set the size of the image to be loaded – and before it actually loads, so that the container will have the correct size. If you’d set the width and height later, the TextField wouldn’t change the wrapping – there’s (as far as I know!) no way to update this (you could always set the htmlText property again with the correct dimensions after the image has loaded, but this would look weird and make everything jump around).

There are many situations where getting an image’s dimensions before loading it is desireable, and Flash doesn’t ship with any built-in methods for this. Thankfully, Antti Kupila has written an excellent class for exactly this purpose, called JPGSizeExtractor.

var _extractor:JPGSizeExtractor = new JPGSizeExtractor();
_extractor.addEventListener(JPGSizeExtractor.PARSE_COMPLETE,onJPGSizeExtractComplete);
_extractor.extractSize("monkey.jpg");
function onJPGSizeExtractComplete(e:Event):void {
var _imgW:Number = _extractor.width;
var _imgH:Number = _extractor.height;
}

Using the _imgW and _imgH variables, you can set the width and height of the embedded object. This will ensure that the TextField “reserves” the appropriate space for the the image.

textfield.htmlText = "<img src='ImageContainer' id='myImageContainer' width='"+_imgW+"' height='"+_imgH+"' />";

There’s still one little problem to work around. Say your MovieClip container is 400×300 px in the library. When it’s embedded in the text field, its set to the correct dimensions (which is the same dimensions as the image its eventually going to contain). However, this will scale the container, meaning that any content you later add to it (the image, a preloader, text) will also look scaled. The way to solve this is to just reset the container’s scale properties:

imageContainer.scaleX = imageContainer.scaleY = 1;

My container contains one child object, which is the frame/background graphics. I’ve set the instance name of this MovieClip to frame_mc. As I’ve reset the container’s scale properties, I need to set the correct dimensions to the frame instead:

imageContainer.frame_mc.width = _imgW;
imageContainer.frame_mc.height = _imgH;

By keeping the containers scale to 1, anything you add to it will keep its scale and aspect ratio. Load the image and add it to the container’s DisplayList – and you’ve got a beautiful text field with text wrapping around a correctly scaled image, of which you have total AS control.

textwrapping02

In my example, I’ve got my text in an XML file, adding the <img> tags through Actionscript. Obviously, if the content had been retrieved from a CMS the <img> tags would’ve probably be embedded in the text, and you would have to write some regular expressions to pull them out, store their position in the string and add them back in using the methods above.

The only thing I’m struggling with so far is center aligning the image – I can’t seem to do it. Nesting an image tag within an <a>tag  is also a no-go, so if your images should function as links you will need to pull those URL’s out and add them back in using MouseEvents. The third issue is with padding – using a MovieClip container still doesn’t enable you to manipulate the left and right, top and bottom paddings individually, and the container doesn’t seem to respond to x and y manipulation once it’s embedded. A possible workaround would be to hide the embedded container and add a new one on top of the TextField… which would be fine, the hidden container doesn’t need to actually contain anything, it’s just a way to make the TextField reserve the appropriate space for whatever DisplayObject you want wrapped.

If anybody knows anything about center alignment of embedding TextField media or of an even better way of wrapping text around DisplayObjects (what about non-square DO’s, for example…) – leave a comment!

Download example source files here

The photo used in the example was taken by e-Eva-a at stock.exchng.

Kudos to Antti Kupila for the JPGSizeExtractor class

This entry was posted in Flash, Front-end and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

4 Comments

  1. Posted November 10, 2009 at 17:22 | Permalink

    Thank you for this study. It is now the most complete text in the web around text field embedding,and wrapping!

  2. Posted November 11, 2009 at 13:36 | Permalink

    Thank you for the kind words, glad it proved useful!

  3. Posted March 26, 2010 at 10:51 | Permalink

    Nice investigative work. This will come in handy for an AS3 project I’m just gearing up to start.

  4. Anders
    Posted April 15, 2010 at 16:33 | Permalink

    Is the “as movie clip” actionScript 3.0 notation? Like:

    var _imageContainer:MovieClip = textfield.getImageReference(‘myImageContainer’) as MovieClip;

    If yes. How do i do this in AS 2.0?

2 Trackbacks

  1. By Wrapping text around a DisplayObject in Flash on November 13, 2009 at 13:02

    [...] wrote a short tutorial on how to wrap text around a DisplayObject in Flash on labs.makingwaves.com. Click here to check it out! This entry was posted in Actionscript, Flash and tagged Actionscript, as3, Flash, ui. Bookmark the [...]

  2. [...] recently wrote a short tutorial on how to wrap text around a DisplayObject in Flash on labs.makingwaves.com. Click here to check it out! This entry was posted in Flash, Tutorials and tagged Actionscript, [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>