Automating repetitive tasks for digital artists with Python

Part 1: Python tricks for artists series
9 readers like this.
Project Goodeberry surprised sheep character

Original render by Cosmos Laundromat. Modified by Jason van Gumster. CC-BY 4.0

Artists and designers should know how to code. There, I said it.

Now, I could go into a good in-depth exposition on how the artist mindset and the developer/engineer mindset aren't all that different, or how the image of the "non-technical artist" is a relatively recent phenomenon. Those are topics for another article. For the purposes of this article, suffice it to say that knowing a little code will not only give you a better understanding of how your digital tools work, but that knowledge will help you create your work more efficiently.

It doesn't matter if you're working on a large-scale collaborative project for a paying customer, or if you're using digital art as your freeform, free-wheeling catharsis engine. We all want to make the most effective use of our time. For myself, if I find that I'm doing some kind of monotonous task more than three times in a row, I'm already thinking about how I might be able to automate it and have my computer do the work for me.

Automation means cobbling together a script. Coding. And when it comes to scripting tasks that relate to digital media, you'd be hard-pressed to find a more suitable language than Python. Python is hugely popular open source scripting language that's used to write all kinds of open source software.

For digital creatives there are other advantages to learning Python. The language syntax is relatively easy to learn and Python is available on all major platforms. This means that your scripts can travel with you, regardless of whether you're running Linux, BSD, or one of those proprietary operating systems. Not only that, Python is well-integrated in a number of digital content creation tools like Blender and GIMP. Even some proprietary tools have integrated Python in them. This means that you can use Python to automate tasks in those programs, or even add new features that are specific to your particular way of working.

"That's great and all," you might say, "but be specific. What can I actually do with Python?"

I'm glad you asked.

This series of articles is meant to answer that question, to let you dip your toe into the stream and get a sense of what's possible with just a little knowledge about scripting. Fair warning: if these articles do whet your appetite for scripting, I highly encourage you to go through one of the many Python courses available online, including the tutorial that's part of the official Python documentation.

I should also mention that the examples I give might make a "real" Python developer cringe. And that's fine. Worst case, we still have a script that does exactly what we need it to. Best case, we get suggestions for improvements in the comments section of this article.

So let's start with something easy. We all know that command line tools like FFmpeg and ImageMagick are usually a faster way to do one-off video or image operations. Let's say all you want to do is encode a video or desaturate a PNG and convert it to a JPEG. It's way faster to fire off a single command than it is to launch a program with a full graphical interface, load your source media, and then perform that one little operation.

The problem, however, is that powerful command line tools like FFmpeg and ImageMagick have a lot of options and flexibility. They do so many things, and they're all controlled by a dizzying array of flags and options that you need to type in correctly. It's difficult to remember the exact magical incantation you need for the one or two specific tasks you need to get done.

For an example, let's say you have a directory full of PNG images generated by your favorite animation software. There are hundreds, or even thousands of individual images in there. Now let's say that you realize that there's no need for all of those images to be saved as 16-bit RGBA PNGs. You could save a ton of disk space and have faster loading times if those images were all converted to 1-bit black-and-white PNG images. Sure, you could re-render, but the images are already there. With FFmpeg you could churn though those images and convert them in far less time... if you could only remember the exact command to do that.

Fortunately, you've had to do this a few times before, so you took a little bit of time and scraped together a little Python script called make_1bit.py. It's way easier to remember make_1bit.py than ffmpeg -i something -flipflop -blah blah -please -o somethingelse or whatever. Here's the content of your script (with line breaks to fit in this column width; see below for the correct way to format your script):

import subprocess

subprocess.call(['ffmpeg', '-f', 'image2', '-i',
'%04d.png', '-pix_fmt', 'monob', '-threads', '0', 
'%04d.png'])

Let's take a quick moment to walk through the script and describe what it does. The first line, import subprocess, imports a Python module called subprocess. Think of modules as chunks of code that someone else has already written. You just need to make your script aware of that code. That's done with the import statement. In this case, you're importing the subprocess module, a Python module made specifically for launching commands as if you were typing them at the command line.

In the next block of code (subprocess.call(['ffmpeg',...])), you actually use code in that module to run FFmpeg for you. The whole FFmpeg command is broken into a list of strings. In Python, a list is simply a collection of data. It's indicated by the square braces ([]) and each bit of data is separated by a comma. In this case, each bit of data is a string, or a bit of text wrapped in single quotes. Each string in the list is an argument (flag) from the FFmpeg command you want to run, in the correct order.

In this particular example, we're assuming that the script is in the same directory as your images and that the images have numbered file names like 0001.png, 0002.png, 0003.png, and so on.

For organizational sake, you may want to put each of those argument pairs on their own lines. That way it's a bit easier to see what's going on. (Note: Python is very particular about "whitespace" (spaces and tabs) in your code. So make sure you use either spaces or tabs don't mix!, and that you use the same number of them when indenting.) If you do that, your script might look like this:

import subprocess

subprocess.call(['ffmpeg',
                 '-f', 'image2',
                 '-i', '%04d.png',
                 '-pix_fmt', 'monob',
                 '-threads', '0',
                 '%04d.png'])

Now all you have to do is run python make_1bit.py from within that directory and, BOOM, files converted! No need to remember all of those various flags for FFmpeg. The script has that remembered for you. Of course, if you want to run FFmpeg directly (or perhaps some variant of this command), it's easy to open your script file and have those flags available and clearly organized as a reference. You can even add comments to your script so you can more easily know what each flag does:

import subprocess

subprocess.call(['ffmpeg',
                 '-f', 'image2',      # Read input as images
                 '-i', '%04d.png',    # Input files (sequential PNGs)
                 '-pix_fmt', 'monob', # Output colorspace is 1-bit
                 '-threads', '0',     # Use all available CPU cores
                 '%04d.png'])         # Output files (overwrite input)

So this is where we start. We make one little script at a time. The point is to save us time and keep us focused on getting work done by simplifying and automating repetitive or tedious tasks.

There will be more in this series... but in the meantime, if you happen to use Python scripting to simplify tasks (whether for creative work or not), perhaps you can use the comments section to explain what you do.

User profile image.
Jason van Gumster mostly makes stuff up. He writes, animates, and occasionally teaches, all using open source tools. He's run a small, independent animation studio, wrote Blender For Dummies and GIMP Bible, and continues to blurt out his experiences during a [sometimes] weekly podcast, the Open Source Creative Podcast. Adventures (and lies) at @monsterjavaguns.

4 Comments

100% agree. I didn't even want to learn to code when I got into Linux, I just wanted a more efficient operating environment. The more I learned about BASH and Python, though, the more efficient my workflow became. Now I'm amazed at how nobody in art school ever even mentioned the potential of a little bit of tech know-how. Live and learn, I reckon.

Okay sorry if I seem a bit brash but seriously: this was the best case scenario for a simple, quick and easy bash script and you decide to use Python?

Despite my misgivings I will admit that sometimes in exceedingly rare cases Python may be the right tool for the job, but this definitely isn't one of them.

P.S. If further articles in this series show an actual need for Python, I'll be fully prepared to eat my words and apologize, so please don't take this the wrong way.

I understand your point and I'd certainly considered that while writing this article. However, this was meant to serve as a ground-level entry into the world of scripting. As much as I like bash, it's not [yet] as cross-platform as Python is... nor is it as prevalently used in creative tools as much as Python.

So *if* you happen to be on the right platform and you're only interested in solving this very specific problem, then yes... bash is the better tool for the job. However, if you're not on a system with a proper bash shell or your interest is in getting started with Python as a means of using it more in the programs you use every day as an artist, then hopefully this [series of] article(s) gives the start you're looking for.

In reply to by Tim Van den La… (not verified)

Jason's use of Python to invoke FFmpeg demonstrates the flexibility of Python. I don't see how providing that code in BASH would have demonstrated anything except that ffmpeg exists and can be used from a shell (which is its default).

Learning Python for the creative apps is significantly better than learning BASH for the same purpose. I use both, but realistically Python makes sense, as nearly any creative application - open source or otherwise - that allows scripting offers (at least) Python hooks. Heck, even MEL has pretty much given way to Python - meaning Python somehow managed to overcome the dreaded NIH syndrome of a closed source company; no small feat.

I also feel there's less of a ceiling to Python; you can start by scripting it, and then end up writing a video editor. With BASH, you might write some amazing utilities, but you're probably not going to script applications or write a stand-alone creative application with it.

I don't think that promoting Python means slandering BASH. They're both open source, there's room for each in a workflow, they're both completely cross-platform (although BASH on Windows presumably suffers from the lack of POSIX compliance), and they're both great languages.

In reply to by Jason van Gumster

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.