Category Archives: Software

Resizing Images and Creating Thumbnails with ImageMagick

My first website, Dino’s Ultima Page, turned 18 years old last week. As a website about games, it’s got hundreds of images, mostly screenshots or other images of in-game objects and people. I spent a lot of time manually making thumbnails for most of the larger images, so that pages would load quickly and larger screenshots would be loaded only when requested.

Now, hopefully a little wiser, I know that such things can be automated. I recently showed how to extract regions of an image using ImageMagick, and this software, which I’m growing to love more and more, is also capable of resizing images (among many other operations).

Resizing a Single Image

Many of the games I remember from the early 1990s ran at a resolution of 320×200. Although they would often be scaled up during gameplay, taking a screenshot (in DOSBox, for instance) results in an image that is 320 pixels wide and 200 pixels high.

A screenshot from Dark Sun: Shattered Lands.

For an image that I’d like to display on a website, the size is a little annoying. It’s too small to make out much of the details, but possibly slightly too large to use as a thumbnail. I’d like to scale it down to create a thumbnail, but then link to a scaled up version of the image.

Using ImageMagick, it’s pretty easy to resize an image. Assuming the image above is called dsun_003.png, we can create the smaller and larger version as follows:

convert dsun_003.png -resize 640x400 dsun_003-large.png
convert dsun_003.png -resize 200x125 dsun_003-small.png

We call the convert command, passing the following as arguments:

  • The name of the original image we’d like to resize
  • The -resize parameter, followed by the new size
  • The name of the output file where the resized image will be saved

Note that I intentionally chose the new image sizes such that the aspect ratio is preserved (which is usually what you want). If you need to change the aspect ratio, check the Resizing documentation for more advanced examples.

This leaves us with a nice thumbnail and a larger image where we can savour the graphics of 1993:

The original image (top-left), the thumbnail (bottom-left) and the larger image (right).

Resizing all images in a Folder

If we can resize a single image from the terminal, then we should be able to automate this process for a large number of images in a folder, saving a lot of time that would otherwise be spent clicking stuff in an image editor.

For instance, I have a few screenshots from King’s Quest 6 in a folder called kq6. Each image has a size of 640×440 and is of type .png.

Six screenshots of King’s Quest 6.

I’d like to resize all images in this folder regardless of how many there are. I can achieve this using a loop in bash:

for filename in $1/*.png; do
    convert $filename -resize 320x220 "$1/$(basename "$filename" .png)-sm.png"
done

Actually, the trickiest part of this is to extract the filename without the extension. That’s the part where we’re using basename, which takes the filename as the first argument, and the suffix to trim off as the second. This solution works where we know the image type a priori and all images in the folder are the same type.

You’ll also note the use of $1. That’s simply the first argument to the script, so that we can use the same script in different places, just passing the name of the folder as an argument. In fact, after saving the script as resizeall.sh and giving it execute permissions, let’s call it on our kq6 folder:

./resizeall.sh kq6

This has the effect of creating smaller versions of all the images in the folder, which have the same name except for a -sm suffix before the file extension:

We’ve generated smaller versions of each image in the folder.

Conclusion

We’ve seen again that ImageMagick is really handy for image manipulation, and the ability to do things from the terminal makes it really easy to automate operations on large numbers of images. In this case, we found it was really easy to resize game screenshots to create thumbnails and larger images to display on a website.

Extracting a Region of an Image with ImageMagick

Selecting a rectangular region of an image and doing something with it is an extremely common operation. Even the simplest image viewers (e.g. Microsoft Paint) allow you to do this. While this is easy enough to do by hand, there are times when it’s useful to do it via the command-line, for example:

  • The image is too big to load into memory via an image viewer
  • You need to extract the same region for many images

In this article, we’ll see how to use ImageMagick to extract a region in an image. Just to give some context, I’m using Linux Kubuntu 19.10 and ImageMagick 7.0.10-23.

Installing ImageMagick

The first thing to do is make sure you have ImageMagick installed. While you can definitely check out the ImageMagick Download page, I’ve found these instructions particularly helpful on Kubuntu.

Analysing an Image

Before we go ahead and use ImageMagick, we first need to study the image that we want to process. Let’s say, for instance, that we’re going to work with the following screenshot from Warcraft II: Beyond the Dark Portal:

A screenshot from Warcraft 2: Beyond the Dark Portal, showing the opening screen of the last level of the Orc campaign. Deathwing is the currently selected unit, and a cheat was used to reveal the entire map.

There are a few regions of interest that we could potentially extract: the minimap, the selected unit’s portrait, the main view, etc. Let’s say we want to extract the minimap. First, we need to figure out the details of its rectangular region, namely the coordinates of its top-right corner, its width, and its height.

We can do this using most basic image viewers. For instance, Linux distributions using the K Desktop Environment (KDE) have a simple Paint-like tool called KolourPaint. If you use the rectangular selection tool and use it to draw a boundary around the region of interest, the program should tell you the details of interest in the status bar. This is easier to do accurately if you zoom in enough and turn on the grid lines, allowing you to see exactly where your selection fits within the pixel boundaries.

Zooming in on the minimap with KolourPaint. The blue and yellow dotted line shows the selected region around the minimap. At the bottom, the details of the selection can be seen: 22,24 – 153,155 … 132×132.

For this particular example, we can see that the region of interest has its top-left corner at the coordinates (22, 24), and it has a size of 132×132.

Extracting the Minimap

All we need is to pass this information to ImageMagick along with the image file, and use the -extract switch to extract the region of interest to a separate file, like this:

magick -extract 132x132+22+24 deathwing.png deathwing-minimap.png

That means: extract a region of size 132×132 at (22, 24) from deathwing.png and save it to deathwing-minimap.png.

And it works beautifully:

The extracted minimap.

Analysing and Extracting the Unit’s Portrait

To extract Deathwing’s portrait, we just need to repeat the same process for a different region. First, we identify the coordinates and size of the region of interest:

This time, the portrait is selected, and the selected region information is: 6,166 – 57,209 … 52×44.

Then we use ImageMagick to extract the desired region, as before. Obviously, we change the details of the region and the output filename:

magick -extract 52x44+6+166 deathwing.png deathwing-portrait.png

And the result is as we expect:

The extracted portrait of Deathwing.

Conclusion

This is great, especially because you can do the analysis step once and repeat the command on many images that have the same structure. For instance, if I wanted to create a website with information about each unit in Warcraft 2, I would just need a screenshot for each unit. I could then simply run a command on each image, and extract the units’ portraits with ease.

Visual Studio Bug with Spaces in Path

About a year ago, I ran into a weird bug. After having cloned a repository from Azure DevOps, I was baffled to see that the Solution Explorer in Visual Studio was not showing any files, even though there were plenty:

This problem still annoys my colleagues to this day. What happened in every case was that there was a space in the name of the project in Azure DevOps, so cloning the repo resulted in a folder that included %20 in the name. As I’m sure you’re aware, that’s the URI-encoded version of a space.

Unfortunately, for whatever reason, Visual Studo does not like this very much. It’s not a big deal though. Simply change that %20 to an actual space, and the files suddenly show up in Solution Explorer:

This problem seems to apply only to .NET Core projects. I haven’t been able to replicate it for older .NET Framework projects.

Analysing Binary Files using xxd

When you’re trying to make sense of a binary file format, a good hex viewer or hex editor is an invaluable tool. As shown in “Ultima 1 Reverse Engineering: Decoding Savegame Files“, a typical workflow involves viewing a hex dump of the binary data, making some small change, taking a second hex dump, and comparing the differences. If you’re lucky, you might even be able to observe patterns in the data directly.

Tandy 1000 graphics data for the space fighters in Ultima 1 can be easily observed in a hex editor such as Okteta.

While a good visual hex editor (such as Okteta under Linux or xvi32 under Windows) is essential to view the binary data in hex and also make direct changes to the data files, a command-line hex viewer for Linux called xxd also exists. As with most things in a Linux environment, a lot of power comes from being able to combine command line tools in a way that produces the results we want. As we shall see, one of the benefits is that although most hex editors don’t have tools to compare hex dumps, we can leverage existing command-line diff tools for Linux.

Reverse Engineering the Ultima 1 Savegame File Format

We’ve already seen in “Ultima 1 Reverse Engineering: Decoding Savegame Files” how to analyse how the bytes in the Ulltima 1 savegame files change in response to actions in the game world. Let’s see how we could do this more easily using Linux command-line tools.

First, we start a new game, and take note of a few things such as the player’s position and statistics:

Ultima 1 when starting a new game.

We can use xxd take a hex dump of the savegame, which by default goes to standard output:

A hex dump of an Ultima 1 savegame file

By redirecting the output to a file (which we’re arbitrarily calling before.hex), we can save this for later comparison:

xxd PLAYER1.U1 > before.hex

Next, we move a couple of spaces to the right and save the game. Again, we take note of the situation in the game world (i.e. that we have moved to the right, and food has decreased by 1):

Ultima 1 after moving a couple of spaces to the right.

We can now take a new hex dump:

xxd PLAYER1.U1 > after.hex

Now that we have a record of the savegame before and after having moved, we can compare the two dumps using popular Linux diff tools such as diff or vimdiff:

vimdiff before.hex after.hex
Comparing hex dumps with vimdiff

In this case, simply moving two steps to the right has changed four different things in the savegame file: the player’s position, food, move count, and tile in the overworld map. It takes a bit more patience to reduce the number of variables at play and come to some conclusions about what the bytes actually represent, but you can hopefully appreciate how well these command-line tools play together.

Analysing The Savage Empire Dialogues

The Ultima 1 savegame is particularly easy to analyse and compare because it’s got a fixed size of 820 bytes, and each field in the game state has a fixed place within that file. Not all binary files provide this luxury.

For instance, the dialogues of The Savage Empire are LZW-compressed and are written using a proprietary scripting language. However, we can still use command-line tools to extract some interesting insights.

Using tools from the Nuvie project, you can extract each character’s dialogue into a separate binary file, numbered from 0 to 76 with some gaps. We can thus write a simple loop in bash syntax from 0 to 76 and invoke xxd on each file, using the parameters -l 16 to print out only the first 16 octets:

for i in $(seq -f "%03g" 0 76)
do
    echo -n "$i "; xxd -l 16 "path_to_dialogue_files/$i.dat"
done

The result is that we can identify an increasing NPC number as well as the NPC’s name and a part of their description within those first few bytes, indicating that although the structure of the data may be complex, there is still a deterministic pattern to it:

First few bytes of the first several NPC dialogues in The Savage Empire.

Conclusion

Whether analysing binary files using hex tools is your thing or not, I hope at this stage you can appreciate how much you can get out of combining a few simple command-line tools together.

Quick Mount in DOSBox under Linux

DOSBox is incredibly handy to run old games. In “DOSBox for Dummies“, I covered basic usage, as well as how to write a Windows batch file to automate some of the more repetitive operations (such as mounting). I also explained how to extend this to games requiring a CD in “Running Games Requiring a CD in DOSBox“.

If your games are all under the same folder, you might want to consider automatically mounting your DOS games folder using a dosbox.conf file. Otherwise, you can resort to scripting via batch files (Windows) or shell scripts (Linux).

For those one-off situations where you just want to try out a game quickly without setting anything up, regardless of where it resides on the filesystem, you can run the following (in Linux) from the folder where your game is:

dosbox -c "mount c $(pwd)" -c "C:"

This is the same method I used in previous articles to pass commands to DOSBox. The only difference is that here I’m taking advantage of command substitution in bash (as seen in “Scripting Backups with bash on Linux“) to pass in the current directory via the pwd command. That way, no matter where your game folder is on the filesystem, DOSBox will start in the right location. Then, all you’ll need to do is invoke the right executable.

Happy retro gaming!