#!/usr/bin/perl -w ####################################### # # Web Gallery Script for Nautilus / GTK Perl GUI # --- For use with ORIGINAL web gallery backend --- # http://jimmac.musichall.cz/original.php3 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 of # the License or (at your option) any later version. # # This program is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied warranty # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA # # Hacked together by Tuomas Kuosmanen # Tweaked to use NetPBM by Jakub Steiner # GTK Perl GUI hacked together by Justin Ribeiro # # Folder Tree taken and hacked from http://www-zeuthen.desy.de/computing/documentation/perl/gtkperl-tutorial/tut-29.html # # Requires GTK Perl, Gnome-Utils. # # Can be run from Nautilus script folder, by selecting image files, and # running script. Can be run standalone from command line or # launcher/shortcut for GUI. # ####################################### # Super Fast Causal Programming use strict; no strict "vars"; use Gtk; set_locale Gtk; init Gtk; ###################################### # # Set these variables for use with the GUI # ###################################### # Default Gallery Name my $DefaultGN = "Web-Gallery"; ###################################### # Setting the following to 0 will turn off the # default checkbox. By default, all checkboxes # are on (checked). ###################################### # Default Small Images Checkbox my $LQsw = 1; # Default Medium Images Checkbox my $MQsw = 1; # Default Large Images Checkbox my $HQsw = 1; # Default Comment Files Checkbox my $CFsw = 1; ###################################### ###################################### # Start Nautilus Action if we have file arguments ###################################### if (@ARGV) { @files = sort(@ARGV); my $dir = $DefaultGN; sub make_dirs { unless (-d "$dir") { mkdir("./$dir") or die "Aargh.\n"; } unless (-d "$dir/thumbs") { mkdir("./$dir/thumbs") or die "Aargh.\n"; } unless (-d "$dir/lq") { mkdir("./$dir/lq") or die "Aargh.\n"; } unless (-d "$dir/mq") { mkdir("./$dir/mq") or die "Aargh.\n"; } unless (-d "$dir/hq") { mkdir("./$dir/hq") or die "Aargh.\n"; } unless (-d "$dir/comments") { mkdir("./$dir/comments") or die "Aargh.\n"; } } sub make_gallery_fake { my $foo = shift; print ("PARAM: $foo\n"); sleep 1; } $w = new Gtk::Window; $label = new Gtk::Label(' Web Gallery generation in progress... '); $pbar = new Gtk::ProgressBar; $vb = new Gtk::VBox(0, 0); $b = new Gtk::Button('Cancel'); $w->add($vb); $vb->add($label); $vb->add($pbar); $vb->add($b); $b->signal_connect('clicked', sub {Gtk->exit(0)}); $w->signal_connect('destroy', sub {Gtk->exit(0)}); $w->show_all(); $i = 0; $pbar->update($i); @files = sort(@ARGV); $num_of_files = scalar @files; $increment = 1 / ( 5 * $num_of_files ); $i = 1; $progress = 0; make_dirs(); #read nautilus metafile if available open(METAXML, "./.nautilus-metafile.xml") or print("no metafile"); @meta_xml = ; close(METAXML); foreach $file (@files) { $pbar->update($progress); $pbar->set_show_text(1); $pbar->set_format_string("$i of $num_of_files"); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } # do the stuff, collect error messages to a variable. $reply=`convert -geometry 120x120 $file $dir/thumbs/img-$i\.jpg 2>&1`; $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } $reply = $reply . `convert -geometry 640x640 $file $dir/lq/img-$i.jpg 2>&1`; $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } $reply = $reply . `convert -geometry 800x800 $file $dir/mq/img-$i.jpg 2>&1`; $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } $reply = $reply . `cp $file $dir/hq/img-$i.jpg 2>&1`; $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } # comment open (COMM, ">$dir/comments/$i\.txt"); print(COMM "image $i: \n"); #check for comments in the metafile #maybe using a proper XML parser would make sense in future foreach $radek (@meta_xml) { chomp($radek); if ($radek =~ m/.*name="([^"]*)".*annotation="([^"]*).*"/) { if ($1 eq $file) { print(COMM "$2\n"); } } } close(COMM); $i++; # print possible error messages if ($reply ne "") { print("There was an error message: $reply\n"); } } ###################################### # End Nautilus Script Action ###################################### } else { ###################################### ## Start The GUI ###################################### my $false = 0; my $true = 1; my $window; my $box1; my $box2; my $button1; my $button2; my $label; my $CheckLQ; my $CheckMQ; my $CheckHQ; my $CheckCF; my $frame; my $table; my $tableCheckBoxes; my $tree_window; my $pane; my $vbox; my $tree_scrolled_win; my $list_scrolled_win; my $entry; my $tree; my $leaf; my $subtree; my $item; my $list; # Create the window $window = new Gtk::Window( "toplevel" ); $window->signal_connect( "delete_event", sub { Gtk->exit( 0 ); } ); $window->set_title( "O.R.I.G.I.N.A.L" ); $window->border_width( 5 ); $box1 = new Gtk::VBox( $false, 0 ); $box1->show(); $box2 = new Gtk::VBox( $false, 10 ); $box2->border_width( 10 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); $window->add( $box1 ); $table = new Gtk::Table( 2, 3, $false ); $table->set_row_spacings( 10 ); $table->set_col_spacings( 5 ); $box2->pack_start( $table, $true, $true, 0 ); # Image Directory Label $label = new Gtk::Label("Image Directory: "); $label->set_justify('left'); $table->attach( $label, 0, 1, 0, 1, "fill", "fill", 0,0 ); $label->show(); # Image Directory Text Entry $entryID = new Gtk::Entry( 50 ); $entryID->set_text( "" ); $entryID->show(); $table->attach( $entryID, 1, 2, 0, 1, "fill", "fill", 0,0 ); # Select Image Directory Button $button1 = new Gtk::Button( "Select..." ); $button1->signal_connect( "clicked", \&select_folder); $table->attach( $button1, 2, 3, 0, 1, "fill", "fill", 0,0 ); $button1->show(); ###### # create a label $label2 = new Gtk::Label("Gallery Name: "); $label2->set_justify('left'); $table->attach( $label2, 0, 1, 1, 2, "fill", "fill", 0,0 ); $label2->show(); # create album name entry $entry2 = new Gtk::Entry( 50 ); #$entry->signal_connect( "activate", \&enter_callback, $entry2->set_text( $DefaultGN ); $entry2->show(); $table->attach( $entry2, 1, 2, 1, 2, "fill", "fill", 0,0 ); $table->show(); # Settings $frame = new Gtk::Frame( "Gallery Creation Settings" ); $frame->set_label_align( 0.5, 0.0 ); $tableCheckBoxes = new Gtk::Table( 2, 2, $false ); $tableCheckBoxes->set_row_spacings( "5" ); $tableCheckBoxes->set_col_spacings( "5" ); $CheckLQ = new Gtk::CheckButton( "Small Images (640px)" ); $CheckLQ->set_active( $LQsw ); $tableCheckBoxes->attach( $CheckLQ, 0, 1, 0, 1, "fill", "fill", 0,0 ); $CheckLQ->show(); $CheckMQ = new Gtk::CheckButton( "Medium Images (800px)" ); $CheckMQ->set_active( $MQsw ); $tableCheckBoxes->attach( $CheckMQ, 0, 1, 1, 2, "fill", "fill", 0,0 ); $CheckMQ->show(); $CheckHQ = new Gtk::CheckButton( "Large Images (Original)" ); $CheckHQ->set_active( $HQsw ); $tableCheckBoxes->attach( $CheckHQ, 1, 2, 0, 1, "fill", "fill", 0,0 ); $CheckHQ->show(); $CheckCF = new Gtk::CheckButton( "Read Nautilus Metafile" ); $CheckCF->set_active( $CFsw ); $tableCheckBoxes->attach( $CheckCF, 1, 2, 1, 2, "fill", "fill", 0,0 ); $CheckCF->show(); $tableCheckBoxes->show(); $frame->add( $tableCheckBoxes ); $frame->show(); $box1->pack_start( $frame, $false, $true, 0 ); $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); $box1->pack_start( $box2, $false, $true, 0 ); $box2->show(); # Create the buttons $button1 = new Gtk::Button( "Create Gallery" ); $button1->signal_connect( "clicked", \&StartButtonEvent); $box2->pack_start( $button1, $true, $true, 0 ); $button1->show(); $window->show(); # Create the close button $button2 = new Gtk::Button( "Exit" ); $button2->signal_connect( "clicked", \&CancelButtonEvent ); $box2->pack_start( $button2, $true, $true, 0 ); $button2->show(); $window->show(); main Gtk; exit( 0 ); ##### # Start Creating Gallery sub StartButtonEvent { # Lets validate a few things first my $path = $entryID->get_text(); my $name = $entry2->get_text(); ValidateTime($path, $name); # Do we actually have images in the folder? GetImages($path); # Create directories CreateDirs($path, $name); # Create the images - @nfiles from GetImages() sub CreateImages(@nfiles); } sub ValidateTime { my ($path, $name) = @_; $togglebutton = $_[0]; if (! -d "$path") { error_message("Not a Directory", "\nThe directory name you entered isn't actually a directory. Please try another.\n"); } $name =~ s/^\s+//; $name =~ s/\s+$//; $name =~ tr/ /_/; $name =~ s/[&@!"'*\/\\\(\)\^=+,<>\[\]\{\};]//g; if (! $name){ error_message("Directory Blank", "\nThe directory name you entered can't be blank. Please try another.\n"); } elsif (-d "$path/$name") { error_message("Directory Exists", "\nThe directory name you entered already exists. Please try another.\n"); } else{ } my $LQtestnum = 0; my $MQtestnum = 0; my $HQtestnum = 0; my $CFtestnum = 0; if ( $CheckLQ->active ) { $LQtestnum++; } if ( $CheckMQ->active ) { $MQtestnum++; } if ( $CheckHQ->active ) { $HQtestnum++; } if ($LQtestnum == 0 && $MQtestnum == 0 && $HQtestnum == 0){ error_message("Nothing Checked", "\nMust have at least one image setting checked (small, medium, large). Please try again.\n"); } } # Need to get the images from the chosen directory sub GetImages { ($path) = @_; opendir(DIR, $path); my @files = readdir(DIR); closedir(DIR); opendir(DIR,"."); my $i = 0; # Need to only get images foreach $file (@files){ next if ($file =~ /^\./); next if !($file =~ /.jpg/ || $file =~ /.JPG/); $nfiles[$i] = $file; $i++; } my $nnum_of_files = scalar @nfiles; if ($nnum_of_files == 0) { error_message("No Images in Directory", "\nThe directory you choose doesn't seem to contain images. Please try another.\n"); } } # make the needed directories sub CreateDirs { my ($path, $dir) = @_; $togglebutton = $_[0]; unless (-d "$path/$dir") { mkdir("$path/$dir") or die "Could not create directory.\n"; } unless (-d "$path/$dir/thumbs") { mkdir("$path/$dir/thumbs") or die "Could not create thumbs directory.\n"; } if ( $CheckLQ->active ) { unless (-d "$path/$dir/lq") { mkdir("$path/$dir/lq") or die "Could not create LQ directory.\n"; } } if ( $CheckMQ-> active ) { unless (-d "$path/$dir/mq") { mkdir("$path/$dir/mq") or die "Could not create MQ directory.\n"; } } if ( $CheckHQ->active ) { unless (-d "$path/$dir/hq") { mkdir("$path/$dir/hq") or die "Could not create HQ directory.\n"; } } if ( $CheckCF->active ) { unless (-d "$path/$dir/comments") { mkdir("$path/$dir/comments") or die "Could not create Comments directory.\n"; } } } # Create Images sub CreateImages { my (@files) = @_; # so hacky...fix this Bub!!! my $path = $entryID->get_text(); my $dir = $entry2->get_text(); my $w; my $label; my $pbar; my $b; my $vb; my $i; $w = new Gtk::Window("toplevel"); $w->set_modal(1); $w->set_title( "Web Gallery Generation" ); $label = new Gtk::Label(' Web Gallery generation in progress... '); $pbar = new Gtk::ProgressBar; $vb = new Gtk::VBox(0, 0); $b = new Gtk::Button('Cancel'); $w->add($vb); $vb->add($label); $vb->add($pbar); $vb->add($b); $b->signal_connect('clicked', \&CancelButtonEvent ); $w->signal_connect('destroy', \&CancelButtonEvent ); $w->show_all(); $i = 0; $pbar->update($i); my $num_of_files = scalar @files; my $LQtestnum = 0; my $MQtestnum = 0; my $HQtestnum = 0; my $CFtestnum = 0; if ( $CheckLQ->active ) { $LQtestnum = 1; } if ( $CheckMQ->active ) { $MQtestnum = 1; } if ( $CheckHQ->active ) { $HQtestnum = 1; } if ( $CheckCF->active ) { $CFtestnum = 1; } my $IncFill = 1 + $CFtestnum + $HQtestnum + $MQtestnum + $LQtestnum; $increment = 1 / ( $IncFill * $num_of_files ); $i = 1; $progress = 0; if ( $CheckCF->active ) { #read nautilus metafile if available open(METAXML, "$path/.nautilus-metafile.xml") or print("no metafile"); @meta_xml = ; close(METAXML); } foreach $file (@files) { $pbar->update($progress); $pbar->set_show_text(1); $pbar->set_format_string("$i of $num_of_files"); #### Block 1 $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } # do the stuff, collect error messages to a variable. $reply=`convert -geometry 120x120 $path/$file $path/$dir/thumbs/img-$i\.jpg 2>&1`; if ( $CheckLQ->active ) { #### Block 2 $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } $reply = $reply . `convert -geometry 640x640 $path/$file $path/$dir/lq/img-$i.jpg 2>&1`; } if ( $CheckMQ->active ) { #### Block 3 $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } $reply = $reply . `convert -geometry 800x800 $path/$file $path/$dir/mq/img-$i.jpg 2>&1`; } if ( $CheckHQ->active ) { #### Block 4 $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } $reply = $reply . `cp $path/$file $path/$dir/hq/img-$i.jpg 2>&1`; } if ( $CheckCF->active ) { #### Block 5 $pbar->update($progress); $progress += $increment; while (Gtk->events_pending) { Gtk->main_iteration; } # comment open (COMM, ">$path/$dir/comments/$i\.txt"); print(COMM "image $i: \n"); #check for comments in the metafile #maybe using a proper XML parser would make sense in future foreach $radek (@meta_xml) { chomp($radek); if ($radek =~ m/.*name="([^"]*)".*annotation="([^"]*).*"/) { if ($1 eq $file) { print(COMM "$2\n"); } } } close(COMM); } $i++; } HideWEvent(); } # Exit the application sub CancelButtonEvent { Gtk->exit( 0 ); return $true; } # Tree Exit the application sub TreeCancelButtonEvent { $tree_window->hide; } # Start the Folder Tree sub select_folder { my $root_dir = "/"; my @titlet; $tree_window = new Gtk::Window("toplevel"); $tree_window->set_usize( 300, 400 ); $tree_window->set_title( "Select Image Folder" ); $tree_window->signal_connect( "delete_event", \&TreeCancelButtonEvent ); $pane = new Gtk::HPaned(); $tree_window->add( $pane ); $pane->set_handle_size( 10 ); $pane->set_gutter_size( 8 ); $pane->show(); # Create a VBox for the Entry and Tree Scrolled Window $vbox = new Gtk::VBox( $false, 0 ); $pane->add1( $vbox ); $vbox->show(); # Create the Text Entry $entry = new Gtk::Entry(); $vbox->pack_start( $entry, $false, $false, 4 ); $entry->signal_connect( 'activate', \&entry_activate ); $entry->show(); # Create a ScrolledWindow for the tree $tree_scrolled_win = new Gtk::ScrolledWindow( undef, undef ); $tree_scrolled_win->set_usize( 150, 400 ); $vbox->pack_start( $tree_scrolled_win, $true, $true, 0 ); $tree_scrolled_win->set_policy( 'automatic', 'automatic' ); $tree_scrolled_win->show(); # Create root tree $tree = new Gtk::Tree(); $tree_scrolled_win->add_with_viewport( $tree ); $tree->set_selection_mode( 'single' ); $tree->set_view_mode( 'item' ); $tree->show(); # Create root tree item widget $leaf = new_with_label Gtk::TreeItem( $root_dir ); $tree->append( $leaf ); $leaf->signal_connect( 'select', \&select_item, "/" ); $leaf->set_user_data( "/" ); $leaf->show(); # Create the subtree if ( has_sub_trees( $root_dir ) ) { $subtree = new Gtk::Tree(); $leaf->set_subtree( $subtree ); $leaf->signal_connect( 'expand', \&expand_tree, $subtree ); $leaf->signal_connect( 'collapse', \&collapse_tree ); $leaf->expand(); } $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); $vbox->pack_start( $box2, $false, $true, 0 ); $box2->show(); # Create the buttons $button1 = new Gtk::Button( "OK" ); $button1->signal_connect( "clicked", \&GrabFolderButtonEvent); $box2->pack_start( $button1, $true, $true, 0 ); $button1->show(); $tree_window->show(); # Create the close button $button2 = new Gtk::Button( "Cancel" ); $button2->signal_connect( "clicked", \&TreeCancelButtonEvent ); $box2->pack_start( $button2, $true, $true, 0 ); $button2->show(); $tree_window->show(); main Gtk; } ### Subroutines For Folder Tree # Taken from - http://www-zeuthen.desy.de/computing/documentation/perl/gtkperl-tutorial/tut-29.html sub expand_tree { my ( $item, $subtree ) = @_; my $dir; my $dir_entry; my $path; my $item_new; my $new_subtree; $dir = $item->get_user_data(); chdir( $dir ); foreach $dir_entry ( <*> ) { if ( -d $dir_entry ) { $path = $dir . "/" . $dir_entry; $path =~ s|//|/|g; $item_new = new_with_label Gtk::TreeItem( $dir_entry ); $item_new->set_user_data( $path ); $item_new->signal_connect( 'select', \&select_item, $path ); $subtree->append( $item_new ); $item_new->show(); if ( has_sub_trees( $path ) ) { $new_subtree = new Gtk::Tree(); $item_new->set_subtree( $new_subtree ); $item_new->signal_connect( 'expand', \&expand_tree, $new_subtree ); $item_new->signal_connect( 'collapse', \&collapse_tree ); } } } chdir( ".." ); } # Callback for collapsing a tree -- removes the subtree sub collapse_tree { my ( $item ) = @_; my $subtree = new Gtk::Tree(); $item->remove_subtree(); $item->set_subtree( $subtree ); $item->signal_connect( 'expand', \&expand_tree, $subtree ); } # Test whether a directory has subdirectories sub has_sub_trees { my ( $dir ) = @_; my $file; my $has_dirs = $false; foreach $file ( <$dir/*> ) { $has_dirs = $true if ( -d $file ); } return ( $has_dirs ); } # Called whenever an item is clicked on the tree widget. sub select_item { my ( $widget, $path ) = @_; my $file; $entry->set_text( $path ); } # Called when enter is pressed in the Entry widget sub entry_activate { my ( $entry ) = @_; my $file; my $path = $entry->get_text(); if ( -d $path ){ } else { $entry->set_text( "/" ); } } # Send the folder back sub GrabFolderButtonEvent { local $path = $entry->get_text(); $tree_window->hide; $entryID->set_text( $path ); } # Hide the Progress Window sub HideWEvent { $w->hide; } # Hide the Error Message Window sub HideButtonEvent { $dialog->hide; } # Error Window sub error_message{ my ($title, $message) = @_; $dialog = new Gtk::Dialog(); $dialog->set_modal(1); $dialog->set_title("Error: $title"); $buttonNW = new Gtk::Button( "OK" ); $buttonNW->signal_connect( "clicked", \&HideButtonEvent ); $dialog->action_area->pack_start( $buttonNW, $true, $true, 0 ); $buttonNW->show(); $labelNW = new Gtk::Label( "$message" ); $dialog->vbox->pack_start( $labelNW, $true, $true, 0 ); $labelNW->show(); $dialog->show(); main Gtk; } }