Image-Shoehorn-Gallery

 view release on metacpan or  search on metacpan

lib/Image/Shoehorn/Gallery.pm  view on Meta::CPAN

				                ],
                                   scale_if    => { x => 400 , y => 300 },
                                   iptc        => ["headline","caption/abstract"],
                                   set_lang    => "en-ca",
                                   set_styles  => {
                                                  image => [
                                                            {title=>"my css",href=>"/styles.css"},
                                                           ],
                                                 },
                                   set_index_images => { default => 1 },
    		                  });

=head1 DESCRIPTION

Image::Shoehorn::Gallery generates HTML slideshows from a directory of image files. But wait, there's more!

Image::Shoehorn uses I<XML::Filter::XML_Directory_2XHTML>, I<XML::SAX::Machines> and a small army of I<Image::*> packages allowing you to :

=over 4

=item *

Create one, or more, scaled versions of an image, and their associate HTML pages. Scaled version may also be defined but left to be created at a later date by I<Apache::Image::Shoehorn>.

Associate HTML are always "baked", rather than "fried" (see also : http://www.aaronsw.com/weblog/000404 )

=item *

Read a user-defined list of IPTC and EXIF metadata fields from each image and include the data in the HTML pages.

=item *

Generate named indices and next/previous links by reading IPTC "headline" data.

=item *

Define one, or more, SAX filters to be applied to "index" and individual "image" documents before they are passed the final I<XML::SAX::Writer> filter for output.

The default look and feel of the gallery pages is pretty plain, but you could easily define a "foofy design" XSL stylesheet to be applied with the I<XML::Filter::XSLT> SAX filter:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 version = "1.0" >

  <xsl:template match = "/">
  <html>
   <xsl:copy-of select = "html/head" />
   <body>

    <!-- lots of foofy design stuff -->
    <xsl:copy-of select = "/html/body/*" />
    <!-- lots of foofy design stuff -->

   </body>
  </html>
  </xsl:template>

 </xsl:stylesheet>

=item *

Generates valid XHTML (strict) and CSS!

=back

=cut

use strict;
package Image::Shoehorn::Gallery;

$Image::Shoehorn::Gallery::VERSION = '0.22';

use Carp;
use Carp::Heavy;
use Digest::MD5 qw (md5_hex);

use DirHandle;

use File::Basename;
use File::Copy;
use File::Path;

use Image::Shoehorn;
use Image::Size qw (imgsize);

use IO::File;
use XML::SAX::Writer;
use XML::Filter::XML_Directory_2XHTML;
use XML::Directory::SAX;

use XML::SAX::Machines qw (Pipeline);
$XML::SAX::ParserPackage = "XML::SAX::Expat";

#

my $directory = undef;
my $source    = undef;
my $dest      = undef;

my $url       = undef;

my $static    = undef;
my $scales    = {};
my $scaleif   = {};

my $views     = [];
my $iptc      = [];
my $exif      = [];

my $maxdepth  = undef;
my $encoding  = undef;
my $lang      = undef;

my $styles    = {};
my $filters   = {};
my $images    = {};

my $verbose   = 0;
my $force     = 0;

my $conf      = undef;

lib/Image/Shoehorn/Gallery.pm  view on Meta::CPAN

    }
  }

  $visit --;
}

sub make_index {
  my $path = shift;

  print STDERR "[make-index] Making $path\n"
    if ($verbose);

  $cur_source = $path;
  $cur_dest   = __PACKAGE__->source_to_dest($path);

  #

  my $src = __PACKAGE__->source_to_dest($path);

  print STDERR "Making '$cur_dest'..."
    if ($verbose);

  if ((! -d $cur_dest) && (! mkpath($cur_dest,0,0755))) {
    print STDERR "Failed to make '$cur_dest', $!\n";
    return 0;
  }

  print STDERR "ok\n"
    if ($verbose);

  #

  my $html = $cur_dest."/index.html";
  my $tmp  = $html.".tmp";

  #

  my $output  = IO::File->new(">$tmp");

  if (! $output) {
    carp "Failed to open '$tmp' for writing, $!\n";
    return 0;
  }

  #

  my $writer  = XML::SAX::Writer->new(Output=>$output);

  my $filters = __PACKAGE__->filters("index");

  my $machine = Pipeline(
			 "LocalSAX_FloatingThumbs",
			 "LocalSAX_Breadcrumbs",
			 ((scalar(@{$filters})) ? @{$filters} : ()),
			 $writer);

  #

  # This is broken, I know.
  # There appears to be some degree of funkiness going
  # on with the inheritance chain for 2XHTML that is 
  # preventing the SAX::Machine from getting the output
  # of 2XHTML and passing it on to $writer. I think, anyway.

  my $xhtml = XML::Filter::XML_Directory_2XHTML->new(Handler=>$machine);

  $xhtml->debug(0);

  if ($encoding) {
    $xhtml->set_encoding($encoding);
  }

  if ($lang) {
    $xhtml->set_lang($lang);
  }

  $xhtml->exclude_root(1);
  $xhtml->exclude(
		  starting => ["\\."],
		  ending   => ["html","tmp","~"],
		  matching => ["^(.*)-(".join("|","thumb",@{$views}).")\.([^\.]+)\$"],
		 );

  #

  my $css = __PACKAGE__->styles("index");

  if (scalar(@$css)) {
    $xhtml->set_styles($css);
  }

  else {
    $xhtml->set_style(\qq(
body {
  background-color: #ffffff;
  margin:0;
}

.breadcrumbs {
 display:block;
  background-color: #f5f5dc;
  padding:5px;
  margin-bottom:5px;
  border-bottom: solid thin;
}

.breadcrumbs-spacer {

}

.directory { margin:10px;float:left; padding: 5px;}

.file      { margin:10px;float:left;padding: 5px;}

.spacer { clear:both; }

.thumbnail { display:block;width:100px;float:left;}

.file ul   { float:left;}

));
  }

lib/Image/Shoehorn/Gallery.pm  view on Meta::CPAN

This is free software, you may use it and distribute it under the same terms as Perl itself.

=cut

package MyXSLT;
use base qw (XML::Filter::XSLT::LibXSLT);

sub set_stylesheet_parameters {
    my $self   = shift;
    my %params = @_;

    if (keys %params) {
	map { push @{$self->{'__params'}},&XML::LibXSLT::xpath_to_string($_=>$params{$_}) } keys %params;
    }
}

sub set_stylesheet_string {
  my $self = shift;
  $self->{Source}{String} = $_[0];
}

# No point until I figure out how
# to pass the filehandles :-(

#sub set_stylesheet_fh {
#  my $self = shift;
#  $self->{Source}{ByteStream} = $_[0];
#}

sub end_document {
    my $self = shift;

    my $dom = $self->XML::LibXML::SAX::Builder::end_document(@_);

    # This is so fucking stupid, but there are bugs
    # somewhere in all the magic that handles XHTML
    # and XSLT so...

    my $parser = XML::LibXML->new;
    $dom = $parser->parse_html_string($dom->toString());

    my $xslt       = XML::LibXSLT->new;
    my $stylesheet = $xslt->parse_stylesheet($self->{StylesheetDOM});

    my $results = $stylesheet->transform($dom,((ref($self->{'__params'}) eq "ARRAY") ? @{$self->{'__params'}} : ()));

    my $parser = XML::LibXML::SAX::Parser->new(%$self);
    $parser->generate($results);
}

package LocalSAX_Image;
use base qw (XML::SAX::Base);

use File::Basename;
use Image::Size qw (imgsize);
use Image::Info;

my $possible_views;

use constant DTD_HTML_ROOT     => "html";
use constant DTD_HTML_PUBLICID => "-//W3C//DTD XHTML 1.0 Strict//EN";
use constant DTD_HTML_SYSTEMID => "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";

sub xml_decl {
  my $self = shift;
  $self->SUPER::xml_decl({
			  Version  => "1.0",
			  Encoding => (Image::Shoehorn::Gallery->encoding() || "UTF-8")
			 });

  # If you're wondering what is going on here,
  # see the note in the STYLESHEET package.

  $self->SUPER::start_dtd({Name=>DTD_HTML_ROOT,
			   PublicId=>DTD_HTML_PUBLICID,
			   SystemId=>DTD_HTML_SYSTEMID});
  $self->SUPER::end_dtd();
}

sub start_document {
  my $self = shift;

  $self->{'__styles'} = scalar(@{Image::Shoehorn::Gallery->styles("image")});
  $possible_views = join("|",@{Image::Shoehorn::Gallery->views()});

  $self->SUPER::start_document(@_);
}

sub start_element {
    my $self = shift;
    my $data = shift;

    $self->{'__last'} = $data->{Name};

    #

    if (($data->{Name} eq "html") && (Image::Shoehorn::Gallery->lang())) {

      $self->SUPER::start_prefix_mapping({Prefix=>"",NamespaceURI=>"http://www.w3.org/1999/xhtml"});

      $self->SUPER::start_element({Name=>"html",Attributes=>{
							     "{}lang" => {Name         => "lang",
									  Value        => Image::Shoehorn::Gallery->lang(),
									  Prefix       => "",
									  LocalName    => "lang",
									  NamespaceURI => "",
									 },
							     "{}xml:lang" => {
									      Name => "xml:lang",
									      Value => Image::Shoehorn::Gallery->lang(),
									      Prefix       => "xml",
									      LocalName    => "xml:lang",
									      NamespaceURI => "http://www.w3.org/1999/xhtml",
									    },
							    }});
      return 1;
    }

    if (($data->{Name} eq "style") && ($self->{'__styles'})){

      foreach my $style (@{Image::Shoehorn::Gallery->styles("image")}) {

lib/Image/Shoehorn/Gallery.pm  view on Meta::CPAN

    $exif{$path} = undef;
  }

  return $exif{$path};
}

sub test {
  my $pkg  = shift;
  my $path = shift;

  if (exists($views{$path})) {
    return $views{$path};
  }

  foreach my $view (@{Image::Shoehorn::Gallery->exif()}) {
    if ($exif{$path}->{$view}) {
      $views{$path} = 1;
      return 1;
    }
  }

  $views{$path} = 0;
  return 0;
}

package Breadcrumbs;

my %crumbs = ();
my %count  = ();

sub get {
  my $pkg = shift;

  if (! $_[0]) {
    return ([],1);
  }

  if (exists $crumbs{$_[0]}) {
    return ($crumbs{$_[0]},$count{$_[0]});
  }

  @{$crumbs{$_[0]}} = split("/",$_[0]);
  $count{$_[0]}     = scalar(@{$crumbs{$_[0]}});

  return ($crumbs{$_[0]},$count{$_[0]});
}

package STYLESHEET;
my $data = undef;

sub data {
  if ($data) { return $data; }
  while (<DATA>) { $data .= $_;  }
  return $data;
}

return 1;

# NOTE : we are not setting the public and system doctypes here
# because they cause even more weirdness with XML::LibXML and it's
# seeming inability to deal with XHTML files. I really don't get
# what's going on so we play a little game and set them event the 
# xml_decl event in the LocalSAX_Image filter is called next. Gah!

# NOTE ALSO : that this is also where we happen to set the encoding

__DATA__
<?xml version="1.0" encoding='iso-8859-1'?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version = "1.0" >

<xsl:output method = "xml" 
            indent = "yes" />

<xsl:param name = "id" />
<xsl:param name = "scales" />
<xsl:param name = "scale" />
<xsl:param name = "doscale" />
<xsl:param name = "static" />

<!-- ======================================================================
     ====================================================================== -->

 <xsl:variable name = "has_id">
  <xsl:choose>
   <xsl:when test = "/html/body/div[@id=$id]">1</xsl:when>
   <xsl:otherwise>0</xsl:otherwise>
  </xsl:choose>
 </xsl:variable>

   <xsl:variable name = "image">
    <xsl:value-of select = "/html/body/div[@id=$id]/div[@class='thumbnail']/img/@src" />
   </xsl:variable>

    <xsl:variable name  = "prev">
     <xsl:value-of select = "/html/body/div[@id=$id]/preceding-sibling::*[1][name()='div']/a/@href" />
    </xsl:variable>

    <xsl:variable name  = "next">
     <xsl:value-of select = "/html/body/div[@id=$id]/following-sibling::*[1][name()='div']/a/@href" />
    </xsl:variable>

    <xsl:variable name = "last" select = "count(/html/body/div[@class='file' or @class = 'directory'])" />

    <xsl:variable name = "prev_title">
     <xsl:choose>
      <xsl:when test = "$prev != ''">
       <xsl:value-of select = "/html/body/div[@id=$id]/preceding-sibling::*[1][@class='file' or @class = 'directory']/a" />
      </xsl:when>
      <xsl:otherwise>
       <xsl:value-of select = "/html/body/div[@class='file' or @class = 'directory'][$last]/a" />
      </xsl:otherwise>
     </xsl:choose>
    </xsl:variable>

      <xsl:variable name = "prev_href">
       <xsl:choose>
        <xsl:when test = "$prev != ''">
         <xsl:value-of select = "$prev" />
        </xsl:when>



( run in 0.968 second using v1.01-cache-2.11-cpan-39bf76dae61 )