thomas.io

December 18, 2017

Why and how I created imageee.com

6 months ago, I wrote an article on how to generate dynamic images for social sharing. This is basically a way to have custom images based on your content when you share your pages on social media.
The result is great and there's a lot of flexibility, but when you have to do this on several projects, you feel like you're doing it over and over again when you could use a shared service to do it once.

So I thought:

"Why not making a service that will do this?".

At that moment I didn't really have time to do it, so I just kept this idea in my head.

While I was creating our blog on DomainHolder.io more recently, I wanted, again, to have images include the title and the website.
Implementating the previous solution for something that simple seemed overkill. So I tried to find alternatives.

I remembered that websites provide placeholder images, like placeholder.com.
It allows you to call this url https://via.placeholder.com/1280x640 and they respond with an image with the size of your choice. Great. What about text inside the image now?

Well, they have something for this actually!

Just add the text parameter and it will include it in the image.

https://via.placeholder.com/1280x640?text=My blog article

With text

This is a good start, but while you can choose the background color, you can't chose a different font and the text starts acting weird when you have too many words:

https://via.placeholder.com/1280x640?text=Lorem ipsum dolor sit amet, consectetur adipiscing elit

Long text

It was a first step, but it lacked customizations.

I kept searching.

And I found imgix.com, this is a SAAS that allows you to do almost everything with images. In our case, we could use this to specify the text, the background, the size, etc.. and they would send back an image.

This looked like what I needed, so I started reading the doc.
They have a nice sandbox mode where you can see how imgix transforms images.

So I came up with this:

DomainHolder test

Good, now how do I get this from a simple url?

Well, that's where it gets tricky, because here's the url:

https://assets.imgix.net/page-weight/canvas.png?bg=D3EBB2&w=1280&h=640&fm=jpg&fit=crop&mark64=aHR0cHM6Ly9hc3NldHMuaW1naXgubmV0L350ZXh0P3c9MTI4MCZ0eHRzaXplPTg5JnR4dHBhZD00MCZ0eHRmb250NjQ9U0dWc2RtVjBhV05oSUU1bGRXVWdUR2xuYUhRJnR4dGNscj0wMDAmdHh0NjQ9VkdobElEVWdUVzl6ZENCR1lXMXZkWE1nUkc5dFlXbHVaWEp6SUU5bUlFRnNiQ0JVYVcxbCZmbT1wbmcmdHh0YWxpZ249Y2VudGVyJTJDbWlkZGxl&markalign=middle%2CCcenter&txt=DomainHolder.io&txtalign=bottom%2Ccenter&txtpad=40&txtsize=48

You can see most of the parameters, but some of them need to be base64 encoded. So I had to make a small helper for this.

function generateSocialImage($title)
{
    $bender = [
        'w' => 1280,
        'txtsize' => 89,
        'txtpad' => 40,
        'txtfont64' => trim(base64_encode('Helvetica Neue Light'), "="),
        'txtclr' => '000',
        'txt64' => trim(base64_encode($title), "="),
        'fm' => 'png',
        'txtalign' => 'center,middle',
    ];

    $bender_url = 'https://assets.imgix.net/~text?' . http_build_query($bender);

    $array = [
        'bg' => 'D3EBB2',
        'w' => 1280,
        'h' => 640,
        'fm' => 'jpg',
        'fit' => 'crop',
        'mark64' => base64_encode($bender_url),
        'markalign' => 'middle,Ccenter',
        'txt' => 'www.DomainHolder.io',
        'txtalign' => 'bottom,center',
        'txtpad' => 40,
        'txtsize' => 48,
    ];

    return 'https://assets.imgix.net/page-weight/canvas.png?' . http_build_query($array);
}

So to get the image in PHP, I just had to do this:

<?php
	echo generateSocialImage('The 5 Most Famous Domainers Of All Time')

It works! And it's fully customizable. But...

  • It's really hard to design a template, I spent probably 30 minutes to make this work
  • It's a paid service, which is ok, but I had no idea how much it would cost. They say "$3.00 per 1,000 images and $0.08 per 1GB", but it's hard to know how many images you would have to generate. I created an account, but I dropped out when I arrived on their dashboard because it was way too overwhelming to configure, to just render a few images
  • I was using their sandbox endpoint, which is probably not a good idea in the long term, even though it worked fine (don't tell them :D)
  • It was still not what I had in mind, which means: a simple url

--

Last friday, I was updating my personal website, and again, I've been stuck with this image problem, so I decided to finally make this service.

It took me less than 7 hours, in a 24 hours time period to make the service and deploy it live.

Here's how it works:

Templates

If you share a blog article, you probably want the title, the website and maybe the description in the image.

If you share a user profile, you want his name, his picture, his bio, his link, etc…

Now if you have a product, it could almost fit in the user template, because you still want an image, a description, a name etc.

That's where I figured that images could be categorized. And with a few templates, I could answer to 80% of the needs.

It's also easier because instead of sending a shitload of parameters, you just use a different endpoint.

Image generation

When you request an image for the first time, it validates the parameters, then it stores the required parameters in the database, and assigns an ID for the request. The ID is the sha1 of all the parameters.

Then it loads the template, populates it with the custom parameters and screenshots it.

The image is saved and is returned to the user.

When you request an image that already exists, it just has to find it with the ID generated before. It means that if you ask for an image that somebody already generated, it won't have to create the image again.

Here's the minimal request to generate an image:

https://api.imageee.com/default?title=This is a test

Result

And here's the example for the DomainHolder blog:

https://api.imageee.com/default?title=The 5 Most Famous Domainers Of All Time&url=www.DomainHolder.io&bg_color=d3ebb2

DomainHolder Blog

Keeping it simple

I want to keep things as simple as possible. Users have the possibility to change the background color, so I wanted to make sure that the font color was always visible.

I could have asked for the font color as well, but if they forgot to send it, the image isn't perfect.

Instead, I just had to evelauate the brightness of the background to define if the theme should be light or dark. This way it requires less parameters.

Luckily, WooCommerce has a function for this:

/**
 * Detect if we should use a light or dark color on a background color.
 *
 * @param mixed $color
 * @param string $dark (default: '#000000')
 * @param string $light (default: '#FFFFFF')
 * @return string
 */
function wc_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {

    $hex = str_replace( '#', '', $color );

    $c_r = hexdec( substr( $hex, 0, 2 ) );
    $c_g = hexdec( substr( $hex, 2, 2 ) );
    $c_b = hexdec( substr( $hex, 4, 2 ) );

    $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;

    return $brightness > 155 ? $dark : $light;
}

With this in place, I don't have to worry about the font color anymore. I might add this as a parameter in the future though.

What's the monetization method?

I made imageee to meet my needs (just like validator.pizza). I don't plan to monetize the service in this current state because this is the type of product where you would spend 10 hours to add a payment feature where your core feature only took 7 hours.

So as long as it doesn't cost me hundreds per month, that should be fine. Also, the good part is that I can flush all the genareted images like once a month to empty the server. This way I don't keep unused images.

That's it for today. Feel free to use www.imageee.com and tell me what you think of it, I'd love to get your feedback.
And let me know if you need more templates!