]> www.average.org Git - mkgallery.git/blobdiff - mkgallery.pl
most things done in new design, except image info
[mkgallery.git] / mkgallery.pl
index 138795edc8c1d8dd30570c794c5d9c113d4d988a..97f1fbc51efbb192ec9b39a0baf1c87058df227a 100755 (executable)
@@ -31,10 +31,25 @@ use Carp;
 use POSIX qw/getcwd/;
 use CGI qw/:html *table *center *div/;
 use Image::Info qw/image_info dim/;
+use Term::ReadLine;
+use Getopt::Long;
+
 use Image::Magick;
 
+my @sizes = (160, 640);
+
 ######################################################################
 
+my $debug = 0;
+my $asktitle = 0;
+my $noasktitle = 0;
+
+GetOptions('asktitle'=>\$asktitle,
+               'noasktitle'=>\$noasktitle,
+               'debug'=>\$debug);
+
+my $term = new Term::ReadLine "Edit Title";
+
 FsObj->new(getcwd)->iterate;
 
 sub new {
@@ -44,30 +59,57 @@ sub new {
        if (ref($this)) {
                $class = ref($this);
                my $parent = $this;
-               my $path = $parent->{-path};
                my $name = shift;
-               $path .= '/' if ($path);
-               $path .= $name;
                my $fullpath = $parent->{-fullpath}.'/'.$name;
-               $self = {-root=>$parent->{-root}, -path=>$path, -base=>$name,
-                               -fullpath=>$fullpath};
+               $self = {
+                               -parent=>$parent,
+                               -root=>$parent->{-root},
+                               -base=>$name,
+                               -fullpath=>$fullpath,
+                               -inc=>'../'.$parent->{-inc},
+                       };
        } else {
                $class = $this;
                my $root=shift;
-               $self = {-root=>$root, -fullpath=>$root};
+               $self = {
+                               -root=>$root,
+                               -fullpath=>$root,
+                               -inc=>getinc($root),
+                       };
        }
        bless $self, $class;
-       print "new $class: ($self->{-root}, $self->{-path}, $self->{-base}, $self->{-fullpath})\n";
+       if ($debug) {
+               print "new $class:\n";
+               foreach my $k(keys %$self) {
+                       print "\t$k\t=\t$self->{$k}\n";
+               }
+       }
        return $self;
 }
 
+sub getinc {
+       my $fullpath=shift;     # this is not a method
+       my $depth=20;           # arbitrary max depth
+
+       my $inc=".include";
+       while ( ! -d $fullpath."/".$inc ) {
+               $inc = "../".$inc;
+               last unless ($depth-- > 0);
+       }
+       if ($depth > 0) {
+               return $inc.'/';                # prefix with trailing slash
+       } else {
+               return 'NO-.INCLUDE-IN-PATH/';  # won't work anyway
+       }
+}
+
 sub iterate {
        my $self = shift;
        my $fullpath .= $self->{-fullpath};
-       print "iterate in dir $fullpath\n";
+       print "iterate in dir $fullpath\n" if ($debug);
 
-       my @rdirlist = ();
-       my @rimglist = ();
+       my @rdirlist;
+       my @rimglist;
        my $D;
        unless (opendir($D,$fullpath)) {
                warn "cannot opendir $fullpath: $!";
@@ -83,18 +125,78 @@ sub iterate {
                }
        }
        closedir($D);
-       my @sdirlist = sort {$a->{-base} cmp $b->{-base}} @rdirlist;
+       my @dirlist = sort {$a->{-base} cmp $b->{-base}} @rdirlist;
        undef @rdirlist; # inplace sorting would be handy here
-       my @simglist = sort {$a->{-base} cmp $b->{-base}} @rimglist;
+       my @imglist = sort {$a->{-base} cmp $b->{-base}} @rimglist;
        undef @rimglist; # optimize away unsorted versions
+       $self->{-firstimg} = $imglist[0];
+
+       print "Dir: $self->{-fullpath}\n" if ($debug);
+
+# 1. first of all, fill title for this directory and create hidden subdirs
+
+       $self->initdir;
 
-       foreach my $dir(@sdirlist) {
-               print "Dir: $dir->{-fullpath}\n";
+# 2. recurse into subdirectories to get their titles filled
+#    before we start writing out subalbum list
+
+       foreach my $dir(@dirlist) {
                $dir->iterate;
        }
-       foreach my $img(@simglist) {
-               print "Img: $img->{-fullpath}\n";
+
+# 3. iterate through images to build cross-links,
+
+       my $previmg = undef;
+       foreach my $img(@imglist) {
+               # list-linking must be done before generating
+               # aux html because aux pages rely on prev/next refs
+               if ($previmg) {
+                       $previmg->{-nextimg} = $img;
+                       $img->{-previmg} = $previmg;
+               }
+               $previmg=$img;
+       }
+
+# 4. create scaled versions and aux html pages
+
+       foreach my $img(@imglist) {
+               # scaled versions must be generated before aux html
+               # and main image index because they both rely on
+               # refs to scaled images and they may be just original
+               # images, this is not known before we try scaling.
+               $img->makescaled;
+               # finally, make aux html pages
+               $img->makeaux;
+       }
+
+# 5. start building index.html for the directory
+
+       $self->startindex;
+
+# 6. iterate through subdirectories to build subalbums list
+
+       if (@dirlist) {
+               $self->startsublist;
+               foreach my $dir(@dirlist) {
+                       $dir->sub_entry;
+               }
+               $self->endsublist;
+       }
+
+# 7. iterate through images to build thumb list
+
+       if (@imglist) {
+               $self->startimglist;
+               foreach my $img(@imglist) {
+                       print "Img: $img->{-fullpath}\n" if ($debug);
+                       $img->img_entry;
+               }
+               $self->endimglist;
        }
+
+# 8. comlplete building index.html for the directory
+
+       $self->endindex;
 }
 
 sub isdir {
@@ -114,10 +216,267 @@ sub isimg {
                }
                return 0;
        }
+       $self->{-isimg} = 1;
        $self->{-info} = $info;
        return 1;
 }
 
+sub initdir {
+       my $self = shift;
+       my $fullpath = $self->{-fullpath};
+       for my $subdir(@sizes, 'html') {
+               my $tdir=sprintf "%s/.%s",$self->{-fullpath},$subdir;
+               mkdir($tdir,0755) unless ( -d $tdir );
+       }
+       $self->edittitle;
+}
+
+sub edittitle {
+       my $self = shift;
+       my $fullpath = $self->{-fullpath};
+       my $title;
+       my $T;
+       if (open($T,'<'.$fullpath.'/.title')) {
+               $title = <$T>;
+               $title =~ s/[\r\n]*$//;
+               close($T);
+       }
+       if ($asktitle || (!$title && !$noasktitle)) {
+               my $prompt = $self->{-base};
+               $prompt = '/' unless ($prompt);
+               my $OUT = $term->OUT || \*STDOUT;
+               print $OUT "Enter title for $fullpath\n";
+               $title = $term->readline($prompt.' >',$title);
+               $term->addhistory($title) if ($title);
+               if (open($T,'>'.$fullpath.'/.title')) {
+                       print $T $title,"\n";
+                       close($T);
+               }
+       }
+       unless ($title) {
+               $title=substr($fullpath,length($self->{-root}));
+       }
+       $self->{-title}=$title;
+       print "title in $fullpath is $title\n" if ($debug);
+}
+
+sub makescaled {
+       my $self = shift;
+       my $fn = $self->{-fullpath};
+       my $name = $self->{-base};
+       my $dn = $self->{-parent}->{-fullpath};
+       my ($w, $h) = dim($self->{-info});
+       my $max = ($w > $h)?$w:$h;
+
+       foreach my $size(@sizes) {
+               my $nref = '.'.$size.'/'.$name;
+               my $nfn = $dn.'/'.$nref;
+               my $factor=$size/$max;
+               if ($factor >= 1) {
+                       $self->{$size} = $name; # unscaled version will do
+               } else {
+                       $self->{$size} = $nref;
+                       if (isnewer($fn,$nfn)) {
+                               doscaling($fn,$nfn,$factor,$w,$h);
+                       }
+               }
+       }
+}
+
+sub isnewer {
+       my ($fn1,$fn2) = @_;                    # this is not a method
+       my @stat1=stat($fn1);
+       my @stat2=stat($fn2);
+       return (!@stat2 || ($stat1[9] > $stat2[9]));
+       # true if $fn2 is absent or is older than $fn1
+}
+
+sub doscaling {
+       my ($src,$dest,$factor,$w,$h) = @_;     # this is not a method
+       my $im = new Image::Magick;
+       my $err;
+       print "doscaling $src -> $dest by $factor\n" if ($debug);
+       $err = $im->Read($src);
+       unless ($err) {
+               $im->Scale(width=>$w*$factor,height=>$h*$factor);
+               $err=$im->Write($dest);
+               warn "ImageMagick: write \"$dest\": $err" if ($err);
+       } else {        # fallback to command-line tools
+               warn "ImageMagick: read \"$src\": $err";
+               system("djpeg \"$src\" | pnmscale \"$factor\" | cjpeg >\"$dest\"");
+       }
+       undef $im;
+}
+
+sub makeaux {
+       my $self = shift;
+       my $name = $self->{-base};
+       my $dn = $self->{-parent}->{-fullpath};
+       my $pref = $self->{-previmg}->{-base};
+       my $nref = $self->{-nextimg}->{-base};
+       my $inc = $self->{-inc};
+       my $title = $self->{-info}->{'Comment'};
+       $title = $name unless ($title);
+
+       print "slide: \"$pref\"->\"$name\"->\"$nref\"\n" if ($debug);
+
+       # slideshow
+       for my $refresh('static', 'slide') {
+               my $fn = sprintf("%s/.html/%s-%s.html",$dn,$name,$refresh);
+               my $imgsrc = sprintf("../.%s/%s",$sizes[1],$name);
+               my $fwdref;
+               my $bakref;
+               if ($nref) {
+                       $fwdref = sprintf("%s-%s.html",$nref,$refresh);
+               } else {
+                       $fwdref = '../index.html';
+               }
+               if ($pref) {
+                       $bakref = sprintf("%s-%s.html",$pref,$refresh);
+               } else {
+                       $bakref = '../index.html';
+               }
+               my $toggleref;
+               my $toggletext;
+               if ($refresh eq 'slide') {
+                       $toggleref=sprintf("%s-static.html",$name);
+                       $toggletext = 'Stop!';
+               } else {
+                       $toggleref=sprintf("%s-slide.html",$name);
+                       $toggletext = 'Play-&gt;';
+               }
+               my $F;
+               unless (open($F,'>'.$fn)) {
+                       warn "cannot open \"$fn\": $!";
+                       next;
+               }
+               if ($refresh eq 'slide') {
+                       print $F start_html(-title=>$title,
+                                       -bgcolor=>"#808080",
+                                       -head=>meta({-http_equiv=>'Refresh',
+                                               -content=>"3; url=$fwdref"}),
+                                       -style=>{-src=>$inc."gallery.css"},
+                               ),"\n";
+                                       
+               } else {
+                       print $F start_html(-title=>$title,
+                                       -bgcolor=>"#808080",
+                                       -style=>{-src=>$inc."gallery.css"},
+                               ),"\n";
+               }
+               print $F start_center,"\n",
+                       h1($title),
+                       a({-href=>"../index.html"},"Index")," | ",
+                       a({-href=>$bakref},"&lt;&lt;Prev")," | ",
+                       a({-href=>$toggleref},$toggletext)," | ",
+                       a({-href=>$fwdref},"Next&gt;&gt;"),
+                       p,
+                       img({-src=>$imgsrc}),"\n",
+                       end_center,"\n",
+                       end_html,"\n";
+               close($F);
+       }
+}
+
+sub startindex {
+       my $self = shift;
+       my $fn = $self->{-fullpath}.'/index.html';
+       my $IND;
+       unless (open($IND,'>'.$fn)) {
+               warn "cannot open $fn: $!";
+               return;
+       }
+       $self->{-IND} = $IND;
+
+       my $inc = $self->{-inc};
+       my $title = $self->{-title};
+       print $IND start_html(-title => $title,
+                       -style=>{-src=>[$inc."gallery.css",
+                                       $inc."lightbox.css"]},
+                       -script=>[{-code=>"var incPrefix='$inc';"},
+                               {-src=>$inc."gallery.js"},
+                               {-src=>$inc."lightbox.js"}]),
+               a({-href=>"../index.html"},"UP"),"\n",
+               start_center,"\n",
+               h1($title),"\n",
+               "\n";
+}
+
+sub endindex {
+       my $self = shift;
+       my $IND = $self->{-IND};
+
+       print $IND end_center,end_html,"\n";
+
+       close($IND) if ($IND);
+       undef $self->{-IND};
+}
+
+sub startsublist {
+       my $self = shift;
+       my $IND = $self->{-IND};
+
+       print $IND h2("Albums"),"\n",start_table,"\n";
+}
+
+sub sub_entry {
+       my $self = shift;
+       my $IND = $self->{-parent}->{-IND};
+       my $name = $self->{-base};
+       my $title = $self->{-title};
+
+       print $IND Tr(td(a({-href=>$name.'/index.html'},$name)),
+                       td(a({-href=>$name.'/index.html'},$title))),"\n";
+}
+
+sub endsublist {
+       my $self = shift;
+       my $IND = $self->{-IND};
+
+       print $IND end_table,"\n",br({-clear=>'all'}),hr,"\n\n";
+}
+
+sub startimglist {
+       my $self = shift;
+       my $IND = $self->{-IND};
+       my $first = $self->{-firstimg}->{-base};
+       my $slideref = sprintf(".html/%s-slide.html",$first);
+
+       print $IND h2("Images"),
+               a({-href=>$slideref},'Slideshow');
+               "\n";
+}
+
+sub img_entry {
+       my $self = shift;
+       my $IND = $self->{-parent}->{-IND};
+       my $name = $self->{-base};
+       my $title = $self->{-info}->{'Comment'};
+       $title = $name unless ($title);
+       my $thumb = $self->{$sizes[0]};
+       my $medium = $self->{$sizes[1]};
+       my $info = $self->{-info};
+       my ($w, $h) = dim($info);
+
+       #print &infobox($info,$base,$fn),"\n";
+       print $IND table({-class=>'slide'},Tr(td(
+               a({-href=>".html/$name-info.html",
+                       -onClick=>"return showIbox('$name');"},$title),
+               br,
+               a({-href=>$medium,-rel=>"lightbox",-title=>$title},
+                       img({-src=>$thumb})),
+               br,
+               a({-href=>$name},"($w x $h)"),
+               br))),"\n";
+}
+
+sub endimglist {
+       my $self = shift;
+       my $IND = $self->{-IND};
+
+       print $IND br({-clear=>'all'}),hr,"\n\n";
+}
+
 ######################################################################
 =cut
 ######################################################################
@@ -167,7 +526,6 @@ sub processdir {
 
 # write HTML header
 
-       print start_html(-title => $title,
                        -style=>{-src=>[$inc."gallery.css",
                                        $inc."lightbox.css"]},
                        -script=>[{-code=>"var incPrefix='$inc';"},