John M
John M

Reputation: 1479

Smart alignment / layout of multiple images on page

Assume I'm developing an application that needs to display a large number of images of different sizes and aspect ratios, like Flickr photostream or Google Image search.

Are there any existing algorithms / libraries that help decide how tall each row should be and how many images should go into each row so that there are as little gaps between images as possible while also not excessively resizing any of the images, keeping them all at relatively similar sizes (and certainly not changing aspect ratios)?

Ideally, it would be a pluggable algorithm receiving as input a list of image sizes, target/average row height, screen width, and returning a list of "row assignments", stating which images go into which row, with what size, and what the row heights are.

This Flickr page is a good example of what I want to achieve:

http://www.flickr.com/explore

Upvotes: 2

Views: 1615

Answers (2)

Andreas Herd
Andreas Herd

Reputation: 1188

It's quite a later answer, but I wrote something like this (with demo): https://github.com/mendrik/diorama

It

  • preserves aspect ratios
  • tries to keep sizes uniform
  • tries to reduce cropping

It works best if there is enough images to find a solution. If you have an endless stream of images, you could take blocks of let's say 10 images and assemble rectangles based on my code. The gist happens in layout.ts 'searchSolution'. It takes 4 arguments, the canvas width/height, an array of image aspect ratios (width/height) and an upper limit to find a solution in milliseconds.

Hope it helps!

Upvotes: 1

M Oehm
M Oehm

Reputation: 29126

There are probably already enough Javascript scripts around that mimick the Flickr layout. But it isn't hard to roll your own.

The algorithm is similar to word-wrapping long lines. Look at the Flickr page you linked: The images in one row all have the same height. The rows have slightly different heights, which gives a non-uniform look, but also ensures that the row extends over the whole screen.

Say that your parent element has a fixed width, but a flexible height that adapts to the image layout. You can then lay out a list of images easily:

  • Keep a list of rows; each row is a list of images. At the beginning, thie row list is empty.

  • Chose a nominal height for the rows. This will be the minimal height of the images. Determine the actual height and width of each image and calculate the nominal width:

    w_nom = w_orig * h_nom / h_orig
    
  • For each image in the list, find a row that can accommodate the image, i.e. the width of the images in the list plus a gutter width plus the image's width must be smaller than the parent element's width. If there is no such row (or if the list of rows is empty), start a new row and place the image.

  • Now every image has its row. For each row, chose a scaling factor for all images such that the width of all images plus a (constant, i.e. unscaled) gutter is the width of the parent. Scale each image's width and height.

  • Now do the layout: Place the images from top to bottom on your parent element. Adjust the parent's height.

This is only a first draft. A more ambitious layout could calculate a "badness" for each row and distribute the images more intelligently. Also, if the last row has only one small image, that gets blown up unreasonably, but if you have a lot of images, the user has to scroll much before seeing that. I also don't know how well this works if it has to be done on the fly when the parent element is resized.

I've made a small mock-up in Javascript here, but it's just a proof of concept - it doesn't work in IE, for example. The code is in the page source and is needlessly complicated because fiddling with the javascript styles is so wordy. The algorithm itself is rather straightforward.

Upvotes: 9

Related Questions