-MANIFEST
-INSTALL
-Makefile.PL
-TODO
-LICENSE
-README
Changes
-lib/Apache/Gallery.pm
-UPGRADE
-htdocs/sound-ogg.png
-htdocs/video-wmv.png
-htdocs/video-asf.png
-htdocs/video-mov.png
-htdocs/application-pdf.png
+htdocs/agfolder.png
htdocs/application-doc.png
+htdocs/application-pdf.png
+htdocs/application-rtf.png
+htdocs/c.png
htdocs/sound-mp3.png
+htdocs/sound-ogg.png
htdocs/sound-wav.png
-htdocs/application-rtf.png
+htdocs/video-asf.png
+htdocs/video-avi.png
+htdocs/video-mov.png
htdocs/video-mpeg.png
htdocs/video-mpg.png
-htdocs/video-avi.png
-htdocs/c.png
-htdocs/agfolder.png
-t/002_inpng.png
-t/005_jpg.jpg
-t/002_graphlibs.t
+htdocs/video-wmv.png
+INSTALL
+lib/Apache/Gallery.pm
+LICENSE
+Makefile.PL
+MANIFEST
+META.yml
+README
t/001_use.t
-t/006_thumbnails.t
+t/002_graphlibs.t
t/002_injpg.jpg
-t/004_cache_dir.t
+t/002_inpng.png
t/003_comment.t
t/003_commenttest
+t/004_cache_dir.t
t/005_imageinfo.t
+t/005_jpg.jpg
+t/006_thumbnails.t
t/007_pod.t
+templates/bright/dircomment.tpl
+templates/bright/directory.tpl
+templates/bright/error.tpl
+templates/bright/file.tpl
+templates/bright/gallery.css
+templates/bright/index.tpl
+templates/bright/info.tpl
+templates/bright/intervalactive.tpl
+templates/bright/interval.tpl
+templates/bright/layout.tpl
+templates/bright/navdirectory.tpl
+templates/bright/navpicture.tpl
+templates/bright/nodircomment.tpl
+templates/bright/nopictureinfo.tpl
+templates/bright/orig.tpl
+templates/bright/pictureinfo.tpl
+templates/bright/picture.tpl
+templates/bright/README
+templates/bright/refresh.tpl
+templates/bright/rss_item.tpl
+templates/bright/rss.tpl
+templates/bright/scaleactive.tpl
+templates/bright/scale.tpl
+templates/bright/showpicture.tpl
+templates/bright/slideshowisoff.tpl
+templates/bright/slideshowoff.tpl
templates/default/dircomment.tpl
templates/default/directory.tpl
templates/default/error.tpl
templates/default/file.tpl
+templates/default/gallery.css
templates/default/index.tpl
templates/default/info.tpl
-templates/default/interval.tpl
templates/default/intervalactive.tpl
+templates/default/interval.tpl
templates/default/layout.tpl
templates/default/navpicture.tpl
templates/default/nodircomment.tpl
templates/default/nopictureinfo.tpl
templates/default/orig.tpl
-templates/default/picture.tpl
templates/default/pictureinfo.tpl
+templates/default/picture.tpl
templates/default/refresh.tpl
-templates/default/scale.tpl
+templates/default/rss_item.tpl
+templates/default/rss.tpl
templates/default/scaleactive.tpl
+templates/default/scale.tpl
templates/default/showpicture.tpl
templates/default/slideshowisoff.tpl
templates/default/slideshowoff.tpl
-templates/default/gallery.css
-templates/new/intervalactive.tpl
templates/new/dircomment.tpl
templates/new/directory.tpl
templates/new/error.tpl
templates/new/file.tpl
+templates/new/gallery.css
templates/new/index.tpl
templates/new/info.tpl
+templates/new/intervalactive.tpl
templates/new/interval.tpl
-templates/new/navpicture.tpl
templates/new/layout.tpl
-templates/new/gallery.css
+templates/new/navpicture.tpl
templates/new/nodircomment.tpl
templates/new/nopictureinfo.tpl
templates/new/orig.tpl
-templates/new/picture.tpl
templates/new/pictureinfo.tpl
+templates/new/picture.tpl
templates/new/refresh.tpl
-templates/new/scale.tpl
+templates/new/rss_item.tpl
+templates/new/rss.tpl
templates/new/scaleactive.tpl
+templates/new/scale.tpl
templates/new/showpicture.tpl
templates/new/slideshowisoff.tpl
templates/new/slideshowoff.tpl
-META.yml Module meta-data (added by MakeMaker)
+TODO
+UPGRADE
package Apache::Gallery;
-# $Author: mil $ $Rev: 316 $
-# $Date: 2006-08-04 16:28:06 +0300 (Fri, 04 Aug 2006) $
+# $Author: mil $ $Rev: 324 $
+# $Date: 2011-02-22 21:56:06 +0100 (Tue, 22 Feb 2011) $
use strict;
use vars qw($VERSION);
-$VERSION = "1.0RC3";
+$VERSION = "1.0.1";
BEGIN {
require Apache2::SubRequest;
require Apache2::Const;
- Apache2::Const->import(-compile => 'OK','DECLINED','FORBIDDEN','NOT_FOUND');
+ Apache2::Const->import(-compile => 'OK','DECLINED','FORBIDDEN','NOT_FOUND','HTTP_NOT_MODIFIED');
$::MP2 = 1;
} else {
use URI::Escape;
use CGI;
use CGI::Cookie;
+use Encode;
+use HTTP::Date;
+use Digest::MD5 qw(md5_base64);
use Data::Dumper;
my $r = shift or Apache2::RequestUtil->request();
+ unless (($r->method eq 'HEAD') or ($r->method eq 'GET')) {
+ return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+ }
+
if ((not $memoized) and ($r->dir_config('GalleryMemoize'))) {
require Memoize;
Memoize::memoize('get_imageinfo');
}
$r->headers_out->{"X-Powered-By"} = "apachegallery.dk $VERSION - Hest design!";
- $r->headers_out->{"X-Gallery-Version"} = '$Rev: 316 $ $Date: 2006-08-04 16:28:06 +0300 (Fri, 04 Aug 2006) $';
+ $r->headers_out->{"X-Gallery-Version"} = '$Rev: 324 $ $Date: 2011-02-22 21:56:06 +0100 (Tue, 22 Feb 2011) $';
my $filename = $r->filename;
$filename =~ s/\/$//;
my $topdir = $filename;
+ my $media_rss_enabled = $r->dir_config('GalleryEnableMediaRss');
+
# Just return the http headers if the client requested that
if ($r->header_only) {
$r->send_http_header;
}
- if (-f $filename or -d $filename) {
+ if (-f $filename or -d $filename) {
return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
}
else {
$r->content_type($subr->content_type());
if ($::MP2) {
+ my $fileinfo = stat($file);
+
+ my $nonce = md5_base64($fileinfo->ino.$fileinfo->mtime);
+ if ($r->headers_in->{"If-None-Match"} eq $nonce) {
+ return Apache2::Const::HTTP_NOT_MODIFIED();
+ }
+
+ if ($r->headers_in->{"If-Modified-Since"} && str2time($r->headers_in->{"If-Modified-Since"}) < $fileinfo->mtime) {
+ return Apache2::Const::HTTP_NOT_MODIFIED();
+ }
+
+ $r->headers_out->{"Content-Length"} = $fileinfo->size;
+ $r->headers_out->{"Last-Modified-Date"} = time2str($fileinfo->mtime);
+ $r->headers_out->{"ETag"} = $nonce;
$r->sendfile($file);
return Apache2::Const::OK();
}
# Instead of reading the templates every single time
# we need them, create a hash of template names and
# the associated Text::Template objects.
- my %templates = create_templates({layout => "$tpl_dir/layout.tpl",
- index => "$tpl_dir/index.tpl",
- directory => "$tpl_dir/directory.tpl",
- picture => "$tpl_dir/picture.tpl",
- file => "$tpl_dir/file.tpl",
- comment => "$tpl_dir/dircomment.tpl",
- nocomment => "$tpl_dir/nodircomment.tpl",
+ my %templates = create_templates({layout => "$tpl_dir/layout.tpl",
+ index => "$tpl_dir/index.tpl",
+ directory => "$tpl_dir/directory.tpl",
+ picture => "$tpl_dir/picture.tpl",
+ file => "$tpl_dir/file.tpl",
+ comment => "$tpl_dir/dircomment.tpl",
+ nocomment => "$tpl_dir/nodircomment.tpl",
+ rss => "$tpl_dir/rss.tpl",
+ rss_item => "$tpl_dir/rss_item.tpl",
+ navdirectory => "$tpl_dir/navdirectory.tpl",
});
my %tpl_vars;
$tpl_vars{TITLE} = "Index of: $uri";
- $tpl_vars{META} = " ";
+
+ if ($media_rss_enabled) {
+ # Put the RSS feed on all directory listings
+ $tpl_vars{META} = '<link rel="alternate" href="?rss=1" type="application/rss+xml" title="" id="gallery" />';
+ }
unless (opendir (DIR, $filename)) {
show_error ($r, 500, $!, "Unable to access directory $filename: $!");
FILE => $dirtitle,
}
);
+
}
elsif (-f $thumbfilename && $thumbfilename =~ /$doc_pattern/i && $thumbfilename !~ /$img_pattern/i) {
my $type = lc($1);
$filetype = "text-$type";
} elsif ($thumbfilename =~ m/\.(mp3|ogg|wav)$/i) {
$filetype = "sound-$type";
- } elsif ($thumbfilename =~ m/\.(doc|pdf|rtf|csv|eps)$/i) {
+ } elsif ($thumbfilename =~ m/$doc_pattern/i) {
$filetype = "application-$type";
} else {
$filetype = "unknown";
%file_vars,
},
);
+
+ if ($media_rss_enabled) {
+ my ($content_image_width, undef, $content_image_height) = get_image_display_size($cgi, $r, $width, $height);
+ my %item_vars = (
+ THUMBNAIL => uri_escape($uri."/.cache/$cached", $escape_rule),
+ LINK => uri_escape($fileurl, $escape_rule),
+ TITLE => $file,
+ CONTENT => uri_escape($uri."/.cache/".$content_image_width."x".$content_image_height."-".$file, $escape_rule)
+ );
+ $tpl_vars{ITEMS} .= $templates{rss_item}->fill_in(HASH => {
+ %item_vars
+ });
+ }
}
}
}
$tpl_vars{BROWSELINKS} = "";
}
+ # Generate prev and next directory menu items
+ $filename =~ m/(.*)\/.*?$/;
+ my $parent_filename = $1;
+
+ $r->document_root =~ m/(.*)\/$/;
+ my $root_path = $1;
+ print STDERR "$filename vs $root_path\n";
+ if ($filename ne $root_path) {
+ unless (opendir (PARENT_DIR, $parent_filename)) {
+ show_error ($r, 500, $!, "Unable to access parent directory $parent_filename: $!");
+ return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+ }
+
+ my @neighbour_directories = grep { !/^\./ && -d "$parent_filename/$_" } readdir (PARENT_DIR);
+ my $dirsortby;
+ if (defined($r->dir_config('GalleryDirSortBy'))) {
+ $dirsortby=$r->dir_config('GalleryDirSortBy');
+ } else {
+ $dirsortby=$r->dir_config('GallerySortBy');
+ }
+ if ($dirsortby && $dirsortby =~ m/^(size|atime|mtime|ctime)$/) {
+ @neighbour_directories = map(/^\d+ (.*)/, sort map(stat("$parent_filename/$_")->$dirsortby()." $_", @neighbour_directories));
+ } else {
+ @neighbour_directories = sort @neighbour_directories;
+ }
+
+ closedir(PARENT_DIR);
+
+ my $neightbour_counter = 0;
+ foreach my $neighbour_directory (@neighbour_directories) {
+ if ($parent_filename.'/'.$neighbour_directory eq $filename) {
+ if ($neightbour_counter > 0) {
+ print STDERR "prev directory is " .$neighbour_directories[$neightbour_counter-1] ."\n";
+ my $linktext = $neighbour_directories[$neightbour_counter-1];
+ if (-e $parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder") {
+ $linktext = get_filecontent($parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder");
+ }
+ my %info = (
+ URL => "../".$neighbour_directories[$neightbour_counter-1],
+ LINK_NAME => "<<< $linktext",
+ DIR_FILES => "",
+ );
+ $tpl_vars{PREV_DIR_FILES} = $templates{navdirectory}->fill_in(HASH=> {%info});
+ print STDERR $tpl_vars{PREV_DIR_FILES} ."\n";
+
+ }
+ if ($neightbour_counter < scalar @neighbour_directories - 1) {
+ my $linktext = $neighbour_directories[$neightbour_counter+1];
+ if (-e $parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder") {
+ $linktext = get_filecontent($parent_filename.'/'.$neighbour_directories[$neightbour_counter+1] . ".folder");
+ }
+ my %info = (
+ URL => "../".$neighbour_directories[$neightbour_counter+1],
+ LINK_NAME => "$linktext >>>",
+ DIR_FILES => "",
+ );
+ $tpl_vars{NEXT_DIR_FILES} = $templates{navdirectory}->fill_in(HASH=> {%info});
+ print STDERR "next directory is " .$neighbour_directories[$neightbour_counter+1] ."\n";
+ }
+ }
+ $neightbour_counter++;
+ }
+ }
+
if (-f $topdir . '.comment') {
my $comment_ref = get_comment($topdir . '.comment');
my %comment_vars;
$tpl_vars{DIRCOMMENT} = $templates{nocomment}->fill_in(HASH=>\%tpl_vars);
}
- $tpl_vars{MAIN} = $templates{index}->fill_in(HASH => \%tpl_vars);
-
- $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars);
+ if ($cgi->param('rss')) {
+ $tpl_vars{MAIN} = $templates{rss}->fill_in(HASH => \%tpl_vars);
+ $r->content_type('application/rss+xml');
+ } else {
+ $tpl_vars{MAIN} = $templates{index}->fill_in(HASH => \%tpl_vars);
+ $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars);
+ $r->content_type('text/html');
+ }
- $r->content_type('text/html');
$r->headers_out->{'Content-Length'} = length($tpl_vars{MAIN});
if (!$::MP2) {
}
my ($orig_width, $orig_height, $type) = imgsize($filename);
- my $width = $orig_width;
my $imageinfo = get_imageinfo($r, $filename, $type, $orig_width, $orig_height);
- my $original_size=$orig_height;
- if ($orig_width>$orig_height) {
- $original_size=$orig_width;
- }
-
- # Check if the selected width is allowed
- my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600');
-
- my %cookies = fetch CGI::Cookie;
-
- if ($cgi->param('width')) {
- unless ((grep $cgi->param('width') == $_, @sizes) or ($cgi->param('width') == $original_size)) {
- show_error($r, 200, "Invalid width", "The specified width is invalid");
- return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
- }
-
- $width = $cgi->param('width');
- my $cookie = new CGI::Cookie(-name => 'GallerySize', -value => $width, -expires => '+6M');
- $r->headers_out->{'Set-Cookie'} = $cookie;
-
- } elsif ($cookies{'GallerySize'} && (grep $cookies{'GallerySize'}->value == $_, @sizes)) {
-
- $width = $cookies{'GallerySize'}->value;
-
- } else {
- $width = $sizes[0];
- }
-
- my $scale;
- my $image_width;
- if ($orig_width<$orig_height) {
- $scale = ($orig_height ? $width/$orig_height: 1);
- $image_width=$width*$orig_width/$orig_height;
- }
- else {
- $scale = ($orig_width ? $width/$orig_width : 1);
- $image_width = $width;
- }
-
- my $height = $orig_height * $scale;
-
- $image_width = floor($image_width);
- $width = floor($width);
- $height = floor($height);
+ my ($image_width, $width, $height, $original_size) = get_image_display_size($cgi, $r, $orig_width, $orig_height);
my $cached = get_scaled_picture_name($filename, $image_width, $height);
$foundcomment = 1;
$tpl_vars{COMMENT} = $comment_ref->{COMMENT} . '<br />' if $comment_ref->{COMMENT};
$tpl_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE};
+ } elsif ($r->dir_config('GalleryCommentExifKey')) {
+ my $comment = decode("utf8", $imageinfo->{$r->dir_config('GalleryCommentExifKey')});
+ $tpl_vars{COMMENT} = encode("iso-8859-1", $comment);
} else {
$tpl_vars{COMMENT} = '';
}
# Fill in sizes and determine if any are smaller than the
# actual image. If they are, $scaleable=1
my $scaleable = 0;
+ my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600');
foreach my $size (@sizes) {
if ($size<=$original_size) {
my %sizes_vars;
return ($width, $height);
}
+sub get_image_display_size {
+ my ($cgi, $r, $orig_width, $orig_height) = @_;
+
+ my $width = $orig_width;
+
+ my $original_size=$orig_height;
+ if ($orig_width>$orig_height) {
+ $original_size=$orig_width;
+ }
+
+ # Check if the selected width is allowed
+ my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600');
+
+ my %cookies = fetch CGI::Cookie;
+
+ if ($cgi->param('width')) {
+ unless ((grep $cgi->param('width') == $_, @sizes) or ($cgi->param('width') == $original_size)) {
+ show_error($r, 200, "Invalid width", "The specified width is invalid");
+ return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+ }
+
+ $width = $cgi->param('width');
+ my $cookie = new CGI::Cookie(-name => 'GallerySize', -value => $width, -expires => '+6M');
+ $r->headers_out->{'Set-Cookie'} = $cookie;
+
+ } elsif ($cookies{'GallerySize'} && (grep $cookies{'GallerySize'}->value == $_, @sizes)) {
+
+ $width = $cookies{'GallerySize'}->value;
+
+ } else {
+ $width = $sizes[0];
+ }
+
+ my $scale;
+ my $image_width;
+ if ($orig_width<$orig_height) {
+ $scale = ($orig_height ? $width/$orig_height: 1);
+ $image_width=$width*$orig_width/$orig_height;
+ }
+ else {
+ $scale = ($orig_width ? $width/$orig_width : 1);
+ $image_width = $width;
+ }
+
+ my $height = $orig_height * $scale;
+
+ $image_width = floor($image_width);
+ $width = floor($width);
+ $height = floor($height);
+
+ return ($image_width, $width, $height, $original_size);
+}
+
sub get_imageinfo {
my ($r, $file, $type, $width, $height) = @_;
my $imageinfo = {};
my $rotate = 0;
+ print STDERR "orientation: ".$imageinfo->{Orientation}."\n";
# Check to see if the image contains the Orientation EXIF key,
# but allow user to override using rotate
if (!defined($r->dir_config("GalleryAutoRotate"))
|| $r->dir_config("GalleryAutoRotate") eq "1") {
if (defined($imageinfo->{Orientation})) {
+ print STDERR $imageinfo->{Orientation}."\n";
if ($imageinfo->{Orientation} eq 'right_top') {
$rotate=1;
}
=back
+=item B<GalleryCommentExifKey>
+
+Set this option to e.g. ImageDescription to use this field as comments
+for images.
+
+=item B<GalleryEnableMediaRss>
+
+Set this option to 1 to enable generation of a media RSS feed. This
+can be used e.g. together with the PicLens plugin from http://piclens.com
+
=head1 FEATURES
=over 4
the folder, but can be changed by creating a file <directory>.folder
with the visible name of the folder.
+It is also possible to set GalleryCommentExifKey to the name of an EXIF
+field containing the comment, e.g. ImageDescription. The EXIF comment is
+overridden by the .comment file if it exists.
+
=back
=head1 DEPENDENCIES