Generate Images for Instagram

Followers of Hashrocket on social media will note our renewed presence
on Instagram, punctuated by a collection of custom images. In this post, I
will try to reverse-engineer these images using ImageMagick.

Hashrocket project manager Suzanne Erin recently started creating a series of
engaging images for our Instagram account to pair with blog posts. An example:

handmade image

Soon, I started to wonder if I could reverse-engineer these
images with code. Here’s what I came up with:

generated image

In this post, I'll explain how I created this image.


I wanted a CLI accepting two arguments: a background image and a blog post
title. With no other interaction, it should return a finished image.

Part of what powers this idea are the folks at Unsplash, who provide wonderful free photographs. I'm a huge
fan of their service, and always try to give the appropriate credit. These images would work with stock photography,

it would cost money and be a little less fun.

Here's what I wanted the program to do:

  • Resize the image
  • Crop the image into the ideal dimensions for Instagram
  • Darken the image so text can be readable on top
  • Add our company logo
  • Add a blog header
  • Add a custom blog title


I decided to use
ImageMagick for the image manipulation. ImageMagick is a FOSS suite for
displaying, converting, and editing images.

The first and hardest task was to build the image editing script. I haven't
done much image processing, so I knew this would be an iterative process. To minimize the thrashing, I decided to break the manipulation into steps, each with its own output. That way, I could inspect each version of the file on its own and diagnose issues.

I started by resizing the image to a workable size, noting that the resize
function forces the image into a box matching the dimensions you specify. I
chose to make the resized image bigger (2000 x 2000) than my crop so
that I would always have enough material to work with.

# Resize
magick "input.jpg" -resize 2000x2000 output/resized.jpg

Next, I cropped the image to 1080 x 1080, which seemed like a good shape for Instagram.

# Crop (1080 x 1080)
magick output/resized.jpg -crop 1080x1080+0+460 output/cropped.jpg

The numbers 0+460 are X/Y coordinates telling the crop function where to start cropping. They also seem to force the
program to make one crop and stop. These numbers put the crop at the
left-middle of the source image, which looks okay most of the time. It could always be made customizable later.

Next, I darkened the image, so any text on top of would be readable.

# Darken image
magick convert output/cropped.jpg -fill black -colorize 40% output/darkened.jpg

Then, I superimposed the Hashrocket logo, 100 pixels down
and to the right on the upper-left-hand corner. Resizing this PNG outside of the program helped me cut down on the repetitive work the program had to do.

# Superimpose logo
magick composite -compose atop -geometry +100+100 assets/logo.png output/darkened.jpg output/with-logo.jpg

Next, I added the header. This required downloading the Hashrocket logo font,
Circular Standard. Saving the font file in the root directory and referencing it in a relative
path makes the program more portable.

# Add header
magick convert output/with-logo.jpg -fill white -font fonts/CircularStd-Book.otf \
  -pointsize 100 -annotate +100+500 'Blog | Hashrocket' output/with-title.jpg

Finally, I added the blog post title, using a bold version of the same font family.

# Add blog title
magick convert output/with-title.jpg -fill white -font fonts/CircularStd-Bold.otf \
  -pointsize 100 -annotate +100+630 "My great blog post" output/ready-for-instagram.jpg

On top of this I added a Thor CLI. Here's the final command that generated my image.

$ ruby ./cli generate --source source.jpg --title "Generate Images\nfor Instagram"

And here's the script after some continued work. We add a setting so the script exits if any command doesn't succeed, we reorder the conversions, we ditch magick so it works on more versions of ImageMagick, and we pipe the output so there are no physical files written.

set -eu -o pipefail

# Resize, crop, darken
convert - \
  -resize 2000x2000 \
  -crop 1080x1080+0+460 \
  -fill black -colorize 40% \
  jpg:- |

# Superimpose logo
composite \
  -compose atop -geometry +100+100 \
  assets/logo.png \
  jpg:- jpg:- |

# Add header and title
convert \
  -fill white -font fonts/CircularStd-Book.otf \
  -pointsize 100 -annotate +100+500 'Blog | Hashrocket' \
  -fill white -font fonts/CircularStd-Bold.otf \
  -pointsize 100 -annotate +100+630 "$1" \
  jpg:- jpg:-

Follow Hashrocket on Instagram to see the final version of this image.


Fun project! I recently added a web layer to this service, so my teammates can generate images without any setup. Thanks to Suzanne for inspiring this project, and to Thomas Allen for helping me clean up the script.

Photo by Casey Horner on Unsplash

Leave a Reply

Your email address will not be published. Required fields are marked *