While developing an app, you often have to load an image whose dimensions are unknown. The question of how to scale the image is frequently asked, so let’s look at a simple function that will scale any image to fit in an arbitrary box.

For the inspiration for this function, let’s look at Adobe Photoshop’s File->Automate->Fit Image functionality. This action’s dialog box asks for a width, height and if you want to allow smaller images to be enlarged.

fitImage

The method that you will use is to first squeeze the image down until it fits the required height. If the new width fits inside the dimensions, then you are done and can scale the image. However, if the width is still outside the box, you need to recalculate the size based on the width to get it within the desired size.

With digital images, sizing up usually results in bad looking images. Since your image may be smaller than the box you are defining, you have a choice to enlarge, or leave it be (since the smaller image does fit within the bounds!)

The fitImage() function

The code for the fitImage function is:

local function fitImage( displayObject, fitWidth, fitHeight, enlarge )
	--
	-- first determine which edge is out of bounds
	--
	local scaleFactor = fitHeight / displayObject.height 
	local newWidth = displayObject.width * scaleFactor
	if newWidth > fitWidth then
		scaleFactor = fitWidth / displayObject.width 
	end
	if not enlarge and scaleFactor > 1 then
		return
	end
	displayObject:scale( scaleFactor, scaleFactor )
end

The parameters that the function will take is a Corona Display object, typically the result of a display.newImage() API call. Next, is the desired width and height of the object after it’s scaled. Your image will fit within this box. The examples fit to a square, but you could select any rectangle that works for your app. The last parameter is a boolean that determines if you want smaller images upsized or not.

Inside the function, the first thing is to calculate the ratio of the image height to the desired height. If the height is larger than the desired height, this value will be less than 1. If the height is already smaller than the desired height, it will be greater than 1.

Next, multiple the width of the object by the new scale factor. If the new width is larger than the desired width, you need to shrink the image some more, so calculate a new scaleFactor based on the width instead of the height.

If the scaleFactor is greater than 1, then the image is actually smaller than the desired box. If you do not want small images enlarged, then simply return and do nothing.

The final step is to use the display:scale() method to actually size the image. Of course the image itself isn’t physically resized, it’s just scaled to fit the area.

Using the fitImage() function

Using the function is fairly straight forward:

local icon = display.newImage( "Icon.png" )
icon.x = 50
icon.y = 300

fitImage( icon, 200, 200, false )

Start by creating your display object using display.newImage(). Position the image where you want it. Now simply call the fitImage(), specifying the box size, width first, and finally if you want to allow enlarging.

Some more examples include:

local moose = display.newImage( "moose.jpg" )
moose.x = display.contentCenterX
moose.y = 100

fitImage( moose, 200, 200, false )

local icon2 = display.newImage( "Icon.png" )
icon2.x = display.contentWidth - 100
icon2.y = 300

fitImage( icon2, 200, 200, true )


local world = display.newImage( "world.jpg" )
world.x = 75
world.y = 450

fitImage( world, 200, 200, false )

This should result in something like:

screenshot

The first image, the moose, started out as a 2048 x 1638 image and was squeezed down to a 200×160 pixel image. There are two variants of the Icon.png image, a 57×57 image. In the one example, enlarging was not permitted, so it remained it’s original size. The second version, enlarging was allowed and you can see how pixelated the enlarged image is. Finally, the world.jpg image started out as a 320×480 image and was squeezed into a 133×200 image while maintaing the original image’s aspect ratio.

Conclusion

Now you can easily scale arbitrary sized images to fit within a space in your app.

  1. I mean that in my browser, in the sample, the &gt + semicolon is displayed NOT translated into >. In my first post i has been translated, that’s why my comment is curious

  2. I’d like to fit an image in a box but maintain the aspect ratio by cropping. I’m using a newContainer for each image. Is that the best solution?

  3. Thanks Rob for the great tutorials.. this is really helpful one.

    I was trying to see how it will work for remote images but it was not working well. I am not sure if i should them after they load locally or you can do the same function for remote images,

    i got this error :

    File: main.lua
    Line: 10
    Attempt to index local ‘displayObject’ (a nil value)

    stack traceback:
    main.lua:10: in function ‘fitImage’
    main.lua:50: in main chunk

    i tried to do delay but still no luck..
    thanks
    Abdul

    • Rob Miracle says:

      It sounds like you’re not passing a valid display object in. We would need to see your code where you are loading the image and trying to call the function. Blog comments don’t handle posted code well. This would be best handled in the forums.

      Rob

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>