Best Show I’ve Seen

Just wanted to let you know about a show I’ve fallen in love with. I’ve seen the commercials and thought it might be interesting to watch, but never got around to it. Once I saw a few episodes I was totally hooked.

A couple of weeks ago I watched two seasons of NBC’s Chuck within 48 hours. I has become my favorite TV series followed by The Office and Lost, and I can’t wait for season 3 to air next March. You can watch all 13 episodes from season 1 starting with the pilot on Warner Bros website. The second season has only about half of its 22 episodes online at nbc.com or hulu.com. You’ll have to rent the DVD or buy episodes on iTunes. You can buy both seasons on iTunes and xbox live I believe.

Be sure to catch up on the first two seasons so you can be up on season 3!

High quality, high performance thumbnails in Flash

Ever need a thumbnail of an image in Flash? I do, and honestly speaking, the resampling that Flash does is less than ideal. Unless you only need to resize by half or bigger. But my thumbnails usually need to be smaller.

I searched for a solution and found on voq.com a promising library with some algorithms that worked quite nicely and a demo. The quality was nice, but the speed was slow. It also fiddled with the color a little bit. If I put the “easyScaling” parameter down from .5 to .25 I ended up with a nicer thumbnail but was slower to make and had more color disfiguration. You could tell what the original piece was better though.

After some more searching I found that Brooks Andrus played with some algorithms using Pixel Bender. The conclusion to that was he found he could do the same thing with the “smoothing” option in the BitmapData.draw() method. And this still leaves me with yucky thumbnails at small sizes.

I began thinking I would need to take the algorithms from the first source and port them into pixel bender like Brooks did for his ThumbGenie application.

I thought I’d try one more option first. I had played around in my mind with the idea of resizing a bitmap in half, then in half again, until I reached my destination size, since resizing by half still had good results. After discussing it with Tyler I tried it out and ended up with some great results. That last resize to get to the final thumbnail size wasn’t half because in an imperfect world your thumbnails aren’t always a power of two times smaller than your original. So I had an odd-man-out scale at the end I was applying. Tyler suggested I put that odd-man-out scale at the first instead. So instead of:

1000x750 * .5 resize * .5 resize * .5 resize * .8 = 100x75

It worked like this:

1000x750 * .8 resize * .5 resize * .5 resize * .5 = 100x75

Doing it that way landed me with even better results! It seems that Flash does it’s best work when resizing by exactly 1/2.

Thumbnail tests

The above image shows my test results as follows taking a snapshot of my homepage in an HTMLLoader in AIR.

  1. Regular BitmapData.draw() method without smoothing (0 miliseconds)
  2. Regular BitmapData.draw() method with smoothing (1 miliseconds)
  3. Using my own method that resizes by the odd scale first, then by halves (8 milliseconds)
  4. Using my method but after the odd scale, only scaling down by quarters (33 miliseconds)
  5. Using the voq Lanczos3 method with easyScaling at .25 and sharpening (694 miliseconds)
  6. Using the voq Lanczos3 method with easyScaling at .25 and no sharping (676 miliseconds)
  7. Using the voq Triangle method with easyScaling at .25 and sharpening (275 miliseconds)
  8. Using the voq Triangle method with easyScaling at .25 and no sharpening (266 miliseconds)

My personal opinion is that the best looking thumb is #3. I was surprised that #4 wouldn’t be as good. I knew the performance would be lower because I was doing more iterations of BitmapData.draw(), but I thought that scaling it to 75% (down a quarter) each time would end up nicer. Looks like 50% is the best scale to use.

The voq.com algos looked pretty decent, but obviously were slow. I’m quite happy with the solution I’ve found. I only had to write a little bit of code, it’s fast enough, and looks better than any other solution I’ve found (even Fireworks resizing IMO).

Here is the method I wrote for this. Note, when scaling up, it seemed to look better to just use smoothing and do it in one draw() and not iterations of 2.

private static const IDEAL_RESIZE_PERCENT:Number = .5;

public static function resizeImage(source:BitmapData, width:uint, height:uint, constrainProportions:Boolean = true):BitmapData
{
	var scaleX:Number = width/source.width;
	var scaleY:Number = height/source.height;
	if (constrainProportions) {
		if (scaleX > scaleY) scaleX = scaleY;
		else scaleY = scaleX;
	}

	var bitmapData:BitmapData = source;

	if (scaleX >= 1 && scaleY >= 1) {
		bitmapData = new BitmapData(Math.ceil(source.width*scaleX), Math.ceil(source.height*scaleY), true, 0);
		bitmapData.draw(source, new Matrix(scaleX, 0, 0, scaleY), null, null, null, true);
		return bitmapData;
	}

	// scale it by the IDEAL for best quality
	var nextScaleX:Number = scaleX;
	var nextScaleY:Number = scaleY;
	while (nextScaleX < 1) nextScaleX /= IDEAL_RESIZE_PERCENT;
	while (nextScaleY < 1) nextScaleY /= IDEAL_RESIZE_PERCENT;

	if (scaleX < IDEAL_RESIZE_PERCENT) nextScaleX *= IDEAL_RESIZE_PERCENT;
	if (scaleY < IDEAL_RESIZE_PERCENT) nextScaleY *= IDEAL_RESIZE_PERCENT;

	var temp:BitmapData = new BitmapData(bitmapData.width*nextScaleX, bitmapData.height*nextScaleY, true, 0);
	temp.draw(bitmapData, new Matrix(nextScaleX, 0, 0, nextScaleY), null, null, null, true);
	bitmapData = temp;

	nextScaleX *= IDEAL_RESIZE_PERCENT;
	nextScaleY *= IDEAL_RESIZE_PERCENT;

	while (nextScaleX >= scaleX || nextScaleY >= scaleY) {
		var actualScaleX:Number = nextScaleX >= scaleX ? IDEAL_RESIZE_PERCENT : 1;
		var actualScaleY:Number = nextScaleY >= scaleY ? IDEAL_RESIZE_PERCENT : 1;
		temp = new BitmapData(bitmapData.width*actualScaleX, bitmapData.height*actualScaleY, true, 0);
		temp.draw(bitmapData, new Matrix(actualScaleX, 0, 0, actualScaleY), null, null, null, true);
		bitmapData.dispose();
		nextScaleX *= IDEAL_RESIZE_PERCENT;
		nextScaleY *= IDEAL_RESIZE_PERCENT;
		bitmapData = temp;
	}

	return bitmapData;
}

Enjoy!

Update: I was getting unsatisfactory images when the resize scale was more than 50%. For example, the original code posted would size an image from 100×100 to 60×60 using one BitmapData.draw() step. And it didn’t look that great.

I found that if I sized the image up to a scale that allowed it to be size back down by exactly 50% that the results were much better. In the above example, the 100×100 would scale up by 120% to 120×120, then scale down 50% to 60×60. The final image looks much better this way. The code has been updated to work like this. It also had the option to turn constrain proportions off.

Update: I’ve posted my code library to Google Code. You can see my final implementation of bitmap resizing in the ImageUtils class.