1#!/usr/local/bin/perl -w 2# 3# Next Generation Pretty 4# 5# Copyright (C) 2006-2012 Kristian Gunstone 6# 7# A simple thumbnail and page generator which 8# uses common software to do the job. 9 10# This program is free software; you can redistribute it and/or modify 11# it under the terms of the GNU General Public License as published by 12# the Free Software Foundation; either version 2 of the License, or 13# (at your option) any later version. 14# 15# This program is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU General Public License for more details. 19# 20# You should have received a copy of the GNU General Public License 21# along with this program; if not, write to the Free Software 22# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23# 24# REQUIRED dependencies: 25# - Anything but Windows (fork won't work) 26# - kernel threading support 27# - perl > 5.8.x (untested on anything lower) 28# - fork perl module (use 'force install forks' in cpan) 29# - Image::ExifTool perl module (use 'force install Image::ExifTool' in cpan) 30# - Image::Magic (use 'force install Image::Magick' in cpan) 31# - Getopt::Long 32# 33# SUGGESTED dependencies: 34# mplayer (with as many codecs as possible) 35# (use 1.0pre7try2, 1.0pre9 has broken gif89a output) 36# display (comes with imagemagick) 37# jhead (for pre-processing) 38# 39# Pre-git Changelog: 40# n3.0/0.9 41# remove duplicate slashed in path 42# thread bug fix when calling jhead 43# template parser minor bugfixes 44# Fixed bug in recursive move 45# Fixed problem in listcalc 46# Incredibly, more bugfixes 47# MORE bugfixes 48# More bugfixes 49# Added --skip-pages 50# Replaced old thumb link code with code similar to prevs 51# Added side padding for thumb/preview link lists 52# Additional argument checks and minor bugfixes 53# n3.0/0.8 54# Modified progress output a little 55# Added config override support 56# Added overwrite support 57# Added template selection argument 58# Comment code bugfixes and cleanups 59# Switched to bsd_glob 60# Fixed bug in directory glob code 61# New tag NPRETTY_TITLE_NOEXIST and code 62# New tag NPRETTY_TITLE_EXIST and code 63# Fixed some problems with tag reading without images present 64# Fixed yet an other comment bug 65# Strip odd chars from filenames (see stripChars) 66# Fixed comment file location problem 67# Added -title argument 68# Fixed bug in thumbs/page calculation from a4 69# Added --destination argument 70# Added (almost) all new arguments to argument parser 71# Argument parser rewrite 72# Fixed bug in comment handler (would apply comment even if it was empty) 73# Fixed a bug in the delimiter + padding code (thanks uchman) 74# n3.0/0.7 75# Skip copying images if --skip-images is set 76# Modified preview list index tag code (Ree filed a complaint) 77# Modified comment tags and code as requested (thanks Ree) 78# Added delimiter padding tag and code (thanks Ree) 79# Fixed a problem with sloppy page creation on very small archives 80# Added preview list index tag and code (thanks Ree) 81# Got rid of zero-indexing on all output (pagenum, thumbnum, etc) 82# Added filesize tag 83# Resampling algorithm selection 84# Quality setting on JPEG/MIFF/PNG 85# Use EXIF-w/h if image is jpeg (speeds up thumb/preview creation) 86# Optimised use of magick object in thumb dimension read 87# Added a 'no video preview available' image and code 88# Using 'cp' for copy instead of builtin routines 89# Now using Image::Magick directly (not the convert binary) 90# width/height check fix 91# n3.0/0.6 92# Rewrote template parser 93# Added video support for previewing 94# --skip-images support (includes video) 95# n3.0/0.5 96# Change dimensions of preview image if larger than original 97# Preliminary video conversion support 98# preview aspect change (no arghandler yet) 99# Thumbnail delimiter code 100# Preprocessor (jhead) code 101# Template code 102# Sloppy page info correction (output was broken) 103# Preliminary thumb+preview generation 104# Proper output filename generation 105# n3.0/0.4 106# Page generation modes 107# Sloppy pages 108# n3.0/0.3 109# File permission read+write checks 110# Basic comment store/load 111# Configuration file support 112# FIX: recursive mode broke if dir did not contain subdirs 113# n3.0/0.2 114# Threading job support 115# Save/Load comment support 116# Preview image support 117# n3.0/0.1 118# Extensive permission checks before job starts 119# No session file 120# Recursive directory parsing 121# Argument parser 122# Simultaneous job handling 123# Comment support 124# 125#Notes: 126#files shouldn't have the same name as a directory 127# 128 129use strict; 130use Image::Magick; 131use Image::ExifTool 'ImageInfo'; 132use Getopt::Long; 133use File::Find; 134use forks; 135use Fcntl ':mode'; 136$SIG{CHLD} = 'DEFAULT'; # Needs to be set to IGNORE during forks 137 138### Arguments 139 140## Defaults 141my $templatefile = "npretty_template.tpl"; 142my $vid_converter_path = ""; 143my $img_path = "."; 144my $dest = "."; 145my $img_dest = "img"; 146my $thumb_dest = "thumbs"; 147my $prevpage_dest = "previews"; #NEW 0.5 148my $preview_dest = "$prevpage_dest/preview"; 149my $thumbpage_prefix = "index"; #Will have number and .html appended 150my $thumb_prefix = "_thumb_"; # Will be prepended with index id 151my $preview_prefix = "_preview_"; # Will be prepended with index id 152 153my $thumb_dimensions = "100x100"; 154my $preview_dimensions = "800x600"; 155my $video_preview_dimensions = "320x240"; 156my $image_quality = "85"; # JPEG/MIFF/PNG only 157my $resize_algorithm = "Box"; 158 # Point, Box, Triangle,Hermite, Hanning, 159 # Hamming, Blackman, Gaussian, Quadratic, 160 # Cubic, Catrom, Mitchell, Lanczos,Bessel, Sinc 161my $sidepad = ".. "; 162my $thumb_keep_aspect = 1; 163my $preview_keep_aspect = 1; 164my $recursive = 0; 165my $maxdepth = -1; 166my $comments = 0; 167my $overwrite = 0; 168my $overwrite_images = 0; 169my $overwrite_thumbs = 0; 170my $overwrite_previews = 0; 171my $jobs = 2; 172my $max_thumbs_per_page = 20; 173my $max_pages = 0; 174my $thumbnail_links = 9; 175my $preview_links = 9; 176my $pagebuild_type = 0; # 0 = number of thumbs, 1 = number of pages 177my $sloppy_mode = 0; 178my $sloppy_files = 3; 179my $generation_mode = 0; # 0 = all, 1 = images only, 2 = pages only 180my $show_preview = 0; # 0 = yes, 1 = no 181 # ^ for viewing images before commenting them 182my $use_vidconverter = 0; 183my $use_preprocessor = 0; 184my $pre_remove_cthumbs = 0; # Remove thumbnails in images 185my $pre_auto_rotate = 0; # Autorotate images 186 187my $delete_originals = 0; 188 189my $commentfile = ".npretty_comments"; 190my $no_video_image = "novideo.gif"; 191 192my $image_view = "display -resize 640x480+0+0 "; 193my $video_view = "mplayer "; 194my @configuration = (".npretty_config", "/home/$ENV{'USER'}/.npretty_config", "/usr/local/etc/npretty/npretty.conf"); 195 196## General 197my $VERSION = "n0.9.3-1"; 198my $vid_converter = "mplayer"; 199my $pre_processor = "jhead"; 200 201## Other 202my $title = ""; 203my $config = ""; 204 205my %filetypes = ( 206 "jpg" => "img", 207 "jpeg"=> "img", 208 "png" => "img", 209 "bmp" => "img", 210 "gif" => "img", 211 "tif" => "img", 212 "mpg" => "vid", 213 "mpeg"=> "vid", 214 "avi" => "vid"); 215 216my %overwritemodes = ("y" => 0, "n" => 1, "A" => 2, "N" => 3); # yes no All None 217 218my @arglist =( 219 "video-preview-dimensions= video preview dimensions XxY", 220 "image-quality= image quality in percent (JPEG/MIFF/PNG only)", 221 "resize-algorithm= resizing algorithm, set to 'help' for list", 222 "keep-thumb-ratio keep aspect ratio of thumbnails", 223 "keep-preview-ratio keep aspect ratio of previews", 224 "use-video use video converter", 225 "use-preprocessor use pre-processor", 226 "pre-remove-cthumbs remove cam thumbs with pre-processor", 227 "pre-auto-rotate auto-rotate images with pre-processor", 228 "jobs= jobs to run simultaneously", 229 "mplayer-path= path to 'mplayer' binary", 230 "image-path= path to images", 231 "image-dest= destination path for images", 232 "thumb-dest= destination path for thumbs", 233 "destination= destination prefix for archive", 234 "preview-dest= destination path for previews", 235 "thumb-dimensions= thumbnail dimensions, XxY", 236 "preview-dimensions= preview dimensions XxY", 237 "thumbs-per-page= max thumbs per page", 238 "pages= max number of pages", 239 "sloppy-files= be sloppy on page calculation", 240 "title= text to prepend to title tag", 241 "config= use config instead of config hierarchy", 242 "sidepad= string to pad thumb/preview lists with", 243 "delete-originals delete original images", 244 "overwrite-images overwrite images", 245 "overwrite-previews overwrite previews", 246 "overwrite-thumbs overwrite thumbnails", 247 "overwrite-all overwrite everything", 248 "overwrite-nothing overwrite nothing", 249 "template template file to use", 250 "skip-images skip image creation", 251 "skip-pages skip page creation", 252 "recursive recursively look for images", 253 "maxdepth traversal depth if recursive", 254 "comments ask for comment on each image", 255 "preview show preview before comment", 256 "sloppy enable sloppiness", 257 "help this text", 258 "version version"); 259 260# Do not fuck with these 261my $i; #Cough 262my @progmap = (); 263my @preview_dimension = (); # index-specific dimensions 264my $useoldcomments = 0; 265 266 267my @threadlist = (); 268my $finishedthreads = 0; 269 270my @badfiles = (); 271my @badfileperms = (); 272 273my @CARGV = (); 274my @page_index = (); 275my $internal_pages = (); # Need to be fixed? 276my $internal_thumbs = (); 277my $NTAG='<!-- Generated by npretty v'.$VERSION.' by gammy. https://github.com/gammy/npretty -->'."\n"; 278 279my @filelist = (); # Original file paths 280my @imglist = (); # New path and new names 281my @thumblist = (); # Thumbnail filenames 282my @prevpagelist = (); # Preview pages 283my @prevlist = (); # Preview filenames 284my %work; # <file> Contains bools, 1 to work, 0 to not. 285my @tmpargs = (); 286my @ov_list = (); 287my $mode; 288 289### Subroutines 290sub usage{ 291 my $padding; 292 print "Usage: npretty <arguments>\n"; 293 print "Example: npretty --image-path=.\n\n"; 294 print "Options:\n"; 295 foreach (@arglist){ 296 print "\t--$_\n"; 297 } 298 print " 299This is free software; see the source for copying conditions. There is NO 300warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; 301 302 exit 0; 303} 304 305sub init_thread{ 306 $threadlist[threads->list()] = threads->create("start_thread", @_); 307} 308 309sub start_thread{ 310 my ($message, $in, $arguments, $out) = @_; 311 print "$message"; 312 my $image = Image::Magick->new; 313 my $ret = $image->Read($in); 314 warn "$ret" if "$ret"; 315 #$ret = $image->Thumbnail(geometry=>"$arguments"); 316 $ret = $image->Resize(geometry=>"$arguments", filter=>"$resize_algorithm"); 317 warn "$ret" if "$ret"; 318 319 ## TEST 320 #$ret = $image->Annotate(font=>'kai.ttf', gravity=>"NorthWest", pointsize=>10, fill=>'white', text=>"zomg (C)"); 321 #warn "$ret" if "$ret"; 322 323 $ret = $image->Set(quality=>$image_quality); 324 warn "$ret" if "$ret"; 325 $ret = $image->Write($out); 326 warn "$ret" if "$ret"; 327 undef $image; 328 threads->self->detach(); 329 return; 330} 331 332sub init_sys_thread{ 333 $threadlist[threads->list()] = threads->create( 334 "start_sys_thread", 335 "$_[0]", 336 "$_[1]" 337 ); 338} 339 340sub start_sys_thread{ 341 print "$_[1]"; 342 system("$_[0]"); 343 threads->self->detach(); 344 return; 345} 346 347sub filesize{ 348 my $file = $_[0]; 349 open(FILE, "<$_[0]") or die "ERROR: Failed to open \"$_[0]\" for read (filesize check)"; 350 seek(FILE, 0, 2); 351 my $filesize = tell(FILE); 352 close(FILE); 353 return $filesize; 354} 355 356sub load{ 357 my ($buf, $filesize, $bytesread) = ("", 0, 0); 358 open(LOADDESC, "<$_[0]") or die "ERROR: Failed to open \"$_[0]\" for read"; 359 seek(LOADDESC, 0, 2); 360 $filesize = tell(LOADDESC); 361 seek(LOADDESC, 0, 0); 362 $bytesread = read(LOADDESC, $buf, $filesize, 0); 363 close(LOADDESC); 364 return "$buf"; 365} 366 367sub save{ 368 open(FILE, ">$_[0]") or die "ERROR: Failed to open \"$_[0]\" for write"; 369 print FILE $_[1]; 370 close(FILE); 371} 372 373sub replaceExifTags{ 374 my ($buf, $info) = @_; 375 376 if($buf=~m/\[NPRETTY_EXIF_.+?\]/){ 377 # Collect 378 my @exiflist; 379 while($buf=~m/\[NPRETTY_EXIF_(.+?)\]/g){ 380 push(@exiflist, $1); 381 } 382 foreach my $exif (@exiflist){ 383 my $found = 0; 384 my $replacement = "Missing"; 385 foreach my $cmp (sort keys %$info){ 386 if("$cmp" eq "$exif"){ 387 $found = 1; 388 last; 389 } 390 } 391 $replacement = $$info{$exif} if $found; 392 $buf =~s/\[NPRETTY_EXIF_$exif\]/$replacement/g; 393 } 394 }else{ 395 #print "DEBUG: No EXIF tags in block\n"; 396 } 397 398 return $buf; 399 400} 401 402sub replaceTags{ 403 my ($buf, %tag) = @_; 404 foreach my $r (sort keys %tag){ 405 my $repl = $tag{"$r"}; 406 $buf =~s/\Q$r\E/$repl/g; 407 } 408 return $buf; 409} 410 411sub setPreviewDimensions{ 412 my ($info, $offset, $image) = @_; 413 414 if("$progmap[$offset]" eq "vid"){ 415 $preview_dimension[$offset] = $video_preview_dimensions; 416 }else{ 417 my ($imgwidth, $imgheight) = (0, 0); 418 if(lc(substr($image, -4)) eq ".jpg" || lc(substr($image, -5)) eq ".jpeg"){ 419 ($imgwidth, $imgheight) = ($$info{'ImageWidth'}, $$info{'ImageHeight'}); 420 }else{ 421 my $magick = Image::Magick->new; 422 $magick->Read("$image"); 423 ($imgwidth, $imgheight) = $magick->Get('width', 'height'); 424 undef $magick; 425 } 426 427 my ($curwidth, $curheight) = (split("x", $preview_dimensions)); 428 #my ($imgwidth, $imgheight) = ($$info{"ImageWidth"}, $$info{"ImageHeight"}); 429 if($imgwidth < $curwidth && $imgheight < $curheight){ 430 $preview_dimension[$offset] = $imgwidth."x".$imgheight; 431 }else{ 432 $preview_dimension[$offset] = $preview_dimensions; 433 } 434 } 435} 436 437sub getPageName{ 438 my $thumbpage = $thumbpage_prefix; 439 $thumbpage .= sprintf("_%03d", $_[0]) if $_[0] != 1; 440 $thumbpage .= ".html"; 441 return $thumbpage; 442} 443 444sub stripChars{ 445 my $in = $_[0]; 446 my $out; 447 448 # Translation map for swedish iso-8859-1 letters 449 $in =~tr/���A��/aaoAAO/; 450 451 # Replace everything else except . 452 for(my $i = 0;$i < length($in); $i++){ 453 my $c = substr($in, $i, 1); 454 if("$c" ne "." && $c=~/[[^\W]|[^\D]]/){ 455 $c = "_"; 456 } 457 $out .= $c; 458 } 459 $out =~s/_+/_/g; 460 return $out; 461} 462 463sub askOverwrite{ 464 print "Overwrite? [y/n/A/N]"; 465 my $checkcomment = ""; 466 while("$checkcomment" ne 'y' && 467 "$checkcomment" ne 'n' && 468 "$checkcomment" ne 'A' && 469 "$checkcomment" ne 'N'){ 470 $checkcomment = <STDIN>; 471 chomp($checkcomment); 472 } 473 return $overwritemodes{$checkcomment}; 474} 475 476sub checkOverwrite{ 477 my $path = shift; 478 foreach(@_){ 479 my $filename = "$path$_"; 480 if(-f "$filename"){; 481 print "\"$filename\" already exists. "; 482 my $ret = askOverwrite(); 483 if($ret == 0){ # yes 484 push(@ov_list, $_); # With no path 485 }elsif($ret == 1){ #no 486 }elsif($ret == 2){ #All 487 foreach my $img (@_){ 488 my $ignore = 0; 489 foreach my $ignoreimg (@ov_list){ 490 if("$img" eq "$ignoreimg"){ 491 $ignore = 1; 492 last; 493 } 494 } 495 $work{$img} = 1 unless $ignore; 496 } 497 last; 498 }elsif($ret == 3){ #None 499 foreach my $img (@_){ 500 my $ignore = 0; 501 foreach my $ignoreimg (@ov_list){ 502 if("$img" eq "$ignoreimg"){ 503 $ignore = 1; 504 last; 505 } 506 } 507 if(-f "$path$img" && $ignore == 0){ 508 $work{$img} = 0; 509 }else{ 510 $work{$img} = 1; 511 } 512 } 513 last; 514 } 515 } 516 } 517 518 foreach(@ov_list){ 519 $work{$_} = $overwrite; 520 } 521} 522 523### Internal variable checks and setup 524 525### Main 526print "npretty v$VERSION by gamkiller.\n\n"; 527 528usage() if @ARGV == 0; 529 530## Extended argument parser (NEW) 531 532foreach my $arg (@ARGV){ 533 if("$arg" =~m/--config=(.+)/s){ 534 $config = $1; 535 @configuration = ("$1"); 536 }else{ 537 push(@tmpargs, $arg); 538 } 539} 540@ARGV = @tmpargs; 541@tmpargs = (); 542 543# Check for configfiles and prepend to arglist 544foreach (@configuration){ 545 if(-f "$_"){ 546 $mode = (stat("$_"))[2]; 547 die "Configuration file \"$_\" is unreadble" if ($mode & S_IRUSR) == 0; 548 open(FILE, "<$_"); 549 @tmpargs = <FILE>; 550 close(FILE); 551 chomp(@tmpargs); 552 s/\s+$// foreach @tmpargs; 553 @ARGV = (@tmpargs, @ARGV); 554 print "Prepended \"$_\" to argument list.\n"; 555 }else{ 556 die "Couldn't find config file \"$_\"\n" if "$config" ne ""; 557 } 558} 559 560# Note that --config is not in @ARGV since we pre-parsed it 561my $result = GetOptions( 562 "destination=s" => \$dest, 563 "jobs=i" => \$jobs, 564 "use-video" => \$use_vidconverter, 565 "use-preprocessor" => \$use_preprocessor, 566 "pre-remove-cthumbs"=> \$pre_remove_cthumbs, 567 "pre-auto-rotate" => \$pre_auto_rotate, 568 "image-quality=i" => \$image_quality, 569 "resize-algorithm=s"=> \$resize_algorithm, 570 "mplayer-path=s" => \$vid_converter_path, 571 "image-path=s" => \$img_path, 572 "image-dest=s" => \$img_dest, 573 "thumb-dest=s" => \$thumb_dest, 574 "preview-dest=s" => \$preview_dest, 575 "video-preview-dimensions=s"=> \$video_preview_dimensions, 576 "thumb-dimensions=s"=> \$thumb_dimensions, 577 "preview-dimensions=s"=> \$preview_dimensions, 578 "thumbs-per-page=i" => sub{$pagebuild_type = 0; $max_thumbs_per_page=$_[1];}, 579 "pages=i" => sub{$pagebuild_type = 1; $max_pages=$_[1];}, 580 "sloppy-files=i" => \$sloppy_files, 581 "title=s" => \$title, 582 "template=s" => \$templatefile, 583 "sidepad=s" => \$sidepad, 584 "delete-originals" => \$delete_originals, 585 "overwrite-images" => \$overwrite_images, 586 "overwrite-previews"=> \$overwrite_previews, 587 "overwrite-thumbs" => \$overwrite_thumbs, 588 "overwrite-all" => sub{$overwrite = 1;}, 589 "overwrite-nothing" => sub{$overwrite = 2;}, 590 "skip-images" => sub{$generation_mode = 2;}, 591 "skip-pages" => sub{$generation_mode = 1;}, 592 "recursive" => \$recursive, 593 "maxdepth=i" => \$maxdepth, 594 "keep-thumb-ratio" => \$thumb_keep_aspect, 595 "keep-preview-ratio"=> \$preview_keep_aspect, 596 "comments" => \$comments, 597 "preview" => \$show_preview, 598 "sloppy" => \$sloppy_mode, 599 "help" => sub{usage(); exit 0;}, 600 "version" => sub{exit 0;} 601); 602 603## Set commentfile 604$commentfile = "$dest/$commentfile"; 605 606## Check that args are within range 607die "Maximum number of jobs is 8 for your own safety" if $jobs < 1 or $jobs > 8; 608die "Incorrect thumbnail dimension format" unless $thumb_dimensions =~m/^[0-9]+?x[0-9]+?$/; 609die "Incorrect preview dimension format" unless $preview_dimensions =~m/^[0-9]+?x[0-9]+?$/; 610die "Incorrect video preview dimension format" unless $video_preview_dimensions =~m/^[0-9]+?x[0-9]+?$/; 611die "Incorrect image quality range" if $image_quality < 0||$image_quality > 100; 612 613if($recursive == 1) { 614 # No traversal limit unless the user explicitly set one using --maxdepth 615 $maxdepth = 0 if $maxdepth == -1; 616} else { 617 $maxdepth = 1; 618} 619 620my @resize_algorithms = qw(Point Box Triangle Hermite Hanning Hamming Blackman Gaussian Quadratic Cubic Catrom Mitchell Lanczos Bessel Sinc); 621if(lc($resize_algorithm) eq "help"){ 622 print "\nAvailable resizing algorithms: @resize_algorithms\n"; 623 exit 0; 624} 625my $exists = 0; 626foreach (@resize_algorithms){ 627 $exists = 1 if "$resize_algorithm" eq "$_"; 628} 629die "Incorrect resize algorithm. Algorithms: @resize_algorithms" unless $exists; 630undef $exists; 631undef @resize_algorithms; 632 633# Expand paths 634$img_path=~s/~/$ENV{'HOME'}/g; 635$dest=~s/~/$ENV{'HOME'}/g; 636$commentfile=~s/~/$ENV{'HOME'}/g; 637 638## Check existence 639die "\"$img_path\" is not a directory.\n" unless -d "$img_path"; 640$useoldcomments = 1 if -f "$commentfile"; 641 642my $found = 0; 643foreach("$templatefile", "$ENV{'HOME'}/$templatefile", "/usr/local/etc/npretty/$templatefile"){ 644 if(-f "$_"){ 645 $templatefile = $_; 646 $found = 1; 647 last; 648 } 649} 650die "Couldn't find template \"$templatefile\"" if $found == 0; 651print "Using \"$templatefile\" as template.\n\n"; 652 653$found = 0; 654foreach("$no_video_image", "$ENV{'HOME'}/$no_video_image", "/usr/local/etc/npretty/$no_video_image"){ 655 if(-f "$_"){ 656 $no_video_image = $_; 657 $found = 1; 658 last; 659 } 660} 661die "Couldn't find novideo image \"$no_video_image\"" if $found == 0; 662 663## Check external programs 664if($use_vidconverter){ 665 if(system("$vid_converter > /dev/null 2>&1") != 0){ 666 print "WARN: Failed to testrun video converter \"$vid_converter\", disabling video conversion.\n"; 667 $use_vidconverter = 0; 668 } 669} 670 671if($use_preprocessor){ 672 if(system("$pre_processor -V > /dev/null 2>&1") != 0){ 673 print "WARN: Failed to testrun pre-processor \"$pre_processor\", disabling pre-processing.\n"; 674 $use_preprocessor = 0; 675 } 676} 677 678## Check permissions 679 680# We have to create destination here to satisfy tests 681unless(-d "$dest"){ 682 print "Creating \"$dest\"..."; 683 die "Could not create \"$dest\"" if mkdir("$dest") != 1; 684 print "ok.\n"; 685}elsif(-e "$dest"){ 686 print "NOTE: \"$dest\" already exists.\n"; 687} 688# Prepend destination to destination variables 689my ($abs_img_dest, $abs_prevpage_dest, $abs_preview_dest, $abs_thumb_dest) = 690($img_dest, $prevpage_dest, $preview_dest, $thumb_dest); 691 692$thumb_dest = "$dest/$thumb_dest"; 693$img_dest = "$dest/$img_dest"; 694$prevpage_dest = "$dest/$prevpage_dest"; 695$preview_dest = "$dest/$preview_dest"; 696 697# Remove duplicate slashes in paths 698$thumb_dest =~s/\/+/\//g; 699$img_dest =~s/\/+/\//g; 700$prevpage_dest =~s/\/+/\//g; 701$preview_dest =~s/\/+/\//g; 702 703# image, thumb, preview and preview page destination check 704foreach ("$thumb_dest", "$img_dest", "$prevpage_dest", "$preview_dest", "$img_path"){ 705 unless(-d "$_"){ 706 die "\"$_\" exists but is not a directory" if(-e "$_"); 707 }else{ 708 $mode = (stat("$_"))[2]; 709 die "\"$_\" is not readable" if ($mode & S_IRUSR) == 0; 710 unless("$_" eq "$img_path"){ 711 die "\"$_\" is not writeable" if ($mode & S_IWUSR) == 0; 712 } 713 } 714} 715#FIXME: More checks here? 716#NOTE: File read+write checks are done after file list collection 717 718## Collection with recursive directory support (NEW) 719$| = 1; # Set canonical output 720#Get file list 721print "Compiling file list..."; 722$img_path = substr($img_path, 0, -1) if substr($img_path, (length($img_path) - 1), 1) eq "/"; 723File::Find::find({wanted => sub { 724 my $depth = $File::Find::name =~ tr#/##; # Count slashes 725 return if $maxdepth > 0 && $depth > $maxdepth; 726 if(-f) { 727 my $name = $File::Find::name; 728 for my $type (keys %filetypes) { 729 push @filelist, $name if 730 $name =~ m/\.\Q$type\E$/i; 731 } 732 733 } 734 }, 735 }, $img_path); 736print "ok.\n"; 737print @filelist . " files.\n"; 738 739#Check permissions on newly added files 740print "\n"; 741foreach (@filelist){ 742 $mode = (stat("$_"))[2]; 743 if( (($mode & S_IRUSR) == 0) || (($mode & S_IWUSR) == 0)){ 744 push(@badfiles, "$_"); 745 push(@badfileperms, $mode); 746 } 747} 748 749if(@badfiles > 0){ 750 print @badfiles . " did not have read+write permissions.\n"; 751 print "Correct these files:\n"; 752 print " # mode\tfile\n"; 753 for(my $i = 0; $i < @badfiles; $i++){ 754 printf("%4d: %04o\t%s\n", $i, ($badfileperms[$i] & 07777), $badfiles[$i]); 755 } 756 print "Cannot continue. Exit.\n"; 757 exit 1; 758} 759 760die "No files means nothing to do" if @filelist == 0; 761 762## Directory creation (except destination which was previously created) 763foreach ("$thumb_dest", "$prevpage_dest", "$preview_dest", "$img_dest"){ 764 unless(-d "$_"){ 765 print "Creating \"$_\"..."; 766 die "Could not create \"$_\"" if mkdir("$_") != 1; 767 print "ok.\n"; 768 }elsif(-e "$_"){ 769 print "NOTE: \"$_\" already exists.\n"; 770 } 771} 772 773## Generate new filenames for images, thumbnails, previews and preview pages 774# and map filetypes to decoders 775for(my $i = 0; $i < @filelist; $i++){ 776 my $s = rindex($filelist[$i], "/") + 1; 777 my ($directory, $filename) = (substr($filelist[$i], 0, $s), substr($filelist[$i], $s)); 778 my $prefix = sprintf("%03d", $i + 1); 779 780 $filename = stripChars($filename); 781 push(@progmap, $filetypes{lc(substr($filename, (rindex($filename, ".") + 1)))}); 782 783 push(@imglist, $prefix."_".$filename); 784 785 substr($filename, rindex($filename, "."), length($filename), ".gif") if "$progmap[$i]" eq "vid"; 786 push(@thumblist, "$prefix$thumb_prefix$filename"); 787 push(@prevlist, "$prefix$preview_prefix$filename"); 788 push(@prevpagelist, "$prefix$preview_prefix" . substr($filename, 0, rindex($filename, ".")) . ".html"); 789 790} 791 792## Check overwrite stuff, ugly :(. 793foreach(@imglist, @thumblist, @prevlist){ 794 if($overwrite == 2){ 795 $work{$_} = 0; 796 }else{ 797 $work{$_} = 1; 798 } 799} 800 801if($overwrite == 0 && $generation_mode != 2){ 802 checkOverwrite("$img_dest/", @imglist) unless $overwrite_images; 803 checkOverwrite("$preview_dest/", @prevlist) unless $overwrite_previews; 804 checkOverwrite("$thumb_dest/", @thumblist) unless $overwrite_thumbs; 805 806 if($overwrite_images){ 807 $work{$_} = 1 foreach (@imglist); 808 } 809 if($overwrite_previews){ 810 $work{$_} = 1 foreach (@prevlist); 811 } 812 if($overwrite_thumbs){ 813 $work{$_} = 1 foreach (@thumblist); 814 } 815} 816 817undef @ov_list; 818 819## Copy files to dest 820if($generation_mode != 2){ 821 for(my $i = 0; $i < @filelist; $i++){ 822 next unless $work{$imglist[$i]}; 823 print "$filelist[$i] -> $img_dest/$imglist[$i]\n"; 824 system("cp \"$filelist[$i]\" \"$img_dest/$imglist[$i]\""); 825 } 826} 827 828goto GENERATION if $generation_mode == 1; 829 830## Save/Load comments 831my %commenthash; 832 833if($comments == 0 and $useoldcomments == 1){ 834 print "\nA comment file was located but comments have been disabled.\n"; 835 print "Would you like to enable comments now? [y/n]"; 836 my $checkcomment = ""; 837 while(lc($checkcomment) ne 'y' && lc($checkcomment) ne 'n'){ 838 $checkcomment = <STDIN>; 839 chomp($checkcomment); 840 } 841 $comments = 1 if "$checkcomment" eq "y"; 842} 843if($comments == 1 and $useoldcomments == 1){ 844 print "\nFound commentfile, loading..."; 845 open(FILE, "<$commentfile"); 846 foreach (<FILE>){ 847 my $offset = index($_, "\t", 0); 848 if($offset == -1){ 849 print "\nWARN: A line in the commentfile is broken! Skipped."; 850 }else{ 851 $commenthash{substr($_, 0, $offset)} = substr($_, ($offset + 1)); 852 chomp($commenthash{substr($_, 0, $offset)}); 853 } 854 } 855 close(FILE); 856 print "ok.\n"; 857 print "Looking up files.\n"; 858 my $found; 859 for(my $j = 0; $j < @filelist; $j++){ 860 $found = 0; 861 foreach(keys %commenthash){ 862 if("$_" eq "$filelist[$j]"){ 863 $found = 1; 864 last; 865 } 866 } 867 if($found == 0){ 868 #FIXME: Replicated code 869 my $previewer = $image_view; 870 $previewer = $video_view if "$progmap[$j]" eq "vid"; 871 system("echo -n \"Previewing \\\"$filelist[$j]\\\"...\"; $previewer \"$filelist[$j]\" > /dev/null 2>&1 && echo \"ok\" || echo \"failed\"") if $show_preview == 1; 872 print "Comment " . ($j+1) . " ($filelist[$j]): "; 873 my $tmp = <STDIN>; 874 chomp($tmp); 875 $commenthash{$filelist[$j]} = $tmp; 876 # Save directly in case user interrupts 877 open(FILE, ">>$commentfile"); 878 print FILE "$filelist[$j]\t$tmp\n"; 879 close(FILE); 880 } 881 } 882}elsif($comments == 1 and $useoldcomments == 0){ 883 print "\n"; 884 for($i = 0; $i < @filelist; $i++){ 885 my $previewer = $image_view; 886 $previewer = $video_view if "$progmap[$i]" eq "vid"; 887 system("echo -n \"Previewing \\\"$filelist[$i]\\\"...\"; $previewer \"$filelist[$i]\" > /dev/null 2>&1 && echo \"ok\" || echo \"failed\"") if $show_preview == 1; 888 print "Comment " . ($i+1) . " ($filelist[$i]): "; 889 my $tmp = <STDIN>; 890 chomp($tmp); 891 $commenthash{$filelist[$i]} = $tmp; 892 # Save directly in case user interrupts 893 open(FILE, ">>$commentfile") or die "couldn't open \"$commentfile\"!"; 894 print FILE "$filelist[$i]\t$tmp\n"; 895 close(FILE); 896 } 897} 898 899if($comments){ 900 open(FILE, ">$commentfile"); 901 foreach (sort keys %commenthash){ 902 my $found = 0; 903 for(my $i = 0; $i < @filelist; $i++){ 904 $found = 1 if "$_" eq "$filelist[$i]"; 905 } 906 if($found){ 907 print FILE "$_\t$commenthash{$_}\n"; 908 }else{ 909 print "Removed $_ from commentfile.\n"; 910 } 911 } 912 close(FILE); 913} 914 915 916print "\nCalculating page layout.\n"; 917## Page pre-calculation 918if($pagebuild_type == 0){ # --thumbs-per-page 919 my $tmpimgcount = 0; 920 for(my $tmpcalc = 0; $tmpcalc < @imglist; $tmpcalc++){ 921 $tmpimgcount++; 922 if(($tmpcalc + 1) % $max_thumbs_per_page == 0){ 923 $internal_pages++; 924 push(@page_index, $tmpimgcount); 925 $tmpimgcount = 0; 926 } 927 } 928 if(@page_index * $max_thumbs_per_page != @imglist){ 929 push(@page_index, (@imglist - (@page_index * $max_thumbs_per_page))); 930 $internal_pages++; 931 } 932 if($page_index[$#page_index] <= $sloppy_files && $sloppy_mode == 1 && $#imglist > $max_thumbs_per_page){ 933 print "Being sloppy, moved $page_index[$#page_index] images to page " . ($internal_pages - 1) . ".\n"; 934 $page_index[($#page_index - 1)] += $page_index[$#page_index]; 935 pop(@page_index); 936 $internal_pages--; 937 } 938}elsif($pagebuild_type == 1){ # --max_pages 939 my $tmpimgcount = 0; 940 $internal_thumbs = int(@imglist / $max_pages); 941 die "ERROR: Fewer thumbs than requested number of pages! Bluntly assuming you made a mistake " if $internal_thumbs < 1; 942 for(my $tmpcalc = 0; $tmpcalc < $max_pages; $tmpcalc++){ 943 push(@page_index, $internal_thumbs); 944 $tmpimgcount += $internal_thumbs; 945 } 946 $page_index[$#page_index] += (@imglist - $tmpimgcount); 947}else{ # Fuckup 948 die "Internal error: Incorrect value in \$pagebuild_type ($pagebuild_type)"; 949} 950 951print "Generating preview and thumbnail pages.\n"; 952 953## Generate thumbnail and preview pages 954 955my $template_buf = load("$templatefile"); 956 957# Read in seperate template blocks 958my %template; 959foreach("THUMB", "BODY", "PREVIEW"){ 960 if($template_buf=~m/\[NPRETTY_BLOCK_$_\](.+?)\[\/NPRETTY_BLOCK_$_\]/s){ 961 $template{$_} = $1; 962 }else{ 963 die "ERROR: Required block $_ was not found in template"; 964 } 965} 966 967die "ERROR: Required block BODY not found in THUMB block" unless $template{"THUMB"} =~m/\[NPRETTY_BODY\]/; 968 969# Replace title tag 970$template{"THUMB"} =~s/\[NPRETTY_TITLE\]/$title/gs; 971$template{"BODY"} =~s/\[NPRETTY_TITLE\]/$title/gs; 972$template{"PREVIEW"} =~s/\[NPRETTY_TITLE\]/$title/gs; 973 974# Get image delimiter 975my ($delimiter, $img_delimiter_rep, $img_delimiter) = (0, 0, ""); 976if($template{"BODY"} =~s/\[NPRETTY_DEL_([0-9]+)\](.*?)\[\/NPRETTY_DEL\]//s){ 977 ($img_delimiter_rep, $img_delimiter) = ($1, $2); 978 last if $img_delimiter_rep == 0; 979 $delimiter = 1; 980 print "Delimiting every $img_delimiter_rep thumbnails.\n"; 981} 982 983# Get all extra buffers needed 984my %sub_template; 985foreach( 986 "PREV_EXIST", "PREV_NOEXIST", "LIST", "LIST_IFSEL", "NEXT_EXIST", "NEXT_NOEXIST", 987 "PREV_IMG_EXIST", "PREV_IMG_NOEXIST", "NEXT_IMG_EXIST", "NEXT_IMG_NOEXIST", 988 "COMMENT_EXIST", "PREV_LIST", "PREV_LIST_IFSEL", "PAD_DEL"){ #NPRETTY_TITLE_EXIST 989 foreach my $tplname ("THUMB", "BODY", "PREVIEW"){ 990 $sub_template{"$tplname$_"} = ""; # To prevent warnings 991 if($template{$tplname} =~m/\[(NPRETTY_$_\])(.*?)\[\/\1/s){ 992 $sub_template{"$tplname$_"} = $2; 993 } 994 } 995} 996 997# Grab delimiter padding 998my $delimiter_padding = $sub_template{"BODYPAD_DEL"}; 999 1000# Prepare the thumbnail linkindex lists 1001my $offset = 0; 1002my @linkindex = (); 1003my @prevlinkindex = (); 1004$offset = 0; 1005 1006my ($tsidepad, $psidepad) = ($sidepad, $sidepad); 1007$tsidepad = "" if $thumbnail_links > $#page_index; 1008$psidepad = "" if $preview_links > $#imglist; 1009 1010$preview_links = @imglist if $preview_links > @imglist; 1011$thumbnail_links = @page_index if $thumbnail_links > @page_index; 1012 1013my ($mincount, $maxcount) = (($preview_links - 1) / 2, ($preview_links + 1) / 2); 1014my ($lmincount, $lmaxcount) = (($thumbnail_links - 1) / 2, ($thumbnail_links + 1) / 2); 1015 1016for(my $pIndex = 1; $pIndex < (@page_index + 1); $pIndex++){ 1017 ## Thumbs 1018 my $thumblist = ""; 1019 my $linkindexbuf = ""; 1020 my $pIndexEx = $pIndex - 1; 1021 my ($lsidepad_left, $lsidepad_right) = ("", ""); 1022 my ($lbeg, $lend) = ($pIndexEx - $lmincount, $pIndexEx + $lmaxcount); 1023 if($lbeg < 1){ 1024 $lbeg = 0; 1025 $lend = $thumbnail_links; 1026 }else{ 1027 $lsidepad_left = $tsidepad; 1028 } 1029 if($lend > @page_index){ 1030 $lbeg = @page_index - $thumbnail_links; 1031 $lend = @page_index; 1032 }else{ 1033 $lsidepad_right = $tsidepad if $lend < @page_index; 1034 } 1035 1036 for(my $i = $lbeg; $i < $lend; $i++){ 1037 my $i_human = $i + 1; 1038 my $thumbpageEx = getPageName($i_human); 1039 my $current; 1040 if($i == $pIndexEx){ 1041 $current = $sub_template{"THUMBLIST_IFSEL"}; 1042 }else{ 1043 $current = $sub_template{"THUMBLIST"}; 1044 } 1045 $current =~s/\[NPRETTY_LIST_PAGE\]/$thumbpageEx/gs; 1046 $current =~s/\[NPRETTY_LIST_NUM\]/$i_human/gs; 1047 $linkindexbuf .= $current; 1048 } 1049 1050 $linkindexbuf = "$lsidepad_left$linkindexbuf$lsidepad_right"; 1051 push(@linkindex, $linkindexbuf); 1052 1053 ## Previews 1054 for(my $iIndex = 0; $iIndex < $page_index[$pIndex-1]; $iIndex++){ 1055 my ($sidepad_left, $sidepad_right) = ("", ""); 1056 my $prevlistbuf = ""; 1057 my ($beg, $end) = ($offset - $mincount, $offset + $maxcount); 1058 if($beg < 1){ 1059 $beg = 0; 1060 $end = $preview_links; 1061 }else{ 1062 $sidepad_left = $psidepad; 1063 } 1064 if($end > @imglist){ 1065 $beg = @imglist - $preview_links; 1066 $end = @imglist; 1067 }else{ 1068 $sidepad_right = $psidepad if $end < @imglist; 1069 } 1070 for(my $i = $beg; $i < $end; $i++){ 1071 my $i_human = $i + 1; 1072 my $current; 1073 if($i == $offset){ 1074 $current = $sub_template{"PREVIEWPREV_LIST_IFSEL"}; 1075 }else{ 1076 $current= $sub_template{"PREVIEWPREV_LIST"}; 1077 } 1078 $current =~s/\[NPRETTY_PREV_LIST_PAGE\]/$prevpagelist[$i]/gs; 1079 $current =~s/\[NPRETTY_PREV_LIST_NUM\]/$i_human/gs; 1080 $prevlistbuf .= $current; 1081 } 1082 $prevlistbuf = "$sidepad_left$prevlistbuf$sidepad_right"; 1083 push(@prevlinkindex, $prevlistbuf); 1084 $offset++; 1085 } 1086} 1087undef $offset; 1088$template{"THUMB"} =~s/\[(NPRETTY_LIST_IFSEL\]).*?\[\/\1//s; 1089$template{"THUMB"} =~s/\[(NPRETTY_PREV_NOEXIST\]).*?\[\/\1//s; 1090$template{"THUMB"} =~s/\[(NPRETTY_NEXT_NOEXIST\]).*?\[\/\1//s; 1091$template{"PREVIEW"} =~s/\[(NPRETTY_LIST_IFSEL\]).*?\[\/\1//s; 1092$template{"PREVIEW"} =~s/\[(NPRETTY_PREV_IMG_NOEXIST\]).*?\[\/\1//s; 1093$template{"PREVIEW"} =~s/\[(NPRETTY_NEXT_IMG_NOEXIST\]).*?\[\/\1//s; 1094$template{"PREVIEW"} =~s/\[(NPRETTY_PREV_LIST_IFSEL\]).*?\[\/\1//s; 1095$template{"BODY"} =~s/\[(NPRETTY_PAD_DEL\]).*?\[\/\1//s; 1096 1097print "\n"; 1098 1099my ($body_write_buf, $thumb_write_buf, $preview_write_buf); 1100 1101$offset = 0; 1102my $offset_human = $offset + 1; 1103for(my $pIndex = 0; $pIndex < @page_index; $pIndex++){ 1104 my $pIndex_human = $pIndex + 1; 1105 printf("Page %3d, %3d files:\n", $pIndex_human, $page_index[$pIndex]); 1106 1107 my $thumbpage = getPageName($pIndex_human); 1108 1109 $body_write_buf = ""; 1110 $thumb_write_buf = $template{"THUMB"}; 1111 # Add list index 1112 $thumb_write_buf =~s/\[(NPRETTY_LIST\]).*?\[\/\1/$linkindex[$pIndex]/s; 1113 1114 # Add previous/next page 1115 my %subtemplate_tag = ( 1116 '[NPRETTY_PREV_PAGE]' => getPageName($pIndex_human - 1), 1117 '[NPRETTY_NEXT_PAGE]' => getPageName($pIndex_human + 1), 1118 '[NPRETTY_PREV_PAGE_NUM]' => ($pIndex_human - 1), 1119 '[NPRETTY_NEXT_PAGE_NUM]' => ($pIndex_human + 1)); 1120 my ($ppagebuf, $npagebuf); 1121 if($pIndex == 0){ 1122 $ppagebuf = $sub_template{"THUMBPREV_NOEXIST"}; 1123 }else{ 1124 $ppagebuf = $sub_template{"THUMBPREV_EXIST"}; 1125 } 1126 if($pIndex == $#page_index){ 1127 $npagebuf = $sub_template{"THUMBNEXT_NOEXIST"}; 1128 }else{ 1129 $npagebuf = $sub_template{"THUMBNEXT_EXIST"}; 1130 } 1131 $ppagebuf = replaceTags($ppagebuf, %subtemplate_tag); 1132 $npagebuf = replaceTags($npagebuf, %subtemplate_tag); 1133 1134 $thumb_write_buf =~s/\[NPRETTY_PREV_EXIST\].*?\[\/NPRETTY_PREV_EXIST\]/$ppagebuf/s; 1135 $thumb_write_buf =~s/\[NPRETTY_NEXT_EXIST\].*?\[\/NPRETTY_NEXT_EXIST\]/$npagebuf/s; 1136 1137 #Title if it exists 1138 if("$title" ne ""){ 1139 $thumb_write_buf =~s/\[(NPRETTY_TITLE_EXIST\])(.*?)\[\/\1/$2/gs; 1140 $thumb_write_buf =~s/\[(NPRETTY_TITLE_NOEXIST\]).*?\[\/\1//gs; 1141 }else{ 1142 $thumb_write_buf =~s/\[(NPRETTY_TITLE_NOEXIST\])(.*?)\[\/\1/$2/gs; 1143 $thumb_write_buf =~s/\[(NPRETTY_TITLE_EXIST\])(.*?)\[\/\1//gs; 1144 } 1145 1146 for(my $iIndex = 0; $iIndex < $page_index[$pIndex]; $iIndex++){ 1147 my $iIndex_human = $iIndex + 1; 1148 my $image = $imglist[$offset]; 1149 1150 printf("%3d \"%s\"\n", $offset + 1, $image); 1151 # Get EXIF 1152 my $EXIF_info = ImageInfo("$filelist[$offset]"); 1153 setPreviewDimensions($EXIF_info, $offset, "$filelist[$offset]"); # FIXME might be moved later 1154 #print " (preview $preview_dimension[$offset])\n"; 1155 1156 my $line_buffer = $template{"BODY"}; 1157 $preview_write_buf = $template{"PREVIEW"}; 1158 1159 #Title if it exists 1160 if("$title" ne ""){ 1161 $preview_write_buf =~s/\[(NPRETTY_TITLE_EXIST\])(.*?)\[\/\1/$2/gs; 1162 $preview_write_buf =~s/\[(NPRETTY_TITLE_NOEXIST\]).*?\[\/\1//gs; 1163 }else{ 1164 $preview_write_buf =~s/\[(NPRETTY_TITLE_NOEXIST\])(.*?)\[\/\1/$2/gs; 1165 $preview_write_buf =~s/\[(NPRETTY_TITLE_EXIST\]).*?\[\/\1//gs; 1166 } 1167 1168 # Add preview ist index 1169 $preview_write_buf =~s/\[NPRETTY_PREV_LIST\].*?\[\/NPRETTY_PREV_LIST\]/$prevlinkindex[$offset]/s; 1170 1171 # Add previous/next preview page 1172 my %preview_tag; 1173 my ($pprevbuf, $nprevbuf); 1174 if($offset == 0){ 1175 $pprevbuf = $sub_template{"PREVIEWPREV_IMG_NOEXIST"}; 1176 $preview_tag{'[NPRETTY_PREV_IMG]'} = ""; 1177 $preview_tag{'[NPRETTY_PREV_IMG_NAME]'} = ""; 1178 }else{ 1179 $pprevbuf = $sub_template{"PREVIEWPREV_IMG_EXIST"}; 1180 $preview_tag{'[NPRETTY_PREV_IMG]'} = $prevpagelist[$offset - 1]; 1181 $preview_tag{'[NPRETTY_PREV_IMG_NAME]'} = $imglist[$offset - 1]; 1182 } 1183 if($offset == $#imglist){ 1184 $nprevbuf = $sub_template{"PREVIEWNEXT_IMG_NOEXIST"}; 1185 $preview_tag{'[NPRETTY_NEXT_IMG]'} = ""; 1186 $preview_tag{'[NPRETTY_NEXT_IMG_NAME]'} = ""; 1187 }else{ 1188 $nprevbuf = $sub_template{"PREVIEWNEXT_IMG_EXIST"}; 1189 $preview_tag{'[NPRETTY_NEXT_IMG]'} = $prevpagelist[$offset + 1]; 1190 $preview_tag{'[NPRETTY_NEXT_IMG_NAME]'} = $imglist[$offset + 1]; 1191 } 1192 $pprevbuf = replaceTags($pprevbuf, %preview_tag); 1193 $nprevbuf = replaceTags($nprevbuf, %preview_tag); 1194 1195 $preview_write_buf =~s/\[(NPRETTY_PREV_IMG_EXIST\]).*?\[\/\1/$pprevbuf/s; 1196 $preview_write_buf =~s/\[(NPRETTY_NEXT_IMG_EXIST\]).*?\[\/\1/$nprevbuf/s; 1197 1198 my $comment = ""; 1199 $comment = $commenthash{$filelist[$offset]} if $comments; 1200 1201 # Insert EXIF data 1202 $line_buffer = replaceExifTags($line_buffer, $EXIF_info); 1203 $preview_write_buf = replaceExifTags($preview_write_buf, $EXIF_info); 1204 1205 my %template_tag =( 1206 '[NPRETTY_SIZE]' => sprintf("%1.1fKiB", filesize("$filelist[$offset]") / 1024), 1207 '[NPRETTY_FILENAME]' => $image, 1208 '[NPRETTY_INDEX_NUM]' => $offset_human, 1209 '[NPRETTY_PAGE]' => $thumbpage, 1210 '[NPRETTY_THUMB]' => "$abs_thumb_dest/$thumblist[$offset]", 1211 '[NPRETTY_PREVIEW]' => "$abs_prevpage_dest/$abs_preview_dest/$prevlist[$offset]", 1212 '[NPRETTY_PREVIEW_PAGE]' => "$abs_prevpage_dest/$prevpagelist[$offset]", 1213 '[NPRETTY_IMAGE]' => "$abs_img_dest/$image", 1214 '[NPRETTY_COMMENT]' => $comment); 1215 1216 if($comments && "$comment" ne ""){ 1217 $preview_write_buf =~s/\[(NPRETTY_COMMENT_EXIST\]).*?\[\/\1/$sub_template{"PREVIEWCOMMENT_EXIST"}/s; 1218 }else{ 1219 $preview_write_buf =~s/\[(NPRETTY_COMMENT_EXIST\]).*?\[\/\1//s; 1220 } 1221 1222 $line_buffer = replaceTags($line_buffer, %template_tag); 1223 $template_tag{"[NPRETTY_PAGE]"} = "../$thumbpage"; 1224 $template_tag{"[NPRETTY_THUMB]"} = "../$thumblist[$offset]"; 1225 $template_tag{"[NPRETTY_PREVIEW]"} = "../$abs_preview_dest/$prevlist[$offset]"; 1226 $template_tag{"[NPRETTY_IMAGE]"} = "../$abs_img_dest/$image"; 1227 $preview_write_buf = replaceTags($preview_write_buf, %template_tag); 1228 1229 # Write preview page 1230 save("$prevpage_dest/$prevpagelist[$offset]", "$NTAG$preview_write_buf"); 1231 $body_write_buf .= $line_buffer; 1232 $body_write_buf .= $img_delimiter if $delimiter && ($iIndex + 1) != $page_index[$pIndex] && (($iIndex + 1) % $img_delimiter_rep) == 0; 1233 1234 $offset++; 1235 $offset_human = $offset + 1; 1236 1237 # Pad remaining blocks if endcount of thumbs is uneven 1238 if($delimiter && $iIndex == $page_index[$pIndex]-1){ 1239 my $remaining = $img_delimiter_rep - ($iIndex + 1) % $img_delimiter_rep; 1240 unless($remaining == $img_delimiter_rep){ 1241 for($i = 0; $i < $remaining; $i++){ 1242 $body_write_buf .= $delimiter_padding; 1243 } 1244 } 1245 } 1246 1247 } 1248 $thumb_write_buf=~s/\[NPRETTY_BODY\]/$body_write_buf/g; 1249 1250 # Write thumbnail page 1251 print "-> $thumbpage\n"; 1252 save("$dest/$thumbpage", "$NTAG$thumb_write_buf"); 1253 print "\n"; 1254} 1255 1256undef $body_write_buf; 1257undef $thumb_write_buf; 1258undef $preview_write_buf; 1259 1260## --skip-images? If so, we're all done. 1261if($generation_mode == 2){ 1262 print "Images skipped.\nDone.\n"; 1263 exit 0; 1264} 1265 1266GENERATION: 1267if($generation_mode == 1){ 1268 # We missed dimension info when we skipped pages 1269 for($offset = 0; $offset < @filelist; $offset++){ 1270 my $EXIF_info = ImageInfo("$filelist[$offset]"); 1271 setPreviewDimensions($EXIF_info, $offset, "$filelist[$offset]"); 1272 } 1273} 1274 1275# We don't need images any more, delete them if requested. 1276if($delete_originals){ 1277 print "Deleting original images.\n\n"; 1278 foreach(@filelist){ 1279 system("rm \"$_\""); 1280 } 1281} 1282 1283## Main loop should begin somewhere around here. 1284 1285## Argument setup for external programs 1286my ($thumb_conv_args, $pre_conv_args, $video_conv_args); 1287 1288$thumb_conv_args = "$thumb_dimensions"; 1289$thumb_conv_args .= "!" unless $thumb_keep_aspect; 1290 1291$pre_conv_args = "-exonly -se "; 1292$pre_conv_args .= "-dt " if $pre_remove_cthumbs; 1293$pre_conv_args .= "-autorot " if $pre_auto_rotate; 1294 1295#$video_conv_args = "-really-quiet -nosound -vo jpeg -frames 1"; 1296$video_conv_args = "-really-quiet -nosound -vo gif89a:5.0:$img_dest/tmpvid.gif -frames 50"; 1297 1298## Initialisation and running of threads 1299 1300my $PROGRESS = 1; 1301my $PROGRESS_MAX = @imglist; 1302 1303# Video conversion 1304 1305if($use_vidconverter){ 1306 print "Converting video frames to images.\n\n"; 1307 my $videos = 0; 1308 for(my $i = 0; $i < @imglist; $i++){ 1309 next unless("$progmap[$i]" eq "vid"); 1310 next unless $work{$imglist[$i]}; 1311 printf("%03d vid->img $img_dest/$imglist[$i]\n", $i); 1312 if(system("$vid_converter $video_conv_args \"$img_dest/$imglist[$i]\" > /dev/null 2>&1") == 0){ 1313 substr($imglist[$i], rindex($imglist[$i], "."), length($imglist[$i]), ".gif"); 1314 rename("$img_dest/tmpvid.gif", "$img_dest/$imglist[$i]"); 1315 }else{ 1316 substr($imglist[$i], rindex($imglist[$i], "."), length($imglist[$i]), ".gif"); 1317 print "WARN: conversion failed!\n"; 1318 system("cp \"$no_video_image\" \"$img_dest/$imglist[$i]\""); 1319 } 1320 unless(-e "$img_dest/$imglist[$i]"){ 1321 print "WARN: conversion failed!\n"; 1322 system("cp \"$no_video_image\" \"$img_dest/$imglist[$i]\""); 1323 } 1324 $videos++; 1325 } 1326 print "No videos to convert!\n" if $videos == 0; 1327}else{ 1328 my $videos = 0; 1329 for(my $i = 0; $i < @imglist; $i++){ 1330 next unless("$progmap[$i]" eq "vid"); 1331 printf("%03d missing video image ..\n", $i); 1332 substr($imglist[$i], rindex($imglist[$i], "."), length($imglist[$i]), ".gif"); 1333 system("cp \"$no_video_image\" \"$img_dest/$imglist[$i]\""); 1334 $videos++; 1335 } 1336 print "No videos to convert!\n" if $videos == 0; 1337 1338} 1339 1340#Set max number of threads to run 1341$jobs = @imglist if $jobs > @imglist; 1342 1343$finishedthreads = 0; 1344if($use_preprocessor){ 1345 print "\nPreprocessing.\n\n"; 1346 while($finishedthreads < @imglist){ 1347 if(threads->list() < $jobs){ 1348 my $cjob = "$pre_processor $pre_conv_args \"$img_dest/$imglist[$finishedthreads]\""; 1349 if($work{$imglist[$finishedthreads]}){ 1350 init_sys_thread("$cjob", "") if $work{$imglist[$finishedthreads]}; 1351 }else{ 1352 print "\"$img_dest/$imglist[$finishedthreads]\", skipped\n"; 1353 } 1354 $finishedthreads++; 1355 } 1356 } 1357 while(threads->list() != 0){}; 1358} 1359 1360$SIG{CHLD} = 'IGNORE'; 1361 1362my $workfile; 1363# Previews 1364print "\nGenerating previews.\n\n"; 1365$finishedthreads = 0; 1366while($finishedthreads < @imglist){ 1367 if(threads->list() < $jobs){ 1368 my $workfile = "$preview_dest/$prevlist[$finishedthreads]"; # . shift(@prevlist); 1369 my $prev_conv_args = "$preview_dimension[$finishedthreads]"; 1370 $prev_conv_args .= "!" unless $preview_keep_aspect; 1371 my @cjob = ("$img_dest/$imglist[$finishedthreads]", "$prev_conv_args", "$workfile"); 1372 my $output = sprintf("[%03d/%03d] %s", $PROGRESS, $PROGRESS_MAX, $workfile); 1373 if($work{$prevlist[$finishedthreads]}){ 1374 init_thread("$output\n", @cjob); 1375 }else{ 1376 print "$output, skipped (already exists)\n"; 1377 } 1378 1379 $finishedthreads++; 1380 $PROGRESS++; 1381 } 1382} 1383while(threads->list() != 0){}; 1384 1385 1386# Thumbnails 1387print "\nGenerating thumbnails.\n\n"; 1388$finishedthreads = 0; 1389$PROGRESS = 1; 1390while($finishedthreads < @imglist){ 1391 if(threads->list() < $jobs){ 1392 $workfile = "$thumb_dest/$thumblist[$finishedthreads]"; #. shift(@thumblist); 1393 my @cjob = ("$preview_dest/$prevlist[$finishedthreads]", "$thumb_conv_args", "$workfile"); 1394 my $output = sprintf("[%03d/%03d] %s", $PROGRESS, $PROGRESS_MAX, $workfile); 1395 if($work{$thumblist[$finishedthreads]}){ 1396 init_thread("$output\n", @cjob); 1397 }else{ 1398 print "$output, skipped (already exists)\n"; 1399 } 1400 $finishedthreads++; 1401 $PROGRESS++; 1402 } 1403} 1404while(threads->list() != 0){}; 1405 1406 1407$SIG{CHLD} = 'DEFAULT'; 1408print "\nDone.\n"; 1409