Amusingly, I worked this out a while ago, when I finished the main work of the Mastodon-scheduling script in my Mastodon Tool Trunk in late January. I meant to post about it then, but things got away from me, so you’ll instead get a short post now.

A black and white photograph of a bearded person in jeans and a leather jacket, drawing a complex image on a cobblestone surface

In getting images acceptable to social media sites like Mastodon, I ran across two problems.

  • Source images can run to sizes far larger than the server will accept.
  • Many online publishers have embraced a variety of new image formats—I’ve seen WebP and AVIF images showing up with greater frequency—that social media sites haven’t caught up to.

When I scheduled the posts manually through a web application, I’d take care of the images manually, as well. I’d download them, put them through an on-computer or web-based converter to get a PNG or JPEG file, and then resize them in GIMP; pardon my use of a name that the developers know offend people and have repeatedly refused to change it. That works, but it takes a lot of time.

For an automated process, I could really only see ImageMagick—or one of its derivatives that occasionally gets some press—as a viable route forward. And with some research, I came to this gem for handling both the image type and the size at once.

convert '*.*' -resize 256x\> -set filename:fn \
  '%[basename]' '%[filename:fn].png'

This exaggerates the job, but it resizes any image wider than 256px to a width of 256px—more likely, I want 1024px, in practice, but this works as an example—and converts it to a PNG file. ImageMagick does, in fact, know about WebP and AVIF, so I have my bases covered until the next technology shows up.

Oh, and if you only want to change one file, instead of everything in the folder, you can simplify that by removing the filename function, leaving something more straightforward, like this.

convert target_image.avif -resize 256x\> target_image.png

Really, though, I had no intentions of using the command line. Rather, I wrote the scheduler script in Ruby, so I need this to happen there. As it turns out, from one of my first Rails projects, I know about the rmagick gem. Using that, I get code that looks more like this, assuming that the script has already downloaded a source image.

require 'rmagick'
def convert_image(filename, max_width)
  outfile = "#{filename}.png"
  img = Image.read(filename).first
  small = img.change_geometry!("#{max_width}x#{max_width}>") do |cols, rows, _img|
    img.resize(cols, rows)
  end
  small.write outfile
  File.delete filename
  outfile
end

You might notice that we have similar features, here. In both cases, we resize to a maximum width—and height, too, since we occasionally see some wildly tall, narrow images—and then save it in the correct image format. This particular implementation then deletes the source file and returns the name of the new version, but we care about that less, in this discussion.

You might notice that the resizing code doesn’t need the backslash, here. We only needed it for working on the command-line, since the shell will interpret the greater-than character (>) as redirecting output to a file. Ruby knows better.

ImageMagick has an absurd number of features, honestly. I even use it to create boring sample images, when I test the scheduler.

convert -size 100x100 xc:#dccea1 test.png

This creates a solid square, using the background color from the blog.

At this point, it usually strikes me as stranger when I discover something that ImageMagick does not do, such as when I wrote the script to create a collage of emoji


Credits: The header image is adapted from untitled by an uncredited PxHere photographer, made available under the terms of the Creative Commons CC0 1.0 Universal Public Domain Dedication.