Resize/convert all images in a folder just by using batch script and FFmpeg

Do you ever had trouble with converting thousands of existing photos, e.g. from PNG to JPEG? Can’t find a neat GUI program to actually do this job painlessly, without browsing through a slew of options? Do you actually want to waste time to make a complicated batch script just to do simple jobs to satisfy your lazy constructive brain, like the way I did?

While I’m sure there are programs that does exactly that out there in the woods, this very simple procedure would also do the same job, in a small code, in so much lesser size.

Assuming you didn’t accidentally stumbled on this simple, unoriginal, and messy post out of nowhere and you had genuine interests as a computer savvy, you can continue reading this post. Actually, no one can stop you anyway.

Assuming that you’re also using one of the modern, very popular OS that is Linux that is Windows, it’s just a code away using Notepad. We’ll gonna make a simple batch script.

The batch script

Batch scripts are very notorious, aside from being a very high-level language (it’s a script interpreted by an interpreted interpreter… sort of), considerable amount of hackish code and workarounds are used just to do a freaking simple job, that a low-level language can easily do, that even Bash has native support. Basic example is the sleep command (used to pause the program for a definite amount of time), which Batch (or cmd) mysteriously doesn’t have, instead you’d rely on ping which is a network diagnostic tool. Most of this is basically a consequence of the nature of its syntax. It was like it was passed along and played by many engineers that does seem to have their own fetishes, err, version of what kind of creature it should be, like a baitch (sorry).

Compared to Bash, the Unix shell equivalent, Batch is frustrating to some extent. In spite of this shortcoming, Batch is still convenient and useful as a script, when you know the way around it. Heck, you can even do a routine that do complicated task, like syncing and patching files and binaries through a server while using queue techniques, just by using batch script (Of course, in conjunction with real native programs). I know, I’ve done this. Source? Nah, you think you can get free shiny codes? Kidding.

Reading this post up to this point, you must have a bit of a background with the things and concepts. If you believe that

@echo off

disables echoing of sound through your sound device, you will have difficult time just understanding the syntax of this code.

Ignoring what I said above and moving on, laying out the fundamentals:

set variable=value
echo %variable%
pause
exit

Knowing these fundamentals will give you much more difficult time in understanding the code that I will provide here. Trust me.

Next level, laying out some example ‘standard’ procedures:

setlocal enabledelayedexpansion

for /f "usebackq skip=2 tokens=1,* delims=:" %%G in ("!temp_folder!\!arrayfile!\temp_") do ...
for /f %%n in ('cmd /q /u /c "echo(%data3%"^|find /c ":"') do ...

...
echo( >NUL
call set /p variable=<%%~arg:~!_array!,1%% 2>NUL

If you’re a batch person, you’re gonna understand this immediately like a native Latin speaker would to Latin. For an unsuspecting programmer that goes straight to writing codes and whatnots without care in the underlying OS, they can scratch their head.

Wonderful, isn’t it?

Giving you a heads up and a valid set of expectations, we now head to the star of the event, the code itself. (Why did it take so long?)

tl;dr

@echo off
cls

set argument=%1
if defined argument (
  pushd "%~1"
) else (
  pushd "%~dp0"
)

set "bname=%~n0"
set "resolution=720"

echo %bname% | find "480"
if %ERRORLEVEL% EQU 0 set "resolution=480"

echo %bname% | find "720"
if %ERRORLEVEL% EQU 0 set "resolution=720"

echo %bname% | find "1080"
if %ERRORLEVEL% EQU 0 set "resolution=1080"

if not exist output mkdir output

for /f "tokens=* delims=" %%G in ('dir /A-D /B *.jpg') do (
  ffmpeg -i "%%~G" -vf scale=-1:%resolution% "output\%%~nG_resized%resolution%.jpg"
)

for /f "tokens=* delims=" %%G in ('dir /A-D /B *.png') do (
  ffmpeg -i "%%~G" -vf scale=-1:%resolution% "output\%%~nG_resized%resolution%.png"
)

exit

Looks so simple, yet complicated enough, in a small code, isn’t it?

If you immediately (or even barely) understood the procedures above, congratulations! If you didn’t, don’t fret! This is actually a very simple batch script compared to those insane ones (I made one myself, well I considered it as one…). This actually just resizes your JPEG/PNG images.

We’re gonna break it down to parts so you can know what parts to edit to manipulate the program to the way you needed, but before that, did you notice the line ffmpeg in the code? We have to get and set that up before this program would even work!

Head over first to https://ffmpeg.org/download.html. Now click the most obvious icon there (I trust you to have a beautiful, imaginative mind.) No, not the download button! The Windows icon! (So much for obvious!) Then click its corresponding link ‘Windows Builds’. It will take you to another page. Now, get either 32-bit or 64-bit static (if you’re in a 64-bit machine). My estimated size for FFmpeg 32-bit is around 12mb (64-bit is larger). I thought I said less size! Well, it is still lightweight for me. After you downloaded it, extract the contents and specifically isolate ffmpeg.exe. Copy it somewhere; any folder will do.

Now, in a related note, you can actually use FFmpeg to convert, encode, re-encode, extract, apply filter, anything that you can do to manipulate your media, be it video, audio or images. It is a little bit manual, but it is part of its charm. You can build automated scripts and macros to precisely do specific jobs. Fine engineering, at best.

Now with your FFmpeg ready, copy the code above and paste it in Notepad. After pasting it in Notepad, save it as a batch file with the extension ‘.bat’ (e.g. “imageresize.bat”), on the directory/folder where you placed ffmpeg.exe previously, and… viola! It is now operational and ready to go. Now you may have got the gist of how things work. You can also use the PATH environment variable to include the folder where ffmpeg.exe is located, or place the ffmpeg.exe directly inside your Windows’ system32 folder to give more freedom to the location of the batch file (you can separate them this way).

To test if it works, from the explorer, drag the folder where the images to convert are contained, and drop it on the .bat file you just created. If successful, ffmpeg.exe will run (as evidenced in the console output), converts your images one by one until all are finished, and it will exit. You will find the output inside the \output folder in the folder of the images you just converted. If all is well, all output files will be present there. If not, well, there must be something wrong, which is beyond the topic of this post (sorry).

Without worrying on what each line does exactly what, we proceed to the code breakdown. No, I haven’t forgotten this one. No, I won’t explain each command one by one as this was intended to be a short post. Look what happened!

Code Breakdown

@echo off
cls

set argument=%1
if defined argument (
  pushd "%~1"
) else (
  pushd "%~dp0"
)

The segment above sets the initial working directory based on whether we supplied an argument to the batch script or not. By dragging and dropping a folder to the batch file, we essentially provided the Explorer an argument to use when running the batch file.

There are many ways to supply an argument to a batch script, like providing it through a shortcut, or running it through cmd.exe with an argument. When there is no argument supplied (essentially, just executing the batch file directly), the working directory defaults back to the current directory where the batch script is located.

So now, there are two ways to use the batch script!

  • Placing the batch script alongside the folder that contains the images to process, and
  • By dragging and dropping the folder itself to the batch script, wherever it is located.

Now, to set what output resolution to use:

set "bname=%~n0"
set "resolution=720"

echo %bname% | find "480"
if %ERRORLEVEL% EQU 0 set "resolution=480"

echo %bname% | find "720"
if %ERRORLEVEL% EQU 0 set "resolution=720"

echo %bname% | find "1080"
if %ERRORLEVEL% EQU 0 set "resolution=1080"

Now, this is a neat old trick. Instead of manually setting the resolution of the output image directly inside the batch script everytime, I opted to set it according to the filename of the batch script itself. If you renamed your batch file from ‘imageresize.bat’ to something like ‘imageresize480.bat’, instead of the default 720 pixels that I set there, the batch file will check the filename first, and since it contains ‘480’, it will now set the resolution variable to 480. Now, if I change the filename to ‘imageresize4807201080.bat’…

if not exist output mkdir output

for /f "tokens=* delims=" %%G in ('dir /A-D /B *.jpg') do (
  ffmpeg -i "%%~G" -vf scale=-1:%resolution% "output\%%~nG_resized%resolution%.jpg"
)

for /f "tokens=* delims=" %%G in ('dir /A-D /B *.png') do (
  ffmpeg -i "%%~G" -vf scale=-1:%resolution% "output\%%~nG_resized%resolution%.png"
)

This is the main segment that does the legwork. I could have used nested for loops and use a variable that containes file extension names to recursively loop through the data, but I figured that it is a bit overkill for our simple, mundane task. Though it could have been extensible and would work brilliantly.

Now, if you know how to use FFmpeg (you can refer to its documentation for its usage), you can of course modify the ffmpeg lines to your needs. This currently resizes the image to a resolution set from the previous code block, preserving its aspect ratio and format. You want to convert it to another format? You can change the extension of the output file. E.g. :

ffmpeg -i "%%~G" "output\%%~nG.bmp"

That’s it! We need to wrap up this abomination of a post now, quick. There are so many possibilities with FFmpeg alone. Now you got it, your ultimate image converter/resizer using FFmpeg!

Finale

In also a related note, assuming that you are a computer wizard/hobbyist/elite/shut-in, you can also build a custom FFmpeg with custom encoders from scratch using Cygwin, a convenient linux shell for Windows. Your ‘nix geekness will really shine there.

Hope this long post helps!