Heading image for post: Generate Images for Instagram

Generate Images for Instagram

Profile picture of Jake Worth

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.

Concept

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, but 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

Implementation

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.

#!/bin/bash
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.

Conclusion

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