\n";
# path array contains basenames from the top dir
# down to the current dir
my @path = split(/[\/\\]/, $dir_state->{dir});
unshift @path, $self->{top_base};
# we want to create relative links to all the dirs
# above the current one, so work backwards
my %uplinks = ();
my $uplink = '';
foreach my $dn (reverse @path)
{
$uplinks{$dn} = $uplink;
if (!$uplink and $page > 1)
{
$uplinks{$dn} = "index.html";
}
else
{
$uplink .= '../';
}
}
my @header = ();
foreach my $dn (@path)
{
my $pretty = $dn;
$pretty =~ s/_/ /g;
if ($uplinks{$dn})
{
push @header, "
$pretty";
}
else
{
push @header, $pretty;
}
}
push @out, '
';
push @out, join(' :: ', @header);
push @out, "
\n";
# now for the prev, next links
push @out, $self->make_index_prev_next($dir_state, $page);
# and now for the album caption
if (exists $dir_state->{captions})
{
my $index_caption = 'index.html';
if (exists $dir_state->{captions}->{$index_caption}
and defined $dir_state->{captions}->{$index_caption})
{
push @out, '
';
push @out, $dir_state->{captions}->{$index_caption};
push @out, "
\n";
}
}
return join('', @out);
} # start_index_page
=head2 make_index_prev_next
my $links = $self->start_index_page($dir_state, $page);
Make the previous next other-index-pages links for the
given index-page. Generally called for the top and bottom
of the index page.
=cut
sub make_index_prev_next {
my $self = shift;
my $dir_state = shift;
my $page = shift;
my @out = ();
if ($dir_state->{pages} > 1)
{
push @out, '
';
# prev
my $label = '< - prev';
if ($page > 1)
{
my $iurl = $self->get_index_pagename(dir_state=>$dir_state,
page=>$page - 1, get_filename=>0);
push @out, "$label ";
}
# pages, but only if more than two
if ($dir_state->{pages} > 2)
{
for (my $i = 1; $i <= $dir_state->{pages}; $i++)
{
if ($page == $i)
{
push @out, " [$i] ";
}
else
{
my $iurl = $self->get_index_pagename(dir_state=>$dir_state,
page=>$i, get_filename=>0);
push @out, " [$i] ";
}
}
}
$label = 'next ->';
if (($page+1) <= $dir_state->{pages})
{
my $iurl = $self->get_index_pagename(dir_state=>$dir_state,
page=>$page + 1, get_filename=>0);
push @out, " $label";
}
push @out, "
\n";
}
return join('', @out);
} # make_index_prev_next
=head2 end_index_page
push @content, $self->end_index_page($dir_state, $page);
Create the end-of-page for an index page.
This contains page content, not full etc (that's expected
to be in the full-page template).
=cut
sub end_index_page {
my $self = shift;
my $dir_state = shift;
my $page = shift;
my @out = ();
push @out, "\n
\n";
push @out, $self->make_index_prev_next($dir_state, $page);
push @out, "
\n";
return join('', @out);
} # end_index_page
=head2 make_index_subdirs
push @content, $self->make_index_subdirs($dir_state, $page);
Create the subdirs section; this contains links to subdirs.
=cut
sub make_index_subdirs {
my $self = shift;
my $dir_state = shift;
my $page = shift;
my @out = ();
if (@{$dir_state->{subdirs}})
{
push @out, "\n\n";
# subdirs
foreach my $image (@{$args{images}})
{
my $image_link = $self->get_image_pagename(dir_state=>$dir_state,
image=>$image, type=>'parent');
my $thumbnail_link = $self->get_thumbnail_name(
dir_state=>$dir_state,
image=>$image, type=>'parent');
my $image_name = $self->get_image_pagename(dir_state=>$dir_state,
image=>$image, type=>'pretty');
push @out, <
EOT
}
push @out, "\n";
}
return join('', @out);
} # make_image_index
=head2 make_index_title
Make the title for the index page.
This is expected to go inside a
.item {
float: left;
vertical-align: middle;
text-align: center;
margin: 10px;
}
.thumb {
width: ${thumb_area_width}px;
height: ${thumb_area_height}px;
overflow: auto;
font-size: small;
}
.albumdesc {
width: 80%;
border: solid 2px;
margin-left: auto;
margin-right: auto;
background: #eeeeee;
color: black;
}
.albumdesc p {
margin: 0.75em;
}
EOT
return join('', @out);
} # make_index_style
=head2 get_index_pagename
my $name = self->get_index_pagename(
dir_state=>$dir_state,
page=>$page,
get_filename=>0);
Get the name of the given index page; either the file name
or the relative URL.
=cut
sub get_index_pagename {
my $self = shift;
my %args = (
get_filename=>0,
@_
);
my $dir_state = $args{dir_state};
my $page = $args{page};
my $pagename;
if ($page == 1)
{
$pagename = 'index.html';
}
elsif ($dir_state->{pages} > 9)
{
$pagename = sprintf("index%02d.html", $page);
}
else
{
$pagename = "index${page}.html";
}
if ($args{get_filename})
{
return File::Spec->catfile($dir_state->{abs_dir}, $pagename);
}
else # get URL
{
return $pagename;
}
} # get_index_pagename
=head2 get_image_pagename
my $name = self->get_image_pagename(
dir_state=>$dir_state,
image=>$image,
type=>'file');
Get the name of the image page; either the file name
or the relative URL from above, or the relative URL
from the sibling, or a 'pretty' name suitable for a title.
The 'type' can be 'file', 'parent', 'sibling' or 'pretty'.
=cut
sub get_image_pagename {
my $self = shift;
my %args = (
type=>'parent',
@_
);
my $dir_state = $args{dir_state};
my $image = $args{image};
my $thumbdir = $self->{thumbdir};
my $img_page = $image;
# change the last dot to underscore
$img_page =~ s/\.(\w+)$/_$1/;
$img_page .= ".html";
if ($args{type} eq 'file')
{
return File::Spec->catfile($dir_state->{abs_dir}, $thumbdir, $img_page);
}
elsif ($args{type} eq 'parent')
{
return "${thumbdir}/${img_page}";
}
elsif ($args{type} eq 'sibling')
{
return ${img_page};
}
elsif ($args{type} eq 'pretty')
{
my $pretty = ${image};
$pretty =~ s/\.(\w+)$//;
$pretty =~ s/_/ /g;
return $pretty;
}
return '';
} # get_image_pagename
=head2 get_thumbnail_name
my $name = self->get_thumbnail_name(
dir_state=>$dir_state,
image=>$image,
type=>'file');
Get the name of the image thumbnail file; either the file name
or the relative URL from above, or the relative URL
from the sibling.
The 'type' can be 'file', 'parent', 'sibling'.
=cut
sub get_thumbnail_name {
my $self = shift;
my %args = (
type=>'parent',
@_
);
my $dir_state = $args{dir_state};
my $image = $args{image};
my $thumbdir = $self->{thumbdir};
my $thumb = $image;
# change the last dot to underscore
$thumb =~ s/\.(\w+)$/_$1/;
$thumb .= ".jpg";
if ($args{type} eq 'file')
{
return File::Spec->catfile($dir_state->{abs_dir}, $thumbdir, $thumb);
}
elsif ($args{type} eq 'parent')
{
return "${thumbdir}/${thumb}";
}
elsif ($args{type} eq 'sibling')
{
return ${thumb};
}
return '';
} # get_thumbnail_name
=head2 get_caption
my $name = self->get_caption(
dir_state=>$dir_state,
img_state->$img_state,
image=>$image)
Get the caption for this image.
This also gets the meta-data if any is required.
=cut
sub get_caption {
my $self = shift;
my %args = (
@_
);
my $dir_state = $args{dir_state};
my $img_state = $args{img_state};
my $image = $args{image};
my @out = ();
if (exists $dir_state->{captions})
{
if (exists $dir_state->{captions}->{$image}
and defined $dir_state->{captions}->{$image})
{
push @out, $dir_state->{captions}->{$image};
}
}
if ($img_state and defined $self->{meta} and @{$self->{meta}})
{
# only add the meta data if it's there
foreach my $fieldspec (@{$self->{meta}})
{
$fieldspec =~ /%([\w\s]+)%/;
my $field = $1;
if (exists $img_state->{info}->{$field}
and defined $img_state->{info}->{$field}
and $img_state->{info}->{$field})
{
my $val = $fieldspec;
my $fieldval = $img_state->{info}->{$field};
# make the fieldval HTML-safe
$fieldval =~ s/&/&/g;
$fieldval =~ s/</g;
$fieldval =~ s/>/>/g;
$val =~ s/%${field}%/$fieldval/g;
push @out, $val;
}
}
}
return join("\n", @out);
} # get_caption
=head2 get_template
my $templ = $self->get_template($template);
Get the given template (read if it's from a file)
=cut
sub get_template {
my $self = shift;
my $template = shift;
if ($template !~ /\n/
&& -r $template)
{
local $/ = undef;
my $fh;
open($fh, $template)
or die "Could not open ", $template;
$template = <$fh>;
close($fh);
}
return $template;
} # get_template
=head2 start_image_page
push @content, $self->start_image_page($dir_state, $img_state);
Create the start-of-page for an image page.
This contains page content, not full etc (that's expected
to be in the full-page template).
It contains the header, link to parent dirs and links to
previous and next image-pages.
=cut
sub start_image_page {
my $self = shift;
my $dir_state = shift;
my $img_state = shift;
my @out = ();
push @out, "\n";
# path array contains basenames from the top dir
# down to the current dir
my @path = split(/[\/\\]/, $dir_state->{dir});
unshift @path, $self->{top_base};
# we want to create relative links to all the dirs
# including the current one, so work backwards
my %uplinks = ();
my $uplink = '';
foreach my $dn (reverse @path)
{
$uplink .= '../';
$uplinks{$dn} = $uplink;
}
my @breadcrumb = ();
foreach my $dn (@path)
{
if ($uplinks{$dn})
{
push @breadcrumb, "
$dn";
}
else
{
push @breadcrumb, $dn;
}
}
push @out, '
';
push @out, $img_state->{cur_img};
push @out, "
\n";
push @out, '
';
push @out, join(' > ', @breadcrumb);
push @out, "
\n";
# now for the prev, next links
push @out, $self->make_image_prev_next(dir_state=>$dir_state,
img_state=>$img_state);
return join('', @out);
} # start_image_page
=head2 end_image_page
push @content, $self->end_image_page($dir_state, $img_state);
Create the end-of-page for an image page.
This contains page content, not full etc (that's expected
to be in the full-page template).
=cut
sub end_image_page {
my $self = shift;
my $dir_state = shift;
my $img_state = shift;
my @out = ();
# now for the prev, next links
push @out, $self->make_image_prev_next(dir_state=>$dir_state,
img_state=>$img_state,
use_thumb=>1);
push @out, "\n
\n";
return join('', @out);
} # end_image_page
=head2 make_image_prev_next
my $links = $self->make_image_prev_next(
dir_state=>$dir_state,
img_state=>$img_state);
Make the previous next other-image-pages links for the
given image-page. Generally called for the top and bottom
of the image page.
=cut
sub make_image_prev_next {
my $self = shift;
my %args = (
use_thumb=>0,
@_
);
my $dir_state = $args{dir_state};
my $img_state = $args{img_state};
my $img_num = $img_state->{num};
my @out = ();
if ($dir_state->{files} > 1)
{
push @out, '';
push @out, "\n";
# prev
push @out, "";
my $label = '< - prev';
my $iurl;
my $turl;
if ($img_num > 0)
{
$iurl = $self->get_image_pagename(dir_state=>$dir_state,
image=>$img_state->{images}->[$img_num - 1],
type=>'sibling');
$turl = $self->get_thumbnail_name(dir_state=>$dir_state,
image=>$img_state->{images}->[$img_num - 1],
type=>'sibling');
}
else
{
# loop to the last image
$iurl = $self->get_image_pagename(dir_state=>$dir_state,
image=>$img_state->{images}->[$#{$img_state->{images}}],
type=>'sibling');
$turl = $self->get_thumbnail_name(dir_state=>$dir_state,
image=>$img_state->{images}->[$#{$img_state->{images}}],
type=>'sibling');
}
push @out, "$label ";
if ($args{use_thumb})
{
push @out, " ";
}
push @out, " | ";
push @out, "";
$label = 'next ->';
if (($img_num+1) < @{$img_state->{images}})
{
$iurl = $self->get_image_pagename(dir_state=>$dir_state,
image=>$img_state->{images}->[$img_num + 1],
type=>'sibling');
$turl = $self->get_thumbnail_name(dir_state=>$dir_state,
image=>$img_state->{images}->[$img_num + 1],
type=>'sibling');
}
else
{
# loop to the first image
$iurl = $self->get_image_pagename(dir_state=>$dir_state,
image=>$img_state->{images}->[0],
type=>'sibling');
$turl = $self->get_thumbnail_name(dir_state=>$dir_state,
image=>$img_state->{images}->[0],
type=>'sibling');
}
if ($args{use_thumb})
{
push @out, " ";
}
push @out, " $label";
push @out, " | ";
push @out, "\n
";
push @out, "
\n";
}
return join('', @out);
} # make_image_prev_next
=head2 make_image_content
Make the content of the image page, the image itself.
=cut
sub make_image_content {
my $self = shift;
my $dir_state = shift;
my $img_state = shift;
my $img_name = $img_state->{cur_img};
my $caption = $self->get_caption(dir_state=>$dir_state,
img_state=>$img_state,
image=>$img_name);
my @out = ();
push @out, "\n";
my $width = $img_state->{info}->{width};
my $height = $img_state->{info}->{height};
push @out, "

\n";
push @out, "
$caption
\n";
push @out, "
\n";
return join('', @out);
} # make_image_content
=head2 make_image_title
Make the title for the image page.
This is expected to go inside a
in the page template.
=cut
sub make_image_title {
my $self = shift;
my $dir_state = shift;
my $img_state = shift;
my @out = ();
# title
push @out, $img_state->{cur_img};
return join('', @out);
} # make_image_title
=head2 make_image_style
Make the style tags for the image page. This will be put in the
part of the template.
=cut
sub make_image_style {
my $self = shift;
my $dir_state = shift;
my $img_state = shift;
my @out = ();
# style
push @out, <
.image {
text-align: center;
margin-left: auto;
margin-right: auto;
}
table.prevnext {
width: 100%;
}
td.prev {
text-align: left;
}
td.next {
text-align: right;
}
EOT
return join('', @out);
} # make_image_style
=head2 images_added_or_gone
Check to see if there are any new (or deleted) images in this
directory.
=cut
sub images_added_or_gone {
my $self = shift;
my $dir_state = shift;
my $dir = File::Spec->catdir($dir_state->{abs_dir}, $self->{thumbdir});
my @pics = @{$dir_state->{files}};
$self->debug(2, "dir: $dir");
# if the thumbnail directory doesn't exist, then either all images
# are new, or we don't have any images in this directory
if (!-d $dir)
{
return (@pics ? 1 : 0);
}
# Read the thumbnail directory
my $dirh;
opendir($dirh,$dir);
my @files = grep(!/^\.{1,2}$/, readdir($dirh));
closedir($dirh);
# check whether a picture has a thumbnail, and a thumbnail has a picture
my %pic_has_tn = ();
my %tn_has_pic = ();
# initialize to false
foreach my $pic ( @pics )
{
$pic_has_tn{$pic} = 0;
}
# Check each file to make sure it's a currently used thumbnail or image_page
foreach my $file ( @files )
{
my $name = $file;
if ($name =~ s/\.html$//)
{
# change the last underscore to a dot
$name =~ s/_([a-zA-Z0-9]+)$/.$1/;
if (exists $pic_has_tn{$name})
{
$pic_has_tn{$name} = 1;
$tn_has_pic{$name} = 1;
}
else
{
$tn_has_pic{$name} = 0;
print "$dir has unused image pages; needs cleaning\n" if $self->{verbose};
return 1;
}
}
elsif ($name =~ /(.+)\.jpg$/i) {
# Thumbnail?
$name = $1;
# change the last underscore to a dot
$name =~ s/_([a-zA-Z0-9]+)$/.$1/;
$self->debug(2, "thumb: $name");
if (exists $pic_has_tn{$name})
{
$pic_has_tn{$name} = 1;
$tn_has_pic{$name} = 1;
}
else
{
$tn_has_pic{$name} = 0;
print "$dir has unused thumbnails; needs cleaning\n" if $self->{verbose};
return 1;
}
}
} # for each file
# now check if there are pics without thumbnails
while (my ($key, $tn_exists) = each(%pic_has_tn))
{
if (!$tn_exists)
{
return 1;
}
}
return 0;
} # images_added_or_gone
=head2 get_image_info
Get the image information for an image. Returns a hash of
information.
%info = $self->get_image_info($image_file);
=cut
sub get_image_info {
my $self = shift;
my $img_file = shift;
my $info = image_info($img_file);
# add the basename
my ($basename, $path, $suffix) = fileparse($img_file, qr/\.[^.]*/);
$info->{file_basename} = $basename;
return $info;
} # get_image_info
=head2 debug
$self->debug($level, $message);
Print a debug message (for debugging).
Checks $self->{'debug_level'} to see if the message should be printed or
not.
=cut
sub debug {
my $self = shift;
my $level = shift;
my $message = shift;
if ($level <= $self->{'debug_level'})
{
my $oh = \*STDERR;
print $oh $message, "\n";
}
} # debug
=head1 Private Methods
Methods which may or may not be here in future.
=head2 _whowasi
For debugging: say who called this
=cut
sub _whowasi { (caller(1))[3] . '()' }
=head1 REQUIRES
Test::More
=head1 INSTALLATION
To install this module, run the following commands:
perl Build.PL
./Build
./Build test
./Build install
Or, if you're on a platform (like DOS or Windows) that doesn't like the
"./" notation, you can do this:
perl Build.PL
perl Build
perl Build test
perl Build install
In order to install somewhere other than the default, such as
in a directory under your home directory, like "/home/fred/perl"
go
perl Build.PL --install_base /home/fred/perl
as the first step instead.
This will install the files underneath /home/fred/perl.
You will then need to make sure that you alter the PERL5LIB variable to
find the modules, and the PATH variable to find the script.
Therefore you will need to change:
your path, to include /home/fred/perl/script (where the script will be)
PATH=/home/fred/perl/script:${PATH}
the PERL5LIB variable to add /home/fred/perl/lib
PERL5LIB=/home/fred/perl/lib:${PERL5LIB}
=head1 SEE ALSO
perl(1).
=head1 BUGS
Please report any bugs or feature requests to the author.
=head1 AUTHOR
Kathryn Andersen (RUBYKAT)
perlkat AT katspace dot com
http://www.katspace.org/tools
=head1 COPYRIGHT AND LICENCE
Copyright (c) 2006 by Kathryn Andersen
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
1; # End of HTML::KhatGallery::Core
__END__