Creating a basic captcha with Imagick
I hate captcha systems, truly, madly, deeply. But spammers force us to create and use them.
Writing captcha systems can be very easy. You need a randomly generated image, a hard to read font, and finally basic server side coding knowledge. I use PHP cos it’s well documented and extremely easy to use, but you can use any other server side language you want. On which ImageMagick can be used of course.
So, let’s list what we want to do:
- Create a random string
- Display it as an image
- Check whether the user entered the string correctly
That’s all.
Creating random string with PHP
This is the easiest. PHP already has a function which creates new random string each second. Yup, that’s the time() function. But the created string has only numbers. To fix that, we encrypt it with some sort of built-in encryption function. That can be md5, sha1, anything. I use md5 now cos that’s which popped in my mind on the first place.
The second thing we want to solve is to not make the user to enter 32 characters, but only 5. Again, PHP’s string manipulation knowledge comes handy, I use substr(). So let’s see our code:
$rand = md5(time()); $str = substr($rand, 0 , 5);
That simple. We now have a 5 characters long completely random string.
Pushing the random string in an image, using IMagick
If you followed my IMagick related posts, you should know that annotating an image with IMagick is simpler than confusing a snail with a mirror. The only difference is that now we’ll have in the image our random string, not a fixed variable’s value. Yeah, that’s dynamic image.
I’ll also use a hard to read font, because using DirectX even a 5-year-old can create a captcha reading software if we use a common font.
You may ask how will the server side code which checks whether the captcha is correct or not will know the user entered the correct code or not. That’s solved with sessions. We start our session in the image generator script, and set the shortened version of our random string in a session variable.
So, when the image is loaded in your HTML, the session variable will get the 5 character long random string as value. The session variable will be checked on the page which checks the user input, if matches the value which was entered by the user, we know it’s human. No, we hope it’s a human.
So, the code to generate the dynamic captcha image:
session_start();
$rand = md5(time());
$str = substr($rand, 0 , 5);
$_SESSION['captcha'] = $str;
$font = '/path/to/your/hard2read/font.ttf';
$image = new Imagick();
$draw = new ImagickDraw();
$pixel = new ImagickPixel( 'white' );
$image->newImage(100, 27, $pixel);
$draw->setFont($font);
$draw->setFontSize( 25 );
$draw->line( $x, $y, $x1, $y1 );
$image->annotateImage($draw, 10, 20, 0, $str);
$image->setImageFormat('png');
header('Content-type: image/png');
echo $image;
We save the above code as captcha.php and try to load it. If everything went well, we should see an image like the one on the left.
The HTML form for our captcha
If you can’t do this by your own, you shouldn’t mess with captcha verification. But just for the sake of the example:
Now the server side script which checks the user input. I write something very basic, don’t validate or sanitize anything. When you write your own user input verifier code, you should validate every single bit of your users’ input, don’t trust em!
session_start();
/*Check if every field has been filled in*/
if (!empty($_POST['uname']) && !empty($_POST['upass']) && !empty($_POST['captcha'])){
/*Check if the CAPTCHA image value matches the user input*/
if ($_SESSION['captcha'] != $_POST['captcha']){
echo 'You failed the CAPTCHA verification. Try again.';
}else{
echo 'Congrats! Everything is cool!';
}
}else{
echo 'You missed to fill in some fields. Try again.';
}
And we’re done.
To play with the example you can do it here.
To download the files which were created through this post, click here.
Vertical text with Imagick
Creating vertical text over an image is extremely simple with Imagick. The text created with Imagick can be used for example as a watermark over an image or any other thing you can think of.
It’s very important to understand that the created object is just an image and that you can not have any text before the below code block and which will be sent to browser output. This includes white-space, page brake or any type of text.
The vertical text is obtained with annotateImage() since it’s 4th parameter of the function is to set the degree of the text. 0 degrees is horizontal text, 90 degrees is vertical text, that simple.
Let’s see the code:
$image = new Imagick();
$draw = new ImagickDraw();
$pixel = new ImagickPixel( 'white' );
$image->newImage(25, 150, $pixel);
$draw->setFontSize( 20 );
$image->annotateImage($draw, 0, 0, 90, 'Devoracles.com');
$image->setImageFormat('png');
header('Content-type: image/png');
echo $image;
The above’s result is what you see below.
As you see it’s extremely simple to create vertical text with Imagick, either if you’re a novice or a pro.
If you have any related question, feel free to ask.
Managing PDF files with Imagick
Many doesn’t know, but with Imagick anyone can manage PDF files. As far as I know you can’t create one, but this function can be extremely useful to create a screenshot of a PDF file on the server’s side.
First of all, the PDF file you just created has to be loaded in Imagick, either the whole document or only one page from it, then you can output it as any type of image, let’s see how to do it:
$pdf = new imagick( 'your.pdf' ); $pdf->setImageFormat( "gif" ); header( "Content-Type: image/gif" ); echo $pdf;
Be aware that you can not output anything else before this code block neither a whitespace or text. Nothing. Also, you can specify any image format you wish as Imagick can output almost any image format.
Look at the above code block. The first line says:
$pdf = new imagick( 'your.pdf' );
If you would like to select a specific page to output from the PDF, just specify the page number as it follows:
/*This would select the cover page: */ $pdf = new imagick( 'your.pdf[0]' ); /*and this the actual 1st page: */ $pdf = new imagick( 'your.pdf[1]' );
Now you should get the idea, if you don’t, feel free to question me.
The last thing I show you is how to create a thumbnail of a PDF. There is no too much difference, the only one is that before outputting the image we resize it using thumbnailImage():
$pdf = new imagick( 'your.pdf' ); $pdf->setImageFormat( "gif" ); $im->thumbnailImage( 200, NULL ); header( "Content-Type: image/gif" ); echo $pdf;
I used ‘NULL’ to preserve the image’s aspect ratio.
As always, if anything is unclear, feel free to question me.
How to save the images processed with Imagick as file
Scenario: You created with Imagick a cool thumbnail, and now you want to send it to a buffer other than the browser window. We already saw that it’s possible to process images on-the-fly, for example you have a 1024*768 wide image and you want to show its thumbnail version without having a thumbnail for the respective image. So what we do now is the exact opposite: we load the image in Imagick, process it, then save as a file. Probably this is the most encountered situation when processing images.
Let’s see the code, then I explain it step by step, as usual:
$im = new Imagick('/path/to/your/image.jpg');
$im->thumbnailImage( 100, null );
$fp =fopen('/path/to/the_new/thumbnail.jpg', 'w');
@fwrite($fp, $im);
@fclose($fp);
Now the explanation:
- st line: we loaded the image in Imagick, it’s now ready to be processed
- nd line: this time we create a thumbnail, store it in memory/cache: the X axis to be 100 pixels and preserve aspect ratio by setting the second parameter to ‘null’
- rd line: create a new file, you specify the path. The file shouldn’t exist, but all the directories Yes! W means we open the file for write
- th line: we write the Imagick object’s ($im) content in the open file
- th line: and finally, we close the file
That was all. We saved again the world.
As always, if you have questions regarding the post, drop a comment and will try to answer as soon as possible.
Create thumbnails on-the-fly using Imagick
OK, this will be simple. I said it’s simple, more simpler than anyone can expect. Let’s see the overcomplicated code:
<?php $im = new Imagick( 'path/to/your/image.jpg' ); $im->thumbnailImage( 200, null ); header( "Content-Type: image/jpg" ); echo $im; ?>
That was all. Yup.
OK, now step by step:
- We instruct Imagick to work with the file from the parameter.
- Ask nicely Imagick to create a thumbnail: width should be 200px and no fixed height. That’s good, cos Imagick will automatically preserve the aspect ratio, so, bye-bye ugly thumbnails
- Set the correct Content-type header
- echo() the Imagick object which contains the image data, namely $im
That’s all. We saved the world again…
If something is not clear, the comments are open, just ask and will try to answer as soon as possible.
Watermarking images using Imagick
This is a perfect day to show all how easy is to use php’s imagick library to watermark an image.
What you need is to have imagick installed and working correctly, a font you will use to write your website’s name on the image and of course an image you will put the text on.
I will explain each step but for those who don’t want to read, here’s the script:
<?php
$img = 'path/to/your/image.jpg';
$text = 'devoracles.com';
$font = 'path/to/your/yourfont.ttf'
$font_size = '20';
$watermark = array();
$image = new Imagick($img);
$image->setImageFormat("jpg");
$draw = new ImagickDraw();
$draw->setGravity(Imagick::GRAVITY_CENTER);
$draw->setFont($font);
$draw->setFontSize($font_size);
$textColor = new ImagickPixel("black");
$draw->setFillColor($textColor);
$im = new imagick();
$properties = $im->queryFontMetrics($draw,$text);
$watermark['w'] = intval($properties["textWidth"] + 5);
$watermark['h'] = intval($properties["textHeight"] + 5);
$im->newImage($watermark['w'],$watermark['h'],new ImagickPixel("transparent"));
$im->setImageFormat("jpg");
$im->annotateImage($draw, 0, 0, 0, $text);
$watermark = $im->clone();
$watermark->setImageBackgroundColor($textColor);
$watermark->shadowImage(80, 2, 2, 2);
$watermark->compositeImage($im, Imagick::COMPOSITE_OVER, 0, 0);
$image->compositeImage($watermark, Imagick::COMPOSITE_OVER, 0, 0);
header("Content-Type: image/jpg");
echo $image;
?>
And the result is:
Watermark with Imagick
That was all, now a bit of explanation for almost all the lines. The first steps, as you see was to set up some variables which will be used in the script, I think the variable names talk for themselves so I don’t have to explain them. Do I?
Next, I instructed imagick to read the image which will be worked with and specified the type of the image, in the above case a “jpg”.
$image = new Imagick($img);
$image->setImageFormat("jpg");
By the way, if you want to write a script you will pass through all your images, thus all the images are watermarked, first assure that the image you work with is from your server, read, no one can use your script to watermark images on another server. The second thing, you can get the image’s extension using mime_content_type(’path/to/your/image.jpg’). Not the best method I admit, but it’s simple and effective.
Let’s proceed further. I fired up a new class, ImagickDraw(), this will let Imagick know what font to use and also the text’s properties like font size, font color, etc. “Imagick::GRAVITY_CENTER” basically means to center the text on it’s, say, layer. You can play with it and try to set other parameters too, like “Imagick::GRAVITY_SOUTH” which means to place the text on the bottom of the layer, “Imagick::GRAVITY_WEST” to put it on the left side, you get the point.
$draw = new ImagickDraw();
$draw->setGravity(Imagick::GRAVITY_CENTER);
$draw->setFont($font);
$draw->setFontSize($f_size);
$textColor = new ImagickPixel("black");
$draw->setFillColor($textColor);
We get then the parameters of the text we want to put on the image and we add an additional 5 pixels to it, both horizontal and vertical axis. The 5 pixels will be needed later to have place for the drop-down shadow of the text. Then we simply create the canvas and with annotateImage() we put the text on the image.
$im = new imagick();
$properties = $im->queryFontMetrics($draw,$text);
$watermark['w'] = intval($properties["textWidth"] + 5);
$watermark['h'] = intval($properties["textHeight"] + 5);
$im->newImage($watermark['w'],$watermark['h'],new ImagickPixel(”transparent”));
$im->setImageFormat(”jpg”);
$im->annotateImage($draw, 0, 0, 0, $text);
OK, now let’s play a bit with the shadow. First we clone the $im object, which is basically the text we’ll put on the image. The color of the image will be the same as the text’s. And now the interesting stuff: shadowImage(). This will create the drop-down shadow and the parameters tells Imagick how to create that shadow. The usage is:
shadowImage ( float $opacity , float $sigma , int $x , int $y )
So the first parameter sets how opaque the shadow has to be, the last two sets where to drop that shadow. Don’t ask me the second what does, i have no idea ![]()
OK, lastly let’s put our shadow on the image with compositeImage().
$watermark = $im->clone();
$watermark->setImageBackgroundColor($textColor);
$watermark->shadowImage(80, 2, 2, 2);
$watermark->compositeImage($im, Imagick::COMPOSITE_OVER, 0, 0);
The last steps are to put the watermark on the image, set the correct content-type header image/jpg in our case and echo the data. Why do we have to set the content-type header? Well, if I’m not mistaken, this is a php script and the browsers, if not overridden expects text/html, which in our case is not good at all.
$image->compositeImage($watermark, Imagick::COMPOSITE_OVER, 0, 0);
header("Content-Type: image/jpg");
echo $image;
That’s all. It was a bit complicated, but I’d rate its difficulty as ‘medium’ but it’s extremely useful in many cases. This is not JavaScript, so the watermark will be in place whatever the user does. If you are at least a bit familiar with object oriented PHP, I say give it a go and try it.
If something is not clear, the comments are open, just ask and will try to answer as soon as possible.







