Enable Smoothing on Images for scaling in Flex 2

While I can’t claim any credit for the solution – most of the credit goes to my colleague from Adobe Consulting Flex Architect Brian O’Conner, and the alternative approach comes from Roger Gonzalez from the Flex Team – I recently came across a small issue. By default, when you embed or load an image in Flex, “smoothing” is set to false. This makes sense since most of the images you’d probably want in their native size, and you’d want pixel perfect. But, when you want to scale the image, either up or down, or rotate the image, the image is rendered with the “nearest neighbor” scaling method. You can read more about the issue in the flash player at Tinic Uro’s Blog. As you can see in the example that follows, the results of this are less than beautiful.

After a little trial and error on my own part, I got some help from the experts, and got a simple solution for enabling smoothing on an image in Flex.


The first approach uses the BitmapAsset class, where init() is called on creationComplete as follows:

import mx.core.BitmapAsset;

[Bindable]
public var mySmoothImage:BitmapAsset;

[Bindable]
[Embed(source="assets/myImage.png")]
public var myImage:Class;

public function init():void
{
mySmoothImage = BitmapAsset(new myImage());
mySmoothImage.smoothing = true;
}

The second approach is somewhat more compact, and uses a class level embed that extends Bitmap, as follows:


[Embed(source="myImage.png")]
public class mySmoothImage extends Bitmap
{
public function mySmoothImage()
{
smoothing = true;
}
}

Below is an example of the same image embedded twice in a flex app, the first with Smoothing enabled, and the second in the default manner. As you change the scale of the image via the slider control, you should be able to notice the difference. This would be valuable for any image that you intend to scale, or perhaps an image that you intend to apply a scale or zoom effect to.

Be warned though, enabling smoothing can affect performance, so you certainly wouldn’t want to enable smoothing for UI elements or items that never intend to scale or rotate.

Click to download the below example

_uacct = “UA-1465179-1”;
urchinTracker();

14 Responses to Enable Smoothing on Images for scaling in Flex 2

  1. cyprian.pl says:

    Great! I’ve been just thinking about smoothing images in Flex. Thanks for the hint.

  2. paolo says:

    Is there a way to make it works with external images loaded on request?

  3. Peter Baird says:

    I’d imagine so. Just wait for the image to load before creating the image class.

  4. paolo says:

    thanks for the reply, but I can’t get it to work.
    I’ve tryed to call a function on complete event of my image, like this:

    public function setImage():void{
    var temp:Class = Class(image.source);
    imageFileSmooth = BitmapAsset(temp);
    imageFileSmooth.smoothing = true;
    image.source = imageFileSmooth;
    }

    I’ve tryed in different ways but always get e casting conflict error.

  5. Eugenio Vitale says:

    In the image ‘complete’ event handler just do something like this:

    var bmp:Bitmap = myImage.content as Bitmap;
    bmp.smoothing = true;

    Hope this help.

  6. Would this work for embeded symbols from a SWF file or is it even necessary?

  7. Aleksandar Dzeletovic says:

    Hi!
    Thank you very much for the guideline. Bellow is the code for smoothing a dynamically loaded picture:

    public function smoothTheImage(e:Event):void{
    var mySmoothImage:Bitmap=new Bitmap;
    mySmoothImage=e.target.content;
    mySmoothImage.smoothing = true;
    var picHolderT:UIComponent= new UIComponent;
    picHolderT.addChild(mySmoothImage);
    this.addChild(picHolderT);
    }

    public function loadTheImage():void{
    var pictLdr:Loader = new Loader();
    var pictURL:String = ‘theImageURL.jpg’;
    var pictURLReq:URLRequest = new URLRequest(pictURL);
    pictLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,smoothTheImage)
    pictLdr.load(pictURLReq);
    }

    I’ve just implemented this (works fine) and I was happy to get rid of that pixelation because most of my current project is based on the Zoom effect.

    Thank you!

  8. Mario says:

    Or thy this:

    public class SmoothImage extends Image {
    private var isImageSmooth:Boolean = true;

    public function SmoothImage() {
    super();
    addEventListener(FlexEvent.CREATION_COMPLETE, smoothImage);
    addEventListener(FlexEvent.UPDATE_COMPLETE, smoothImage);
    }

    private function smoothImage(event:Event):void {
    if (isImageSmooth) {
    var bitmap:Bitmap = ((event.target as Image).content as Bitmap);
    if (bitmap != null) {
    bitmap.smoothing = true;
    }
    }
    }

    public function set smooth(smooth:Boolean):void {
    isImageSmooth = smooth;
    }
    }

  9. Bernhard says:

    Thanks for those examples!

    Could you provide a litte more code to show how to call your methods in a typical case within a MXML file?

  10. Bernhard says:

    Here an enhanced and more complete example based on the comment of DIGITALUnderworld, including the mx:Image tag. And don’t forget to use a policy file crossdomain.xml to allow the access to the remote jpg. (note the checkPolicyFile flag in the code)

  11. I cribbed the code from Aleksandar and ended up with something that smooths images nicely through all resizings of the browser/flex app.

    I created a class (using the flex class-creation wizard to make >src>com>firebrowse>simpleportfolio>SmoothImage.as (but your classpath can vary)) and the contents of that class are:

    (*note – ignore the tags)

    package com.firebrowse.simpleportfolio
    {
    import mx.controls.Image;
    import mx.core.BitmapAsset;
    import mx.events.FlexEvent;

    public class SmoothImage extends Image {

    public function SmoothImage() {
    super();
    addEventListener(FlexEvent.CREATION_COMPLETE, smoothImage);
    addEventListener(FlexEvent.UPDATE_COMPLETE, smoothImage);
    }

    private function smoothImage(event:FlexEvent):void {

    var bitmap:BitmapAsset = ((event.target as Image).content as BitmapAsset);
    if (bitmap != null) {
    bitmap.smoothing = true; //this is for embedded images
    } else {
    if (event.target.content != null) {
    event.target.content.smoothing = true; //this is for non-embedded (loaded) images
    }
    }
    }

    } // end class
    }

    ————–

    This can be called in MXML with the SmoothImage tag rather than the Image tag:

    (make sure to import your class, in my case:
    import com.firebrowse.simpleportfolio.*;)

    ————-
    SmoothImage can also be used in ActionScript, just like an image:

    var thisImg:SmoothImage = new SmoothImage();
    thisImg.source = ‘../assets/home.png’;
    thisImg.percentHeight = 100;
    thisImg.scaleContent = true;
    thisImg.maintainAspectRatio = true;
    imgContainer.addChild(thisImg); //etc.

  12. rui says:

    and loading dynamic images, from a File.nativePath withou a loader?

    i need to load images/convert to bitmap without using loader… garbageCollection don’t remove de content from memory… sucks…

    please!

  13. Tim says:

    One thing to keep in mind when trying to smooth images loaded from another domain, unless there’s cross domain policy file, smoothing won’t work because it’s a violation of the security sandbox. We’ve run into this issue at work.

  14. Josh says:

    Can someone please tell me why I can’t smooth an image if its from a different domain!? Why do I need a crossdomain.xml to do a SMOOHTING filter, I don’t want access to the bitmapData? I have had it with Flash… Please let SilverLight be better.