- Index
Introductions
Windows Image Processing Scripts
Performing Calculations
Editing, Debugging and Runtime Error Testing
Beyond the Batch File
Visual Basic Script (VBS)
Further Information
Most of the commands in IM Examples were written specifically with LINUX and
UNIX shell scripting in mind. Generally as these systems are designed with
batch processing and network servers in mind. However more and more users of
IM want to use it from the Windows Environment. This section provides details
and examples of how you can use IM in that environment and more importantally
how to convert a UNIX shell command (as used in these example pages) to its
Windows DOS equivelent.
I wish to express specific thanks to Wolfgang Hugemann
<ImageMagick_AT_Hugemann.de> who completely re-wrote the original notes
and expanded them to cover a much larger range of topics, of specific concern
to window users. What you see here is his work, and IM users are indebted to
him for his time and patience.
Introduction
Under Windows, simple IM commands are usually run in the Windows Command Shell
("DOS Shell" run by starting
cmd.exe). For complex operations,
performed in a lengthy command line or in a series of command lines, you will
probably better write a script. For a series of simple commands, this will most
probably be a DOS batch file, executed in the Windows Command Shell. This
approach, however, has its shortcomings, as the DOS batch file command set is
rather limited in comparison to those of common UNIX command shells.
When running IM under Windows, you basically have the following alternatives:
- The Windows command shell ("DOS window")
- This is run by
cmd.exe (32-bit mode) on Windows NT 4.0,
Windows XP and successive versions and is present on any Windows computer.
- Cygwin
- A bash-like command shell (http://www.cygwin.com/). When using this shell, the IM examples
presented in the rest of this Usage section can be run rather exactly as
they appear there. (You will however still have to rename the IM program
convert.exe, see below.)
- The Windows Powershell
- The much more powerful successor of the ancient DOS shell, based on the
.NET 2.0 technology. The Powershell shipped with Windows 7 and is run by
powershell.exe. It can be downloaded for Windows XP and Vista
at Microsoft's website.
- The Windows Script Host
- The Windows Script Host is based on the .COM technology. It is present on
any contemporary Windows computer and WSH scripts are much more powerful
than simple DOS batch files. The Windows Script Host offers several
programming interfaces, with VBScript (Visual Basic Script) and JScript
(Java Script) being the most common. Th IM command line tools can be
invoked by using the DOS shell commands
Run or
Exec of the Shell object (see below).
What's the use of an IM script on my Windows PC?
The following examples basically assume that you run IM on a Windows desktop
computer, probably attached to a network. Well, there are a lot of readily
available image manipulation programs, such as Adobe Photoshop, Corel's Paint
Shop Pro, IrfanView (
http://www.irfanview.com/) and even GIMP (
http://www.gimp.org/). So why should you bother to perform image
processing by command line programs and scripts?
The genuine advantage of using ImageMagick instead of a mouse-driven interface
is that you can completely automate routine manipulations, either for single
files or for bulks of files. Tasks such as...
- Bulk format conversion
- This is offered by quite a lot of Windows programs, such as IrfanView.
However, IM's versatility when it comes to image formats is unsurpassed.
You can for instance convert all the pages of a PDF into a series of JPEGs
(if GhostScript is installed on your computer).
- Shrinking and preprocessing digital photographs
- When embedding digital photographs into a word processor document, you
should usually reduce their resolution, such that the document can be
printed faster. The same holds if you convert the document into a PDF via
a PDF printer driver such as FreePDF.
Preprocessing could also comprise colour and lens correction routines.
- Placing your logo into a bulk of digital photographs
- Applying a series of operations to a bulk of digital photographs
- Having worked out a series of working steps by use of a mouse-driven
program, you might wish to automate these steps for future bulk
processing. However, script languages (such as Adobe's Action Script) are
not very common in Windows image processing programs.
- Combining several images to a catalog image
Although some of these tasks (especially bulk-shrinking) is also offered by
freeware programs (especially by IrfanView's batch processing), you are never
free of choice in what processing steps to apply: you have to live with those
offered by the program. For instance, IrfanView's batch processing offers to
place a text string into a bulk of photographs, but not a logo. It also offers
to change the gamma value, but the histogram of the photograph cannot be
clipped at its ends (as done by "
-contrast-stretch" in
IM, see
Normalize and Contrast
Stretch).
IM scripts are especially suited for productive use in a company network,
because ready-made scripts can be applied by anyone ¨C end users do not
necessarily have to know about what's going on in the background. Thus
standard workflow steps on images can be completely automised (and really
standardised). Several of the scripts presented in the following were derived
for productive use in our small company (working in the field of accident
reconstruction).
I am neither an outstanding Windows script programmer nor someone most
familiar with IM's command line tools. There are probably more elegant
approaches to some of the problems treated in the following. The points I want
to make are:
- to demonstrate some basic techniques of Windows script programming with
IM's command line tools.
- to prove that the use of IM-based scripts is neither art for art's sake
nor an academic pastime.
- to show that IM's command line tools can do real work in a local network
(and not only on webservers).
Windows Image Processing Scripts
Using Batch files under Windows
Let's assume you have a perfect Windows script (a DOS batch file, a VBScript,
or whatever) that takes the name(s) of the input file(s) as command line
parameter(s), performs some manipulation and spits out the result as a single
image or a series of images. You surely won't like to start a DOS command
shell everytime (see below) and provide the script with the filenames by
typing them. To avoid such cumbersome ways of proceeding, you can basically
use
Drag & Drop or
SendTo:
When using
Drag & Drop, you place the DOS batch file or the
VBScript (or whatever) in a location that is easily accessible, like the
desktop or the directory which holds the files to be processed. You then
select the files to be processed in the Windows Explorer and just drop them
onto the script. The filenames will be handed over to the script as the
command line parameters and can be referred to in the script.
As an alternative, you can place your script in the
SendTo folder. The
programs contained in this folder appear in the context menu of the Windows
Explorer when right clicking in the Explorer's file pane. Again, the names of
the selected files are handed over as command line parameters. The SendTo
folder is named
SendTo. Its location seems to move with each new
Windows version. A bullet-proof way to find it is typing
shell:sendto into the run box.
Converting Scripts: UNIX Shell to Window DOS
When invoking IM commands directly from the DOS command shell
(
cmd.exe) you have to modify the sample scripts presented on this
site (if they don't stem from this very page). The sample scripts are
generally intended to be run in a Linux command shell. In order to run them
from a DOS command shell, you have to perform the following modifications:
convert is a Windows command in the Windows system directory
(for converting FAT32 to NTFS). It is suggested you rename the IM convert
command to imconvert.exe to distinguish the two commands. You
can't rename the system command, as the next Windows service pack would
probably just restore it, ignoring the renamed version.
- Most often, double quotes '
"' have to be used in place of
single quotes ''' so that the command arguments remain
correct. Watch out for quotes within quotes such as in -draw operator. You can use
single quotes within a DOS double quoted argument as these are passed to
IM for handling, and not processed by the script.
- Backslashes '
\' appearing on the end of the shown example
lines represents a 'line continuation' which appends the next line to the
same command line sequence.
Just append all the lines onto one line and remove those backslashes. OR
replace them with '^' character to denote line continuation
in DOS batch files.
- All reserved shell characters which are not in double quotes must be
escaped with a '
^' (caret or circumflex) if used in
a literal sense (i.e. not fulfilling their usual purpose). These
reserved shell characters are: '&', '|',
'(', ')', '<',
'>', '^'.
This especially means that:
- The special character '
>' (used for resize geometry)
needs to be escaped using '^'. For example
"-resize 100x100^>"
- Similarly the 'internal fit resize' flag '
^' needs to be
doubled to become '^^'.
- UNIX shell escaping backslashes '
\' are not needed to escape
parenthesis '()' or exclamation marks '!'.
- UNIX shell escaping backslashes '
\' will need to be replaced
with a circumflex '^' when that escape characters such as
'<' and '>'.
For example: "-resize 100x100\>" will become
"-resize 100x100^>".
- In DOS batch files, the percent '
%' character also has
a special meaning as it references to the command line parameters, i.e.
%1, %2, .... In a DOS batch file, single percent signs (as
they appear in the "FOR command") thus have to be doubled to
'%%'
- Keep in mind that Windows filenames can include space characters. Such
filenames have to be included in double quotes:
"file
name.jpg" or "file name".jpg. A filename passed to
a script / batchfile via Drag & Drop or SendTo as a command line
parameter needs special attention, as it is passed to the script without
bracketing quotes if it doesn't contain space characters and with double
quotes in case that it does.
- Comments in UNIX shell scripts start with an unquoted '
#'
anywhere in a line and continue to the end of the line. Color settings
(such as "#FF0000" for a red color) will often be quoted with
to remove this special meaning. This quoting is not needed, but using
double quotes '"" around them does not matter and should be
kept.
In DOS, comments can only appear at the start of a line using
'REM' (or '@REM') or '::'. They
also continue to the end of the line. It is your choice which method of
commenting you should use. However commenting any batch file is always
recommended, so you know what the command is attempting to do when you go
back to the script years later. Makes it easier for others too.
All scripts should start with a comment explaining what the script does
and how it should be used. This is just good programming practice.
- When executing a DOS batch file, the individual commands are echoed by
default, IE: displayed in the DOS box. (In a UNIX shell you would instead
need a special command or option to print commands as they are executed.)
You can turn off this output by starting your script with
"
@ECHO OFF".
The special starting comment "#!/path/to/shell" in UNIX shell
scripts is not needed for DOS batch files. So this line can be replaced by
the "@ECHO OFF" command for DOS batch files.
For example, this UNIX shell script...
#!/bin/sh
# Create a negated rose image and overlay a comment
convert -background none -fill red -gravity center \
-font Candice -size 140x92 caption:'A Rose by any Name' \
\( rose: -negate -resize 200% \) +swap -composite \
output.gif
|
will become something like this in a Windows DOS batch file...
@ECHO OFF
:: Create a negated rose image and overlay a comment
imconvert -background none -fill red -gravity center ^
-font "C:\path\to the\font\candice.ttf" ^
-size 140x92 caption:"A Rose by any Name" ^
( rose: -negate -resize 200%% ) +swap -composite ^
C:\where\to\save\output.gif
|
I have written a basic Linux shell ¡ú DOS batch file converter by the use of
SED (
Streaming
EDitor). SED is a common UNIX / Linux text file
manipulation program which is also available for Windows at
http://sed.sourceforge.net/. Like IM is
a command-driven image manipulator, SED is a command-driven editor.
The SED script
cim.txt that performs the needed manipulations
looks like this (when stripped of any comments):
s/convert/IMconvert/ig
s/'/\"/g
s/%/%%/g
s/\\\([()!]\)/\1/g
s/\([&|<>]\)/^\1/g
s/^[ ]*#/::/
s/\(^.*\)\( #.*$\)/\2\n\1/
s/\(.:.*\.[a-z,A-Z]*\)[ ]/\"\1\" /g
s/\\[ ]*$/^/
s/^[ ][ ]//
|
You can download the fully commented version file
sed_script.zip.
If you place the SED script
cim.txt in the same folder as the
Linux shell script which is to be converted, you invoke the conversion by:
%programfiles%\GnuWin32\bin\SED -f cim.txt linux.scr > windows.bat
|
You can also invoke the convertion via SendTo or Drag & Drop by use of the
following batch file:
SET SP=%programfiles%\GnuWin32\bin
%SP%\SED -f %SP%\cim.txt "%~1"> "%~dpn1.bat"
|
This batch file assumes that you have placed the SED script
cim.txt within SED's program folder. It takes the filename of the
Linux shell script as the only command line parameter and generates a batch
file with the same name, but extension '.bat' in the same folder. (The crytic
filename manipulation "%~dpn1.bat" is explained in the next section.)
Please note: The above SED script will only perform the rudimentary
replacements mentioned above. It will NOT turn sophisticated Linux shell
scripts (like those presented on
Fred Weinhaus' website) into
the equivalent batch file!
Windows Filenames Handling
As has been said above, IM is particulary
useful when applying a standard sequence of processing steps to an image file.
In such a case, the filename will be passed to the script as a command line
parameter, either via Drag & Drop or via SendTo. Using these techniques, the
filename handed to the DOS batch file will be a fully qualified filename, i.e.
include the drive name and the directory path. You can test this be dropping a
file onto the following batch file:
Due to the
PAUSE statement, the DOS box will stay open until
the user presses a key, such that you can inspect the result. Try the above with
a filename that contains spaces and you will notice that the filename will be
bracketed by double quotes.
When using this filename in an
IMconvert command line, this
behaviour can cause trouble. Let us perform a simple conversion from any other
format to JPEG. The most basic code would be:
imconvert %1 %1.jpg
PAUSE
|
This will produce a JPEG file (with standard quality and resolution) in
the same directory, tailed with an additional ".jpg" extension. The above code
works on any filename, whether it contains spaces or not. If you want to get rid
of the original extension, things become a little trickier:
imconvert %1 "%~dpn1.jpg"
PAUSE
|
The above batch file manipulates the filename by use of the
~
operator:
| %~1
| expands %1 removing any surrounding quotes (")
|
| %~f1 | expands %1 to a fully qualified path name
|
| %~d1 | expands %1 to a drive letter only
|
| %~p1 | expands %1 to a path only
|
| %~n1 | expands %1 to a file name only
|
| %~x1 | expands %1 to a file extension only
|
These modifiers can be combined, such that "
%~dpn1" means "drive
+ path + name without extension and bracketing quotes". Consequently, we have
to bracket the name by double quotes, such that the code also works for
filenames including spaces. (If it doesn't, the quotes do no harm.) The
PAUSE statement is for testing purposes only and can be dropped
in the final batch file.
If you just want to test your code without actually invoking IM, you should
write:
ECHO imconvert %1 "%~dpn1.jpg"
PAUSE
|
which will just show the result of your string manipulation.
Batch Processing Several Files
The DOS
FOR command can be used to process a series of files in
the same manner. In order to scale all JPEG files in the current directory by
50%, you could type the following line into a DOS box:
FOR %a in (*.jpg) DO imconvert %a -resize 50% small_%a
|
Please note that the percent sign is
not doubled. If you however place
this command in a batch file you will have to replace it by
FOR %%a in (*.jpg) DO imconvert %%a -resize 50%% small_%%a
|
Again, it is convenient to invoke this bulk operation by Drag & Drop or
SendTo, passing a fully qualified filename (or a folder name) to a DOS batch
file which is possibly located in another directory (such as
shell:sendto). In this case, have to make the file's directory
the current directory in a first step:
@ECHO OFF
%~d1
CD %~p1
MD small
FOR %%a in (*.jpg) DO imconvert %%a -resize 50%% small\%%a
PAUSE
|
In this batch file we
- change the drive by supplying the drive name (d: or whatever)
- make the file's folder the current directory
- create a sub-directory named "small"
- scale all JPEG files by 50% and place these shrunken versions in the new
sub-directory.
There are several shortcomings and caveats of the
FOR statement
which we will come to in the following. One of them is that you basically
perform only one single command after
DO. You can however group
a series of DOS commands in parantheses "(", ")" and thereby perform a simple
sequence of commands:
@ECHO OFF
%~d1
CD %~p1
FOR %%a in (*.jpg) DO (
ECHO Processing file: "%%~nxa"
imconvert %%a -blur 30 -negate %%a.miff
composite %%a.miff %%a -compose overlay "%%~dpn1_light"%%~xa
DEL %%a.miff
)
PAUSE
|
This batch file will process all images found in the directory passed as the
command line argument. First it blurs the original image and negates it,
storing the intermediate result in a file with an additional
"
.miff" extension. Then it superposes the original image over
this modified version, thereby lightening the darker sections of the original
image. Finally the intermediate image is deleted.
Please note that in the above, emphasis must be put on the
simple sequence
of commands: You cannot make use of
GOTO jumps within the
block. If you need such behaviour, you have to call another batch file by the
FOR loop:
%~d1
CD %~p1
MD small
FOR %%a in (*.jpg) DO CALL "%~dp0process" "%%~fa"
|
Where "
process.bat" is the batch file which does the actual
work and which is located in the same directory as the calling batch file. The
command line parameter 0 ("
%0") is the name of the batch file
itself, such that "
%~dp0process" calls the batch file
process.bat in the same directory. The
FOR statement
provides just the filename, which is turned into a fully qualified filename via
"
%~fa". In the present case, the code in the batch file
process.bat would be the same as the one that was put between the
parantheses in the above example:
imconvert %%1 -blur 30 -negate %%1.miff
composite %%1.miff %%1 -compose overlay "%%~dpn1_light"%%~x1
DEL %%1.miff
|
The use of a separate batch file, however, offers all the (limited)
possibilities of a DOS batch file again. This does not make any difference in
this example, but we will show the benefits of this approach further down. In
case that we don't want to bother with two batch files, we can create
a
process.bat script within the calling batch file via
ECHO, and deleted it when the job is finished:
ECHO imconvert %%1 -blur 30 -negate %%1.miff >%~dp0process.bat
ECHO composite %%1.miff %%1 -compose overlay "%%~dpn1_light"%%~x1 >>%~dp0process.bat
ECHO DEL %%1.miff >>%~dp0process.bat
%~d1
CD %~p1
MD small
FOR %%a in (*.jpg) DO CALL "%~dp0process" "%%~fa"
DEL %~dp0process.bat
|
When using the
ECHO command, we have to escape any special DOS
characters, especially the percent sign.
And yes, IM could have done all the above in a single processing command,
removing the need for the "
.miff" intermediate image, but that is
not the point of this example.
Batch processing a (sub-)directory tree
There are several techniques to process all files in a (sub-)directory tree.
The simplest approach is to use the "
/R" flag in the
FOR statement to make it loop over all the files in all
sub-directories under the current directory. In order to convert all TIFF
files in the subdirectory tree to JPEG you thus simply type:
FOR /R %%a IN (*.tif) DO imconvert %%a "%%~dna.jpg"
|
When using the "
/R" flag, you are always looping through the
entire subdirectory tree, without options for sorting or filtering files.
In the oncoming example, we will generate photo index prints for all
subdirectories and place these within the root directory. This offers an easy
way to perform a visual search for a certain photograph, similar to the
preview in the Windows Explorer, but without the (time-consuming) need to
re-scan the entire directory tree for each search.
As a start, we approach the problem with the help of two batch files, one
performing the loop and one doing the actual work. The index prints will be
low-quality JPEG files named
IDX_0001.jpg, IDX_0002.jpg,
IDX_0003.jpg and so on. First we establish the loop:
DEL IDX_????.JPG
SET COUNT=0
FOR /F "delims=" %%a in ('DIR /S /B /AD ^|FIND /I "Porsche" ^|SORT') DO CALL c.bat "%%a"
DEL title.txt
|
The first line cleans up any results from previous searches. In the second
line, we define the environment variable COUNT, which we will use to generate
the
IDX_nnnn.JPG filenames. In the third line, we establish
a list of all subdirectories via
DIR /S /B /AD, extract those
directories that contain the word "Porsche" (case-insensitive by use of the
option
/I) and sort this filtered list. Sorting will ensure that
the numerical ordering of the IDX files will coincide with the alphabetical
ordering of the directory pathnames. The option
"delims=" will
inhibit the standard behaviour of truncating the lines after the first blank.
When calling the batch file
C.BAT, we bracket the pathname by
quotes to ensure that blanks are treated correctly. In the last line, we
delete a temporary file that is created by the batch file
C.BAT.
We now come to the actual work:
CHCP 1252
DIR %1\*.jpg>nul || goto END
:: Generate IDX filename
SET /A COUNT+=1
SET TFILE=000%COUNT%
SET TFILE=IDX_%TFILE:~-4%.jpg
:: Generate title
SET PNAME=%1
ECHO %PNAME:~1,-1% >title.txt
montage -geometry 210x140+0+5 -tile 6x -title @title.txt %1\*.jpg -quality 30%% %TFILE%
jhead -cl %1 %TFILE%
:END
|
In the first line we change the code page to ANSI, as special characters in
pathnames (such as German umlauts) would otherwise be coded differently in
Windows and DOS. In the second line, we check whether the directory actually
contains any photographs and skip the rest of the batch if not. (Executing the
rest of the batch instead would actually do no harm, as
montage
would simply generate no output, but the count of the IDX files would no
longer be consecuitive.)
We then generate the filename TFILE of the index file by incrementing COUNT,
attaching some leading zeros, extracting the last 4 characters via
%TFILE:~-4% and concatenating to
IDX_nnnn.jpg. (The
use of the
SET /A statement to perform calculations is explained
somewhat further down on this page.)
In the following lines we free the pathname PNAME of the quotes by cutting off
the first and last character via
%PNAME:~1,-1% and store the
result in the intermediate file
TITLE.TXT which will be passed to
IM's Montage. This ensures that the string is treated literally, so that we
don't have to escape the backslashes in Windows pathnames.
Montage then combines the photographs in rows by six (
-tile 6x)
and titles them with the pathname. The resulting index print will be 1260
pixels wide and is stored with 30% JPG quality in order to reduce storage
demands.
In the last line, we use the program
JHEAD to write the pathname
into the JPEG comment. This offers the possibilty to filter the index prints
within the Windows Explorer by text-searching the files for certain substrings
in the filename.
We can combine the two batch files, placing the code of the "working
batch" into the
FOR loop:
SETLOCAL EnableDelayedExpansion
DEL IDX_????.JPG
SET COUNT=0
FOR /F "delims=" %%a in ('DIR /S /B /AD ^|FIND /I "Porsche" ^|SORT') DO (
DIR %%a\*.jpg>nul
IF !ERRORLEVEL!==0 (
SET /A COUNT+=1
SET TFILE=000!COUNT!
SET TFILE=IDX_!TFILE:~-4!.jpg
ECHO %%a >title.txt
montage -geometry 210x140+0+5 -tile 6x -title @title.txt "%%a\*.jpg" -quality 30%% !TFILE!
jhead -cl %%a !TFILE!
)
)
DEL title.txt
|
Basically, two modifications have to be applied to the initial code:
- We have to enable delayed expansion and refer to the environment
variables used within the
FOR loop by bracketing them with
exclamation marks instead of percent signs.
- We have to avoid the
GOTO statement which would reset the
command processor.
Per default, the environment variables within a
FOR loop are
not evaluated at runtime. Instead, the code is pre-processed using the
list given in the paranthesis. A reference to
%COUNT% within the
FOR loop therefore always hands back the same value. In order to
enable the runtime evaluation of environment variables, you have to switch on
delayed expansion. This can be done when calling the command processor via
cmd /V:on or be generally switched on in the registry, using the
following REG file:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"DelayedExpansion"="1"
[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"DelayedExpansion"="1"
|
However, the dummy-proof version is setting this option in the batch itself by
use of
SETLOCAL EnableDelayedExpansion which will also limit any
changes to environment variables to the current version of the command
processor, which is probably desired.
References to the runtime values of environment variables within the loop now
have to use exclamation marks instaed of percent signs.
The use of
GOTO statements within a
FOR loop is
a possible source of very subtle errors and should therefore be avoided. In
our batch we can however easily exchange the jump by an
IF
statement bracketing the code block with the montage code.
Reusing the Output of an IM command
In recent versions of Windows, the
FOR statement has become much
more powerful, see
DOS "For"
Command Help. By using the "
/F" option, you can read the input
for the substitution variable from a file, a string or from the output of
another DOS command or another program. The latter is especially useful with
IM.
To get a rough idea on what IM's overlay methods really are about, you could
use the following batch file:
imconvert -size 80x80 -flip gradient: compose_src.png
imconvert compose_src.png -rotate -90 compose_dst.png
FOR /F %%A in ('imconvert -list compose') DO ^
composite compose_src.png compose_dst.png -compose %%A compose_%%A.png
|
Src
|
Dst
|
|
Multiply
|
Screen
|
Overlay
|
This script composes two gradient images together, using every possible
Alpha Composition method available, so you can see how
operators effect image colors. Only some of the images it generates are shown
above. This is similar to the images that were generated for
Composition Tables, so you can see how operators
affect image colors.
As the above lines are are assumed to be a batch file, we have to double the
percent signs.
The above script first creates two orthogonal gray-scale images with gradients
covering the entire color range. The IM command
imconvert -list
compose will provide us with a list of possible options, each placed
within a single output line. Please note that we have to use single quotes when
referring to a command in the parenthesis.
Using the "
/F" option, the
FOR command will then
process each of these output lines and hand it over to the command executed by
DO. As a consequence, the two gradient images are superposed
applying all the overlay methods that IM knows of. The output files are named
accordingly to the overlay method.
In the next example, we illustrate the color spaces which IM provides. We use
the same gradient technique as above to generate the surfaces of a cube as
spanned by the three coordinates of the color space:
imconvert -size 256x256 gradient: gy.miff
imconvert gy.miff -rotate 90 gx.miff
imconvert -size 256x256 xc:black black.miff
::R + G top left
imconvert gy.miff gx.miff -flop black.miff -set colorspace %1 -combine ^
-resize 260x300! -background none -shear 0x-30 ^
-virtual-pixel Transparent RG.miff
:: R + B top right
imconvert gy.miff black.miff gx.miff -set colorspace %1 -combine ^
-resize 260x300! -background none -shear 0x30 RB.miff
:: G + B bottom
imconvert black.miff gx.miff gy.miff -set colorspace %1 -combine ^
-resize 260x300! -background none -shear 0x30 -rotate 120 ^
-crop 520x300+0+75 GB.miff
imconvert -set colorspace %1 RG.miff RB.miff +append top.miff
imconvert -set colorspace %1 -size 520x150 xc:Transparent w.miff
imconvert top.miff w.miff -append topx.miff
composite -geometry +0+299 GB.miff topx.miff colorspace_%1.png
DEL *.miff
|
colorspace RGB
|
colorspace sRGB
|
A similar example to the above using UNIX shell scripting is given in Isometric Cube using Shears.
This batch file takes the color space as a command line parameter
"
%1". It then generates the three sides of the cube and shears and
mounts them such that we get an isometric view, where the point (0,0,0) lies at
the centre of a hexagon. The final picture is named after the color space (IE.
"
%1") and stored as a PNG.
We now want to call this batch file (saved as "
cspace.bat") from
another batch file that provides the names of the color spaces:
FOR /F %%A in ('imconvert -list colorspace') DO CALL cspace %%A
|
We can also filter the output of the
-list option by piping it in
DOS:
imconvert -list colorspace | FIND "RGB" >>clist.txt
FOR /F %%A in (clist.txt) DO CALL cspace %%A
DEL clist.txt
|
In this example, we filter those lines from the output that contain "RGB" and
write them to the file
clist.txt. This file is than used as the
input for the
FOR /F command. We can also do this in one run,
avoiding the temporary file:
FOR /F %%A in ('imconvert -list colorspace ^| FIND "RGB"') DO CALL cspace %%A
|
In this case, the pipe symbol "
|" has to be escaped, because it is
not bracketed by double quotes (only by the single quotes needed for the
FOR statement) and is ¨C at least in command line above ¨C not
meant in is usual sense.
Processing Single Line Output
This technique can also usefully be applied to a single-line output. We can for
example apply an automatised gamma correction that roughly sets the average
brightness of a picture to the middle of the quantum range (i.e. 127 for a
color depth of 8 bit) by a technique explained on
Fred Weinhaus' website:
FOR /F %%a in ('identify -format "%%[fx:log(mean)/log(0.5)]" %1') DO ^
imconvert %1 -gamma %%a "%~dpn1"_c.%~x1
|
This batch file is handed a fully qualified filename as the command line
parameter "
%1", most likely via Drag & Drop or SendTo. The
output of IM's Identify command then provides with a gamma value, which will
set the image's average brightness to the middle of its dynamic range. This
value is calculated using a
FX Format
Expression. The single line output of the Identify command is saved into
the "
%%a" variable, and passed to the IMconvert command as an
argument for the
Gamma Color Correction.
Please note that the
FOR command seems to be quite sensitive
when it comes to line continuations: If you use them at all, make sure that you
better don't start the next line with spaces.
With the same
FOR technique, we can read from the EXIF
information embedded in a photograph and write it into the top left corner of
the image:
FOR /F "tokens=1,2" %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
imconvert %1 -pointsize 18 -fill white -gravity northwest ^
-annotate +0+0 "%%i %%j" "%~dpn1"_dated%~x1
|
  |
Photos are typically saved using JPEG format. Reading and re-saving JPEG
images causes slight degrading of the image due to JPEG Lossy Compression and as such saving back to JPEG is not
recommended.
|
In the above batch file, the filename of the photograph is supplied as the
single command line parameter, which is referred to as "
%1". The
Identify command reads the date and time that the photograph was taken from
the EXIF information within the JPEG file. The
FOR command then
hands this output over to IMconvert which annotates the photograph accordingly
in the upper left corner.
The EXIF date and time information is formatted as "yyyy:mm:dd hh:mm:ss", EG:
"2006:12:26 00:22:38". Thus date and time are separated by a space character.
By default, the
FOR statement would only find the first token
("word") in each line, with tab and space characters as the standard
delimiters. Thus in the example above, the standard processing would only
handle back the date, but not the time. Using the option
"
tokens=1,2" we declare our interest in both tokens, which are
named consecutive, IE. "
%x, %y". We can however change the rather
unconventional formatting of the date by the following code:
FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
imconvert %1 -pointsize 18 -fill white -gravity northwest ^
-annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1
|
We now defined the colon ('
:') as an additional delimiter,
causing the date to be broken up into the three tokens "
%i",
"
%j", "
%k". The next delimiter found is the space
character separating date and time. With the asterisk ("*") we asking the rest
of the line to be stored in the fourth token "
%l". We can now
format the date as we like to. We have chosen the Anglo-American notation
"mm/dd/yyyy" as in the above example.
Performing Calculations
The DOS command interpreter is poor when it comes to calculations. You can use
it to perform simple integer arithmetics. But for doing more complex floating
point mathematics, you have access to IM's
FX Format Expression, or a third party DOS calculator program.
Using IM's FX Expressions
IM's
FX Format Expression can be used
for floating point mathematics and can add that maths to larger formated
strings, as has been demonstrated above in the first example of the section
Processing Single Line Output. By use of the
SET command, the result can be stored in an environment variable
and used later in the batch file. As a simple example, we may wish to adjust
the font size date-time string in the above example according to the
dimensions of the photograph:
FOR /F %%i IN ('identify -format "%%[fx:min(w,h)*0.05]" %1') DO SET psize=%%i
FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
imconvert %1 -pointsize %psize% -fill white -gravity northwest ^
-annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1
|
In the first line we evaluate the smaller dimension of the photograph by
"
%[fx:min(w,h)]", take 5% of this value and store it in the
environment variable PSIZE. This value is referred to in the next statement
(
%psize%) to set the font size of the time-date information.
And here we calculate a random angle between as an integer between
-15?and +15?to create a rotated thumbnail image.
FOR /F %%x IN ('convert null: -format "%%[fx:int(rand()*31)-15]" info:') DO SET angle=%%x
imconvert %1 -thumbnail x90 -matte ^
-background none -rotate %angle% "%~dpn1"_rotated.png
|
The
FX Expressions cannot only
generate numbers, but can also generate multiple numbers, embedded in a larger
string. For example in
Border with
Rounded Corner it was used to directly generate a complex draw string
based on image width and height information. This added feature, along with
avoiding and further dependence on other external programs makes this method
a preferable method for doing calculations in your batch script.
Using the SET command
The
SET command can perform some simple integer math and some
basic string manipulation when the "
/A" option is invoked. In the
following example, we roughly calculate the width of the time-date string by
use of the
SET command:
:: Determine the font height
FOR /F %%i IN ('identify -format "%%[fx:min(w,h)*0.05]" %1') DO SET psize=%%i
:: The width of the date-time string is roughly 9 times its height
SET /A pwidth=%psize% * 9
:: Calculate the average brightness in this section
:: and choose the text color accordingly
FOR /F %%i IN ('identify -format "%%[fx:mean]" -crop %pwidth%x%psize%+0+0 %1') DO SET mean=%%i
IF %mean% LEQ 0.5 (SET fcolor=white) ELSE SET fcolor=black
:: Annotate the photograph
FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
imconvert %1 -pointsize %psize% -fill %fcolor% -gravity northwest ^
-annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1
|
This sample batch file chooses the color of the date-time string according to
the average brightness (
%mean%) in the area where it will be
placed: If it is less than 50%, the string will be white, else it will be
black. The example also makes use of the
IF statement. Please
note that the
ELSE part has to be placed in the same line and
that the first command has to be bracketed.
Using Other External Calculators
As an alternative, you can use a DOS program which provides floating point
math, such as
EVAL. If you place this file in the IM program directory or in the
Windows system directory, you can perform floating point calculations in any
DOS shell window.
By using the
EVAL program, the
FOR command and
environment variables, we can make the color cube example from above somewhat
more flexible and its various calculations more transparent:
imconvert -size 256x256 gradient: gy.gif
imconvert gy.gif -rotate 90 gx.gif
imconvert -size 256x256 xc:black black.gif
:: Set the dimension of the color cube / hexagon and calculate the various lengths
SET l1=512
FOR /F %%i IN ('EVAL "round(cos(degree*30)*%l1%)"') DO SET l2=%%i
FOR /F %%i IN ('EVAL "2*%l2%"') DO SET l3=%%i
FOR /F %%i IN ('EVAL "round((1+sin(degree*30))*%l1%/2)"') DO SET l4=%%i
FOR /F %%i IN ('EVAL "round(%l1%/4)"') DO SET l5=%%i
imconvert gy.gif gx.gif -flop black.gif -set colorspace %1 -combine ^
-resize %l2%x%l1%! -background none -shear 0x-30 ^
-virtual-pixel Transparent RG.miff
imconvert gy.gif black.gif gx.gif -set colorspace %1 -combine ^
-resize %l2%x%l1%! -background none -shear 0x30 RB.miff
imconvert black.gif gx.gif gy.gif -set colorspace %1 -combine ^
-resize %l2%x%l1%! -background none -shear 0x30 -rotate 120 ^
-crop %l3%x%l1%+0+%l5% GB.miff
imconvert -set colorspace %1 RG.miff RB.miff +append top.miff
imconvert -set colorspace %1 -size %l3%x%l4% xc:Transparent w.miff
imconvert top.miff w.miff -append topx.miff
composite -geometry +0+%l1% GB.miff topx.miff colorspace_%1.png
DEL *.miff
DEL *.gif
|
Editing, Debugging and Runtime Error Testing
In principle, DOS batch files can be written in any editor, even with Windows'
Notepad. You should however use an editor with syntax highlighting for DOS
batch files. I personally think that
Notepad++ is the
tool of choice, but talking of editors tends to make people nasty. So: yes,
any other editor will do.
As far as I know, there is no free batch file IDE (integrated development
environment) on the market. One would think that this should be something
which comes with the operating system, but this has never been the case. So
far, I have written all my batch files with Notepad++, but for those who write
batch files on a regular basis, the
Running Steps batch IDE might be of help. It is shareware and costs about
$80.
Comprehensive explanations of the DOS commands can be found at
http://www.computerhope.com/msdos.htm.
As the DOS batch language itself, debugging batch files is a rather odd
business. I would test any batch file in a DOS box as a start. When testing
Drag & Drop or SendTo, it is recommendable to end the batch file with
a
PAUSE statement such that the DOS box stays open after the
batch job has been finished.
Considering runtime error messages, the general approach is to check the DOS
ERRORLEVEL and jump to an according error message generated by
the
ECHO command. I found that one of the most probable error
sources is that the IMconvert programm is not properly found on the machine
running the script. So if you intend to share your batch scripts with others,
you should first of all check whether IMconvert is accessible:
@ECHO OFF
Imconvert -version 2>nul@
IF NOT %errorlevel%==0 GOTO NoMagick:
IMconvert ...
GOTO END:
:NoMagick
ECHO ImageMagick (IMconvert.exe) not fount.
ECHO Did you forget to rename convert.exe?
PAUSE
:END
|
With the same technique you can perform any other error check and jump to
the according error message at the end of the batch file.
Summing it up
The above examples prove that the simple DOS batch file is
astonishingly versatile when it is combined with the possibilities offered by
IM. Yet the examples also show that doing calculations can turn out to be rather
cumbersome. Summing it up, the features offered by a DOS batch file are still
far below those offered by a real script or even programming language.
Please note that in the examples above, we applied the manipulations
either to a single file or to all files in a directory (tree). Things will
become (at least) very difficult, if we want to pick an abitrary number of files
from a directory and apply some manipulations to them, e.g. combine them in a
definite way. The command line parameters are limited to the number of nine,
i.e. %1 to %9.
The DOS batch file language lacks sophisticated control structures, like
structured control loops, not to speak of enumerations (
FOR... EACH...
IN... DO... END). The access to (text) files via the
FOR
statement is also rudimentary. Such things are offered by the Windows Script
Host, which is another chapter to treat.
Visual Basic Script (VBS)
The scripting capabilities of the
Microsoft Windows
Script Host (WSH) are more sophisticated than those of the simple batch
file language. The WSH is language-independent in the sense that it can make
use of different Active Scripting language engines. By default it interprets
and runs plain-text JScript files (Java Script) and VBScript files
(VisualBasic Script). The Windows Script Host is distributed and installed by
default for Windows 98 and newer (it may however have been switched off on
a possible target machine because of security concerns). The WSH implements an
object model which exposes a set of COM interfaces that allow you to address
system objects, especially the file system.
I will not discuss the Windows Script Host in detail over here, as this is
done elsewhere (and probably better than I could do), but rather give some
practical examples how to address typical problems. The examples are given in
VisualBasic Script, but the JScript code would be very much alike, thus it
should be easy to re-write the examples in JScript, if this is your favourite
language.
Like batch files, VB Scripts can be written in any editor and I would again
suggest Notepad++ as the editor of choice. As for batch files, Microsoft
offers no IDE taylored to support the development if VBScripts. There has been
a Microsoft Script Editor shipped with Microsoft Office 2000 through 2003, but
I have never tried it. Microsoft also provides the (very rudimentary)
Microsoft Script Debugger, but again, I have not much personal experience with
it. There are several commercial VBS IDEs offered as shareware at reasonable
prices, like
VbsEdit.
A Basic Example: Lens Correction
As the use of the WSH generates some overhead, our start example is not too
basic, in order to demonstrate the advantages of VBScript compared to a simple
batch file. In the following, we will correct the lens distortion for the
Nikon 995 digital camera by use of IM's
barrel
distortion. The correction parameter(s) depend on the focal length, which
is looked up via
identify first.
For the correction of the Nikon 995 lens, we only need the parameter
b
(i.e.
a, c = 0), which can be calculcated from the focal length
f by:
b = 0.000005142
f ³ - 0.000380839
f ² + 0.009606325
f - 0.075316854
This dependency was found by means of the
lensfun database which lists the barrel distortion parameters for this
lens.
So here is our VBScript:
const strConv = "IMConvert" ' name of the IM Convert program
const strAdd = "_ptr" ' string atached to the filename
'
Dim wsh,fs
Set wsh = CreateObject("Wscript.Shell")
Set fs = CreateObject("Scripting.FileSystemObject")
'
' names of the in- and output files
strFileIn = WScript.Arguments(0)
Pos = InStrRev(strFileIn,".")
strFileOut = Left(strFileIn,Pos - 1) & strAdd & Mid(strFileIn, Pos)
'
' evaluation of the focal length and calculation of parameter b
command = "cmd /k identify -format ""%[EXIF:FocalLength]"" " & strFileIn
Set objExec = wsh.Exec(command)
strf = objExec.StdOut.Readline
f = eval(strf)
b = 0.000005142 * f * f * f -0.000380839 * f * f + 0.009606325 * f -0.075316854
d = 1 - b
'b=replace(b,",",".") ' only needed in the German version
'd=replace(d,",",".")
'
Command = strConv & " """ & strFileIn _
& """ -quality 80%% -virtual-pixel black -filter point -distort Barrel ""0.0 " _
& b & " 0.0 " & d & """ """ & strFileOut & """"
wsh.run command, 7, true
|
The three lines after the definition of the string constants are standard
overhead, as we always need a
Shell object in order to start IM's
programs via its
Exec or
Run method. As we always
process files, the
FileSystemObject is also also commonly needed.
The only script argument is a filename, which we usually provide via Drag
& Drop or SendTo. The filename is stored in
strFileIn, from
which we derive the name of the output file
strFileOut. We then
run IM's Identify program in a DOS command box, using the option
/K in order to wait for the command to complete before continuing
the execution of the script. The result (i.e. the EXIF rational representing
the focal length) is stored in
strf. EXIF rationals are provided
as nominator / denominator, e.g. 82 / 10 = 8.2mm. The rational thus has to be
evaluated before using it in the formula which calculates the parameter
b.
The parameter
d is calculated and provided to the IMconvert command,
too, as it does not seem to be calculated automatically if omitted (as claimed
in the documentation).
Replacing of the decimal comma by a decimal point is of course only needed in
the German version, but added here because it provides a very common pitfall:
When converting decimals to strings, VBScript inevitably uses the local
settings. This behaviour is convenient when program output is concerned, but
can generate problems if the string is handed to another program, especially
IMconvert.
In the last two lines, we construct the IMconvert command line and execute the
statement via the Run method of the Shell object. The parameter 7 minimises
the window and TRUE tells the script to wait for the result.
The above script lins out the general strategy when using VBScript with IM's
command line tools: These are called either
- via the Run command of the Shell object, if no textual output is expected
- within a command shell if their textual output has to evaluated, as
typically is the case with Identify.
Working with Several Files
One genuine advantage of VBScript in comparison to DOS batch files is that you
can easily work with an abitrary count of command line arguments. You could
for instance pick an arbitrary number of filenames in the Windows Explorer and
combine the selected images to an index print via IM's Montage. The basic code
would be:
Dim FName()
Dim wsh,fs
Set wsh = CreateObject("Wscript.Shell")
Set fs = CreateObject("Scripting.FileSystemObject")
'
NArgs = WScript.Arguments.Count
Redim FName(NArgs-1)
strInputFiles = ""
For i = 0 to NArgs - 1
FName(i) = """" & WScript.Arguments(i) & """"
strInputFiles = strInputFiles & " " & Fname(i)
next
'
Command = "montage -geometry 210x140+0+5 -tile 6x " & strInputfiles & " -quality 80% " & fs.getParentFolderName(FName(0)) & "\index.jpg"""
wsh.run command, 7, true
|
The script demonstrates several techniques to handle multiple input files.
First of all, you can determine the number of command line arguments via
WScript.Arguments.Count. For larger scripts it is convenient to
store the filenames in an array: You define an dynamic array via
Dim
FName() and redimension it via
Redim FName(NArgs-1). When
generating the command line, the script also demonstrates how to determine the
parent folder via the FileSystemObject:
fs.getParentFolderName(FName(0)).
The command line of Montage will possibly become very long, because in the
input file list, each file is named by its fully qualified filename.
Practically speaking, this will seldomly generate problems, as the command
line handed to the Run method is allowed to be very long. (How long exactly
seems to depend on the Windows version.)
Quite often, the filenames will have to be sorted aphabetically, as Drag &
Drop or SendTo will pass them to the script in abitrary order. This can be
done by bubble sorting:
for i = 0 to NArgs - 1
for j = i + 1 to NArgs - 1
if FName(i) > FName(j) then
Temp = FName(i)
FName(i) = FName(j)
FName(j) = Temp
end if
next
next
|
![[clip]](clip.jpg)
You can download a copy of all the files and images involved in the file
strip.zip.
A more sophisticated application of the concept outlined above is presented at
the right: A set of video frames has been mounted to two parallel "film
strips" by means of a VBScript and ImageMagick. The perforation gives a visual
hint that the progression of the frames is from top to bottom, i.e. column by
column ¨C in contrast to the usual western reading pattern left-to-right and
then top-to-bottom. The entire script which performs the job can be downloaded
by clicking on the image example.
Marginal note: The red time code at the rigth top of each frame was generated
by an
AVIsynth script. The frames were
dumped by exporting them from
VirtualDub. With the embedded time code, the frames do not necessarily
have to be temporally equidistant, i.e. can be chosen as needed in the Windows
Explorer and sent to the script, which is placed in the SendTo folder.
Working with Text Files
When working with scripts on a client computer, the input information is
generally supplied via Drag & Drop or SendTo, i.e. basically consists of
filenames which will be processed in a manner predefined by the script. Any
additional information has either to be supplied by user interaction at
runtime or to be supplied in form of a text file.
Basically, we have the following options:
- The script accepts image files as input, accompanied by a (possibly
optional) text file, supplying additional information.
- The script accepts a single text file for input, which lists the images to
be processed as well as any additional information needed.
In the former case, it is suitable to place the optional text file in the same
directory as the images, assigning a standard name to it. The script may then
derive the parent directory name from the input images and open the text file
in the same directory if present. An example of this approach is the "film
strip" mentioned above: At the start of the script we will probably define
some standard ordering of the frames, depending of the number of images passed
to the script. But there might be scenarios in which we want to deviate from
the standard ordering of the frames. Thus we could place a text file named
ordering.txt in the frames directory, which, if present, will
control the ordering of the frames:
strTxtFile="ordering.txt"
PDir = fs.getParentFolderName(FName(0)) & "\"
Wsh.CurrentDirectory = PDir
If fs.FileExists(strTxtFile) then
Set objFile = fs.OpenTextFile(strTxtFile, 1)
bCtrlFile = True
NCols = objFile.ReadLine
objFile.close
else
bCtrlFile = False
end if
|
![[clip]](wm.jpg)
You can download a copy of all the files and images involved in the file
wmpr.zip.
A useful application of the second concept can be found in the perspective
mapping of an image to a target plane as
demonstrated on Fred
Weinhaus' website. We could use this concept to "skin" a perspectively
distorted image onto a perspectively (mostly) correct version, as demonstrated
to the right: In the upper part, the left image shows a photograph taken at
the screne of a minor accident. The right photograph was taken at a later
visit to the scene, from a somewhat elevated position. In the lower part, the
accident photograph (i.e. the planar road surface) is mapped onto the target
photograph by means of a perspective transformation. (The aim of this is to
visualise the orientation angle of the faint skid mark left by the right front
tyre of the black car.)
In order to perform this task, the user has to choose four points in the
source image and their target points in the perspectively correct image. We
could do this by hand, determining the coordinates in the source image and in
the target image by picking the points in an image viewer (like
IrfanView), noting their coordinates and
supplying these to an IMconvert command line.
This tedious work can however be simplified by the freeware program
WinMorph, which offers
a convenient interface to do just this: Pick some source points and their
according target points from two pictures. The yellow polylines in the two
photographs connect the four chosen points in each picture.
The morphing algorithm itself is however not suited to perform a perspective
correction. (The basic functioning of this algorithm is explained in the
Distorts part in the Usage section of the IM
website. A demonstration of its usability for morphing is found in Fred
Weinhaus'
ShapeMorph script.)
WinMorph stores its information in a structured text file which contains
(amongst other information) the filenames of both the source and the target,
as well as the coordinates of source and target points. Thus we can derive all
information needed for IM's perspective distortion from the WinMorph file. The
script performing the job can be downloaded by clicking on the image example.
Testing and Debugging VBScripts
Basically, we are using VBScript to construct the argument list for IM's
command line tools, which are then run either themselves or within a DOS box.
This means that first of all you should ensure that
- the command line itself does what we expect it to do
- the command line is constructed correctly by the script.
So as a start, you should test the command line itself within a DOS box. When
first testing the script, you should not run the IM command, but rather
display the text string in a message box via MsgBox(strCommand),
because if the command line itself is wrong, there is little any debugging
tool could do. The simple message box is also helpful when debugging the
script and I never really felt the need for a sophisticated debugger.
Considering runtime testing, you should ensure
- IM's command line tools can be accessed correctly
- the user has selected what you expected her/him to select, i.e. several
files (possibly of certain type), a directory, a text file, etc.
Error messages can easily be displayed by the use of MsgBox(...).
Further Information
Unfortunatally there is no known tutorial (other than this) which specifically
cover using ImageMagick commands in DOS batch files. However the
PC-Ask.com web site
has a useful summary of DOS commands (look in the secion on
"
FOR"), while
DOS "For" Command Help web page has a better explaination of using the
"
FOR" command.
You may also like to look at '
Bonzo'
Batch Script
page.