Perl Photo Tools - Part 2. Resizing and the Database
Apr 27 2009 Programming

A bulk image resizer, and a script for entering them into a database.
Using MySQL, DBI, and Image Magick.  

I tried a php application which shall remain nameless but it didn't suit me. I didn't like the layout, the naming conventions or the directory structure. Additionally I don't like the idea of uploading to some place in the cloud and having someone else as authority over my precious photo collection.

Our directories are laid out like this.
'photos'
'photos - 200'
'photos - 400'
'photos to merge'
With new images going into 'photos to merge' and completed images to photos.

#!/usr/bin/perl

use warnings;
use strict;

# e dziewa july 2008
# create thumbs and such

use Image::Magick;

my $filesfrom = 'photos to merge';
my $filesto = 'photos - 200';
my ( @undone, @copyonly, @thumbundone );

do_jpg();

sub do_jpg {
    my ( $i, $j, $k, $l ) = 0;
    my $filename;
    opendir (DIRHANDLE, $filesfrom) or die "couldn't open $filesfrom:\n $!";

    while ( ($filename = readdir(DIRHANDLE))) {
        next if $filename =~ /^\.\.?$/;
        my ( $string, $string2, $basename ) = ();

        if ( ( $basename = $filename ) =~ s/^(.+)?\.[Jj][Pp][Gg]/$1/ ) {
            $string = "$filesfrom" . '/' . "$filename";
            $string2 = "$filesto" . '/' . "$basename" . ' - 200px.jpg';
            thumbit( $string, $string2 );
            $i++; print "\n$basename"; $l++;
        }

        elsif ( ( $basename = $filename ) =~ s/^(.+)?\.png/$1/ ) {
            $string = "$filesfrom" . '/' . "$filename";
            $string2 = "$filesto" . '/' . "$basename" . ' - 200px.png';
            thumbit( $string, $string2 );
            $j++; print "\n$basename"; $l++;
        }

        else {
            $k++; push( @undone, $filename ); $l++
        }
    }

    foreach ( @undone ) { print "\nbad filename -> $_" }
    foreach ( @copyonly ) { print "\ncopied -> $_" }
    foreach ( @thumbundone ) { print "\ncouldn't copy -> $_" }
    print "\nconverted \( $i jpg \) \( $j png \) $l total images.\n";
}

sub thumbit {
    my $inimg = Image::Magick->new;
    $inimg->Read($_[0]);

    my ($width, $height, $size, $format) = $inimg->Ping( $_[0] );
    if ( $width > 200 || $height > 200 ) {
        $inimg->AdaptiveResize( geometry=>'200x200' );
        $inimg->Comment( 'e. dziewa' );
        $inimg->Write("$_[1]");
    }

    elsif ( $inimg ) {
        $inimg->Comment( 'e. dziewa' );
        $inimg->Write("$_[1]");
        push( @copyonly, "$_[0] \( W -> $width \) \( H -> $height \)" );
    }

    else {
        push( @thumbundone, $_[0] );
    }
    undef $inimg;
}


Download 200
Download 400

I've split up the generating into 2 seperate files because they can take some time. After completion move the files from 'photos to merge' to photos manually. But before moving generate a listing of them with `ls -1 'photos to merge' > fileslist`.

The database structure.

CREATE TABLE `contents` (
  `id` smallint(4) unsigned NOT NULL auto_increment,
  `filename` varchar(255) NOT NULL,
  `webname` varchar(255) NOT NULL,
  `filesize` int(11) NOT NULL,
  `width` smallint(4) NOT NULL,
  `height` smallint(4) NOT NULL,
  `two_filename` varchar(255) NOT NULL,
  `two_webname` varchar(255) NOT NULL,
  `two_filesize` int(11) NOT NULL,
  `two_width` smallint(3) NOT NULL,
  `two_height` smallint(3) NOT NULL,
  `four_filename` varchar(255) NOT NULL,
  `four_webname` varchar(255) NOT NULL,
  `four_filesize` int(11) NOT NULL,
  `four_width` smallint(3) NOT NULL,
  `four_height` smallint(3) NOT NULL,
  PRIMARY KEY  (`id`)
)


Enter the data.


#!/usr/bin/perl

# e dziewa july 2008

use warnings;
use strict;

# print "you might want to sync time before adding photos\n";
# generate filelist with ls -1 directoryname > fileslist
# should do this within the previous script.

use Image::Magick;
my $filelist = 'fileslist';
my @fields;

my $na = 'null';
my $workingdir = '/absolutepath/photos/';
my $user = 'YOURuserNAME';
my $pass = 'YOURpass';
my $db = 'YOURdbNAME';
my $host = 'YOURhost';
use DBI;

my $i = 0;

open( IFH, "<", $filelist ) or die "couldn't open $filelist\n-> $!\n";
while ( <IFH> ) {
    chomp;
    my $twocopy = $_;
    my $fourcopy = $_;
    ( my $ext = $_ ) =~ s/^.+(.{4})$/$1/;

    setfields( $_ );

    stripext( $twocopy );
    $twocopy .= ' - 200px'; $twocopy .= $ext;
    $workingdir = 'photos - 200/';

    setfields( $twocopy );

    stripext( $fourcopy );
    $fourcopy .= ' - 400px'; $fourcopy .= $ext;
    $workingdir = 'photos - 400/';

    setfields( $fourcopy );
    insert();
    $i++; # slow -> print "$i  ";
    $workingdir = 'photos/';
}

close IFH;
print "\n $i records inserted\n";

sub insert {
    my $dbh = DBI->connect("DBI:mysql:database=$db;host=$host", "$user", "$pass", {'RaiseError' => 1}) or die "couldn't connect to $db\n$!\n";

    my $statement = $dbh->prepare("insert into contents (
        id,
        filename,
        webname,
        filesize,
        width,
        height,
        two_filename,
        two_webname,
        two_filesize,
        two_width,
        two_height,
        four_filename,
        four_webname,
        four_filesize,
        four_width,
        four_height
    )
    values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
    ");
    $statement->execute( $na, $fields[0], $fields[1], $fields[2], $fields[3], $fields[4], $fields[5], $fields[6], $fields[7], $fields[8], $fields[9], $fields[10], $fields[11], $fields[12], $fields[13], $fields[14]
    );
    $statement->finish();
    $dbh->disconnect();
    @fields = ();
}

sub stripext {
    chop $_[0]; chop $_[0]; chop $_[0]; chop $_[0];
}

sub setfields {
    $_ = $_[0];
    push( @fields, $_ );
    my $webname = $_;
    ( $webname = $webname ) =~ s/\&/\&amp;/g;
    # very bad and wrong ( $webname = $webname ) =~ s/ /\&nbsp;/g;
    push( @fields, $webname );
    my $size = -s $workingdir.$_;
    push( @fields, $size );
    my $img = Image::Magick->new;
    my ($width, $height, $sz, $format) = $img->Ping("$workingdir$_");
    push( @fields, $width );
    push( @fields, $height );
    undef $img;
}


Download

All the photos have been sized and the database is populated. Now we're ready for displaying. See Part 3.

   
Comments
No comments.
Comments for this entry available via RSS.
Comment Area
Your Name
Your Email (will not be published)
Your Website
Your Comment
Profanity is Prohibited
eric.dziewa.com is running WordPress.
WhiteSpace theme designed by E. Dziewa.
All content © E. Dziewa.
Thanks for stopping by.