Developing a Contentful Powered Photo Mosaic for David Gray

Celebrating the 20th Anniversary of White Ladder

Image for post
Image for post

Last week, David Gray celebrated the 20th anniversary of his chart topping studio album, White Ladder. You may know it from such hits as “Babylon” and “This Year’s Love.” The influence of this record runs deep, from other “soul-baring” artists being encouraged by its success to the droves of fans it touched. In order to visualize this impact, Mick Management approached me to develop an evolving photo mosaic of the album cover, consisting of both artist and fan testimonials.

Years ago, I enjoyed seeing some of the photo mosaic work Uprising was doing for artists but I was never actually approached to create a digital mosaic myself. I knew I was going to use Contentful to provide a CMS to the client for adding and updating memories which would be added to the mosaic. This would be the first time I really utilized Contentful’s media hosting abilities and incredibly useful Images API. But first, let’s breakdown the logic behind creating photo mosaics.

Image for post
Image for post

In order to create a photo mosaic, you first need an original image which will become the subject of the mosaic. In our case, we will be using the album cover. You will also need a set of images which will be used as the tiles of the mosaic. We’ll be using the photos of those artists and fans whom we have testimonials for. You then need to decide on the fidelity of your mosaic tile grid. A higher number produces a higher quality image but requires duplication in the image set if there aren’t enough images. Whereas a lower number may not produce a very detailed mosaic. What you’re looking for is a nice median value. We chose a 20x20 grid.

You then need to calculate the average color of each cell of the original image’s grid as well as the average color of each photo in your set of photos. Once you know these averages, you can calculate the distances between colors of the of the original photo’s cells and the set of photos’ colors. You can then place the photos with the smallest color distance within the corresponding cells of the original image. Depending on the amount of images in your set vs. the amount of cells, you may need to implement some replication to fill out the mosaic. Finally, most photo mosaics will blend the original photo on top to increase the relation with the original image.

If you’re interested in the logic behind photo mosaics, I would highly recommend reading this academic paper by Manuel Lopez Michelone and Marcelo Perez Medel. It was incredibly useful!

We can use HTML5 canvas to calculate the average color of an image. In order to do this, we must first load the image and draw it to a temporary canvas. Once we do this, we can get the image’s data and increment through all pixels to calculate the average. Here’s a rough version of this technique.

Loading the image and drawing onto temporary canvas.

let canvas = document.createElement('canvas')canvas.height = image.height
canvas.width = image.width
let context = canvas.getContext('2d')context.drawImage(image, 0, 0)

Getting the image data.

context.getImageData(0, 0, canvas.width, canvas.height).data

Note that this gets the data of the entire image. If you only wanted to get a portion of the image (when calculating the averages of the original image,) you can adjust the getImageData parameters. Here’s the docs on that.

Calculating the average.

let components = data.lengthlet R = 0
let G = 0
let B = 0
let A = 0
for (let i = 0; i < components; i += 4) {
let r = data[i]
let g = data[i + 1]
let b = data[i + 2]
let a = data[i + 3]

R += r
G += g
B += b
A += a
}
let pixelsPerChannel = components / 4R = R / pixelsPerChannel | 0
G = G / pixelsPerChannel | 0
B = B / pixelsPerChannel | 0
A = A / pixelsPerChannel / 255
let average = [R, G, B, A]

Once you have averages for for both the original image’s cells and the set of photos, you’ll want to calculate the distances between them. I found an excellent Node library by Zachary Schuessler which does exactly that: DeltaE. This library provides three algorithms for calculating color distances. The only catch? Our colors need to be in LAB format. (Currently, there are in RGBA.) No worries, I quickly found another library which can help us. The aptly named, color-convert. This library provides a very simple method of converting between color formats. For example, here’s how you would convert from RGB to LAB.

convert.rgb.lab(255, 0, 0)

With our colors converted, we can then calculate the distances using DeltaE.

let distance = DeltaE.getDeltaE00(
{
L: color1[0],
A: color1[1],
B: color1[2]
}, {
L: color2[0],
A: color2[1],
B: color2[2]
}
)

Once you have all these distances, it is then up to you on how you might assemble the final product. We knew we wanted to make each cell of the mosaic clickable (to open the testimonial) so I utilized a CSS grid to create our final solution. The HTML is very basic. Just create a parent div with 200 children divs. Each child div should receive a background image of the associated set photo.

<div id="mosaic">
<div class="cell" :style="background-image: url(photo.jpg)"></div>
...
</div>

Notice how I am also setting the original image to be the background image of the gridded element.

#mosaic{
background: url(original.jpg);
background-size: cover;
display: grid;
grid-auto-rows: 1fr;
grid-template-columns: repeat(20, auto);
}

In the case of our mosaic, we also needed to make sure the CSS grid held the shape of a responsive square. To do this, you can use some:before selector magic.

#mosaic:before{
content: '';
width: 0;
padding-bottom: 100%;
grid-row: 1 / 1;
grid-column: 1 / 1;
}
#mosaic > *:first-child{
grid-row: 1 / 1;
grid-column: 1 / 1;
}

On the styling of the children divs, you can use a mix-blend-mode property to blend the cell photo into the original image using one of the blend modes you might find in Photoshop. For our solution, I used lighten, filtered them gray, and added a bit of opacity.

#mosaic div{
background-size: cover;
filter: grayscale(100%);
mix-blend-mode: lighten;
opacity: 0.6;
}

Thanks again to Mick Management and David Gray for bringing me in on this special occasion. If you’re a fan of the release or simply wish to learn about the impact it has had on so many, be sure to check out our mosaic. Fans of the band may also be interested in pre-ordering the 20th anniversary editions.

Written by

I develop websites for rock 'n' roll bands and get paid in sex and drugs. Previously Silva Artist Management, SoundCloud, and Songkick. Currently: Available

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store