image resizing in perl

perl is really versatile, and can do a lot of things. moreover, you can do it in a lot of different ways. the difficult part being sometimes to choose the way you want to do it...

so i need to resize an image within perl. this is for games::risk, a perl implementation of the famous board game (btw, try it and tell me if you like it!). i want the background image to fit the window size on resize events. of course, i want it to be fast - but i also want something maintainable.

looking on cpan, i found 3 modules: gd, image::magick and image::imlib2. using gd to resize a picture is a nightmare, therefore i ditched it for image::resize which is a convenient wrapper around gd.

here are the needed incantations to resize:
  • with imlib2

  • my $old = Image::Imlib2->load($src);
    my $new = $old->create_scaled_image($w, $h);

  • with image::magick - note that the operation is done inplace, so one needs to clone the image first to compare the same things.

  • my $old = Image::Magick->new;
    my $new = $old->Clone;
    $new->Scale(width=>$w, height=>$h);

  • with image::resize

  • my $old = Image::Resize->new($src);
    my $new = $old->resize($w, $h);

so i benchmarked them and found that on average, image::imlib2 is a few times faster than image::magick, which is itself around the same speed or a bit faster than image::resize.

however, image::imlib2 has a drawback: the only way to get back the new image is to save it to a file, where one can get the new image as a scalar directly:
  • image::resize with $img->jpeg
  • image::magick with $img->ImageToBlob

therefore, one must also take this into account in the benchmarking! so here's the latest version of the bench:


use 5.010;
use strict;
use warnings;

use Benchmark qw{ :all };
use Image::Size;

use Image::Resize;
use Image::Imlib2;
use Image::Magick;

my $src = "src.jpg";
my $dst = "dst.jpg";

my ($w, $h) = imgsize($src);
my @sizes = (
[10,10], [100,100], [1000,1000],
[640,400], [840,600], [1024,768],
[$w,$h], [$w/2,$h/2], [$w/4,$h/4],
[$h,$w], [$h/2,$w/2], [$h/4,$w/4],

my $imlib2 = Image::Imlib2->load($src);
my $resize = Image::Resize->new($src);
my $magick = Image::Magick->new; $magick->Read($src);

foreach my $s ( @sizes ) {
my ($width, $height) = @$s;
say "-> ${width}x${height}";
local $/;

cmpthese( -3, {
imlib2 => sub {
my $img = $imlib2->create_scaled_image($width, $height);
open my $fh, '<', $dst;
return <$fh>;
magick => sub {
my $img = $magick->Clone;
return $img->ImageToBlob;
resize => sub {
my $img = $resize->resize($width,$height);
return $img->jpeg; # $img->png
} );
say '';

and i was quite astonished to see that image::imlib2 is still 2 or 3 times faster that image::magick or image::resize!

so, imlib2 may not the best api around, but sure it's fast...


rationalizing perl module versions

versioning sucks. nobody agrees on what version numbers should look like. everybody has some good reasons not to like a given scheme. and i would say that everybody is right - at least from their point of view.

if you throw in the way that perl deals with version (used by cpan and cpanplus), you add more fuzzyness to the whole thing. eg, 1.40 is supposed to be more recent than 1.300 (yes, 1.40 is understood as 1.400). and i won't even talk of digits 3 to 6, or developer releases...

add to that developers who change their versioning scheme every now and then, or the ones who knows the way perl works and use 2 or 3 digits after the dot (yes module::starter, i'm staring at you - but you're not the only one)...

yup, versioning is a nightmare for packagers. this sucks.

so, after some time bugging mandriva admins, we finally have a shiny rpm macro %perl_convert_version that normalizes perl versions to a x.y.z scheme. here is its content for whoever is interested:

perl -Mversion -le '$v=version->new(%{1})->normal; $v=~s/^v//; print $v'

and we're going to use it on all perl modules packaged by mandriva. yes, this means that the rpm version will potentially be different than the upstream version on cpan. but that's the price to pay to have rpm and other non-perl aware tools to work correctly.

for the migration to be as smooth as possible, the following needs to be done:
  1. push the rpm macro on mandriva build system. done.
  2. fix cpanplus::dist::mdv to use it.
  3. update youri's update check to recognize it.
  4. update mdvsys to recognize it during mdvsys update.
  5. fix our perl packages spec files.
in order to move on, i'm therefore happy to announce that cpanplus::dist::mdv 1.1.0 has been released, which (among other changes), now uses the rpm macro %perl_convert_version. that's one ticked off the list. :-)


cpan2pkg reaches maturity

i finally took some time to work on app::cpan2pkg - and i'm happy to report that it now chains upstream builds, which means that all basic features are in.

therefore, i just released app::cpan2pkg 1.0.0 on cpan. detailed changelog:
  • updating prereqs + moving on when module installed from upstream
  • splitted module in poe session + worker
  • moved info from app:cpan2pkg to module attributes
  • don't submit on upstream build-system if missing prereqs on it
  • cpan2pkg documentation written
yes, cpan2pkg can build, install, import and automatically build packages from cpan for linux, while following dependencies. does it work? sure, i already used it successfully.

note however that there are some caveats...

the first one of course is that it only supports mandriva currently. this is not a fatality, i expect other distributions (and why not other platforms such as *bsd or solaris) to be handled later on if they want. after all, i'm using cpan2dist underneath to generate the packages, and there exist some backends besides cpanplus::dist::mdv. if you're interested, here's the git repository - and i'm ready to give push rights. heck, if you insist i might even agree to move to github which seems to have all the hype those days.

the second one is that the interface is rather ugly and has a lot of rough edges. i'm waiting for dams to continue his work on curses::toolkit, so i can drop curses::ui::poe. i might also provide a tk or wx version at some point. in the meantime, you have to know the application a bit to understand what's going on. i intend to polish it later on.

finally, the code can be cleaned - but you don't care as a user.

so, that's it. cpan2pkg is live... enjoy!


autoformat and nopaste plugins join padre's nest

after much hesitation, i finally decided to migrate the autoformat and nopaste plugins to padre's svn repository.

not that i prefer svn - after all, i used git for a reason when i started those plugins - but it's handy to benefit of padre's translators for my plugins for free... (btw, if your language is not supported, you're more than welcome to join padre's development team!)

but the nice thing is that gabor told me that if padre gets a good enough git plugin for padre, he will switch padre's repository to git!

good enough here means that even people unfamiliar with git can use it, whatever the platform (yup, windows, i'm staring at you)... and btw, do you remember that there's an on-going contest for best padre plugin?

so what are you waiting for?


padre 0.35 released

on behalf on padre's development team, i'm happy to announce version 0.35 of padre, the perl ide. it is available here, and here's the full list of changes.

some of the highlights are:
  • single instance support
  • context-sensitive right-click menu for perl documents
  • ctrl+left+click on a perl variable / function will jump to its definition
  • launching a browser now happens in the background
  • new translation: japanese
  • various fixes and bug closing
please report any test failure via the padre-dev mailing list or via our bug tracker.


dependencies done right

dave has a point regarding cpan module dependencies: it can be troublesome to install everything correctly. however, we can get the best of both worlds... if we create packages from cpan modules for linux distributions. indeed, we can then use all the tools that the distributions have worked on and polished since so long a time. not counting the fact that's definitely the goal of a linux distribution to simplify things, and integrate software ready to be used.

to do so, we're standing once again on the shoulders of giants: cpanplus comes with various backends. of course, the most used is the one that really installs the modules. but with cpanplus::dist, it's easy to create modules for your distribution: debian, mandriva or fedora backends exist. and thus, creating a package for your distribution is as easy as (for mandriva in this case):
$ cpan2dist --format CPANPLUS::Dist::Mdv Foo::Bar
$ sudo rpm -Uvh ~/rpm/RPMS/noarch/perl-Foo-Bar.rpm
of course, this is only half of the story. after all, we don't want the users to do this - we're indeed trying to save them the hassle of building the modules.

so, we need to create the rpms (or debs) and provide them in the distribution. which is a bit more difficult, since we need to create the packages for the wanted module, and all the prereqs. and for each of them, we need to import them in the distribution build system. all that can take quite some time.

which is why i'm currently working on app::cpan2pkg (readers of this blog have already heard about that), which does everything automatically - well, that's the goal, at least. if you're a contributor, just run:
$ cpan2pkg Foo::Bar
it will build automatically the packages for Foo::Bar and all its dependencies, import them in the distribution repository, and send them (in order) on the distribution build system, where they will be made available for users later on...

and the end result is achieved, as an end user:
$ sudo urpmi perl-Foo-Bar
that will install Foo::Bar along with all its dependencies. no build fuss, no dependency done wrong, no need to have this gcc or that lib installed. everything will be fetched & installed for you...

so, we still retain the testing culture because packagers continue the regular build with all the test suite. users have their modules ready to be installed as easy as ever. and maybe we'll stop hearing about people complaining about long dependency chains. because dave is right: who gives a shit about that?

note to self: now just go back to work on it so i can release v1.0.0!


adopt a mandriva package campaign

mandriva is a great distribution, with tons of packages available. the downside is that contributors have a lot work to do, and usually maintain quite a lot of rpms. and when they go mia, or leave to see whether sky is still blue elsewhere, their packages become orphan.

that's sad.

and as time goes by, we end up with a huge list of unmaintained packages. :-(

this is where you can help. those packages are available. for you. for free.

have a look to the list. try to see if you're using regularly some of them. or even better, if you contribute to upstream project, either as a coder, or a translator. then claim your will to jump in.

you might fear that you don't know anything about rpm packaging. but that's the beauty of this campaign: the rpms are already created, and just need to be maintained. that is, update them when there's a new version, or fix a packaging bug. when this is the case (and assuming you have the rights to upload a package), a single command will update it to latest version:

$ mdvsys update your-package new-version
then, update your system to this version and check if it works correctly. remember, you grabbed a package because you're using it - so you know whether the new version behaves as expected!

and if there is a problem that you don't know how to fix, ask on cooker mailing-list. there will be a lot of experienced people that will be able to help you. and as time goes by, you'll become more and more comfident, ready to package new software not yet available in mandriva.

now is your turn to chime in. come on, you know you want to do it...


best plugin for padre contest

for those of you that missed it, i remind you that you have one month to come up with the best plugin for padre...

take this chance to discover padre, and see how easy it is to work with/on it! what are you waiting for?