[TriLUG] Digital Photos, Thumbnails, and Web Pages

William Sutton william at trilug.org
Tue Dec 6 06:38:17 EST 2005


While we're throwing home-grown scripts into the mix...

attached is a Perl script I wrote some time ago to archive phtoos/desktop 
wallpapers/graphic art/etc that I come up with...its chief features are 
the ability to specify the following:
- max thumb height
- max thumb width
- max thumbs per column
- max sample thumbs
- alternating row display colors to group similar items

plus it stores an md5sum hash of photo information so that you can add 
images to a directory and have them processed without reprocessing the 
entire thing....good if--like me--you have lots of photocds lying around

see the comments in the code for details

if the attachment gets stripped, you can retrieve it from wget 
http://trilug.org/~william/dl/index.pl

create a directory /home/your_name/gallery/scripts and drop the program in 
the scripts directory; your galleries go in /home/your_name/gallery 
(adjust in code to suit)

requires ImageMagick, Image::Magick (Perl module), and File::Slurp

I could make it use XML::Simple to take the input parameters as an XML 
file and Getopts::Long to take named parameters if that's your thing....

-- 
William Sutton


On Tue, 6 Dec 2005, John F. Davis wrote:

> On Mon, Dec 05, 2005 at 07:48:21AM -0500, Scott Chilcote wrote:
> > Hi Folks,
> > 
> > After taking several pictures at our Thanksgiving event last month, I 
> > got requests to send the pictures to some of my relatives.  I'm pretty 
> > sure they don't want thirty or so 3-megapixel images arriving in their 
> > mailboxes.
> > 
> ...
> stuff deleted
> ...
> > 
> > I'm looking for something basic.  I'd write it myself if I had less 
> > going on right now.
> > 
> > What are other people using to accomplish this?
> > 
> 
> Hello,
> 
> I wrote a simple script which generates thumbnails and creates web page
> with links to them in bash.  It does not generate the thumbnails on the
> fly.  Intead it simply creates them as permanent files on the disk.  In
> my opinion disk space is cheap now days, but cpu cycles and time are
> not.
> 
> If you are interested, here is the result
> 
> http://www.trilug.org/~davis/nov_30
> 
> and here is portion of the code:
> 
> Happy Trails,
> 
> John F. Davis
> 
> ...........................
> makepicpage.sh
> ..........................
> #!/bin/bash
> 
> page="index.html"
> >$page
> 
> cat ~/bin/template.head > $page
> 
> 
> printf "<Table>\n" >> $page
> let i=0;
> for filename  in *.jpg *.JPG  ; do
> 	test -f "$filename" || continue;
> 	[[ "$filename" != *-t.jpg ]] || continue;
> 	[[ "$filename" != *-t.JPG ]] || continue;
> 
> 	if ((i%5==0)) ; then 
> 		let j=0;
> 		printf "<TR>\n" >> $page
> 	else
> 		((j++))
> 	fi
> 
> 	printf "<TD>" >> $page
> 	stem=${filename%.*};
> 	extension=${filename##*.};
> 
> 	printf "<a href=\"%s\"><img src=\"%s\"></a>" "$filename" "$stem-t.$extension" >> $page
> 	printf "</TD>\n" >> $page
> 
> 	if ((j==4)) ; then 
> 		printf "</TR>\n" >> $page
> 	fi
> 
> 	((++i));
> 
> 	makethumbs.sh $filename ;
> 	if [[ $? -ne 0 ]] ; then
> 		echo "failure. makethumbs.sh failed."
> 		exit
> 	fi
> 
> done
> 
> 
> printf "</Tbody>\n" >> $page
> printf "</Table>\n" >> $page
> 
> cat ~/bin/template.footer >> $page
> 
> exit
> 
> .......................
> makethumbs.sh
> .......................
> 
> #!/bin/bash
> # check for proper parms
> if [ $# -ne 1 ] ; then
> 	echo "usage: $0 <input file> 
> 	echo "eg. $0 file1.jpg 
> fi
> 
> # find the file extension part
> #echo $1
> # %.* deletes one match of "period anything" from the end.
> stem=${1%.*}
> #  ##*. deletes as many matches of "anything period" that exist.
> extension=${1##*.}
> #echo $stem
> #echo $extension
> 
> 
> convert $1 -thumbnail 100x100 $stem-t.$extension
> if [ $? -ne 0 ] ; then
> 	echo "failure.  convert failed to convert file."
> 	exit
> fi
> 
> 
> 
-------------- next part --------------
#!/usr/bin/perl

use strict;
use Data::Dumper;
use File::Slurp;
use Image::Magick;

################################################################################
#
################################################################################

# notes:
# expects a directory structure of the following:
# /home/your_name/gallery
#   /photos
#       /2005-10-20
#       /2005-10-21
#       /2005-11-15
#   /art
#       /2004-05-30
#       /2004-07-19
#   ...

my $root      = "/home/your_name/gallery";      # top gallery directory
my $dump_file = "$root/scripts/dump.txt";       # Data::Dumper file
my $md5sum    = "/usr/bin/md5sum";              # md5sum program
my $catalog;

my $color0 = "FFFFFF";
my $color1 = "AAAAAA";

my $max_thumb_x      = 150;     # max allowable thumb width
my $max_thumb_y      = 150;     # max allowable thumb height
my $max_thumb_col    = 5;       # max thumbs per column
my $max_thumb_sample = 10;      # max number of sample thumbs on index pages
                                # (shows all thumbs on detail pages)

################################################################################
#
################################################################################

# preload a data file containing information about known images and thumbs;
# this stops us from reprocessing things;  the eval() reads a Data::Dumper
# formatted output
if (-e $dump_file)
{
    my $dump_data = read_file($dump_file);
    $dump_data =~ s/VAR1/catalog/;
    eval($dump_data);
}
else
{
    $catalog = {};
}

# operate per top directory
my @top_dirs = map { chomp($_); $_; } `ls -1 $root`;

foreach my $top_dir (@top_dirs)
{
    next unless (-d "$root/$top_dir");
    next if $top_dir eq "scripts";

    print "* working on $top_dir\n";

    my @gallery_dirs = map { chomp($_); $_; } `ls -1 $root/$top_dir`;

    # operate per gallery directory
    foreach my $gallery_dir (@gallery_dirs)
    {
        next unless (-d "$root/$top_dir/$gallery_dir");

        print "    * working on $top_dir - $gallery_dir\n";

        my @gallery_files =
          map { chomp($_); $_; } `ls -1 $root/$top_dir/$gallery_dir`;

        # operate per gallery file
        foreach my $gallery_file (@gallery_files)
        {
            next unless (-f "$root/$top_dir/$gallery_dir/$gallery_file");
            next if $gallery_file =~ m/\.html/;

            # rename if filename is mixed case
            if ($gallery_file ne lc($gallery_file))
            {
                print "            * lc($gallery_file)\n";
                my $new_file = lc($gallery_file);
                `mv $root/$top_dir/$gallery_dir/$gallery_file $root/$top_dir/$gallery_dir/$new_file`;
                $gallery_file = $new_file;
            }

            # see if we can skip the file
            my $sum = `$md5sum $root/$top_dir/$gallery_dir/$gallery_file`;
            chomp($sum);
            $sum =~ s/\s+.+$//;

            my $catalog_sum =
              $catalog->{$top_dir}->{$gallery_dir}->{$gallery_file}->{md5sum};

            #print "        * $catalog_sum ?= $sum\n";
            next if $catalog_sum eq $sum;

            print "        * working on $gallery_file\n";

            # analyze the file and catalog its data
            my $pm = new Image::Magick;
            $pm->Read("$root/$top_dir/$gallery_dir/$gallery_file");

            my $file_data = {
                             path           => "$root/$top_dir/$gallery_dir",
                             name           => $gallery_file,
                             height         => $pm->Get('height'),
                             width          => $pm->Get('width'),
                             'x-resolution' => $pm->Get('x-resolution'),
                             'y-resolution' => $pm->Get('y-resolution'),
                             'md5sum'       => $sum,
                            };

            $catalog->{$top_dir}->{$gallery_dir}->{$gallery_file} = $file_data;

            # now, operate on the data
            # need to create a thumbnail
            my $thumbnail = "$root/$top_dir/$gallery_dir/thumb/$gallery_file";
            unless (-e $thumbnail)
            {
                unless (-d "$root/$top_dir/$gallery_dir/thumb/")
                {
                    print "            * making thumb dir\n";
                    `mkdir $root/$top_dir/$gallery_dir/thumb`;
                }

                my $scaling_factor = 0;
                if ($file_data->{width} > $file_data->{height})
                {
                    $scaling_factor = $max_thumb_y / $file_data->{width};
                }
                else
                {
                    $scaling_factor = $max_thumb_x / $file_data->{height};
                }
                my $scaled_x = int($file_data->{width} * $scaling_factor);
                my $scaled_y = int($file_data->{height} * $scaling_factor);

                $pm->Scale(width => $scaled_x, height => $scaled_y);
                $pm->Write($thumbnail);
            }
        }
    }
}

print "\n* saving catalog\n";
write_file($dump_file, Dumper($catalog));

print "\n\n";

#print Dumper $catalog;
print "* creating general index\n";
my @galleries = sort keys %{$catalog};

my $html = "";

foreach my $gallery (@galleries)
{
    print "* creating samples for $gallery\n";
    my $gallery_title   = "$gallery gallery";
    my @gallery_samples = undef;

    my $sample_count = 0;
    my $i            = 0;
    my $j            = 0;

    my $set_count = scalar keys %{$catalog->{$gallery}};

    foreach my $set (sort keys %{$catalog->{$gallery}})
    {
        last if ($sample_count == $max_thumb_sample);
        print "    * working on set $set\n";

        if ($j == $max_thumb_col)
        {
            $i++;
            $j = 0;
        }

        my @files = (
                     map { $catalog->{$gallery}->{$set}->{$_}; }
                       sort keys %{$catalog->{$gallery}->{$set}}
                    );

        $gallery_samples[$i][$j] = $files[0];
        $j++;
        $sample_count++;
    }

    $html .= <<END_HTML;
  <B>$gallery_title</B> <FONT SIZE="-1" COLOR="#666666">($set_count sets)</FONT><BR><BR>

  <TABLE CELLPADDING="5" CELLSPACING="0" BORDER="0">
END_HTML

    foreach my $row (@gallery_samples)
    {

        $html .= <<END_HTML;
  <TR>
END_HTML

        #print Dumper $row;
        foreach my $col (@{$row})
        {
            $html .= <<END_HTML;
    <TD VALIGN="CENTER" ALIGN="CENTER" HEIGHT="$max_thumb_y" WIDTH="$max_thumb_x"><A HREF="$root/$gallery/index.html"><IMG SRC="$col->{path}/thumb/$col->{name}" ALT="$col->{path}" BORDER="0"></A></TD>
END_HTML
        }

        $html .= <<END_HTML;
  </TR>
END_HTML

    }

    $html .= <<END_HTML;
  </TABLE>

  <BR>

END_HTML
}

write_file("$root/index.html", body_html("General Gallery Index", $html));

foreach my $gallery (@galleries)
{
    print "* creating index for $gallery\n";
    $html = "";

    my $gallery_title = "$gallery gallery";

    my $i = 0;
    my $j = 0;

    $html .= <<END_HTML;
  <B>$gallery_title</B><BR><BR>

  <TABLE CELLPADDING="5" CELLSPACING="0" BORDER="0">
END_HTML

    my $highlight = 1;
    my $group     = "";

    my @colors = ($color0, $color1);

    foreach my $set (sort keys %{$catalog->{$gallery}})
    {
        print "    * working on set $set\n";

        $set =~ m/^(\d+)-/;
        my $block = "$1";

        if ($block ne $group)
        {
            $group = $block;
            $highlight = ($highlight == 1 ? 0 : 1);
        }

        my @files = (
                     map { $catalog->{$gallery}->{$set}->{$_}; }
                       sort keys %{$catalog->{$gallery}->{$set}}
                    );
        my $pic_count = scalar(@files);

        $html .= <<END_HTML;
  <TR BGCOLOR="#$colors[$highlight]">
    <TD COLSPAN="$max_thumb_col"><I>$set set</I> <FONT SIZE="-1" COLOR="#000000">($pic_count pics)</FONT></TD>
  </TR>
  <TR BGCOLOR="#$colors[$highlight]">
END_HTML

        for (my $j = 0 ; $j < $max_thumb_col ; $j++)
        {
            if (!defined $files[$j])
            {
                $html .= <<END_HTML;
    <TD VALIGN="CENTER" ALIGN="CENTER" HEIGHT="$max_thumb_y" WIDTH="$max_thumb_x"></TD>
END_HTML
            }
            else
            {
                my $col = $files[$j];

                $html .= <<END_HTML;
    <TD VALIGN="CENTER" ALIGN="CENTER" HEIGHT="$max_thumb_y" WIDTH="$max_thumb_x"><A HREF="$col->{path}/index.html"><IMG SRC="$col->{path}/thumb/$col->{name}" ALT="$col->{path}" BORDER="0"></A></TD>
END_HTML
            }
        }

        $html .= <<END_HTML;
  </TR>
END_HTML
    }

    $html .= <<END_HTML;
  </TABLE>

  <BR>

END_HTML

    write_file("$root/$gallery/index.html", body_html($gallery_title, $html));
}

foreach my $gallery (@galleries)
{
    print "* working on gallery $gallery\n";

    my $i = 0;
    my $j = 0;

    foreach my $set (sort keys %{$catalog->{$gallery}})
    {
        print "    * working on set $set\n";

        my @files = (
                     map { $catalog->{$gallery}->{$set}->{$_}; }
                       sort keys %{$catalog->{$gallery}->{$set}}
                    );

        #print Dumper $catalog->{$gallery}->{$set};
        my $num_thumbs  = scalar(@files);
        my $thumb_count = 0;

        $html = <<END_HTML;
  <B>$set set</B><BR><BR>

  <TABLE CELLPADDING="5" CELLSPACING="0" BORDER="0">
END_HTML

        while ($thumb_count < $num_thumbs)
        {
            $html .= <<END_HTML;
      <TR>
END_HTML

            for (my $j = 0 ; $j < $max_thumb_col ; $j++)
            {
                if (!defined $files[$thumb_count])
                {
                    $html .= <<END_HTML;
        <TD VALIGN="CENTER" ALIGN="CENTER" HEIGHT="$max_thumb_y" WIDTH="$max_thumb_x"></TD>
END_HTML
                }
                else
                {
                    my $col = $files[$thumb_count];

                    $html .= <<END_HTML;
        <TD VALIGN="CENTER" ALIGN="CENTER" HEIGHT="$max_thumb_y" WIDTH="$max_thumb_x"><A HREF="$col->{path}/$col->{name}"><IMG SRC="$col->{path}/thumb/$col->{name}" ALT="$col->{path}" BORDER="0"></A></TD>
END_HTML
                }

                $thumb_count++;
            }

            $html .= <<END_HTML;
      </TR>
END_HTML
        }

        $html .= <<END_HTML;
  </TABLE>

  <BR>

END_HTML

        write_file("$root/$gallery/$set/index.html",
                   body_html("$set set", $html));
    }
}

################################################################################
#
################################################################################

sub body_html
{
    my $title = shift;
    my $body  = shift;

    my $HTML = <<END_HTML;
<HTML>
<HEAD>
  <TITLE>$title</TITLE>
</HEAD>
<BODY>
$body
</BODY>
</HTML>
END_HTML
}


More information about the TriLUG mailing list