#!/usr/bin/perl
use strict;
use File::Find;
use File::Basename;
use File::Spec;
use Getopt::Long;
use Date::Manip;
use Math::Round;
use Image::ExifTool;
use Encode;
my ($version, $program, $date);
my ($longside,$thumblongside,$title, $subtitle, $cssfile, $photographer, $participants, $keywords, $description, $cssfile, $ncols, $nores);
my ($dir,$file,$thumbfile,$copyright,$writecaption,$writedate,$output,$author,$period,$imageCounter,$imgCounter);
my ($DateTimeOriginal,$captionAbstract,$imgWidth,$imgHeight,$factor,$width,$height,$status,$ssifooter,$ggmaps);
my (@imgTitles,@imgFilenames,@imgWidths,@imgHeights);
my $CoordFormat = Encode::decode_utf8("%d° %d' %.2f\"");
$version = "0.2";
$date = "2006-11-24";
$program = $0;
$program =~ s/(\.\/)//;
my $usage = "$program (version $version, $date)\nUsage: $program --dir myphotos/dir/ --ncols 4 --longside 900 --thumblongside 200 --output \"index.shtml\" [--cssfile \"/path/to/your/css/file.css\"] [--title \"Your photogallery title\"] [--subtitle \"Your photogallery subtitle\"] [--photographer \"the photographer(s) name(s)\"] [--participants \"the participant(s) name(s)\"] [--writecaption] [--writedate] [--copyright \"your copyright info\"] [--keywords \"waterfall,mountains,lakes,hotel,cablecar\"] [--description \"your HTML description tag content\"] [--ssifooter \"/your/path/to_ssi/file.html\"] [--ggmaps 0.005] [--nores]\n";
#get parameters
GetOptions("dir=s" => \$dir,
"ncols=i" => \$ncols,
"longside=i" => \$longside,
"thumblongside=i" => \$thumblongside,
"output=s" => \$output,
"title=s" => \$title,
"subtitle=s" => \$subtitle,
"cssfile=s" => \$cssfile,
"photographer=s" => \$photographer,
"period=s" => \$period,
"participants=s" => \$participants,
"keywords=s" => \$keywords,
"author=s" => \$author,
"copyright=s" => \$copyright,
"description=s" => \$description,
"writecaption" => \$writecaption,
"writedate" => \$writedate,
"ssifooter=s" => \$ssifooter,
"ggmaps" => \$ggmaps,
"nores" => \$nores
);
unless ($dir) {
die "$usage you have to specify a directory containing the images (--dir)!\n";
}
unless ($ncols) {
die "$usage you have to specify the number of columns (--ncols)!\n";
}
unless ($longside) {
die "$usage you have to specify the long side of a web-photo in pixel (--longside)!\n";
}
unless ($thumblongside) {
die "$usage you have to specify the long side of a thumbnails in pixel (--thumblongside)!\n";
}
unless ($output) {
die "$usage you have to specify a output filename (--output)!\n";
}
#treat strings to be correctly utf8
if ($dir) {
$dir = Encode::encode("utf8",$dir);
}
if ($output) {
$output = Encode::encode("utf8",$output);
}
if ($title) {
$title = Encode::encode("utf8",$title);
}
if ($subtitle) {
$subtitle = Encode::encode("utf8",$subtitle);
}
if ($cssfile) {
$cssfile = Encode::encode("utf8",$cssfile);
}
if ($photographer) {
$photographer = Encode::encode("utf8",$photographer);
}
if ($period) {
$period = Encode::encode("utf8",$period);
}
if ($participants) {
$participants = Encode::encode("utf8",$participants);
}
if ($keywords) {
$keywords = Encode::encode("utf8",$keywords);
}
if ($author) {
$author = Encode::encode("utf8",$author);
}
if ($copyright) {
$copyright = Encode::encode("utf8",$copyright);
}
if ($description) {
$description = Encode::encode("utf8",$description);
}
if ($ssifooter) {
$ssifooter = Encode::encode("utf8",$ssifooter);
}
open(INDEXFILE,">",$dir.$output) or die "Can't open file ".$dir.$output." for writing: $!\n";
#print XHTML header
print INDEXFILE qq(
);
#include css file
if ($cssfile) {
print INDEXFILE "\n";
}
#create title
if ($title) {
print INDEXFILE "".$title."\n";
}
else {
print INDEXFILE "Photogallery by photoGallery.pl";
}
#add generator and charset information
print INDEXFILE qq(
);
#add author information
if ($author) {
print INDEXFILE "\n";
}
#add description and keywords
if ($description) {
print INDEXFILE "\n";
}
if ($keywords) {
print INDEXFILE "\n";
}
#add generation date
print INDEXFILE "";
#close header and start body
print INDEXFILE qq(
);
#add title and subtitle
if ($title) {
print INDEXFILE "
".$title."
\n";
}
if ($subtitle) {
print INDEXFILE "
".$subtitle."
\n";
}
#add date (period) information
if ($period) {
print INDEXFILE "
Pictures taken: ".$period."
\n";
}
#add photographer information
if ($photographer) {
print INDEXFILE "
Photographer: ".$photographer."
\n";
}
#add participant information
if ($participants) {
print INDEXFILE "
Participants: ".$participants."
\n";
}
#opening table
print INDEXFILE "
\n";
$imageCounter = 0;
#read directory and count image files
opendir(DIR, $dir) or die "can't open directory $dir: $!";
print "\nprocessing directory \"$dir\"\n";
#test if thumbnails directory exists
unless (-d $dir."thumbnails") { #see if directory exists
mkdir($dir."thumbnails");
}
while (defined($file = readdir(DIR))) {
$file = File::Spec->rel2abs($dir.$file);
#first check if it is a jpeg file
my ($base, $dir, $ext) = fileparse($file,'\..*');
if ($ext eq ".jpg" || $ext eq ".JPG" || $ext eq ".jpeg" || $ext eq ".JPEG") {
#first read width and height value
my $exifTool = new Image::ExifTool;
$exifTool->Options(Charset => 'UTF8');
my $imgInfo = $exifTool->ImageInfo($file,"Caption-Abstract","ImageWidth","ImageHeight");
my @tags = $exifTool->GetRequestedTags();
my $captionAbstract = Encode::encode("utf8",$exifTool->GetValue($tags[0]));
my $imgWidth = Encode::encode("utf8",$exifTool->GetValue($tags[1]));
my $imgHeight = Encode::encode("utf8",$exifTool->GetValue($tags[2]));
push(@imgTitles,$captionAbstract);
push(@imgFilenames,$base);
push(@imgWidths,$imgWidth);
push(@imgHeights,$imgHeight);
$imageCounter++;
}
}
closedir(DIR);
print "working on $imageCounter images ...\n\n";
#read directory and count image files
opendir(DIR, $dir) or die "can't open directory $dir: $!";
$imgCounter = 0;
while (defined($file = readdir(DIR))) {
$thumbfile = File::Spec->rel2abs($dir."thumbnails/".$file);
$file = File::Spec->rel2abs($dir.$file);
#first check if it is a jpeg file
my ($base, $dir, $ext) = fileparse($file,'\..*');
if ($ext eq ".jpg" || $ext eq ".JPG" || $ext eq ".jpeg" || $ext eq ".JPEG") {
print "working on image ".($imgCounter + 1)." of a total of $imageCounter images\n";
#first read width and height value
my $exifTool = new Image::ExifTool;
#set a few parameters
$exifTool->Options(Charset => 'UTF8', CoordFormat => $CoordFormat);
my $imgInfo = $exifTool->ImageInfo($file,"DateTimeOriginal","Caption-Abstract","ImageWidth","ImageHeight","Country-PrimaryLocationName","Province-State","City","GPSLatitude","GPSLatitudeRef","GPSLongitude","GPSLongitudeRef","GPSAltitude","GPSAltitudeRef","Model","ExposureTime","ApertureValue","FocalLengthIn35mmFormat","ISO","GPSDestLatitude","GPSDestLatitudeRef","GPSDestLongitude","GPSDestLongitudeRef","GPSImageDirection","GPSImageDirectionRef","GPSDestDistance","GPSDestDistanceRef");
#get individual parameters
my @tags = $exifTool->GetRequestedTags();
my $DateTimeOriginal = Encode::encode("utf8",$exifTool->GetValue($tags[0]));
my $captionAbstract = Encode::encode("utf8",$exifTool->GetValue($tags[1]));
my $imgWidth = Encode::encode("utf8",$exifTool->GetValue($tags[2]));
my $imgHeight = Encode::encode("utf8",$exifTool->GetValue($tags[3]));
my $country = Encode::encode("utf8",$exifTool->GetValue($tags[4]));
my $province = Encode::encode("utf8",$exifTool->GetValue($tags[5]));
my $city = Encode::encode("utf8",$exifTool->GetValue($tags[6]));
my $lat = Encode::encode("utf8",$exifTool->GetValue($tags[7]));
my $latRef = Encode::encode("utf8",$exifTool->GetValue($tags[8]));
my $lon = Encode::encode("utf8",$exifTool->GetValue($tags[9]));
my $lonRef = Encode::encode("utf8",$exifTool->GetValue($tags[10]));
my $alt = Encode::encode("utf8",$exifTool->GetValue($tags[11]));
my $altRef = Encode::encode("utf8",$exifTool->GetValue($tags[12]));
my $cameraModel = Encode::encode("utf8",$exifTool->GetValue($tags[13]));
my $exposure = Encode::encode("utf8",$exifTool->GetValue($tags[14]));
my $aperture = Encode::encode("utf8",$exifTool->GetValue($tags[15]));
my $focalLength = Encode::encode("utf8",$exifTool->GetValue($tags[16]));
my $iso = Encode::encode("utf8",$exifTool->GetValue($tags[17]));
my $destLat = Encode::encode("utf8",$exifTool->GetValue($tags[18]));
my $destLatRef = Encode::encode("utf8",$exifTool->GetValue($tags[19]));
my $destLon = Encode::encode("utf8",$exifTool->GetValue($tags[20]));
my $destLonRef = Encode::encode("utf8",$exifTool->GetValue($tags[21]));
my $imageDir = Encode::encode("utf8",$exifTool->GetValue($tags[22]));
my $imageDirRef = Encode::encode("utf8",$exifTool->GetValue($tags[23]));
my $imageDist = Encode::encode("utf8",$exifTool->GetValue($tags[24]));
my $imageDistRef = Encode::encode("utf8",$exifTool->GetValue($tags[25]));
#creating thumbnail
if ($imgWidth > $imgHeight) {
$factor = $imgHeight / $imgWidth;
$width = $thumblongside;
$height = nearest(1,($width * $factor));
}
else {
$factor = $imgWidth / $imgHeight;
$height = $thumblongside;
$width = nearest(1,($height * $factor));
}
unless ($nores) {
$status = system("convert ".$file." -resize ".$width."x".$height." ".$thumbfile);
die "could not create thumbnail $thumbfile" if $status == 1;
}
#now write out information to HTML file
if (($imgCounter % $ncols) == 0) {
if ($imgCounter != 0) {
print INDEXFILE "\n";
}
print INDEXFILE "
\n";
}
print INDEXFILE "
".$captionAbstract."
\n";
#resizing original image
if ($imgWidth > $imgHeight) {
$width = $longside;
$height = nearest(1,($width * $factor));
}
else {
$height = $longside;
$width = nearest(1,($height * $factor));
}
#$status = system("convert ".$file." -resize ".$width."x".$height." ".$file);
#die "could not resize $file" if $status == 1;
#now write out the html file containing the big image
open(PHOTOFILE,">",$dir.$base.".html") or die "Can't open file ".$dir.$base.".html for writing: $!\n";
#print XHTML header
print PHOTOFILE qq(
);
#include css file
if ($cssfile) {
print PHOTOFILE "\n\t\n";
}
#create title
print PHOTOFILE "\t$captionAbstract\n";
#add author information
if ($author) {
print PHOTOFILE "\t\n";
}
#add charset, description and keywords
print PHOTOFILE "\t\n";
print PHOTOFILE "\t\n";
print PHOTOFILE "\t\n";
#add generation date
print PHOTOFILE "\t\n";
#close header and start body
print PHOTOFILE qq(
);
if ($height > $width) {
#case: portrait image
#add previous or next image and image metadata
print PHOTOFILE "
);
#close html file
close(INDEXFILE);
#subroutine to calculate degree/minutes/seconds to decimal degrees
sub dms2dd {
my $deg = shift;
my $min = shift;
my $sec = shift;
return ($deg + ($min / 60) + ($sec / 3600));
}
# subroutine acos (source: http://jan.ucc.nau.edu/~cvm/latlon_formula.html)
# input: an angle in radians
# output: returns the arc cosine of the angle
# description: this is needed because perl does not provide an arc cosine function
sub acos {
my($x) = @_;
my $ret = atan2(sqrt(1 - $x**2), $x);
return $ret;
}
# subroutine distance calculation on earth
# (source: http://jan.ucc.nau.edu/~cvm/latlon_formula.html)
sub distEarth {
my $lat1 = shift; #lat1 in dec degrees
my $lon1 = shift; #lon1 in dec degrees
my $lat2 = shift; #lat2 in dec degrees
my $lon2 = shift; #lon2 in dec degrees
my $r = 6371; #radius of the earth
my $pi = atan2(1,1) * 4;
#calculate radians
$lat1 *= ($pi/180);
$lon1 *= ($pi/180);
$lat2 *= ($pi/180);
$lon2 *= ($pi/180);
#calculate distance
return acos(cos($lat1)*cos($lon1)*cos($lat2)*cos($lon2) + cos($lat1)*sin($lon1)*cos($lat2)*sin($lon2) + sin($lat1)*sin($lat2)) * $r;
}
# subroutine distance calculation on earth
# (source: http://www.movable-type.co.uk/scripts/LatLong.html)
sub iniBearingEarth {
my $lat1 = shift; #lat1 in dec degrees
my $lon1 = shift; #lon1 in dec degrees
my $lat2 = shift; #lat2 in dec degrees
my $lon2 = shift; #lon2 in dec degrees
my $r = 6371; #radius of the earth
my $pi = atan2(1,1) * 4;
my $deltaLong = $lon2 - $lon1;
#calculate radians
$lat1 *= ($pi/180);
$lon1 *= ($pi/180);
$lat2 *= ($pi/180);
$lon2 *= ($pi/180);
my $x = sin($deltaLong) * cos($lat2);
my $y = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($deltaLong);
my $result = rad2Brng(atan2($y,$x));
return $result;
}
# subroutine radians to bearing
# (source: http://www.movable-type.co.uk/scripts/LatLong.html)
sub rad2Brng {
my $rad = shift;
my $pi = atan2(1,1) * 4;
return abs((($rad + 2 * $pi) % (2 * $pi)) * 180 / $pi);
}