diff options
author | Andy Shevchenko <andy@smile.org.ua> | 2006-10-06 11:54:08 +0000 |
---|---|---|
committer | Andy Shevchenko <andy@smile.org.ua> | 2006-10-06 11:54:08 +0000 |
commit | 03cc05032e79823648523bdd434d4f1b3d86a41b (patch) | |
tree | 29a13765f37f045b12b945d0a40877e76ae3aaa8 | |
parent | 32b6758f8688e0aea2210eb335bd9be6c8c79ff8 (diff) | |
download | renrot-03cc05032e79823648523bdd434d4f1b3d86a41b.tar.gz renrot-03cc05032e79823648523bdd434d4f1b3d86a41b.tar.bz2 |
Move main() to the end of file. Refactoring: configOptions -> cfgOpts.
Remove --color. Add 'use color' to configuration file ("use color = Yes" is default).
Processing message look tunned, now it shows '(m of n)' file processed.
Fix tag target in the Makefile.
Possible fix bug with clearing EXIFs when --no-backup is given
git-svn-id: file:///svnroot/renrot/branches/RENROT_STABLE@268 fe2816f4-e837-0410-b10a-f608c9d244a1
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Makefile.PL | 2 | ||||
-rw-r--r-- | README | 39 | ||||
-rw-r--r-- | TODO | 10 | ||||
-rw-r--r-- | etc/colors.conf | 3 | ||||
-rw-r--r-- | etc/renrot.conf | 2 | ||||
-rwxr-xr-x | renrot | 435 |
7 files changed, 263 insertions, 236 deletions
@@ -1,4 +1,11 @@ $Log$ +Revision 1.148.2.7 2006/10/06 11:54:08 andy +Move main() to the end of file. Refactoring: configOptions -> cfgOpts. +Remove --color. Add 'use color' to configuration file ("use color = Yes" is default). +Processing message look tunned, now it shows '(m of n)' file processed. +Fix tag target in the Makefile. +Possible fix bug with clearing EXIFs when --no-backup is given + Revision 1.148.2.6 2006/09/02 19:03:17 andy Release as 0.24. @@ -617,4 +624,3 @@ Id keyword is added to renrot file. Revision 1.1 2005/10/17 13:39:38 zeus ChangeLog file is added. Its the very begining. - diff --git a/Makefile.PL b/Makefile.PL index 4579c16..9e3262e 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -22,7 +22,7 @@ rpm : tardist # CVS tagging tag : - cvs tag "renrot_$(shell date +'%Y%m%d%H%M%S')" + $(PERLRUN) -e 'use POSIX qw(strftime); $$date = strftime("%Y%m%d%H%M%S", localtime()); system("cvs tag $(NAME)_$$date");' END return $postamble; } @@ -96,25 +96,40 @@ the script: renrot --no-mtime *.jpg -RESTRICTIONS ------------- +RESTRICTIONS AND BUGS +------------ --- ---- + +RenRot has some restrictions and known bugs at runtime. + +1. Script handles a whole directory without recursion and only with one +extension of files. + +2. Algorithm treat each file with given extension as the image. Otherwise, +file will be renamed to the current time stamp when --no-rename option is +omitted. -RenRot has some restrictions at runtime. First off, script handles a whole -directory without recursion and only with one extension of files. Second, -algorithm treat each file with given extension as the image. Otherwise, file -will be renamed to the current time stamp when --no-rename option is omitted. -Third, rename operation is not permited between different partitions due to -hard link technology used (this will be avoided in future). Rotation process -is available only on JPEG files. +3. Rename operation is not permited between different partitions due to hard +link technology used (this will be avoided in future). -It seems that for Perl v.5.8.7 and 5.8.8, at least on FreeBSD 6 the bug, which -cause crash of the renrot, exists. In case when total amount of the files size -to process is bigger than RAM amount, the renrot falls with error: +4. Rotation process is available only on JPEG files. + +5. It seems that for Perl v.5.8.7 and 5.8.8, at least on FreeBSD 6 the bug, +which cause crash of the renrot, exists. In case when total amount of the +files size to process is bigger than RAM amount, the renrot falls with error: Out of memory during "large" request for XXXX bytes ... This doesn't occure for Perl v.5.6.1. +6. Still no way to set the tags with the same name but located in the +different groups. + +7. The colorization is started after the configuration files were parsed. +While that is not happened the messages will be colorized by default color +scheme. + +8. The colorization is not working under Windows platform. + DEBUGGING --------- @@ -7,6 +7,13 @@ TODO SEMANTICS q optional feature +BUGS + +- fix cleaning EXIFs when --no-backup is given + +- make possible to use same EXIF tags in different groups + + EXIF tags q to write to some tag the options passed to renrot @@ -45,6 +52,9 @@ User interface - GUI on PerlTk (due to WinCE hasn't real console) with some additional functions such as keywordizer +- to implement help output by topics (sole -h outputs list of topics like + rename,rotate,keyword e.t.c. and -h keyword outputs help for keyword related + File naming diff --git a/etc/colors.conf b/etc/colors.conf index 73297ce..2ac6e60 100644 --- a/etc/colors.conf +++ b/etc/colors.conf @@ -3,6 +3,9 @@ # # Note: These variables can be overriden by command line options. +# Use colorized output. This NOT works under Win32. +#Use color = No + # Setup colors for different facilities #Color = debug: 'green' diff --git a/etc/renrot.conf b/etc/renrot.conf index 3b564e7..9c478c0 100644 --- a/etc/renrot.conf +++ b/etc/renrot.conf @@ -75,3 +75,5 @@ # Use IPC for execution external command #use IPC = No +# Use colorized output (not works under MS Windows) +#use color = Yes @@ -57,7 +57,7 @@ if (defined %Image::ExifTool::UserDefined::RenRot) { # # Parsed configuration file in hash # -my %configOptions = ( +my %cfgOpts = ( 'aggregation delta' => 900, 'aggregation directory' => 'Images', 'aggregation mode' => 'none', @@ -70,8 +70,9 @@ my %configOptions = ( 'mtime' => 1, 'name template' => '%Y%m%d%H%M%S', 'trim' => 1, + 'use color' => 1, 'use ipc' => 0, - ); + ); ######################################################################################## # @@ -84,7 +85,6 @@ my $aggrTemplate; # template for the files aggregation taken from CLI my $aggrVirtual; # flag to do links instead real file moving while aggregation my $aggrVirtDir; # directory name for virtual aggregation my $backup = 1; # make or not a backup of the original files -my %colorsFromCli; # colors are got from CLI my $comfile; # file with commentary my $configFile; # configuration file my $countFF = 1; # use fixed field for counter @@ -186,6 +186,9 @@ my @multOpts = ( 'tagfile', ); +my @files; # array of the sorted filenames to process +my %filenameshash; # hash for old file names + ######################################################################################## # # Colors hash @@ -203,7 +206,7 @@ my %colors = ( sub printColored { my $facility = shift; - if (defined $useColor and $useColor != 0) { + if ($cfgOpts{'use color'} != 0) { if (defined $facility and defined $colors{$facility}) { print STDERR colored [$colors{$facility}{value}], @_; return; @@ -217,7 +220,7 @@ sub printColored { sub procmsg { return if ($quiet != 0); - if (defined $useColor and $useColor != 0) { + if ($cfgOpts{'use color'} != 0) { if (defined $colors{'process'}) { print colored [$colors{'process'}{value}], @_; return; @@ -289,7 +292,6 @@ sub boolConverter { sub getOptions { my $showVersion = 0; # need version my $showHelp = 0; # need help - my @tmpColors; my @tmpTags; my $getOptions = GetOptions ( "aggr-delta=i" => \$aggrDelta, @@ -299,7 +301,6 @@ sub getOptions { "aggr-virtual!" => \$aggrVirtual, "aggr-virtual-directory=s" => \$aggrVirtDir, "backup!" => \$backup, - "color=s" => \@tmpColors, "comment-file=s" => \$comfile, "config-file|c=s" => \$configFile, "counter-fixed-field!" => \$countFF, @@ -340,7 +341,6 @@ sub getOptions { dbgmsg (3, " --aggr-virtual: ", boolConv($aggrVirtual), "\n") if (defined $aggrVirtual); dbgmsg (3, " --aggr-virtual-directory: $aggrVirtDir\n") if (defined $aggrVirtDir); dbgmsg (3, " --backup: ", boolConv($backup), "\n"); - dbgmsg (3, " --color:\n", join("\n", @tmpColors), "\n") if (scalar(@tmpColors) > 0); dbgmsg (3, " --comment-file: $comfile\n") if (defined $comfile); dbgmsg (3, " --config-file: $configFile\n") if (defined $configFile); dbgmsg (3, " --counter-start: $countStart", @@ -395,20 +395,10 @@ sub getOptions { $extToProcess =~ s/^\*?\.?/\./ if ($fileCount == 0); dbgmsg (1, "getOptions(): Process with '$extToProcess' extension.\n"); - # Convert multiple color parameters to colors hash - foreach my $colorStr (@tmpColors) { - my %color = strToHash($colorStr, 'reset'); - foreach my $key (keys %color) { - $colorsFromCli{$key} = $color{$key}; - } - } - # Convert multiple tag parameters to tags hash foreach my $tagStr (@tmpTags) { my %tag = strToHash($tagStr); - foreach my $key (keys %tag) { - $tagsFromCli{$key} = $tag{$key}; - } + map { $tagsFromCli{$_} = $tag{$_} } keys %tag; } } @@ -519,9 +509,7 @@ sub parseConfigFile { my %hConfig = @_; if (-f $file) { my %tmpConfig = getConfig($fc + 1, $file); - foreach my $key (keys %tmpConfig) { - $hConfig{$key} = $tmpConfig{$key}; - } + map { $hConfig{$_} = $tmpConfig{$_} } keys %tmpConfig; } return %hConfig; } @@ -556,9 +544,7 @@ sub parseConfig { @rcFiles = ($file) if (defined $file); - foreach my $rcfile (@rcFiles) { - %configOptions = parseConfigFile(0, $rcfile, %configOptions); - } + map { %cfgOpts = parseConfigFile(0, $_, %cfgOpts) } @rcFiles; } ######################################################################################## @@ -593,158 +579,16 @@ sub dirValidator { # switchColor() switches to user defined color scheme # sub switchColor { - dbgmsg (1, "Switch to user defined color scheme.\n"); - # Parse configuration file color set - foreach my $cKey (keys %configOptions) { + foreach my $cKey (keys %cfgOpts) { next if ($cKey !~ m/^color#\d+#\d+$/); # skip not a color - my %color = strToHash($configOptions{$cKey}, 'reset'); - foreach my $key (keys %color) { - $colors{$key} = $color{$key}; - } - } - - # Merge colors from configuration file with command line arguments - map { $colors{$_} = $colorsFromCli{$_} } keys %colorsFromCli; -} - -######################################################################################## -# -# MAIN() renames and rotates given files -# - -# parse command line options -getOptions(); - -parseConfig($configFile); - -switchColor(); - -# redefining options set in configuration file with set via CLI ones -$configOptions{'aggregation delta'} = $aggrDelta if (defined $aggrDelta); -$configOptions{'aggregation directory'} = $aggrDir if (defined $aggrDir); -$configOptions{'aggregation mode'} = $aggrMode if (defined $aggrMode); -$configOptions{'aggregation template'} = $aggrTemplate if (defined $aggrTemplate); -$configOptions{'aggregation virtual'} = $aggrVirtual if (defined $aggrVirtual); -$configOptions{'aggregation virtual directory'} = $aggrVirtDir if (defined $aggrVirtDir); -$configOptions{'keywordize'} = $keywordize if (defined $keywordize); -$configOptions{'keywords file'} = $keywordsFile if (defined $keywordsFile); -$configOptions{'keywords replace'} = $keywordsReplace if (defined $keywordsReplace); -$configOptions{'mtime'} = $mtime if (defined $mtime); -$configOptions{'name template'} = $nameTemplate if (defined $nameTemplate); -$configOptions{'trim'} = $trim if (defined $trim); -$configOptions{'use ipc'} = $useIPC if (defined $useIPC); - -dbgmsg (1, "main(): Show what would have been happened (no real actions).\n") if ($dryRun != 0); - -# Validate aggregation mode possible values -if (not grep (/^$configOptions{'aggregation mode'}$/, ('none', 'delta', 'template'))) { - warnmsg ("Aggregation mode isn't correct!\n"); -} - -$configOptions{'aggregation directory'} = dirConv($configOptions{'aggregation directory'}); -$configOptions{'aggregation virtual directory'} = dirConv($configOptions{'aggregation virtual directory'}); - -fatalmsg ("Current or multilevel directory isn't possible now, sorry. Check aggregation arguments.\n"), die - if ($configOptions{'aggregation mode'} ne "none" and - (dirValidator($configOptions{'aggregation directory'}) == 0 or - dirValidator($configOptions{'aggregation virtual directory'}) == 0)); - -# Calculate ExifTool's verbosity -my $exiftoolVerbose = ($verbose > $maxVerbosity) ? ($verbose - $maxVerbosity) : 0; - -# ExifTool object configuration -my $exifTool = new Image::ExifTool; -$exifTool->Options(Binary => 1, Unknown => 1, DateFormat => '%Y%m%d%H%M%S', Verbose => $exiftoolVerbose); - -my $file; # file in the directory -my @files; # array of the sorted filenames to process -my @filenames; # array of the filenames to process -my $angleSuffix; # suffix to add to the end of the rotated files -my $counterSize; -my %filenameshash; # hash for old file names - -chdir ($workDir) || ( fatalmsg ("Can't enter to $workDir!\n"), die ); - -# All things in ARGV will be treated as file names to process -@files = @ARGV; - -# if no file is given -if (scalar(@files) == 0) { - opendir(DIR, "./") || ( fatalmsg ("Can't open $workDir!\n"), die ); - while ( defined ( $file = readdir DIR )) { - next if (! -f $file); # skip absent file or not a file - push (@files, $file) if (substr($file, length($file) - length($extToProcess)) eq $extToProcess); + my %color = strToHash($cfgOpts{$cKey}, 'reset'); + map { $colors{$_} = $color{$_} } keys %color; } - closedir(DIR); -} - -# independently of @files initialization doing this -foreach $file ( @files ) { - next if (! -f $file); # skip absent file or not a file - next if (grep {/^$file$/} @excludeList); # skip excluded file - push (@filenames, $file); -} - -# No file to process? -if (scalar(@filenames) == 0) { - fatalmsg ("No files to process!\n"); - exit 1; -} - -# Parse configuration file tag set -foreach my $cKey (keys %configOptions) { - next if ($cKey !~ m/^tag(file)?#\d+#\d+$/); # skip not a tag or tagfile - my %tag = strToHash($configOptions{$cKey}); - foreach my $key (keys %tag) { - $tags{$key} = $tag{$key}; - if ($cKey =~ m/^tagfile/) { - dbgmsg (4, "main(): Read data from '$tags{$key}{value}' for '$key'\n"); - $tags{$key}{value} = getFileData($tags{$key}{value}); - } - } -} - -# Put command line arguments to appropriate tags -$tags{'Comment'} = {value => getFileData($comfile)} if (defined $comfile); -$tags{'UserComment'} = {value => $userComment} if (defined $userComment); -# Merge tags from configuration file with command line arguments -foreach my $key (keys %tagsFromCli) { - $tags{$key} = $tagsFromCli{$key}; -} - -# Print parsed tags at debug level -my @dbgTags; -foreach my $key (sort (keys %tags)) { - my $group = defined $tags{$key}{group} ? $tags{$key}{group} : ""; - my $value = defined $tags{$key}{value} ? $tags{$key}{value} : ""; - push (@dbgTags, "$key [$group] = $value"); -} -dbgmsg (4, "Tags:\n", join("\n", @dbgTags), "\n") if (scalar(@dbgTags) > 0); - -# Preparing the variable, which contains the format of the counter output -if ($countFF != 0) { - my $size = length((scalar(@filenames) - 1) * $countStep + $countStart); - $counterSize = "%." . $size . "d"; - dbgmsg (1, "main(): Counter size: $size (amount files in cache: ", scalar(@filenames), ")\n"); -} else { - $counterSize = "%d"; -} - -# Validate angle value -if ((defined $rotateAngle and not grep(/^$rotateAngle$/, keys %rotangles)) or - (defined $rotateThumbnail and not grep(/^$rotateThumbnail$/, keys %rotangles))) { - fatalmsg ("Angle should be 90, 180 or 270!\n"); - exit 1; + dbgmsg (1, "Switch to user defined color scheme.\n"); } -@files = sort @filenames; -dbgmsg (4, "main(): Pushed files(", scalar(@files), "):\n", join("\n", @files), "\n"); - -renRotProcess(); -aggregationProcess(); - ######################################################################################## # # keywordizer() validates keywords @@ -771,55 +615,60 @@ sub keywordizer { # renRotProcess() renames and rotates given file set # sub renRotProcess { + my $exifToolObj = shift; + my $counterSize = shift; my $fileCounter = $countStart; # file counter my $newFileName; # the name file to be renamed to my $info; # ImageInfo object my @keywordArr; # array for keywords - if ($configOptions{'keywordize'} != 0) { - @keywordArr = keywordizer ($configOptions{'keywords file'}); - errmsg ("Keywords file doesn't exist!\n") if (not -e $configOptions{'keywords file'}); + if ($cfgOpts{'keywordize'} != 0) { + @keywordArr = keywordizer ($cfgOpts{'keywords file'}); + errmsg ("Keywords file doesn't exist!\n") if (not -e $cfgOpts{'keywords file'}); } if (scalar(@keywordArr) > 0) { dbgmsg (2, "Keywords count: ", scalar(@keywordArr), "\n"); - if ($configOptions{'keywords replace'} != 0) { - $exifTool->SetNewValue(Keywords => \@keywordArr); + if ($cfgOpts{'keywords replace'} != 0) { + $exifToolObj->SetNewValue(Keywords => \@keywordArr); } else { - $exifTool->SetNewValue(Keywords => \@keywordArr, AddValue => 1); + $exifToolObj->SetNewValue(Keywords => \@keywordArr, AddValue => 1); } } # Convert trim boolean value to string - my $trimStr = (not defined $configOptions{'trim'} or $configOptions{'trim'}) ? '-trim' : ''; + my $trimStr = (not defined $cfgOpts{'trim'} or $cfgOpts{'trim'}) ? '-trim' : ''; dbgmsg (1, "renRotProcess(): Trim string: '$trimStr'\n"); dbgmsg (1, "renRotProcess(): Initializing tags ...\n"); foreach my $key (sort (keys %tags)) { - $exifTool->SetNewValue($key, $tags{$key}{value}, Group => $tags{$key}{group}); + $exifToolObj->SetNewValue($key, $tags{$key}{value}, Group => $tags{$key}{group}); } procmsg ("RENAMING / ROTATING\n"); procmsg ("===================\n"); + my $file_num = scalar(@files); + my $file_rem = 0; foreach my $file (@files) { - procmsg ("Processing file: $file ...\n"); + $file_rem++; + procmsg ("Processing file: ($file_rem of $file_num) $file ...\n"); # Setup defaults - $info = $exifTool->ImageInfo($file); + $info = $exifToolObj->ImageInfo($file); # analyzing whether to rotate - $angleSuffix = rotateFile($exifTool, $info, $file, $trimStr); + my $angleSuffix = rotateFile($exifToolObj, $info, $file, $trimStr); # analyzing whether and how to rename file - $newFileName = renameFile($exifTool, $info, $file, $fileCounter); + $newFileName = renameFile($exifToolObj, $info, $file, $fileCounter, $counterSize, $angleSuffix); # Writing tags. - tagWriter($exifTool, $newFileName) if ($noTags == 0); + tagWriter($exifToolObj, $newFileName) if ($noTags == 0); # seting mtime for the file if been asked for - mtimeSet($exifTool, $info, $newFileName); + mtimeSet($exifToolObj, $info, $newFileName); procmsg ("\n"); @@ -885,6 +734,8 @@ sub renameFile { my $infoObj = shift; my $file = shift; my $fileCounter = shift; + my $counterSize = shift; + my $angleSuffix = shift; my $newFileName; my $unixTime = getUnixTime(getTimestamp($exifToolObj, $infoObj)); @@ -897,9 +748,11 @@ sub renameFile { my $fileNameOriginal = $exifToolObj->GetValue("RenRotFileNameOriginal"); if (not defined $fileNameOriginal) { $tags{'RenRotFileNameOriginal'} = {value => $file, group => 'RenRot'}; - $exifTool->SetNewValue("RenRotFileNameOriginal", - $tags{'RenRotFileNameOriginal'}{value}, - Group => $tags{'RenRotFileNameOriginal'}{group}); + $exifToolObj->SetNewValue( + "RenRotFileNameOriginal", + $tags{'RenRotFileNameOriginal'}{value}, + Group => $tags{'RenRotFileNameOriginal'}{group} + ); dbgmsg (2, "renameFile(): set RenRotFileNameOriginal to $file.\n"); } else { dbgmsg (2, "renameFile(): RenRotFileNameOriginal: $fileNameOriginal.\n"); @@ -910,9 +763,11 @@ sub renameFile { $newFileName = template2name($exifToolObj, $infoObj, - $configOptions{'name template'}, + $cfgOpts{'name template'}, $fileCounter, - $file); + $file, + $counterSize, + $angleSuffix); if ($filenameshash{$newFileName . $ext}) { $newFileName .= "." . sprintf($counterSize, $fileCounter) . $ext; } else { @@ -977,7 +832,7 @@ sub mtimeSet { my $exifToolObj = shift; my $infoObj = shift; my $file = shift; - if ($configOptions{'mtime'} != 0) { + if ($cfgOpts{'mtime'} != 0) { my $mTime = getUnixTime(getTimestamp($exifToolObj, $infoObj)); if ($dryRun == 0) { utime $mTime, $mTime, $file; } else { procmsg ("Setting mtime.\n"); } @@ -1026,33 +881,40 @@ sub exifWriter { # aggregationProcess() aggregates files to separate directories by request # sub aggregationProcess { - return if ($configOptions{'aggregation mode'} eq "none"); + return if ($cfgOpts{'aggregation mode'} eq "none"); + my $exifToolObj = shift; + my $counterSize = shift; my $file; my $info; my $NewDir; + my $file_num = scalar(keys(%filenameshash)); + my $file_rem = 0; procmsg ("AGGREGATION\n"); procmsg ("===========\n"); - if ($configOptions{'aggregation mode'} eq "template") { - dbgmsg (1, "aggregationProcess(): Template: $configOptions{'aggregation template'}\n"); + if ($cfgOpts{'aggregation mode'} eq "template") { + dbgmsg (1, "aggregationProcess(): Template: $cfgOpts{'aggregation template'}\n"); my $fileCounter = $countStart; foreach $file (sort (keys %filenameshash)) { - dbgmsg (4, "aggregationProcess(): Processing file: $file\n"); - $info = $exifTool->ImageInfo($file); - $NewDir = template2name($exifTool, + $file_rem++; + dbgmsg (4, "aggregationProcess(): Processing ($file_rem of $file_num) file: $file\n"); + $info = $exifToolObj->ImageInfo($file); + $NewDir = template2name($exifToolObj, $info, - $configOptions{'aggregation template'}, + $cfgOpts{'aggregation template'}, $fileCounter, - $file); + $file, + $counterSize, + "0cw"); aggregateFile($file, $NewDir) if ($dryRun == 0); - procmsg ("Aggregate: $file -> $NewDir\n", "\n"); + procmsg ("Aggregate: ($file_rem of $file_num) $file -> $NewDir\n", "\n"); $fileCounter += $countStep; } - } elsif ($configOptions{'aggregation mode'} eq "delta") { + } elsif ($cfgOpts{'aggregation mode'} eq "delta") { my $DirCounter = 1; my $timestampPrev; my $filePrev; @@ -1060,27 +922,28 @@ sub aggregationProcess { foreach $file (sort (keys %filenameshash)) { $filetmp = $file; - dbgmsg (4, "aggregationProcess(): Processing file: $file\n"); + $file_rem++; + dbgmsg (4, "aggregationProcess(): Processing ($file_rem of $file_num) file: $file\n"); if ($DirCounter == 1) { $timestampPrev = $filenameshash{$filetmp}; $filePrev = $filetmp; - $NewDir = $configOptions{'aggregation directory'} . "." . sprintf($counterSize, $DirCounter); + $NewDir = $cfgOpts{'aggregation directory'} . "." . sprintf($counterSize, $DirCounter); $DirCounter++; aggregateFile($file, $NewDir) if ($dryRun == 0); } else { # Check for new direcroty creation - if (($filenameshash{$filetmp} - $timestampPrev) > $configOptions{'aggregation delta'}) { - $NewDir = $configOptions{'aggregation directory'} . "." . sprintf($counterSize, $DirCounter); + if (($filenameshash{$filetmp} - $timestampPrev) > $cfgOpts{'aggregation delta'}) { + $NewDir = $cfgOpts{'aggregation directory'} . "." . sprintf($counterSize, $DirCounter); $DirCounter++; } aggregateFile($file, $NewDir) if ($dryRun == 0); $timestampPrev = $filenameshash{$filetmp}; } - procmsg ("Aggregate: $file -> $NewDir\n", "\n"); + procmsg ("Aggregate: ($file_rem of $file_num) $file -> $NewDir\n", "\n"); } } else { - errmsg ("Aggregation mode $configOptions{'aggregation mode'} isn't implemented!\n"); + errmsg ("Aggregation mode $cfgOpts{'aggregation mode'} isn't implemented!\n"); } } @@ -1103,13 +966,13 @@ sub aggregateFile { my $file = shift; my $NewDir = shift; - if ($configOptions{'aggregation virtual'} == 0) { + if ($cfgOpts{'aggregation virtual'} == 0) { makeDir($NewDir); my $newfilename = $NewDir . "/" . $file; rename ($file, $newfilename) || ( fatalmsg ("$file -> $newfilename\n"), die ); } else { - makeDir($configOptions{'aggregation virtual directory'}); - $NewDir = $configOptions{'aggregation virtual directory'} . "/" . $NewDir; + makeDir($cfgOpts{'aggregation virtual directory'}); + $NewDir = $cfgOpts{'aggregation virtual directory'} . "/" . $NewDir; makeDir($NewDir); my $newfilename = $NewDir . "/" . $file; if (not -l $newfilename) { @@ -1246,17 +1109,17 @@ sub rotateImg { dbgmsg (3, "rotateImg(): $cmd\n"); system $cmd || ( fatalmsg ("System $cmd failed: $?\n"), die ); + # preparing to write tags to the just rotated file + my $exifAfterRot = new Image::ExifTool; + $exifAfterRot->Options(Binary => 1); + $exifAfterRot->SetNewValuesFromFile($oldfile, '*:*'); + $exifAfterRot->SetNewValue("Orientation", 1, Type => 'ValueConv'); + if ($backup != 0) { rename ($oldfile, $origfile) || ( fatalmsg ("$oldfile -> $origfile\n"), die ); } rename ($newfile, $oldfile) || ( fatalmsg ("$newfile -> $oldfile\n"), die ); - # preparing to write Orientation tag to the just rotated file - my $exifAfterRot = new Image::ExifTool; - $exifAfterRot->Options(Binary => 1); - $exifAfterRot->SetNewValuesFromFile($origfile, '*:*'); - $exifAfterRot->SetNewValue("Orientation", 1, Type => 'ValueConv'); - # writing the changes to the EXIFs exifWriter($exifAfterRot, $oldfile); } @@ -1295,7 +1158,7 @@ sub rotateThumbnail { my $origThumb = ${$$infoObj{ThumbnailImage}}; - if ($configOptions{'use ipc'} == 0) { + if ($cfgOpts{'use ipc'} == 0) { # extracting the thumbnail image my $ThumbnailOriginal = $file . "_thumborig"; unless ( open ( OLDTHUMBNAIL, ">$ThumbnailOriginal" ) ) { @@ -1406,7 +1269,6 @@ Tag writing options: Colorizing options: --use-color (*) colorized output - --color <COLOR> ... setup color(s) Misc options: --dry-run show what would have been happened @@ -1429,6 +1291,8 @@ sub template2name { my $template = shift; # the template to be used my $fileNo = shift; # counter for %c my $fileName = shift; # file name for %n and %e + my $counterSize = shift; + my $angleSuffix = shift;# suffix to add to the end of the rotated files my ($base, $ext); # file name %n and extension %e if ($fileName =~ m/^(.*)\.([^\.]+)$/) { @@ -1533,6 +1397,137 @@ sub template2name { return $thename; } +######################################################################################## +# +# MAIN() renames and rotates given files +# + +getOptions(); +parseConfig($configFile); +switchColor(); + +# redefining options set in configuration file with set via CLI ones +$cfgOpts{'aggregation delta'} = $aggrDelta if (defined $aggrDelta); +$cfgOpts{'aggregation directory'} = $aggrDir if (defined $aggrDir); +$cfgOpts{'aggregation mode'} = $aggrMode if (defined $aggrMode); +$cfgOpts{'aggregation template'} = $aggrTemplate if (defined $aggrTemplate); +$cfgOpts{'aggregation virtual'} = $aggrVirtual if (defined $aggrVirtual); +$cfgOpts{'aggregation virtual directory'} = $aggrVirtDir if (defined $aggrVirtDir); +$cfgOpts{'keywordize'} = $keywordize if (defined $keywordize); +$cfgOpts{'keywords file'} = $keywordsFile if (defined $keywordsFile); +$cfgOpts{'keywords replace'} = $keywordsReplace if (defined $keywordsReplace); +$cfgOpts{'mtime'} = $mtime if (defined $mtime); +$cfgOpts{'name template'} = $nameTemplate if (defined $nameTemplate); +$cfgOpts{'trim'} = $trim if (defined $trim); +$cfgOpts{'use color'} = $useColor if (defined $useColor); +$cfgOpts{'use ipc'} = $useIPC if (defined $useIPC); + +dbgmsg (1, "main(): Show what would have been happened (no real actions).\n") if ($dryRun != 0); + +# Validate aggregation mode possible values +if (not grep (/^$cfgOpts{'aggregation mode'}$/, ('none', 'delta', 'template'))) { + warnmsg ("Aggregation mode isn't correct!\n"); +} + +$cfgOpts{'aggregation directory'} = dirConv($cfgOpts{'aggregation directory'}); +$cfgOpts{'aggregation virtual directory'} = dirConv($cfgOpts{'aggregation virtual directory'}); + +fatalmsg ("Current or multilevel directory isn't possible now, sorry. Check aggregation arguments.\n"), die + if ($cfgOpts{'aggregation mode'} ne "none" and + (dirValidator($cfgOpts{'aggregation directory'}) == 0 or + dirValidator($cfgOpts{'aggregation virtual directory'}) == 0)); + +# Calculate ExifTool's verbosity +my $exiftoolVerbose = ($verbose > $maxVerbosity) ? ($verbose - $maxVerbosity) : 0; + +# ExifTool object configuration +my $exifTool = new Image::ExifTool; +$exifTool->Options(Binary => 1, Unknown => 1, DateFormat => '%Y%m%d%H%M%S', Verbose => $exiftoolVerbose); + +chdir ($workDir) || ( fatalmsg ("Can't enter to $workDir!\n"), die ); + +# All things in ARGV will be treated as file names to process +@files = @ARGV; + +# if no file is given +if (scalar(@files) == 0) { + opendir(DIR, "./") || ( fatalmsg ("Can't open $workDir!\n"), die ); + my $file; + while ( defined ( $file = readdir DIR )) { + next if (not -f $file); # skip absent file or not a file + push (@files, $file) if (substr($file, length($file) - length($extToProcess)) eq $extToProcess); + } + closedir(DIR); +} + +# independently of @files initialization doing this +my @filenames; + +foreach my $file ( @files ) { + next if (not -f $file); # skip absent file or not a file + next if (grep {/^$file$/} @excludeList); # skip excluded file + push (@filenames, $file); +} + +# No file to process? +if (scalar(@filenames) == 0) { + fatalmsg ("No files to process!\n"); + exit 1; +} + +# Parse configuration file tag set +foreach my $cKey (keys %cfgOpts) { + next if ($cKey !~ m/^tag(file)?#\d+#\d+$/); # skip not a tag or tagfile + my %tag = strToHash($cfgOpts{$cKey}); + foreach my $key (keys %tag) { + $tags{$key} = $tag{$key}; + if ($cKey =~ m/^tagfile/) { + dbgmsg (4, "main(): Read data from '$tags{$key}{value}' for '$key'\n"); + $tags{$key}{value} = getFileData($tags{$key}{value}); + } + } +} + +# Put command line arguments to appropriate tags +$tags{'Comment'} = {value => getFileData($comfile)} if (defined $comfile); +$tags{'UserComment'} = {value => $userComment} if (defined $userComment); + +# Merge tags from configuration file with command line arguments +map { $tags{$_} = $tagsFromCli{$_} } keys %tagsFromCli; + +# Print parsed tags at debug level +my @dbgTags; +foreach my $key (sort (keys %tags)) { + my $group = defined $tags{$key}{group} ? $tags{$key}{group} : ""; + my $value = defined $tags{$key}{value} ? $tags{$key}{value} : ""; + push (@dbgTags, "$key [$group] = $value"); +} +dbgmsg (4, "Tags:\n", join("\n", @dbgTags), "\n") if (scalar(@dbgTags) > 0); + +# Validate angle value +if ((defined $rotateAngle and not grep(/^$rotateAngle$/, keys %rotangles)) or + (defined $rotateThumbnail and not grep(/^$rotateThumbnail$/, keys %rotangles))) { + fatalmsg ("Angle should be 90, 180 or 270!\n"); + exit 1; +} + +@files = sort @filenames; +dbgmsg (4, "main(): Pushed files(", scalar(@files), "):\n", join("\n", @files), "\n"); + +# Preparing the variable, which contains the format of the counter output +my $counterSize; + +if ($countFF != 0) { + my $size = length((scalar(@filenames) - 1) * $countStep + $countStart); + $counterSize = "%." . $size . "d"; + dbgmsg (1, "main(): Counter size: $size (amount files in cache: ", scalar(@filenames), ")\n"); +} else { + $counterSize = "%d"; +} + +renRotProcess($exifTool, $counterSize); +aggregationProcess($exifTool, $counterSize); + __END__ =head1 NAME @@ -1786,10 +1781,6 @@ no tags will be written. Default is to write tags. colorized output. This NOT works under Win32. -=item B<--color> I<COLOR> - -setup color for choosen facility - =item B<--dry-run> show what would have been happened (no real actions) |