Archive for the ‘Programming’ Category

Imagick resize filter comparison using PHP

Monday, January 24th, 2011

For some time I’ve been using GD lib for generating thumbnails. The solution was never satisfying since you need different functions to output different image formats. For some reason the getimagesize() function stoped working so I decided it was time to rewrite the code, and this time Imagick caught my attention.

Thanks to the Imagick PHP class the thumbnail generating process is really easy. You don’t have to do much, just pass the dimension of the thumbnail, what filter to use, blur factor and if it should try to use best-fit. Done! Except for one thing. There are 16 filters to choose from and the computation penalty varies. So which filter is the best one?

For the tests I was using a JPEG photo with dimensions 2551 x 1701 (w x h) and 949 Kib in size. To test the filter I created thumbnails in the sizes 640, 200, 180, 130, 75 and 50 pixels in a square box model, that is the thumbnail must not be larger than a 50×50 pixel box. To measure the time it takes for each filter to generate the thumbnails I was using the Linux shell time command:
$ time php resize.php image_Z.jpg

And here is the complete PHP script:

<?php
$filter = Imagick::FILTER_BOX;
$i = new Imagick($argv[1]);
$i->setImageOpacity(1.0);
$h = $i->getImageHeight();
$w = $i->getImageWidth();

echo "According to Imagick the image is ".$w."x".$h." pixels.\n";

$sizes = array(


'_F' => 640,
'_E' => 200,
'_D' => 180,
'_C' => 130,
'_B' => 75,
'_A' => 50

);

foreach ($sizes as $label => $size) {


echo "Resizing to ".$size."x".$size."... ";
$i->resizeImage($size, $size, $filter, 1, true);
$i->writeImage(str_replace('_Z', $label, $argv[1]));
echo “Done\n”;

}

?>

Now I just ran the script for all the filters to measure the times. The times are the mean value of all runs. The size column is simply the size of the 640 pixel thumbnail.

Filter Real User Sys Size
undefined 1.273 0.645 0.110 179844
point 0.967 0.795 0.155 202263
box 1.006 0.840 0.140 186783
triangle 1.155 0.935 0.155 178033
hermite 1.075 0.925 0.130 181151
hanning 1.216 1.045 0.150 190509
hamming 1.259 0.990 0.165 191234
blackman 1.188 1.035 0.135 189332
gaussian 0.785 0.540 0.130 172981
quadratic 0.657 0.515 0.125 172130
cubic 0.769 0.605 0.150 167606
catrom 0.769 0.595 0.155 186291
mitchell 0.803 0.620 0.130 179844
lanczos 0.995 0.855 0.125 190593
bessel 1.058 0.890 0.125 177809
sinc 1.178 1.000 0.135 189332

Now, let’s picture that with a graph.

Imagick filter comparison graph

Imagick filter comparison graph (click for larger image)

Take a look at the smaller thumbnail, less than 200 pixels. It’s here you’ll see the difference between the various filters. For my test image the Quadratic and Cubic filters generates a very blury thumbnail. I guess you have to test the filters for the type of images you will resize, in my case the Lanczos and Catrom filters generated about the same result. I decided to go with Catrom since it is faster.

JavaScript Date Format in Swedish

Wednesday, March 10th, 2010

Found myself “late-night-surfing” again, but this time I actually found something interesting. Steven Levithan has written an easy-to-use and easy-to-extend JavaScript date format function. So, to encourage his great work I publish the Swedish translation.

// Internationalization strings
dateFormat.i18n = {
dayNames: [
"Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör",
"Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag"
],
monthNames: [
"Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec",
"Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"
]
};

The complete code at its latest version can be found at Stevens blog, JavaScript Date Format.

Smarty for e-mail templates

Sunday, November 29th, 2009

As you’ve realized Smarty can be used to more than just site templates. You can set up templates for almost anything, for example e-mails. When you do this you have to decide on an approach, and I’ll cover three of them here.

Simple and straightforward
You can see this approach in the Smarty manual. The template simply states the message body, and if you have multiple bodies, say one in plain text and one in HTML, you can do like this.

mail.text.tpl:
Hi {$name},

You've got mail!

mail.html.tpl:
// HTML-header here
<body>
<h1>Hi {$name},</h1>

<p>You've got mail!</p>
</body>

Now you can simply fetch your two versions of the mail body and use them with your PHP code to send mails. The benefit here is that you keep a good abstraction, the person who makes the mail templates does not have to care about hos the mail is sent. A drawback is that you can’t store all information for this e-mail in one place; where do you store the subject?

The advanced solution
The advanced solution creates just one template containing all data needed for the e-mail message. Your template could look like this:
gotmail.mail.tpl:
Date: {$mail.date|date_format:"%a, %d %b %Y %H:%M:%S %z"}
From: "{$sender.name}" <{$sender.email}>
To: "{$recipient.name}" <{$recipient.email}>
Subject: New mail

Hi {$recipient.name},

You've got mail!

Here you just fetch the mail data and sends it. The benefit is that you store all data related to the e-mail at the same place. The drawbacks are that this method needs extra parsing to work with the built-in PHP mail() function and the abstraction is poor since the person creating the template now has to know how to enter all mail headers as well.

Best of all?
In this version you get the benefits from the two previous versions, eleminating the drawbacks. Here we can store all information about the e-mail in the template and we can still use them when sending the e-mail using PHP. Consider this template:
gotmail.mail.tpl:
Hi {$name},

You've got mail!
{assign var="subject" value="New mail"}

Now you can, as in the simple version, fetch the template to get the body text and then use the get_template_vars() Smarty method to get the subject from the template. Just apply some more Smarty tweaking using the built-in {capture} function or simply {insert} the templates from the first example to get a multi-body message in just one template file.

The code above should be considered as proof-of-concept or pseudo code, there are a few problems not solved in the examples above.