Director: Better, faster great-looking image resampling

A few months ago I was posted about how Director’s scaling code looks great when shrinking something more than 50%, but for shrinking stuff less than 50%, the image gets jaggy.

My solution at the time was to use some bilinear resampling code written for Lingo, which I modified from an existing function written by Josh Chunick. It worked like a charm, but it was pretty slow. Good for an occasional resample, but too slow to use in, say, a game.

Well, when doing some graphics experiments for a new game, I decided to see what happened if I first doubled the source image before shrinking it down to a size less than 50% of the original. I originally didn’t try this because I figured that the double-sized pixels would add jagginess into the final image, negating the benefit of Copypixel’s greater-than-50% scale.

But I was wrong.

The resulting image looks great even when scaling small amounts. It’s a little slower than a single copypixels operation, but still incredibly quick and much faster than the bilinear scaling code. So I’ve written a new image resampler that uses a single copypixels operation if the scaling is more than 50%, and uses the double-before-shrinking technique if the scaling is less than 50%. The new code is posted below. Check out my previous blog entries to see examples of how Director fails with smaller scales, and how Bilinear fails with larger scales.

I should add a new tag on my blog for “Duh”.

on resampleImage theImage,  newWidth,  newHeight
  -- 2006 Hanford Lemoore; feel free to use, redistribute, and modify.

  -- this resamples an image to a new size (smaller) using copypixels so that the image
  -- looks smooth.  only use this to shrink images.

  -- This uses a double-before-shrinking procedure when scaling less than 50% to get a better
  -- image than copypixels alone. for more information see the site:
  -- http://blog.hanfordlemoore.com/2006/07/12/director-better-faster-great-looking-image-resampling  newimage = image(newWidth, newHeight, 32)
   if newimage.rect = theimage.rect then
    -- return the original image
    return theimage
  else if (newimage.width < (theimage.width/2)) and  (newimage.height < (theimage.height/2)) then
    -- use copypixels like normal
    newimage.copypixels(theimage,newimage.rect,theimage.rect)
    return newimage
  else
    -- first upsample, then downsample
    tempImage = image(theImage.width * 2, theImage.height * 2, 32)
    tempImage.copypixels(theimage, tempimage.rect, theimage.rect)
    newimage.copypixels(tempimage, newimage.rect, tempimage.rect)
    return newimage
  end if
end

Leave a Reply

For security, enter the word TURING below:
Comments RSS feed