
The algorithm for a perfectly balanced photo gallery - jtreitz
http://www.crispymtn.com/stories/the-algorithm-for-a-perfectly-balanced-photo-gallery
======
Mgccl
Since I'm a CS theory person, I can offer some theoretical improvements on the
running time and make the problem even more general...

Instead of minimize the linear difference of partition, we might want to
minimize the standard deviation, or basically any convex function, and still
do it in the same time bound.

One can reduce this problem to find a k-edge path of minimum weight on a
complete DAG. The naive algorithm will run in O(kn^2), but we can improve the
running time to O(kn) by realize the weight on this DAG has the Monge
property. This is very practical to implement.

I posed it as a problem on daily haskell exercise
[http://dailyhaskellexercise.tumblr.com/post/58060450750/the-...](http://dailyhaskellexercise.tumblr.com/post/58060450750/the-
minimum-weight-path-of-length-k-in-a-dag-with).

In this application, k is very large. n is just a constant multiple of k. We
can use a _theoretically_ better algorithm that takes n2^O(sqrt(log n loglog
n)) time. (this is almost O(n^(3/2))). I doubt it will ever be implemented
with speed comparible to the O(kn) solution. See
[http://www.cs.ust.hk/mjg_lib/bibs/DPSu/DPSu.Files/sdarticle_...](http://www.cs.ust.hk/mjg_lib/bibs/DPSu/DPSu.Files/sdarticle_204.pdf)

I shall post a solution tomorrow since I'm currently touring NYC with my gf...

~~~
jongleberry
a solution would be awesome, especially in javascript. i actually found a case
where their linear algorithm, [https://github.com/crispymtn/linear-
partition](https://github.com/crispymtn/linear-partition), failed.

~~~
Mgccl
See the updated content in the link and the code in here
[http://www.chaoxuprime.com/posts/2013-08-16-more-
algorithms-...](http://www.chaoxuprime.com/posts/2013-08-16-more-algorithms-
on-perfectly-balanced-photo-gallery.html) Both in Haskell. you can see how to
implement it from scratch...

------
8ig8
WordPress recently added 'Tiled' galleries via their JetPack plugin. It seems
like a similar approach. You can see an example gallery here:

[http://ma.tt/2013/07/jay-z-picasso/](http://ma.tt/2013/07/jay-z-picasso/)

Additional info: [http://jetpack.me/support/tiled-
galleries/](http://jetpack.me/support/tiled-galleries/)

Code: [https://github.com/crowdfavorite-mirrors/wp-
jetpack/tree/mas...](https://github.com/crowdfavorite-mirrors/wp-
jetpack/tree/master/modules/tiled-gallery)

~~~
medell
This completely missed my radar back in May. Much appreciated.

------
andrewingram
It like how it looks, but much like Flickr I dislike how it's biased towards
landscape pictures. Some of my best photos are portrait, but they get
overshadowed by the landscape ones.

I imagine the algorithm to cater to both is much harder, because you wouldn't
be able to treat each row in isolation, can it actually be solved to a good
standard?

~~~
solarexplorer
If you prefer portaits: use columns instead of rows and scroll horizontally
instead of vertically.

If you want to avoid the bias you have to try something else: e.g. reorder the
images, overlap them, convert to square format…

~~~
eru
You can also use free placement, i.e. not restricted to either rows or
columns.

------
bane
Side-topic. Shooting Holi [1] without putting your camera in an airtight
sealed enclosure is a good way to ruin your equipment.

[http://en.wikipedia.org/wiki/Holi](http://en.wikipedia.org/wiki/Holi)

[http://www.lensrentals.com/blog/2013/05/how-to-ruin-your-
gea...](http://www.lensrentals.com/blog/2013/05/how-to-ruin-your-gear-
in-5-minutes-without-water)

~~~
gknoy
Given that that article says that the supposedly-sealed lenses were also
vulnerable, do you have advice on how one would successfully enclose a lens to
protect it from the dust?

~~~
tomkarlo
You can buy underwater / splash bags for cameras that are basically very thick
zip-lock bags. They're much cheaper and lighter than a true (rigid) underwater
photography enclosure, but they're basically airtight above water and will
keep the dust off your gear. You won't be able to change lenses, however, and
zooming might be difficult or impossible, so you'd probably be limited to just
putting on a 24mm lens and shooting that all the time.

[http://www.bhphotovideo.com/c/product/547694-REG/DiCAPac_WPS...](http://www.bhphotovideo.com/c/product/547694-REG/DiCAPac_WPS10_WP_S10_Waterproof_Case.html)

------
quarterto
I just implemented pretty much the same thing from scratch for my wedding
gallery¹.

For each row, it tries 3-10 images, sums their aspect ratios, divides the
total row width by the sum to get a candidate height, then picks the height
that's closest to the average of the existing rows.

To make things look a bit nicer, it rejects candidate rows with the same
number of images as the last row.

I might release the code on Github if I can make it modular enough. Currently
it depends on jQuery but that's really only for element creation.

¹ [http://mattandsophiegetmarried.com](http://mattandsophiegetmarried.com),
I'm the guy with the waistcoat, purple cravat and massive grin.

~~~
FreeFull
I end up with some of the photos ending up behind other photos. Firefox 23
here.

~~~
aestra
Same in Firefox 22. Scrolling seems broken, and removing the "find on page"
part of Firefox clears all the images.

------
martin-adams
What's just as impressive is the full size view of the image. The background
brings the ambient colour of the photo to make it more immersive. Very nice!

~~~
wingerlang
I agree, that looks very nice.

I might be wrong here but I think the background is just the picture, although
scaled and has got many filters on it.

~~~
jtreitz
Actually, you're right! It's the same picture, scaled down to around 500x500
and with a heavy gaussian blur applied to it. The trick is to have a subtle
grain effect over it to eliminate gradient artifacts.

~~~
jffry
It looks really great!

------
mcgwiz
It looks nice (much like Google Image results) but IMO it's not "equally
distributed". For example, an image that has dimensions 800x531 gets ~2.3x the
space as one with dimensions 531x800. That arbitrarily incentivizes/rewards
landscape photos w.r.t. portraits. "Equally-distributed" would probably
require an algorithm that works mosaically (without row constraints) and
couldn't achieve "taking up all the space available [in a rectangular
region]".

Still, looks nice.

------
emilw
Maybe I'm missing the point but why is this an achievement? I've seen Google
images do this for years (from the backend, sends the users viewport
dimensions and then automatically calculates the optimum filling). For years
(Warning NSFW!) vusker.com has been doing this client-side in their thumbnail
and gallery view. Plus look at the vertically stacked posts from Pinterest.

It seems more a marketing ploy to get attention to the great service
chromatic.io is providing?

~~~
emilw
Granted, maybe pinterest is a bad example in regards to optimum page filling.

~~~
emilw
I substitute it with flickr's latest design overhaul.

~~~
gknoy
BTW, thank you for the NSFW warning, as in a thread like this it's very
tempting to blindly open galleries to compare layout. Very considerate of you.

------
moron4hire
he writes an excellent example of why "all that computer sciency stuff" is
usefull in day to day programming, yet still wants to take pride in his
ignorance, like this is some strange sort of fluke.

~~~
kaffeinecoma
You're being a little harsh here. I think he was actually trying to impart the
idea that it's worthwhile to have a foundation in CS, even if you don't
necessarily work on deep algorithmic code every day. He drew on some (perhaps
foggily remembered) CS background to successfully solve a problem, so why
knock him?

------
fsckin
The demo [0] is pretty impressive. Photo sites like Instagram and 500px give a
fixed ratio, while flikr does nothing quite appealing as this. Nice work.

[0] [http://www.chromatic.io/FQrLQsb](http://www.chromatic.io/FQrLQsb)

------
joebo
This works well when the photos are not time sequential. I find it harder to
follow the story when the photos are ordered by the partition fit instead of
the time taken. It would be neat to optionally incorporate time into the
algorithm.

~~~
jtreitz
We do not change the order of the photos, we just try to find a good set of
breaking points inside that order.

Actually, Chromatic tries to read the EXIF "DateTimeOriginal" information to
sort the photos and falls back to the "LastModifiedDate" if the former doesn't
work.

------
dgreensp
This looks like a pretty slick, mobile-compatible photo gallery, but without
the code it isn't very useful. They talk about Chromatic like a real product,
but "free web service" basically means "demo".

~~~
bestham
I would love for the code to be released, something similar and selfhosted
with a simple static backend (or my favorite: Kirby) would live on any low end
box. Please consider selling the design and assets on Themeforest.

------
kenster07
"Remember the days in college when you learned all about the big Oh!'s and re-
implemented all these sort-algorithms for the hundredth time? If you are a web
developer like me, chances are you never had to touch a single one of these
algorithms ever again." +1

It's a good start, but when the window is shrunk, the result isn't as
impressive.

------
EGreg
This is why I always preferred vertical masonry. Sites such as VKontakte,
Google Image Search, and the recent Flickr app tile things horizontally, but
this sometimes means you have to crop the images to fit into your masonry. Not
so with vertical masonry, which you can just resize to have constant width.

~~~
jmathai
Vertical masonry doesn't work well to communicate an ordered list of items.
Photos are often just that...a story of an experience that happened
chronologically.

The inability to read left to right on columnar data makes this really hard.

~~~
EGreg
If something really happened chronologically, then perhaps it's acceptable to
have a horizontal scrollbar, or not right-justify the right edge.

This particular algorithm seems to mix up the order of the photos in order to
best fit them on a line, so it can hardly be said to show chronological order.

------
sergiotapia
Why not use Masonry or Isotope?

[http://masonry.desandro.com/](http://masonry.desandro.com/)

[http://isotope.metafizzy.co/](http://isotope.metafizzy.co/)

~~~
CaveTech
Because those don't horizontally balance.

------
blt
Given that clear textbook explanation and he decided to port a Python
implementation instead of writing it from scratch? What a waste of an
opportunity for a fun day at work...

------
myfonj
It is hard not to mention series of articles [0] on the same topic by
Christopher 'vjeux' Chedeau [1] in this context.

[1]
[http://blog.vjeux.com/?s=%22Image+Layout+Algorithm%22](http://blog.vjeux.com/?s=%22Image+Layout+Algorithm%22)
[0]
[https://news.ycombinator.com/user?id=vjeux](https://news.ycombinator.com/user?id=vjeux)

------
fangel
I too made something similar recently. I decided to use dynamic programming.
This way it's easy to ensure that you don't end up with a half row at the end.
It also doesn't require changes to the ordering of the images.
[http://fangel.github.io/packing-images-in-a-
grid/](http://fangel.github.io/packing-images-in-a-grid/)

------
jwarren
Great post with gorgeous results. The service is really very nice too!
Fantastic work.

Question: will you ever implement profiles or permanent galleries?

------
baerbradford
I made something similar a while back to generate backgrounds on a music
website. I took a different approach, and it's not as clean. If anyone is
interested to see a different attempt, take a look at the JS.

[http://wwwstu.tcu.edu/baerbradford/tiles.html](http://wwwstu.tcu.edu/baerbradford/tiles.html)

------
adventured
Interestingly when I load up their demo gallery at:
[http://www.chromatic.io/FQrLQsb](http://www.chromatic.io/FQrLQsb) and click
on one of the images to enlarge it, then click again to drop back into the
gallery view, the gallery breaks horribly (about 1/3 of the images vanish).

FF 22 on Windows 8

------
alariccole
I've studied this a great deal, and developed a custom masonry type layout to
mitigate the row/column bias. I believe it is a much more balanced layout than
the article shows. Using it in Imagist, a paid app. Open to a few beta testers
for iOS 7 as well, if you want to judge for yourself.

~~~
lsinger
Yes, please?

~~~
alariccole
Testflight for iOS 7: [http://tflig.ht/WwNYgp](http://tflig.ht/WwNYgp)

------
gbog
Since when it is ok to suppose visitors know to click the escape key to go
back. And where is the link to go up to the gallery. I had to mess with the
url or I was gone for a long back button session. Morevoer it is very slow.

Just to add some negativeness to the generaly positive comments here.

~~~
uptown
By "go back" i'm assuming you're referring to closing a full-size image. I've
found three ways they can do this. They can press ESC. Click the image itself.
Or click in the negative space surrounding the image excluding the "Previous"
and "Next" regions.

Doesn't really seem like a huge issue since there are multiple ways to
accomplish the objective, though I suppose a small "X" could be added if you
wanted a visual cue.

------
44Aman
I really like this, made a quick one with snaps from Angkor Wat in Cambodia:
[http://www.chromatic.io/lTOfsdP](http://www.chromatic.io/lTOfsdP)

------
nkuttler
Can sombody tell me why this uses the photos as background images for divs? It
seems to me like this gallery could also use img tags (which is semantic,
crawlable, yadda..)

~~~
zodiac
I think it's so that they can use css media queries. Here's a list of pros and
cons for div background vs img tags:
[http://stackoverflow.com/questions/492809/when-to-use-img-
vs...](http://stackoverflow.com/questions/492809/when-to-use-img-vs-css-
background-image)

------
chanux
For some reason I was expecting (perfectly) balanced files of a photo gallery
on disk. What I actually got was equally interesting though.

------
tech-no-logical
that looks very good, but navigating with the 'back' button breaks the app.
tested on FF24 / opera 15.

~~~
hijinks
back button also breaks it in chrome 28 on a mac

------
salberts
The gallery layout can be seen in G+ for a while now. But the ambient effect
in full-screen mode is awesome!

------
brianbreslin
I would love to see chromatic as a service I can pay for, maybe sell me a
wordpress plugin?

------
glogla
Is there some kind of static gallery generation software that can do something
like this?

------
anonymoushn
Is it supposed to reload previously viewed images when the user scrolls up or
down?

~~~
jtreitz
Yes, we figured the page scrolls slow if there are too many photos in the DOM
at the same time so the lazy-load-function also removes them when out of
scope.

------
normalocity
Anyone else in this thread think that this blog post covers a painfully
trivial calculation problem? What's next - someone's going to write a full
blog post to explain to me how to perfectly toast my toast using these visual
sensor things that seem to be built into my head (eyes)?

------
kmfrk
Counting down to when Marissa Meyer pulls the acquisition trigger ... :)

------
jongleberry
i made a library for this:

[https://github.com/jonathanong/horizontal-grid-
packing](https://github.com/jonathanong/horizontal-grid-packing)

------
grumps
Only the title loads on Chrome in Android 4.2.2

------
colinm
btw this breaks zoom.

~~~
user24
Your comment is almost useless. On which browser? Which operating system? What
do you expect to happen? What actually happens?

[http://www.chiark.greenend.org.uk/~sgtatham/bugs.html](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html)

~~~
PavlovsCat
Bug reports can only be as useful as the people who receive them. Try zooming
with any browser; you'd expect it to, hum, zoom, but what actually happens is
that after zooming, the pictures get resized again, so no matter how you zoom,
it always looks the same.

