Kun Janos around Adobe’s <Flex> and <Flash>

about me, my life and my work

Flex Image Resize Produces Poor Quality Images

Posted by admin on March 9th, 2009

Flash/Flex/AIR produces a poor quality(pixelated) image when you load a larger image and try to re size it in the player to a much smaller size.
I searched the web and found this post http://www.cafesilencio.net/blog/bitmapdata-resize-quality-in-flex-and-air, tried the code but I didn’t see any improvements on the image quality.
It seams that Flash player doesn’t use a bilinear/bicubic interpolation algorithm to resize images, probably that’s why the produced image is so bad.
I came up with a solution, it seams that if you first apply a Blur effect on the image, then resize it, the produced image will appear much nicer. Of course the amount of Blur has to be calculated, otherwise we will end up with a poor quality image…again.
Check out the image before/after my solution, also you can try out the solution here resize1 (don’t forget to check the “Apply Blur” check box to see my re size solution)
Here is the code for resize images using blur.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
	creationComplete="applyEffects()">
 
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.core.UIComponent;
 
			[Bindable] private var blurQualityDP:ArrayCollection = new ArrayCollection([{label: 'Low', value: BitmapFilterQuality.LOW}, 
																						{label: 'Medium', value: BitmapFilterQuality.MEDIUM},
																						{label: 'High', value: BitmapFilterQuality.HIGH}
																							]);
 
			public static function getUIComponentBitmapData( target:UIComponent ):BitmapData {
				var bd:BitmapData = new BitmapData( target.width, target.height, true, 0 );
				var m:Matrix = new Matrix();
 
				bd.draw( target, m, null, null, null, true );
				return bd;
			}
 
			private function applyEffects():void {
				var w:int = widthSlider.value;
				var ratio:Number = w / originalImage.width;
				var h:int = originalImage.height * ratio;
 
				if (applyBlur.selected){
					var blurXValue:Number = Math.max(1, originalImage.width / w) * 1.25;
					var blurYValue:Number = Math.max(1, originalImage.height / h) * 1.25;
 
					var blurFilter:BlurFilter = new BlurFilter(blurXValue, blurYValue, int(blurQuality.selectedItem.value));
					originalImage.filters = [blurFilter];
				} else {
					originalImage.filters = [];
 
				}
				var bd:BitmapData = getUIComponentBitmapData(originalImage);
 
 
				var rbd:BitmapData = resizeImageBD(bd, w, h);
				img1.source = new Bitmap(rbd, PixelSnapping.AUTO, true);
			}
 
 
			public static function resizeImageBD( bitmapData:BitmapData, width:Number, height:Number ):BitmapData {
				var newBitmapData:BitmapData	= new BitmapData( width, height, true, 0x000000 );
				var matrix:Matrix				= new Matrix();
				matrix.identity();
				matrix.createBox( width / bitmapData.width, height / bitmapData.height );
				newBitmapData.draw( bitmapData, matrix, null, null, null, true );
				return newBitmapData;
			}
 
		]]>
	</mx:Script>
	<mx:VBox>
 
		<mx:HBox>
			<mx:Label text="Image Width" />
			<mx:HSlider id="widthSlider" 
				value="300" minimum="0" maximum="1600" 
				width="800" 
				change="applyEffects()" liveDragging="true"
				snapInterval="5"
				dataTipPrecision="0"/>
			<mx:CheckBox id="applyBlur" label="Apply Blur" change="applyEffects()"/>
 
			<mx:ComboBox id="blurQuality" dataProvider="{blurQualityDP}" change="applyEffects()"/>
		</mx:HBox>
 
		<mx:Label text="Image Width: {widthSlider.value}" />
 
		<mx:Canvas>
 
			<mx:Image id="originalImage" source="@Embed(source='test7.jpg')"
				x="100" y="100"/>
 
			<mx:Image id="img1" 
				/>
 
		</mx:Canvas>
	</mx:VBox>
 
</mx:Application>

2 Responses to “Flex Image Resize Produces Poor Quality Images”

  1. datafunk Says:

    Hi Janos,

    Thanks for the post, in my search to high-quality resizing with flex/air, it was very helpfull. But I also found this way to resample bitmap data.
    envrac.org

    Greetz,

  2. nikola Says:

    Thanks for this source code! I was looking for a Flex component which would support bi cubic interpolation while scaling the original image. Based on your source code I managed to make a new component which supports this. Here’s the source code:


    package custom_components
    {

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.IBitmapDrawable;
    import flash.display.LoaderInfo;
    import flash.display.MovieClip;
    import flash.display.PixelSnapping;
    import flash.events.Event;
    import flash.filters.*;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    import mx.controls.Image;
    import mx.core.UIComponent;
    import mx.core.mx_internal;

    use namespace mx_internal;

    public class SmoothImage extends Image {

    public function SmoothImage():void {
    super();
    }

    override mx_internal function contentLoaderInfo_completeEventHandler(evObj:Event):void {

    var currTarget:LoaderInfo = evObj.currentTarget as LoaderInfo;

    // create a copy of original bitmap
    var originalImage:BitmapData = new BitmapData(currTarget.width, currTarget.height);
    originalImage.draw(evObj.target.loader as IBitmapDrawable);

    // blur values are arbitrary - for me 7 worked fine - you can experiment with these
    var blurXValue:Number = 7;
    var blurYValue:Number = 7;

    // setting up the blur filter
    var blurFilter:BlurFilter = new BlurFilter(blurXValue, blurYValue, int(BitmapFilterQuality.LOW));

    // applying the blur filter to the copy of the original image
    originalImage.applyFilter(originalImage,
    new Rectangle(0, 0, originalImage.width, originalImage.height),
    new Point(0, 0),
    blurFilter);

    // resizing the original image
    var rbd:BitmapData = resizeImageBD(originalImage, this.width, this.height);

    // assigining the resized version of the image to the Image component
    this.source = new Bitmap(rbd, PixelSnapping.AUTO, true);

    super.contentLoaderInfo_completeEventHandler(evObj);
    }

    public static function resizeImageBD( bitmapData:BitmapData, width:Number, height:Number ):BitmapData {
    var newBitmapData:BitmapData = new BitmapData( width, height, true, 0x000000 );
    var matrix:Matrix = new Matrix();
    matrix.identity();
    matrix.createBox( width / bitmapData.width, height / bitmapData.height );
    newBitmapData.draw( bitmapData, matrix, null, null, null, true );
    return newBitmapData;
    }
    }
    }

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">