Debugging Dynamic
Image Scripts with PerlMagick
|
Part of Dylan's Collection of PerlMagick Stuff
I frequently receive mail from people who've installed PerlMagick but can't get it to work properly. This page contains some hints on debugging your PerlMagick scripts and avoiding some of the more common configuration errors. All these examples were tested on Windows 2000 with PerlMagick 5.4.1 but should be relevant to PerlMagick CGI scripts on any platform.
NOTE: The Perl scripts on this page have been written with the novice in mind. There are terser, more elegant ways to write much of this code, but I didn't want to obfuscate anything - hopefully, it should be clear from reading these scripts exactly what they're doing.
Recent versions of PerlMagick are very twitchy when it comes to the location of the DLLs and MGK files. Depending on operating system, Perl version, ImageMagick version and whether it's running from the console or from a web server, try moving the entire DLL package (basically the contents of the DLLs ZIP) into each of the following locations in turn:
C:\imagemagick\ (this one must be drive C: - d:\imagemagick
has never worked in my experience)
C:\perl\bin (or wherever your copy of perl.exe lives)
C:\perl\site\lib\auto\Image\Magick (or wherever your copies of magick.dll
and magick.lib live)
In all cases, add the relevant directory to your system path and create/set the MAGICK_HOME variable to point to it.
Finally, don't just dump copies all over the place - or if you do, remember where you've put them! I've had one or two situations where scripts were failing because they were finding a second copy of the DLLs in an unexpected location.
When I have time, I'm going to do some digging and try and work out what causes these problems and if there's a reliable way around them, but in the meantime I'm afraid it's a case of keep experimenting and let me know what works :)
binmode
settingsSome users have reported that they have to call
binmode STDOUT;to put the standard-out port into binary mode, before writing images to STDOUT. See the Perl docs on binmode for more info.
All PerlMagick operations return false if successful, and return a non-zero (ie. 'true') error message if any errors occurred. To see these errors, use code like this:
#!/bin/perl
use Image::Magick;
my $image = new Image::Magick();
my $last_error;
$last_error = $image->Read("missing.jpg"); if ($last_error) { print ($last_error); }
If any errors were encountered reading the image, you'll get a result something like:
Warning 335: Unable to open file (delegates.mgk) [No such file or directory]
or
Warning 330: Unable to open file (missing.jpg) [No such file or directory]
The warning codes are documented in the PerlMagick documentation on the ImageMagick site, although I'm not sure how recent or accurate this documentation is. Read the error messages carefull - the warnings above look similar, but you'll notice the first one is a warning about delegates.mgk - indicating an ImageMagick configuration problem - and the second is missing.jpg, which indicates that PerlMagick is working OK but it can't find the file you've specified.
One of the biggest problems with developing PerlMagick scripts that generate dynamic images is that they use the Content-type header to indicate to the browser they're returning an image, rather than text. Consequently, any error messages or warnings are interpreted by the browser to be corruptions in the stream of GIF or JPG data that it's been told to expect, and instead of an image or a nice set of error messages, we get that good old 'broken image' icon. The way around this is to use a debug flag, which you can explicitly set to enable warning messages. The following script is a modified version of the image01.pl test script, which includes a debug flag.
#!/usr/local/bin/perl use Image::Magick; my $DEBUG = 0; # set $DEBUG=1 to enable error messages if ($DEBUG) { print ("Content-type: text/html\r\n\r\n"); # Return text so we can read the error messages print ("Debug mode ENABLED"); } else { print ("Content-type: image/jpeg\r\n\r\n"); # Return the JPEG content header } my $image=Image::Magick->new; my $last_error; $last_error = $image->Set(size=>'30x180'); if ($DEBUG and $last_error) { print "$last_error\n"; } $last_error = $image->Read("gradient:#ff0000-#0000ff"); if ($DEBUG and $last_error) { print "$last_error\n"; } $last_error = $image->Raise('3x3'); if ($DEBUG and $last_error) { print "$last_error\n"; } $last_error = $image->Rotate(-90); if ($DEBUG and $last_error) { print "$last_error\n"; } binmode STDOUT; $last_error = $image->Write('jpg:-'); if ($DEBUG and $last_error) { print "$last_error\n"; }
Running this script with debug mode disabled on my (deliberately crippled) web server produced the normal broken image. When I enabled debug mode, the page displayed the following:
Debug mode ENABLED Warning 335: Unable to open file (delegates.mgk) [No such file or directory] Warning 310: no images to mogrify (Raise) Warning 310: no images to mogrify (Rotate) Warning 310: No images to write
The 'Unable to open file (delegates.mgk)' indicates straight-away that it's a PerlMagick configuration problem (the other error messages are consequences of this - if PerlMagick can't find it's configuration files, so it can't initialise the image, which means all subsequent operations will fail 'cos there's no initialised image to apply them to) Sure enough, I'd crippled the server by deleting the contents of the C:\IMAGEMAGICK directory. Restoring these files and running the script again produced this...
Debug mode ENABLED JFIFHHC $.' ",#(7),01444'9=82<.342C 2!!22222222222222222222222222222222222222222222222222 .RQ!S45Arta $Q13q!2A ?ljDc-H^+zW/~y]"ޜm/EL3:qX Ta)0OR6"&H(] 0GOR6z"&!ԍ|#&8=H(]= RcLFb> 2OV6iG:pGBǓ.Ta*Yes, it looks like total garbage, but it's actually the source stream of a JPEG image - the clue is the JFIF header (highlighted in red) which indicates it's in JPEG File Interchange Format. Now we know that PerlMagick is producing something which appears to be a valid JPEG image, so we turn off the debug mode and run it again and sure enough...
- Be careful with warn()
Standard Perl practice is to use warn() to indicate non-fatal errors. warn directs messages to stderr (the error stream) rather than stdout (the normal output stream). For console applications, this is fine, but in a CGI script, the stdout stream is the stuff that gets sent to the browser, and messages sent to stderr can end up almost anywhere - error logs, pop-up error messages on the web server's console, /dev/null. If you know how your particular web server works, you can use this to - for example - pipe PerlMagick warnings into the web servers' error log, but for simple debugging purposes I always find it's easier to use print() and send the error messages to stdout where you can see them from your browser.
Page maintained by Dylan Beattie. <imagemagick [at] dylanbeattie [dot] net>
Copyright © 2001 dylanbeattie.net.
The information contained in this page may be freely distributed and modified
subject to the terms of the ImageMagick distribution agreement.