Hack 24 Solve the Bitmap-Shift Bug

figs/moderate.gif figs/hack24.gif

In Flash Player 6 and below, bitmap images are displaced and distorted. Place the bitmap at the right location and correct for the distortion in those versions of the Flash Player.

As with most extensive tools, you must learn a few tricks to overcome Flash Player's drawbacks. Bitmap shifting is one such drawback; it's a bug dating back to the earliest Flash Players and was corrected only recently?in Flash Player 7.

Even if you're creating movies with Flash MX 2004, you still have to deal with this problem if you're exporting your movies for Flash Player 6 or below. And considering Flash Player 7 is not yet ubiquitous, this problem will face Flash developers for some time.

Flash has a primarily vector-based renderer, and the bitmap-rendering routines in the Flash Player have a few calculation problems that end up distorting the bitmap display. As a result, a compiled Flash movie running in a browser won't always look the same as it did when being tested in authoring: bitmap images may have their content shifted or appear to jump or shake even though there's no movement on the image at all. Macromedia technote 14256 "Bitmaps shift in Macromedia Flash" (http://www.macromedia.com/support/flash/ts/documents/bitmaps_shift.htm) discusses the so-called image-shift bug.

In practical terms, when you use an image in Flash, some content of the image is shifted 1 pixel down and to the right. The entire image is not shifted, just some pixels within it. Not only is most of the image shifted, it's also distorted; you may notice some pixel rows/columns disappearing or getting duplicated. If you use the image inside a movie clip, depending on your registration point (the movie clip origin), you'll notice different portions of the image getting distorted.

It's easier to understand with a visual example. Consider the sample image on the left of Figure 3-45, When you import this image into the Flash authoring tool (including Flash MX 2004), position it properly (on whole pixels, with no decimal places in the X and Y values), and export it as a Flash Player 6 movie, the result is the distorted image on the right of Figure 3-45.

Figure 3-45. A sample image (left) showing the image-shift bug (right)
figs/flhk_0345.gif


The content was shifted down and to the right. While the left column and the top row of pixels were unaltered, because of the shift on the rest of the content, the top and left outlines became stronger while the bottom and right outlines almost disappeared. Depending on the bitmap's registration point, you'll notice different areas of the image shifting.

How Not to Fix It

This bug is widely known in the Flash community, although getting around it is still black magic for most people. Unfortunately, several solutions are floating around, most of which are ineffective or have more drawbacks than they're worth. For clarification's sake, avoid or otherwise be careful if you're trying to fix this bug by any of these techniques:


Using 99% alpha on your image

This fixes the flickering problem on a tweened animation, but it modifies your image colors (albeit imperceptibly) and slows movie playback if you have any animation on top of your image. And it doesn't fix the content-shift problem.


Using a 2-pixel transparent border

This is hard to do (you have to create all images with a transparent border) and will not fix the content-displacement problem, but rather just hide it from the user.


Toggling the Allow Smoothing option in the bitmap properties in the Library

While this will fix image flickering if you're shifting from a moving image to a still image, this has nothing to do with the image-shift bug and also doesn't fix it.


Breaking apart the image and moving parts of it

This simply divides the problem and moves it to other parts of the image.


Resizing the image by a fraction

While resizing does work in avoiding unsolicited pixel displacements, it will modify your image anyway.

While these so-called "solutions" are effective to some extent, they fail to really fix the problem, so it's hard to recommend any of them, save for image resizing (which is useful in one special case?read further).

How to Fix It (the Good Way)

On careful examination, you'll notice this bug occurs only when your image's X and Y positions within the clip or on the Stage are positive. An easy solution then, is to move your image to the area of a movie clip in which the Flash Player has to deal with negative numbers to calculate each pixel position. Doing this is easy: after placing your image on the Stage in the desired position, convert it to a movie clip symbol by pressing F8. In the Convert to Symbol dialog box, shown in Figure 3-46, give it a name, and, more importantly, select the bottom-right box as being the position for the registration point. This positions the movie clip contents?your image?on the top-left side of the middle axis (i.e., in the quadrant for which X and Y positions are negative).

Figure 3-46. Setting the registration point in the Convert to Symbol dialog box
figs/flhk_0346.gif


Moving the registration point is enough to fix the image bug when using images in the Flash authoring environment; you won't have any more image shifting or flickering bugs.

One slight problem though?Macromedia "fixed" the bug in Flash Player 7 by reversing the problem! In Flash Player 7, the bug occurs when your image's X and Y positions are negative rather than positive. The rationale there was that almost everyone will place their images in the positive portion of the clip coordinates.

This means that the fix for the bug in Flash Player 6 actually causes a problem in Flash Player 7. If you are exporting in Flash Player 7 format, you should not use this hack.


How to Fix It in Dynamically Loaded Files (the Effective Way)

While the previous solution is enough to get around the image-shift bug when working with bitmaps inside the Flash authoring tool, it does not apply when loading images into Flash with loadMovie( ). Unfortunately, you can't move a loaded image's registration point so that the graphic location is in the upper-left quadrant (negative X and Y coordinates); since the loaded image is a movie clip container itself, the image content will still be on the positive side of the axes. For example, the following code produces the same results as Figure 3-45; content is shifted down and to the right:

// Creates and loads the image into the Stage

this.createEmptyMovieClip("myImage", 1);

this.myImage.loadMovie("testImage.jpg");

However, there's a simple solution to this problem. By scaling the image by a very small fraction?so small it's unnoticeable?you can force the Flash Player to use precise values that'll make the end image seem correct when calculating pixel position. This has to be done after the image is loaded.

The image can be scaled slightly in several ways. The following code fires the resize commands as soon as the image is loaded, thus counteracting the bug:

// Creates and loads the image into the myImage clip 

// and places it on stage

this.createEmptyMovieClip("myImage", 1);

this.myImage.loadMovie("testImage.jpg");



// Creates a "watcher" movie to fix the size as soon as it's loaded

this.createEmptyMovieClip("myImageLoader", 2);

this.myImageLoader.onEnterFrame = function( ) {

  if (this._parent.myImage._width > 1) {

    // Image has been loaded

    this._parent.myImage._xscale = 99.98;

    this._parent.myImage._yscale = 99.98;

    this.removeMovieClip( );

  }

};

While resizing the image is usually not desirable, in this special case it's acceptable because it's the best way to avoid the image-shift bug. Usually, distortion, if any, caused by resizing isn't noticeable. In the preceding code, for example, resizing the test image solves the bitmap-shift problem, but it still maintains the same width and height; if you do a trace( ) on the image _width after loading, you'll notice it displays the original image width.

?Zeh Fernando