Sunday, December 18, 2005

Dynamically loading bitmaps with smoothing in Flash Player 8

We have gotten a bunch of feedback on this oversight in Flash Player 8. Well oversight might be an understatement, it's really a bug. When you dynamically load a bitmap in a Flash 8 file, smoothing is always turned off and rotating or scaling an image will yield ugly artifacts. Originally I made this choice for performance reasons, as smoothed display is much slower than the standard 'nearest neighbour' scaling method. Little did I know that there would be an uproar among users :-)

Now, there is some good news. Flash Player 8.5 will fix this for AS3.0 and we will even add a new property to the AS2.0 MovieClip class which will allow you to turn this on and off dynamically. The current name of that boolean property is MovieClip.forceSmoothing, which subject for change though. This property will be enabled for version 8 Flash content also, not only 8.5. Once we update the Flash Player 8.5 alpha on the labs site (I can't tell you when/how/if this will happen since I do not know) you should definitely check it out and give us feedback on it.

In the meantime there is a workaround using BitmapData which has been floating around already. For those of you who have not played with the BitmapData object yet and feel left out, let me post a little snippet which will do the job:

import flash.display.*;

function loadBitmapSmoothed(url:String, target:MovieClip) {
// Create a movie clip which will contain our
// unsmoothed bitmap
var bmc:MovieClip = target.createEmptyMovieClip(
"bmc",
target.getNextHighestDepth());

// Create a listener which will notify us when
// the bitmap loaded successfully
var listener:Object = new Object();

// Track the target
listener.tmc = target;

// If the bitmap loaded successfully we redraw the
// movie into a BitmapData object and then attach
// that BitmapData to the target movie clip with
// the smoothing flag turned on.
listener.onLoadInit = function(mc:MovieClip) {
mc._visible = false;

var bitmap:BitmapData = new BitmapData(
mc._width,
mc._height,
true);

this.tmc.attachBitmap(
bitmap,
this.tmc.getNextHighestDepth(),
"auto",
true);

bitmap.draw(mc);
};

// Do it, load the bitmap now
var loader:MovieClipLoader = new MovieClipLoader();
loader.addListener(listener);
loader.loadClip(url, bmc);
}

To use this snippet simple paste the function into your code and then load a bitmap this way f.ex.:

createEmptyMovieClip("myMC",getNextHighestDepth());
loadBitmapSmoothed("mypic.jpg",myMC);

This leaves you with a movie clip which contains the smoothed bitmap. Here is a sample .fla and .swf. Obviously this snippet might not be exactly suitable for your needs, especially if you need to handle loading events, but it should give you an idea how it generally works.

67 Comments:

Anonymous Anonymous said...

I'm not quite clear, will this only be fixed in 8.5 player, or will there also be an update to the 8 player that will fix this?

Monday, December 19, 2005 6:44:00 AM  
Anonymous Mario Klingemann said...

I wonder what happens with the original movie that you have loaded? As I understand it that one will still eat up some memory, won't it? So wouldn't it be more effective to delete the movie after the draw command? And what's your recommended method of doing that removeMovieClip(), unloadMovie() or maybe createEmptyMovieClip() at the same level?

Monday, December 19, 2005 12:21:00 PM  
Anonymous Anonymous said...

what about the _quality = "best"; ?

That would also make the bitmaps smooth while being rotated and scaled, right?

Monday, December 26, 2005 10:54:00 AM  
Anonymous Daniel Todd said...

^^ Nope it won't, thats the whole problem :(

Saturday, December 31, 2005 4:17:00 AM  
Anonymous Anonymous said...

This code is great! My one question is if there is a way to do this and preserve alpha channels. The alpha channel in my pngs drop out when I use this code. Thanks!

Wednesday, January 04, 2006 10:40:00 PM  
Anonymous Daniel Todd said...

^^ I think you might be able to use this but I haven't tested it myself:

myBitmapData.transparent = true;

Monday, January 09, 2006 3:53:00 PM  
Anonymous Shinobu said...

oh yes I tried this workaround before. However this will not work if the images being loaded are on a different network. the Sandboxing eliminates the ability to capture or manipulate bitmap data generated from these. But still better than nothing (waits for 8.5)

Thursday, January 19, 2006 8:55:00 AM  
Anonymous Anonymous said...

you can preserve the alpha channels using this line instead of the existing one:

var bitmap:BitmapData = new BitmapData(mc._width, mc._height, true, 0x000000);

don't ask my why it needs the redundant 0x000000 to function though!

Monday, January 30, 2006 9:54:00 AM  
Anonymous Anonymous said...

What if you are using the loader component? Any way to force _quality="BEST" on this? Will this be fixed?

Monday, January 30, 2006 12:48:00 PM  
Blogger sotirov said...

The copy bitmap will only work for images from the same domain. There is an issue with the Flash player security settings that will prevent you to do make bitmap copy for resources residing in another domain. An option is to put them in swf files but the issue remains open for FLV files server from a streaming server.
If anyone is aware of a workaround please post it.

Sunday, February 05, 2006 7:29:00 AM  
Anonymous Banana said...

Why can you only load images from thesame domain?! That really s***, because what to do when you'd like to load images from Flickr? What if php doesn't run on your server?!
Please people do something about this.. You're helping nobody with this!

Sunday, February 19, 2006 3:04:00 AM  
Anonymous Anonymous said...

Thank you very much for this information! Really helped me for a project I have to finish in two(!) days..;)

Even the hint to preserve alpha channels worked!

Thanks again and best regards, Roger

Tuesday, February 21, 2006 6:18:00 PM  
Anonymous Anonymous said...

how can I save an image (the screen shot) from flash into local disk?

sun

Saturday, February 25, 2006 4:42:00 AM  
Anonymous Anonymous said...

I do not know if you will even read this.

I am loading a jpg from another site and then am scaling it using:

mc._height = 164
mc._width = 164

Of couse without smoothing this look like crap. How could I do the smoothing and then resize the movie clip?

Wednesday, March 22, 2006 10:38:00 AM  
Anonymous Anonymous said...

it's a nice workaround but there are several drawbacks you should'nt forget:

- converting needs performance big time
- doing anims with those bitmaps aint not fun too

just stumbled on this bug while working on a gallery - bitmapping 700x400 pics needs 100% load for at least 1-2secs (@3ghz)
and for the planned anims its a complete showstopper.

looks like the peeps over a macromedia never use their own stuff =)

Tuesday, March 28, 2006 8:30:00 AM  
Anonymous Anonymous said...

I would really like to know the reasons as to why this sandbox thingy exists for the draw function. I see no reason, if I would like to steal an image or a video off-site for some reason, I certainly wouldn't use flash.

How come it's not documented? I had to spend two hours figuring out what return -5 meant, I thought I had some error in my code first (BitmapData.draw() is not even documented to have any return).

This kills so many creative possibilities it's ridiculous, it would really be sad if this is forced to be there for legal reasons or something, but if not, please fix asap cause it's killing me and my applications...

/Markus

Tuesday, April 11, 2006 1:26:00 AM  
Anonymous Deneb Meketa said...

To those objecting to the cross-domain restrictions, three things.

First, you can use BitmapData.draw across domains if what you're draw()ing is a SWF, and that SWF calls System.security.allowDomain to permit access by your domain (or all domains).

Second, there was an omission in FP8: we didn't provide a way to permission BitmapData.draw() across domains when the thing you're draw()ing isn't a SWF (e.g. it's a bitmap). This will be fixed in FP9; you will be able to use policy files to permit such things.

Third, while of course we understand that security is frustrating, please don't take the attitude that we don't understand what we're doing or that we're trying to mess up your lives. The reason you have any livelihood at all writing Flash content is that the Flash Player is on >95% of Internet-connected machines in the world. That would quickly cease to be the case if anyone managed to write a malicious SWF that stole files off your machine or impersonated you to your bank. Preventing problems like this is very difficult, and sometimes has the unfortunate effect of requiring you to prove the legitimacy of what you're doing, so that we can distinguish your legitimate case from a variety of illegitimate cases. Believe me, we hate introducing barriers for Flash developers. But, in the end, we can't live with security vulnerabilities, so we do our best to design a secure runtime.

As time goes by, hopefully we'll do a better job documenting how to deal with Flash security. The new AS3 docs will contain a big chapter on security, and while it will be big and confusing, it's a start, and it will be getting more love in future releases.

Monday, May 01, 2006 7:20:00 PM  
Anonymous III said...

a simple proxy script will serve the purpose of fixing the bitmap.draw sandbox limitations. I've already implemented the solution without any issue. Works great and I don't have to wait on FP9.

Monday, May 15, 2006 11:35:00 AM  
Anonymous Toni said...

First, excuse my english. There is a methot to get images from another domain. Create a php file, hosted at the same domain that the swf. This php could get the image data from another domain, like from flickr.com, for example. This work.

Monday, June 19, 2006 2:41:00 PM  
Anonymous Lars said...

Hi,

Flash Player 9 has been released.

I can't find any information about "MovieClip.forceSmoothing". Is there a documentation I've missed?

Thanks, Lars

Wednesday, June 28, 2006 2:31:00 AM  
Anonymous Paul Neave said...

This issue still doesn't seem to be fixed in Flash 9. In the preview release of Flash 9 I tried the follow code:

stage.quality = StageQuality.BEST;

var request:URLRequest = new
URLRequest("http://www.google.com/intl/en/images/logo.gif");
var loader:Loader = new Loader();
loader.load(request);
addChild(loader);

When you zoom in on the Flash movie the image remains aliased and not
smoothed. Please tell me I'm missing something, that there's a simple
way to smooth an image once loaded in, and not that this issue still
hasn't been fixed.

Many thanks.

Sunday, July 02, 2006 9:49:00 AM  
Anonymous Anonymous said...

Still haven't managed to fix this bug in the released version of Flash 9, eh? Does anyone with a half a brain work on the Flash player team anymore?

Wednesday, July 05, 2006 8:51:00 PM  
Anonymous Toni said...

I use this php script in the same host i have the swf.

// put ...php?src=IMAGEURL

header("Content-type: image/jpeg");
$file = fopen ($_GET["src"], "r");
if (!$file) {
echo "Unable to open remote file.\n";
exit;
}
while (!feof ($file)) {
$line = fgets ($file, 1024);
echo $line;
}
fclose($file);

You can test it at http://www.familiacastilloquero.com/

The php is at http://www.familiacastilloquero.com/traeimagen.php?src=http://static.flickr.com/66/160704305_e86f330d71.jpg?v=0

Friday, July 21, 2006 4:45:00 AM  
Anonymous Anonymous said...

So wait--- how do we use the snippet??

Thursday, October 26, 2006 11:59:00 PM  
Anonymous Rick said...

Great, was looking for a fix for this!

Wednesday, November 22, 2006 10:34:00 AM  
Blogger robert said...

God Bless you my Son!!

Thursday, March 29, 2007 1:39:00 PM  
Blogger Wanni said...

Thank you very much for this snippet, it helped me loads!

Wednesday, May 23, 2007 10:23:00 PM  
Anonymous astgtciv said...

Another possible solution for the smooth image loading is a tiny FP7 swf used as an RSL in your project with the express purpose of loading images under it. If you attachMovie() a shared movieclip from the FP7 RSL in the main FP8+ swf, and then load an image under the attachedMovie, the image seems to load using FP7 rules (i.e., smoothed). The full discussion is here.

Thursday, May 24, 2007 2:07:00 AM  
Anonymous tranda said...

it really works

thx a lot

Friday, June 01, 2007 2:47:00 AM  
Blogger Charlene said...

Hi there! Can you help me with where to put loadBitmapSmoothed("mypic.jpg",myMC);??

I'm loading a bunch of pictures into a clip dynamically that I'm enlarging on rollover and a bit of a newbie to AS. a snippit of my code...

function thumbnails_fn(k) {
thumbnail_mc.createEmptyMovieClip("t"+k, thumbnail_mc.getNextHighestDepth());
tlistener = new Object();
tlistener.onLoadInit = function(target_mc) {
target_mc._xscale = target_mc._yscale = 75;
target_mc._x = hit_left._x+(target_mc._width+5)*k;
target_mc.pictureValue = k;

help would be greatly appreciated!!

Saturday, June 09, 2007 12:13:00 AM  
Blogger fil said...

Cheers Tinic!

The fix worked an absolute treat.

Friday, June 29, 2007 3:17:00 AM  
Blogger Mark Richmond said...

Tinic,

I'm using Flash CS3 and I can't find any reference to the MovieClip.forceSmoothing parameter. Did that get cancelled? Right now I'm using a proxy script and bitmapData to get external images (i.e. Flickr) to smooth in Flash 8 and bypass the security issues. This is NOT an effective solution. Is there a simpler way to smooth images loaded from other servers in CS3?

Thanks,

Mark

Monday, July 02, 2007 1:43:00 PM  
Anonymous Anonymous said...

hi.

in Flash CS3 check out from help
ActionScript classes > MovieClip > forceSmoothing (MovieClip.forceSmoothing property)

it's there but it only works with loadmovie()?
Im using movieliploader and this gives no effect.

Thursday, August 02, 2007 1:44:00 AM  
Blogger avijit dutta said...

We are developing an dynamic animated image gallery using Flash 8 & AS2, for which the images are called up from a different domain. I have used the reflection class (in which bitmapdata.draw() works ) to achieve reflections. This works fine when the images are called from the same domain. But, when the images are called from another domain, the reflection class does not work because bitmapdata.draw() does not work on crossdomain images due to sandbox security. Although the images are showing up. I have been trying this for the last few days with little success.

Please help me how to do ?

you can check same gallery at :

http://www.amazon.com

Tuesday, August 07, 2007 11:39:00 PM  
Blogger avijit dutta said...

can you tell me how can i use bitmapdata.draw on loaded image from cross domain server. i am continue trying but little success.

Please help me.

Wednesday, August 08, 2007 2:37:00 AM  
Anonymous Anonymous said...

Adobe needs to fix this for good !
In the meantime your snippet worked smoothly ! ;-)
Thanks a lot !

Wednesday, August 08, 2007 3:37:00 AM  
Anonymous Anonymous said...

Is it possible to apply a smooth with BitmapData on a picture of the library linked by attachMovie?

Tuesday, August 14, 2007 6:46:00 AM  
Anonymous <a href="http://drugscenterhere.com">ShopMan</a> said...

I like articles like this. Thanks!

Sunday, August 26, 2007 12:39:00 AM  
Anonymous Anonymous said...

You are a Genious man!, Im not a programmer, just a flash designer with some knlwledge of AS2 coding, and this issue have bother me for a long time, I have tested your solution and works perfect
Thanks!!!

Monday, August 27, 2007 3:32:00 PM  
Anonymous <a href="http://m1.aol.com/phentermine4">Phentermine</a> said...

Great Article! Thank You!

Tuesday, August 28, 2007 4:00:00 PM  
Anonymous <a href="http://m1.aol.com/phentermine4">Buy Phentermine</a> said...

Thanks to author! I like articles like this, very interesting.

Wednesday, August 29, 2007 3:25:00 AM  
Anonymous harry said...

Hi,

I'm using the following code, yet I cannot get the image smoothing to work.

var myBitmapData:BitmapData = new BitmapData(96,96,true);
myMatrix = new Matrix();
myMatrix.scale(.15,.15);

var mc_1:MovieClip = this.createEmptyMovieClip("mc", this.getNextHighestDepth());
mc_1.attachBitmap(myBitmapData,myMatrix,"auto",true);
myBitmapData.draw(_root.car,myMatrix);

Any help would be apprecaited.

Wednesday, August 29, 2007 10:56:00 PM  
Anonymous <a href="http://free-metro-pcs-ringtones.blogspot.com">Free Ringtones</a> said...

nice blog!

Sunday, September 02, 2007 12:39:00 PM  
Anonymous Anonymous said...

What a friggin´ mess of a solution to anti-alias dynamically loaded images!

Why in the world is this excruciating problem not solved yet..?!?

Monday, September 03, 2007 4:47:00 AM  
Anonymous <a href="http://buy-viagra2007.blogspot.com">buy viagra</a> said...

nice blog!Nice information

Monday, September 03, 2007 3:57:00 PM  
Anonymous <a href="http://buy-levitra--ooz.blogspot.com">Levitra</a> said...

:-) ochen\' zaebatyj blog!

Tuesday, September 04, 2007 3:59:00 AM  
Anonymous <a href="http://buy-soma--ooz.blogspot.com">Buy Soma</a> said...

soglasen s vami ochen\' zaebatyj blog!

Thursday, September 06, 2007 4:01:00 AM  
Anonymous <a href="http://search.cnn.com/search?query=site:cialis-online-2007.blogspot.com?cialis_online.html">Anonymous</a> said...

Keep up the great work. It very impressive. Enjoyed the visit!

Sunday, September 09, 2007 2:46:00 PM  
Anonymous <a href="http://m2.aol.com/LorenLynn03/index8.html">Anonymous</a> said...

Nice! Nice site! Good resources here. I will bookmark!

Sunday, September 09, 2007 9:12:00 PM  
Blogger macw said...

Hi. Solution works well with loaded images, thank you for that.
Problem to be solved now....how do I mask the loaded image using your provided code?

simply setting

mc.setMask(masker);

in the onLoadInit function does not do the trick.


Thanks in advance
-----------------------
well that was easier than expected.
never mind
needed to refer to my initial movieClip -doh-

-----------------------



marc

Monday, September 17, 2007 12:34:00 PM  
Blogger Charles said...

Hi Tinic

What's the current status of this? In Flash player 9 we still are having issues. We can set the stage quality to BEST to get decent looking images, but this doesn't work in AIR!

Can you advise how we might be able to do proper anti-aliasing in AS3 code instead? Maybe some mip map or something?

thanks
charles

Monday, September 17, 2007 3:04:00 PM  
Blogger xoc said...

What has me really confused is that the dynamically loaded jpegs are smoothed here: http://www.actionscript.org/resources/articles/129/1/MovieClipLoaders-Part-2---Looping-and-Listeners/Page1.html

Anyone know what the story is?

Wednesday, September 26, 2007 7:52:00 PM  
Anonymous Jason Faulkner said...

This example has worked great for me,.
However I'm working on a photographers website and am noticing that there is a loss in image quality, ie: contrast and original color is washed out,.

I'm using the bitmapData example above, then setting the stage.scale="showall";
for scalability..
compare here:
http://shanemccauley.com/4/ - contrast issue

http://shanemccauley.com/3/ - previous version, some distortion, decent contrast values..

any ideas ?

Monday, October 01, 2007 11:46:00 AM  
Anonymous Anonymous said...

Hello,

Awesome script. Works well.
Question, How can I create a loader for this? All I need is a percentage loader.

Thank you.

Tuesday, October 09, 2007 6:50:00 PM  
Anonymous Anonymous said...

This code is great but how do you use it for a WHOLE GALLERY of images pulling from a folder through XML?


Ive spent the last 6 hours trying to figure it out and cant! help!!!!

Sunday, October 21, 2007 3:04:00 PM  
Blogger Tyler said...

thanks for the help, was wonering for a while how you could do this in AS2.

Tuesday, November 27, 2007 2:21:00 PM  
Blogger Tyler said...

This code is great but how do you use it for a WHOLE GALLERY of images pulling from a folder through XML?


Ive spent the last 6 hours trying to figure it out and cant! help!!!!


If you figure out how to modulate this code over to a class(which goes pretty easy) then you can load your gallery using the call to load the external asset for each image. Piece of cake.

Tuesday, November 27, 2007 2:24:00 PM  
Anonymous collin said...

The way to do it in flash 9 is MUCH simpler.

in the completeHandler function the code it simply:

var image:Bitmap = Bitmap(loader.content);
image.smoothing = true;
aContainer.addChild(image);

Tuesday, November 27, 2007 9:47:00 PM  
Anonymous Anonymous said...

Gracias!!

Monday, December 03, 2007 9:05:00 PM  
Blogger Carles said...

Thanks! I think i'll switch as soon as possible to AS3, it pays for the effort :)

Tuesday, December 18, 2007 10:15:00 AM  
Blogger zeekle said...

Make smoothing DEFAULT !!

Tuesday, December 18, 2007 10:36:00 PM  
Blogger Frank R said...

Thank you for this, it proved perfect for my application.

Thursday, January 03, 2008 6:04:00 AM  
Blogger Josh said...

THanks for the code... THis will same me a headache. I was rackin my brain for hours trying to figure this out.

Sunday, January 06, 2008 2:02:00 PM  
Anonymous itsricky said...

how on earth should i go about preloading this data? i have a series of neccesarily high res jpg's but there isa pretty long hang time with this script. is is great though dont get me wrong...

preload?? any ideas?

Tuesday, January 15, 2008 2:36:00 PM  
Blogger Matt said...

Yeah... no offense to you personally but this is very idiotic on the part of adobe/macromedia (at the time).
I mean if flash 6/7 both support bitmap smoothing by default why wouldn't flash 8? and how rediculous is it that such a complicated work around is necessary just to create smooth rotations/scalings on bitmaps. :| I really like certain things about flash 8 but this is totally a drawback and having to write in that rediculous function to smooth bitmaps has to be a big performance hinderer.
Anyway... i saw that it still isn't fixed in player 9 for AS2/flash8 published files so I guess for now I am stuck either using drawing methods to rotate images or to use flash 7 movies for them.

Tuesday, January 29, 2008 9:26:00 AM  
Blogger Brian said...

HI There,

I found this very useful but wanted a more OO way of using it so I slapped into a class. Great resource and little more reusable this way. Hope it helps.

Save it as LoadBitmapSmoothed.as and call it thusly

LoadBitmapSmoothed.load(thumbs[i], thisTmb.img);

Cheers

import flash.display.*;
class LoadBitmapSmoothed {
private static var bmc:MovieClip;
private static var listener:Object;
private static var loader:MovieClipLoader;
public static function load(url:String, target:MovieClip) {
bmc = target.createEmptyMovieClip("bmc",target.getNextHighestDepth());
listener = new Object();
listener.tmc = target;
listener.onLoadInit = function(mc:MovieClip) {
mc._visible = false;
var bitmap:BitmapData = new BitmapData(mc._width, mc._height, true);
this.tmc.attachBitmap(bitmap, this.tmc.getNextHighestDepth(),"auto", true);
bitmap.draw(mc);
};
loader = new MovieClipLoader();
loader.addListener(listener);
loader.loadClip(url, bmc);
}
}

Thursday, February 28, 2008 5:56:00 PM  
Blogger Brian said...

HI There,

I found this very useful but wanted a more OO way of using it so I slapped into a class. Great resource and little more reusable this way. Hope it helps.

Save it as LoadBitmapSmoothed.as and call it thusly

LoadBitmapSmoothed.load(thumbs[i], thisTmb.img);

Cheers

import flash.display.*;
class LoadBitmapSmoothed {
private static var bmc:MovieClip;
private static var listener:Object;
private static var loader:MovieClipLoader;
public static function load(url:String, target:MovieClip) {
bmc = target.createEmptyMovieClip("bmc",target.getNextHighestDepth());
listener = new Object();
listener.tmc = target;
listener.onLoadInit = function(mc:MovieClip) {
mc._visible = false;
var bitmap:BitmapData = new BitmapData(mc._width, mc._height, true);
this.tmc.attachBitmap(bitmap, this.tmc.getNextHighestDepth(),"auto", true);
bitmap.draw(mc);
};
loader = new MovieClipLoader();
loader.addListener(listener);
loader.loadClip(url, bmc);
}
}

Thursday, February 28, 2008 5:57:00 PM  

Post a Comment

<< Home