Creating nice Mosaic Images with Perl

I needed a background header-image for my other website (www.vfl3.de) . I already uploaded a lot of photos to that website and wanted to use them in some way for that header. I thought of creating a mosaic-like background picture which is automatically recreated once a week. So any new uploaded pictures will be automatically considered when the script runs.


./mosaic_poster.pl /path/to/pictures 950 200


The first argument is the path in the filesystem where the script looks for the pictures. With the second and third argument you can specify the ranges of the mosaic-picture (e.g. 950×200 pixel)


#!/usr/bin/perl -w
use strict;
use Image::Magick;
use List::Util 'shuffle';

my $im_srcdir = $ARGV[0];
my $im_width = $ARGV[1] || 800;
my $im_height = $ARGV[2] || 600;
my $poster_out = $ARGV[3] || "poster.jpg";

unless ($im_srcdir) {
print "Usage: $0 imagesourcedir [width] [height] [output-filename]\n";
print "width (default: 800), height (default: 600) and output-filename (default: poster.jpg) are optional.\n";
exit;
}

# create a new image with black background
my $poster = Image::Magick->new(magick=>'jpg');
$poster->Set(size=>"$im_width"."x"."$im_height");
$poster->ReadImage('xc:black');

#Get images for tiles
my @imagesfound = find $im_srcdir -type f -iname '*jpg' -print|grep -v thumbs;
my @randlist = shuffle(@imagesfound);
my $xpos = 0; # incrementer for x axis
my $ypos = 0; # incrementer for y axis
my $row_total = $im_height / 50; # number of rows
my $col_total = $im_width / 50; # number of columns
my $cnt_tiles = '';

# for each row
while( $ypos < $row_total ){
$xpos = 0;

#for each column
while( $xpos < $im_width ){
# if the random list is all used up, regenerate it
my $cnt_elements = @randlist;
if( $cnt_elements lt 1 ){
@randlist = ();
@randlist = shuffle(@imagesfound);
}

# remove image from random list so it is not reused in this row
my $currimage = pop @randlist;
chomp $currimage;

# open the tile
my $tile = Image::Magick->new(magick=>'jpg');
$tile->ReadImage($currimage);
my $height = $tile->Get('height');
my $width = $tile->Get('width');

#Resize tile to 100x100 and cut off 50x50 (to be sure, that all tiles have the same size)
$tile->Resize(geometry=>'100x100');
$tile->Mogrify('crop', '50x50');

# insert the tile into the existing large template
$poster->Composite(image=>$tile,x=>$xpos,y=>($ypos*50),geometry=>'0,0,50,50');

# increase tile count and stop loop, when we have enough tiles
$cnt_tiles++;
last if (($row_total*$col_total) eq $cnt_tiles);

# move to next column
$xpos += 50;
}

# move to next row
$ypos++;
}

# reduce quality
$poster->Set(quality=>'75');

# write new image
$poster->Write($poster_out);