Q: We have many JPG images in our IFS. We need to make thumbnail versions of these. The images change frequently, so the thumbnails need to be updated often. How can we do that on the System i--preferably using open-source tools? Is there something for PASE?
A: There's an open-source tool called ImageMagick that can do all sorts of things to images, including generating thumbnails, converting formats, cropping, changing the colors, and more. I've discovered an AIX copy of ImageMagick that appears to run nicely in PASE.
Traditionally, converting image formats (e.g., from JPG to PNG), scaling images, changing colors, cropping, and the like would be done with software such as Adobe Photoshop, the GNU Image Manipulation Program (GIMP), Paint Shop Pro, and so forth. What makes ImageMagick different is that it's a command-line tool. You issue a command, and that tells ImageMagick what to do to your image. That ability makes the tool suitable for a non-interactive situation, such as creating thumbnails in batch. In fact, it's particularly well suited to a Unix shell script environment, so you can easily use it from a PASE shell script.
I've set up the following website as a place to download a PASE-compatible version of ImageMagick and to provide instructions for installing it:
http://www.scottklement.com/imagemagick
I've also heard that version 2.6 of Zend Core (the environment that you use to run PHP on IBM i) comes with ImageMagick. I haven't installed this version of PHP yet, but if you have, or if you plan to install it soon, you might not need to install ImageMagick from my site.
With ImageMagick installed, you can try using it. To do that, start a PASE command prompt with the following command:
CALL QP2TERM
If you haven't already done so, add the /usr/local/bin directory (or whichever directory you've installed ImageMagick in) to your PATH. From the PASE command prompt, type the following:
export PATH=$PATH:/usr/local/bin
Now ImageMagick should be ready to use. Try converting an image. Here's a very simple example:
convert TestPic.jpg TestPic.png
This command converts the image named TestPic.jpg to PNG format and saves the result as TestPic.png. If all is well, nothing prints on the screen, but when ImageMagick is done, you have a file named TestPic.png. If an error occurs, you see error messages printed on the screen.
ImageMagick provides the following commands that might be useful in a batch-processing environment:
ImageMagick also provides tools you can use to display images on the screen. To use those from PASE, you have to have X Windows set up and a viewer such as Cygwin/X or VNC installed on your PC. Explaining that process is beyond the scope of this article, but if that interests you, send me an e-mail at tips@scottklement.com and if enough people are interested, I'll cover it in a future article.
You can type one of the above commands, with no parameters, to see all the options that can be passed to them. They are extensive and capable of many feats, so I can't cover them all here. For more information, see the documentation on the ImageMagick home page:
http://www.imagemagick.org
Suffice it to say that if you want to create a PNG image that's a 120x120-pixel thumbnail of TestPic.jpg, you type this:
convert TestPic.jpg -resize 120x120 TestPic.png
The easiest way to do a mass conversion of images is to use a shell script. To create one, type the following two commands from a regular i5/OS command line:
EDTF '/tmp/myscript.sh'
Before typing the script, you have to prepare the EDTF tool to create an ASCII file with Unix end-of-line characters. To do that, follow these steps:
The EDTF tool is a green-screen editor similar to SEU with which you can type the shell script. Here's a sample script:
#!/usr/bin/sh
readfiles() {
while read jpgfile; do
convert "$jpgfile" -resize 120x120 "thumbs/$jpgfile"
if test $? -ne 0; then
echo "convert \"$jpgfile\" -resize 120x120 \"thumbs/$jpgfile\"";
echo "failed.";
exit 1;
fi
done
}
ls *.[Jj][Pp][Gg] | readfiles
At the bottom of this code, you see the ls command. It's making a list of all .JPG files in the current directory. That list is then sent to the readfiles function (which works a lot like a subprocedure).
The readfiles routine reads one file name at a time from the list. For each file name, it runs the convert command to create a 120x120 thumbnail, also in JPG format, in the thumbs subdirectory. If the convert command fails, it returns a non-zero exit status. The if statement in the preceding script checks that exit status, and if it's not zero, it prints an error and aborts the script.
A slightly more sophisticated script can check whether the thumbnail exists, and if so, only regenerate it if the image file is newer than the thumbnail. This is done by using the -nt (newer than) capability of the test utility.
#!/usr/bin/sh
readfiles() {
while read jpgfile; do
if test "$jpgfile" -nt "thumbs/$jpgfile"; then
convert "$jpgfile" -resize 120x120 "thumbs/$jpgfile"
if test $? -ne 0; then
echo "convert \"$jpgfile\" -resize 120x120 \"thumbs/$jpgfile\"";
echo "failed.";
exit 1;
fi
fi
done
}
test -d thumbs || mkdir thumbs
ls *.[Jj][Pp][Gg] | readfiles
As you can see, this script isn't much different. Just an extra if statement that checks whether the original jpgfile is newer than the thumbnail. If it is, a new thumbnail is generated. If the thumbnail is older (because the original JPG has been changed) then the thumbnail is regenerated.
As you can see, with ImageMagick writing a script that mass converts images is easy. Now, how can you run that script from a CL program?
PGM
ADDENVVAR ENVVAR(PATH) REPLACE(*YES) +
VALUE('/QOpenSys/usr/bin+
:/usr/ccs/bin+
:/QOpenSys/usr/bin/X11+
:/usr/sbin+
:/usr/bin+
:/usr/local/bin')
CD '/HOME/KLEMSCOT'
OVRPRTF FILE(STDOUT) TOFILE(QSYSPRT) HOLD(*YES)
OVRPRTF FILE(STDERR) TOFILE(QSYSPRT) HOLD(*YES)
STRQSH CMD('/tmp/myscript.sh')
DLTOVR *ALL
ENDPGM
The ADDENVVAR command makes sure that the /usr/local/bin directory is in my path. The CD command sets my current directory to /HOME/KLEMSCOT, which is where I have my JPG files that I want to generate thumbnails of.
The OVRPRTF commands are used to direct the output (either the messages or errors) and are written to the spool so you can troubleshoot any problems. If you want to direct the output to a log file instead of the spool, you can use OVRDBF instead of OVRPRTF.
The STRQSH command runs the script. I prefer to use QShell to run scripts from batch--even PASE scripts--because it does a better job of dealing with the standard streams (i.e., stdin, stdout, and stderr). You could potentially run the same script with QP2SHELL instead of STRQSH, but you'd have to make sure the standard streams are opened properly--otherwise you might have problems.
Good luck!