Dynamically Resizing Backgrounds That Don't Distort

By Daniel Wood, 20 March 2017

Introduction

If background images are used sensibly, they can provide a beautiful backdrop to areas of your solution, such as a login screen, splash screen, or indeed the entire solution. FileMaker allows the user stretch the window both horizontally and vertically in any ratio they wish. Anchoring has allowed us to try and compensate for this in our designs, but often images suffer because they are themselves a fixed aspect ratio, and deviating from that ratio will either stretch and distort the image if 'maintain aspect ratio' is off, otherwise result in blank space around the image edge if aspect ratio is on - both options are not ideal for a background image.

In this article we present a technique that allows you to resize an image and have it re-generate a thumbnail version upon resizing of the layout. This thumbnail version is a cropped version of the original, but respects the original image's aspect ratio.  If you choose your image sensibly, you can make a layout background that looks great no matter what dimensions your window is set to.

 

What is the issue here?

It all comes down to aspect ratio.  I'm sure you've all come across this issue at some point or another when developing: You have a container on a layout, and as you resize the layout, the image becomes stretched and distorted:

Stretching an image

Stretch Settings

So here we have a container where we have set it to reduce or enlarge to fit, and we don't maintain proportions (the aspect ratio). This is good in that it fills the entire container, but bad in that the image looks terrible when stretched.

Aspect ratio is just the ratio of width to height of an image.  Typical aspect ratios such as 16:9 simply mean that if the width of the image was 16 centimetres for example, then the height would be 9. If the width were 32, the height would be 18, and so on.

So how about turning on maintaining original proportions (aspect ratio): 

Stretch with aspect ratio maintaining

Now we have the image looking good, but the rest of the container cannot be occupied by anything in order for us to keep aspect ratio.  This would be fine if our container was displaying something like a persons photo, or a company logo.  However in this article we want a container that is going to be used as a background image. Imagine using the above as a background, who wants massive areas of nothing in the background?  Conversely who wants a horrible distorted image.  Is there a nice middle-ground here?

 

Requirements for our background image

First, let's define a few rules for what will make a successful background image:

  • We don't want the image to zoom if possible (so no pixelation)
  • We don't want the image to stretch or distort (so no breaking of aspect ratio)
  • We don't want any large borders around the image (so fill the entire layout object)

 

Prevention of Pixelation when Zooming

This is an issue that would occur if the dimensions of our FileMaker Window were greater than the original image dimensions. If we wish to satisfy conditions 2 and 3, we can't make the image larger than it's original dimensions, this results in pixelation of the image - you simply cannot make an image bigger than it actually is without sacrificing quality of the image.

The solution to this one then is pretty straightforward, make sure your background image you use has a dimension that is sufficiently large so that it is unlikely your user will be able to resize their FileMaker window larger than the images dimensions.

on iOS this is fine, you know what dimensions you can work with as it's constrained by the size of the device screen. Similarly on monitors you are constrained in window size to the monitor size, however different users can be on different monitors so you must choose wisely.

 

Prevention of Distortion and Borders

The way we prevent distortion of the background image, while keeping it filling the layout object, is best illustrated with a diagram: 

One In this example the green rectangle represents the dimensions of our background image. The blue rectangle is our screen dimensions.

Both image and screen have the same aspect ratio of 2:1 and so in order to fully occupy the screen, we simply generate a thumbnail image 1/2 the size of the original image, it should fit it nicely.

Screen Shot 2017 03 20 at 6.22.03 PM

This one is a bit trickier. Our screen is now 600x200,  which is an aspect ratio of 3:1.  To demonstrate how we will scale down our background image to fill this screen size, we'll use this crudely put together FileMaker layout and the GIF below!

http://i.imgur.com/mjf9kCV.gif

PRO DEVELOPER TIP:  When resizing layout objects in layout mode, if you hold the cmd+shift keys while resizing, the image is resized respecting it's original aspect ratio. That is how in the above GIF I am able to resize it correctly. (also of note, holding option+drag will constrain the object to the same width and height when resizing...)

We must maintain aspect ratio of the background image, so the first step is scaling the background down to a size where the largest dimension of the screen is matched to that of the image. Our resulting image in green is now still in it's aspect ratio, but sized down.

The second step is to center the image (in green) over our layout background (in blue).  This is actually achieved simply by setting the layout object properties to align centered both vertically and horizontally.  The final step is to ensure that the layout object is set to crop the image

Here is another example:

Screen Shot 2017 03 20 at 6.31.24 PM

Here the height is slightly more than the width of the screen. You might find a user doing this if the layout contains a portal or list and they want to maximise screen height, or if they are using portrait orientation on an iOS device.

Here is the transformation that occurs:

http://i.imgur.com/8Cq58lU.gif

Much like the first example, this one is simply scaling the original image down to the maximum dimension. The difference here is the maximum dimension is the height, not the width. Scaling down stops at the point the height is reached.

With the fact the background image is centered horizontally/vertically and cropped on the layout, the final effect is for the background image to be positioned centered in relation to the original image.

 

Wrapping it all up in a Custom Function

In order to generate the required thumbnail image, we need to know:

  • The width and height of the raw image
  • The width and height of the layout background object
  • The image to use

The first point can be obtained using the GetContainerAttribute function, we can return the width and height of the image in the container.

The second set of dimensions is obtained using the GetLayoutObjectAttribute function. With it, we can tell the dimensions of the layout background object at any point in time - recall that given the container is anchored and resizing, it's dimensions change as the window is resized.

In the demo file you'll find a custom function called @IMAGE_bgThumbnail. This takes as it's parameters the image to use in the thumbnail, and the object name on the layout that the thumbnail is to be sized for.

If you want to find out exactly what the calculation is have a looksee in the function.

 

Getting things to work nicely

So you now have a custom function to use, and hopefully an image to use also. You can create a calculation function to produce the desired resulting container field to use for your background. Put this on your layout and you're all set, right?  

Well not quite, there is a little matter of having the calculation refresh itself when the screen is resized.  The mere act of resizing a screen (and thus the background object) is not enough to force the redrawing of the thumbnail.

To achieve this, we need to use an onLayoutResize layout script trigger. The script that runs will be responsible for refreshing the background layout object.

Screen Shot 2017 03 20 at 6.50.13 PM

The script itself is pretty basic, there are a few ways you can refresh the background object:

  • Refresh Window
  • Refresh Object
  • Freeze Window

We use Refresh object in the demo because it allows us to only refresh the background image, and not all other things on the layout.

As an interesting side note, freeze window also works. We assume this is because if a freeze window step is used, then the script when it exits silently does a 'refresh' window to bring the screen back to it's required current state. Quite nice to know!

http://i.imgur.com/TuZSlw4.gif 

Here is an example from our demo file. In it, we are resizing the window to be wider horizontally. As we resize, we don't instantly see the thumbnail image resize - this occurs upon release of the mouse after resizing. At this point in time the script to refresh the object runs and we see the change.

The end result image is a thumbnail that is not zoomed in, it is not stretched or distorted either. It is however cropped, but from the center of the image out.  If you choose your images wisely the end result is a nice alteration to the background image that the user should not notice much change in.

 

What's the point?

User experience! If you present a background image to a user with large borders because you don't want to stretch your image, the user will notice.  Conversely if you present a stretched image, the user will notice. All of these add to a negative user experience. While background images aren't critical - and most of the time not actually useful - they do have their place in certain parts of a solution if used in a certain way, so you might as well make it the best experience possible.

 

Demo File

What good is an article like this without a demo file to accompany it right? Well here it is! No username and password, fully unlocked just go for it.

DynamicBackgrounds.zip

 

 

 

Something to say? Post a comment...

Comments

  • Stuart 27/03/2017 10:57am (8 years ago)

    Nice work Daniel

  • Stefano Scarano 21/03/2017 12:26am (8 years ago)

    Thank you Daniel, very useful!

RSS feed for comments on this page | RSS feed for all comments

Categories(show all)

Subscribe

Tags