Il suffit de lancer ce script depuis le répertoire gal de SPGM.
S'il y a besoin de modifier les paramètres de configuration pour un répertoire donné et ses sous-répertoires, il est possible de le faire dans un fichier appelé .conf dans le répertoire en question (voir tout en bas). Ça ne fonctionne que pour des scalaires, pas pour des tableaux; donc c'est pas possible de modifier les différentes tailles, par exemple... sauf si quelqu'un me file un patch :-p.
create_thb.pl
#! /usr/bin/perl
#
# by Julien Wajsberg <flash@minet.net>
#
# January 2005
# GPLv2
use strict;
use warnings;
use Image::Magick;
use Image::EXIF;
use File::Find ();
#### conf ####
my $default_conf = {
thumbnail_prefix => "_thb_",
internal_pattern => qr/^_/,
thumbnail_geometry_landscape => "160x120",
thumbnail_geometry_portrait => "160x120",
resizes_landscape => [ qw/800x600 1024x768/ ],
resizes_portrait => [ qw/600x800 768x1024/ ],
quality => 80,
};
my $conf_filename = ".conf";
my $conf = $default_conf;
##############
my @transprogram = qw/exiftran -ai/;
$| = 1;
my $image = new Image::Magick;
# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
sub wanted;
File::Find::find({
wanted => \&wanted,
preprocess => \&preprocess,
postprocess => \&postprocess,
}, '.');
exit;
##############################
#
# "wanted" function for "find"
#
sub wanted {
doaction($_) unless -d;
}
###############################
#
# "preprocess" function for "find"
#
sub preprocess {
print "*** Entering $File::Find::dir\n";
# read config file for this directory
if (-r $conf_filename) {
open CONF, $conf_filename;
while (<CONF>) {
my ($key, $value) = /^\s*(\w+)\s*=\s*(\w+)$/;
next unless $key and $value;
$conf->{$key} = $value;
}
close CONF;
}
my @entries;
while ($_ = shift) {
next if /$conf->{internal_pattern}/;
push @entries, $_ if /^.*\.jpg\z/is;
push @entries, $_ if -d;
}
return @entries;
}
###############################
#
# "postprocess" function for "find"
#
sub postprocess {
# reset conf
$conf = $default_conf;
}
###################################
#
# this function is called by wanted
#
# 1st arg : shortname of the file
#
sub doaction($) {
my $shortname = shift;
my $x;
my $thumbnail = $conf->{thumbnail_prefix} . $shortname;
my $resizes;
my $thumbnail_geometry;
print $shortname, " :\n";
# rotating if necessary
if (need_rotation($shortname)) {
print " rotating";
$x = dorotate($shortname);
if ($x) {
warn " : $x" if $x;
print " -> something strange happened, let's skip this file !\n";
return;
}
print ".\n";
} else {
print " already correctly oriented.\n";
}
# pinging the file, to get the dimensions
my ($width, $height) = $image->Ping($shortname);
# orientation : landscape or portrait
if ($width < $height) {
$resizes = $conf->{resizes_portrait};
$thumbnail_geometry = $conf->{thumbnail_geometry_portrait};
} else {
$resizes = $conf->{resizes_landscape};
$thumbnail_geometry = $conf->{thumbnail_geometry_landscape};
}
if (all_resizes_done($shortname, $resizes)) {
print " nothing left to do.\n";
return;
}
# reading the file
print " reading";
$x = $image->Read($shortname);
if (defined $x and "$x") {
warn " : $x";
print " -> something strange happened, let's skip this file !\n";
return;
}
print ".\n";
# thumbnail generation
my $clone = $image->Clone();
if (! ref $clone) {
warn " : $clone";
print " -> something strange happened, let's skip this file !\n";
return;
}
print ' thumbnail : resizing to ', $thumbnail_geometry;
$x = doresize($clone, $thumbnail_geometry, $thumbnail);
if (defined $x and "$x") {
warn " : $x";
print " -> something strange happened, let's skip this file !\n";
return;
}
# various geometries generations
foreach my $geometry (@$resizes) {
my $clone = $image->Clone();
my $outputfile = '_' . $geometry . '_' . $shortname;
print " resizing to $geometry";
$x = doresize($clone, $geometry, $outputfile);
if (defined $x and "$x") {
warn " : $x";
print " -> something strange happened, let's skip this file !\n";
return;
}
}
@$image = ();
}
#############################################
#
# resizes an image
#
# 1st arg : imagemagick object
# 2nd arg : destination geometry
# 3rd arg : name of the file to write
# returns an error string if an error happens
#
sub doresize($$$) {
my ($image, $geometry, $outputfile) = @_;
do { print " -> $outputfile already exists.\n"; return; } if (-f $outputfile);
my ($destwidth, $destheight) = split /x/, $geometry;
do { print " -> original image too small.\n"; return; }
unless ($image->Get('width') > $destwidth or $image->Get('height') > $destheight);
my $x = $image->Resize(geometry => $geometry);
return "$x" if (defined $x and "$x");
print ", writing file $outputfile";
$x = $image->Write(filename => $outputfile, quality => $conf->{quality});
return "$x" if (defined $x and "$x");
print ".\n";
return;
}
#################################################
#
# losslessly rotates an image using @transprogram
#
# 1st arg : image filename
#
sub dorotate($) {
my $filename = shift;
system "@transprogram $filename 1> /dev/null 2>&1";
if ($? == -1) {
return "failed to execute: $!";
} elsif ($? & 127) {
return sprintf ("child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without');
} else {
my $value = $? >> 8;
return "child exited with value $value" if ($value);
}
return;
}
#################################################
#
# looks for already existing resized files
#
# 1st arg : image filename
# 2nd arg : resizes array
#
sub all_resizes_done ($$) {
my ($name, $resizes) = @_;
# looking for the thumbnail
my $thumbnail = $conf->{thumbnail_prefix} . $name;
return 0 if ( ! -f $thumbnail);
# looking for other versions
foreach my $geometry (@$resizes) {
my $version = '_' . $geometry . '_' . $name;
return 0 if ( ! -f $version);
}
return 1;
}
#################################################
#
# returns true if the filename need to be rotated
#
# 1st arg : image filename
#
sub need_rotation ($) {
my $filename = shift;
my $exif = new Image::EXIF($filename);
my $info = $exif->get_image_info();
return 0 if
or ($info->{'Image Orientation'} eq 'Top, Left-Hand'));
return 1;
}
Exemple de fichier .conf utilisé pour La Sélection
thumbnail_geometry_portrait = 384x512 thumbnail_geometry_landscape = 640x480 quality = 90
