qr code All content created by a human. No AI.

BIT-101

Bill Gates touched my MacBook Pro

Getimage


[ app , tool ]

Problem Statement

Sometimes when I am developing a program or technique, I need an image to load as a background or to do some image processing on, etc. It usually doesn’t matter what the image is, I just need it for testing.

My usual workflow up to now:

  1. Do an image search for something like “cats”.
  2. Find an acceptable image that is neither tiny or massive and roughly the same aspect ratio as I need.
  3. Save it, giving it a usable name like “image.png”, instead of “GettyImages-1208220393-e1612811442160.jpg”
  4. Open it up in an image editor, or use imagemagick to:
  5. Resize it to some usable dimensions. I like 800x800 as that’s the size of my canvas in my creating coding template project. But sometimes I want a different size. Scaling in imagemagick is easy, cropping is a bit more complicated, so I usually open up Gimp.
  6. If the image is not a PNG, convert it to PNG, as the graphics framework I use only loads PNGs.

First world problems, I know. But we can do better for this kind of repetitive task.

Some solutions…

Direct Random Image Download

I looked around for random image APIs. The category of tool I wanted was something where I could hit an API endpoint and the result would be a random photo, not a JSON list of images and attributes.

There are a few. Surprisingly few.

The most promising was PicSum - does exactly what I want. Specify a width and height and it serves up a random image. And it’s free. Sadly, they are all stupid AI generated garbage. Not that it matters for my purpose, but it really annoyed me to look at those things.

I then found that if you use the same API endpoints with picsum.photo it will serve up an actual photo. But it does some redirects to another site that took some getting around. I got it working with a simple shell script. If you want to try that, here it is:

#!/bin/sh
TEMP_FILE="$(mktemp)"
if [[ -z $1 ]]
then 
curl -L https://picsum.photos/800 > $TEMP_FILE
elif [[ -z $2 ]]
then 
curl -L https://picsum.photos/$1 > $TEMP_FILE
else
curl -L https://picsum.photos/$1/$2 > $TEMP_FILE
fi

magick $TEMP_FILE img.png
rm $TEMP_FILE

It uses imagemagick to rename and convert the image to a PNG.

There were a few other similar services, but most of what I tried was either a paid service or broken.

PlaceCats seems workable, if you just want cats. :)

Image Search Services

Then there are other image services. Unsplash and Pexels are two that I’ve used in the past extensively - but only through the UI, not API. But both have APIs. And there are plenty of others.

At this point, I had ideas in my head that I wanted to build a command line app in Go to do this, so I dug into Pexel’s API.

https://www.pexels.com/api/

And went about creating an app.

The getimage app

I created an API key, but to be honest, I initially forgot to use it in my request and it worked fine, so… ? Anyway, I fixed the code and am using the API key now.

They do have rate limiting of 200 requests an hour, or 20,000 requests a month. And there’s a header to see how many requests you have left. But this header was reporting -1 when I was not using the API key. The header did not exist at all when I was using the key. Again, not sure what’s going on with that part of it, but I’m not trying to get away with anything and I don’t think I’ll ever hit up against those limits anyway.

You have to do a search first, using some search term. This will give you a list of results. I programmed in a list of likely search terms:

animals
art
beach
buildings
car
cat
china
city
dog
fashion
fire
flower
food
forest
graffiti
holiday
horse
house
japan
landscape
plants
restaurant
shop
street
woman
woods

When you run the program it just randomly chooses one of those.

You get back a page of results that includes 15 images by default. You can request a larger page size, but that works for me. I then randomly choose one of those results.

Each image has a number of different version (sizes). Generally like:

original
large2x
large
medium
small
portrait
landscape
tiny

I found that large2x were generally the right size for me. At least 900-1000px in each dimension. So I pick that one out. The original size was way too large.

I then load that image using the URL supplied in the JSON.

I then shell out to imagemagick to do the resizing and conversion. So you do need to have imagemagick installed. There is an imagemagick library with Go bindings I could use to make this more self-contained. And maybe I’ll look into that eventually.

Resizing was the trickiest part, but I worked it out with a two-pass system. I make one call to scale the original image to fill the entire space of the requested size. This usually leaves the image too large in one dimension. A second imagemagick call crops it down to the right size. I use a “gravity” of “center” when cropping, which usually keeps the main subject of the image, rather than cropping half of it out.

Making it better

Up do now this worked perfectly for my needs. I’d get a random image sized to 800x800, converted to PNG and saved as “image.png” just by calling getimage.

But I can do better than that. What is a command line app without parameters?

The size was the first part. Pretty easy. Width and height were hardcoded as 800x800. I just added command line params -w and -h. They’re optional. Both default to 800.

I also added a -g param for geometry. This is just a shorcut to -w and -h. If you want a 400x400 image, just say getimage -g 400x400. Geometry will override the width and height settings if you use both.

Then image name. I was defaulting to “image.png” but added a -o parameter for the output name. I started adding logic to allow you to specify different file types, such as gif, jpg, etc. But I realized that since I’m running it through imagemagick, the extension on the output name specifies the output format as well. Free functionality!

Next was search term. Added an -s param to allow you to search for, say “tigers” or “airplanes” or whatever you want, rather than the random search I set up. I can’t guarantee you’ll get a result, but it’ll try.

Then at one point I wanted to grab a specific image I saw somewhere and was annoyed that I’d have to download it, name it, resize it, convert it. So I added a -u param. This lets you specify a URL directly to an image. If you specify this, it will bypass the search functionality, attempt to download the given image, then do the resizing, renaming, converting.

To summarize:

Usage of getimage:
  -g string
    	geometry of image as widthxheight
  -h int
    	height of image (default 800)
  -o string
    	the name (and file type) to save the image as (default "image.png")
  -s string
    	term to search for
  -u string
    	a direct URL to an image - will bypass search, downoad and resize image
  -w int
    	width of image (default 800)

I’m pretty damn happy with this. Even in just a few days, I’ve used this regularly.

Final words

If you use this, be responsible. Get an API key and don’t abuse it with too many requests. Also, look at Pexel’s attribution rules. If you wind up using the images for anything other than test fodder, follow those rules.

I think this would be pretty easy to adapt to use other services such as Unsplash. Looking over their API, it would only require very minor changes in the JSON parsing. Maybe I’ll make that an option at some point.

I’ve also thought about making a config file where you can specify your own defaults, search terms, etc. Provider could be part of that.

Source and a bit more info here:

https://codeberg.org/bit101/getimage

Installation

If you have Go installed on your system, it’s as easy as:

go install codeberg.org/bit101/getimage@latest

You’ll also have to set the environmental variable PEXELS_API_KEY with your actual API key value.

And, as mentioned, installing imagemagick is a must.

Tested on Linux, MacOS, and even Windows!

« Previous Post

Comments? Best way to shout at me is on Mastodon

Or share this post directly on Mastodon