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:
Soon, I started to wonder if I could reverse-engineer these images with code. Here’s what I came up with:
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