aboutsummaryrefslogtreecommitdiff
path: root/renrot
diff options
context:
space:
mode:
authorAndy Shevchenko <andy@smile.org.ua>2012-07-15 19:07:40 +0000
committerAndy Shevchenko <andy@smile.org.ua>2012-07-15 19:07:40 +0000
commitf8bae68a3a08ef61e26e5bc60a51e43a3c18a4a3 (patch)
tree413acd16d9600153346090cef9292b9284d5e302 /renrot
parent21c543a147355a7cc2fb3a72b0136f1b7977c6d5 (diff)
downloadrenrot-f8bae68a3a08ef61e26e5bc60a51e43a3c18a4a3.tar.gz
renrot-f8bae68a3a08ef61e26e5bc60a51e43a3c18a4a3.tar.bz2
cli: introduce new parser to make life easier
Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com> git-svn-id: file:///svnroot/renrot/trunk@604 fe2816f4-e837-0410-b10a-f608c9d244a1
Diffstat (limited to 'renrot')
-rwxr-xr-xrenrot697
1 files changed, 416 insertions, 281 deletions
diff --git a/renrot b/renrot
index ac693ce..7397980 100755
--- a/renrot
+++ b/renrot
@@ -72,81 +72,115 @@ if (%Image::ExifTool::UserDefined::RenRot) {
########################################################################################
#
# Parsed configuration file in hash
+# Note: unfortunately we still need manual adaptation in getOptions()
#
-my %cfgOpts = (
- 'aggregation delta' => 900,
- 'aggregation directory' => 'Images',
- 'aggregation mode' => 'none',
- 'aggregation template' => '%Y%m%d',
- 'aggregation virtual' => 0,
- 'keywords' => 0,
- 'keywords file' => '.keywords',
- 'keywords replace' => 0,
- 'mtime' => 1,
- 'name template' => '%Y%m%d%H%M%S',
- 'trim' => 1,
- 'use color' => 0,
- 'use ipc' => 0,
- 'contact sheet' => 0,
- 'contact sheet tile' => '7x5',
- 'contact sheet title' => 'Default Contact Sheet Title',
- 'contact sheet dir' => 'Contact.Sheet',
- 'contact sheet file' => 'cs-%c.jpg',
- 'contact sheet background' => 'FFF',
- 'contact sheet bordercolor' => 'DDD',
- 'contact sheet mattecolor' => 'CCC',
- 'contact sheet fill' => '000',
- 'contact sheet font' => 'Helvetica',
- 'contact sheet label' => '%t',
- 'contact sheet frame' => '3',
- 'contact sheet pointsize' => '11',
- 'contact sheet shadow' => 1,
- 'contact sheet thm font' => 'Helvetica',
- 'contact sheet thm fill' => 'gray34',
- 'contact sheet thm grad fr' => 'FFFFFF',
- 'contact sheet thm grad to' => '909090',
- 'contact sheet thm text' => "thumbnail\n\nNA",
- 'contact sheet rank' => 0,
- 'contact sheet rank file' => '.rank',
- 'generate thumbnail size' => '160x120',
+my $co_aggr = {
+ # aggregation time delta in seconds (file with delta > $delta is placed in new DIR)
+ 'delta' => { type => 'i', default => 900 },
+ # counterless directory name for "delta" type aggregation
+ 'directory' => { type => 's', default => 'Images' },
+ # aggregation framework
+ 'enabled' => { type => '!', default => 0},
+ # define aggregation mode, possible values are: none, delta or template
+ 'mode' => { type => 's', default => 'none' },
+ # template for the files aggregation taken from CLI
+ 'template' => { type => 's', default => '%Y%m%d' },
+ # flag to do links instead real file moving while aggregation
+ 'virtual' => { type => '!', default => 0 },
+};
+
+my $co_cs = {
+ # background, look ImageMagick documentation for montage options
+ 'background' => { type => 's', default => 'FFF' },
+ # bordercolor, look ImageMagick documentation for montage options
+ 'bordercolor' => { type => 's', default => 'DDD' },
+ # tmp directory for the montage operations
+ 'dir' => { type => 's', default => 'Contact.Sheet' },
+ # contact sheet generation
+ 'enabled' => { type => '!', default => 0 },
+ # file name for the montage
+ 'file' => { type => 's', default => 'cs-%c.jpg' },
+ # fill, look ImageMagick documentation for montage options
+ 'fill' => { type => 's', default => '000' },
+ # font, look ImageMagick documentation for montage options
+ 'font' => { type => 's', default => 'Helvetica' },
+ # frame, look ImageMagick documentation for montage options
+ 'frame' => { type => 's', default => '3' },
+ # label, look ImageMagick documentation for montage options
+ 'label' => { type => 's', default => '%t' },
+ # mattecolor, look ImageMagick documentation for montage options
+ 'mattecolor' => { type => 's', default => 'CCC' },
+ # pointsize, look ImageMagick documentation for montage options
+ 'pointsize' => { type => 's', default => '11' },
+ # ranking
+ 'rank' => { type => '!', default => 0 },
+ # file with images ranks
+ 'rank file' => { type => 's', default => '.rank' },
+ # shadow, look ImageMagick documentation for montage options
+ 'shadow' => { type => '!', default => 1 },
+ # is $extToProcess files are the thumbnails?
+ 'thm' => { type => '!', default => 0 },
+ # font, look ImageMagick documentation for montage options
+ 'thm font' => { type => 's', default => 'Helvetica' },
+ # fill, look ImageMagick documentation for montage options
+ 'thm fill' => { type => 's', default => 'gray34' },
+ # thumbnail background gradient from
+ 'thm grad fr' => { type => 's', default => 'FFFFFF' },
+ # thumbnail background gradient to
+ 'thm grad to' => { type => 's', default => '909090' },
+ # thumbnail text
+ 'thm text' => { type => 's', default => "thumbnail\n\nNA" },
+ # tile in the montage
+ 'tile' => { type => 's', default => '7x5' },
+ # title for the montage
+ 'title' => { type => 's', default => 'Default Contact Sheet Title' },
+};
+
+my $co_g = {
+ 'generate thumbnail size' => { type => 's', default => '160x120' },
+ # mtime taken from CLI
+ 'mtime' => { type => '!', default => 1 },
+ # template for the filename taken from CLI
+ 'name template' => { type => 's', default => '%Y%m%d%H%M%S' },
+ # jpegtran -trim
+ 'trim' => { type => '!', default => 1 },
+ # colorized output
+ 'use color' => { type => '!', default => 0 },
+ # rotate thumbnail via pipe
+ 'use ipc' => { type => '!', default => 0 },
+};
+
+my $co_kw = {
+ # whether or not to fill Keywords tag
+ 'enabled' => { type => '!', default => 0 },
+ # file with keyword set
+ 'file' => { type => 's', default => '.keywords' },
+ # whether to add keywords to the existent ones or replace them
+ 'replace' => { type => '!', default => 0 },
+};
+
+my $config_opts = {
+ 'aggregation' => $co_aggr,
+ 'contact sheet' => $co_cs,
+ 'general' => $co_g,
+ 'keywords' => $co_kw,
+};
+
+my @config_sections = (
+ 'aggregation',
+ 'contact sheet',
+ 'general',
+ 'keywords',
);
########################################################################################
#
# Command line options
#
-my $aggrDelta; # aggregation time delta in seconds (file with delta > $aggrDelta is placed in new DIR)
-my $aggrDir; # counterless directory name for "delta" type aggregation
-my $aggrMode; # define aggregation mode, possible values are: none, delta or template
-my $aggrTemplate; # template for the files aggregation taken from CLI
-my $aggrVirtual; # flag to do links instead real file moving while aggregation
my $backup = 1; # make or not a backup of the original files
my $comfile; # file with commentary
my $configFile; # configuration file
-my $contactSheet; # contact sheet generation
-my $contactSheetTile; # tile in the montage
-my $contactSheetTitle; # title for the montage
-my $contactSheetFile; # file name for the montage
-my $contactSheetDir; # tmp directory for the montage operations
-my $contactSheetThm = 0;# is $extToProcess files are the thumbnails?
-my $contactSheetBg; # background, look ImageMagick documentation for montage options
-my $contactSheetBd; # bordercolor, look ImageMagick documentation for montage options
-my $contactSheetMt; # mattecolor, look ImageMagick documentation for montage options
-my $contactSheetLb; # label, look ImageMagick documentation for montage options
-my $contactSheetFn; # font, look ImageMagick documentation for montage options
-my $contactSheetFl; # fill, look ImageMagick documentation for montage options
-my $contactSheetFr; # frame, look ImageMagick documentation for montage options
-my $contactSheetPntSz; # pointsize, look ImageMagick documentation for montage options
-my $contactSheetShadow; # shadow, look ImageMagick documentation for montage options
-my $contactSheetThmFn; # font, look ImageMagick documentation for montage options
-my $contactSheetThmFl; # fill, look ImageMagick documentation for montage options
-my $contactSheetThmGrFr;# thumbnail background gradient from
-my $contactSheetThmGrTo;# thumbnail background gradient to
-my $contactSheetThmText;# thumbnail text
-my $contactSheetRank; # ranking
-my $contactSheetRankFile; # file with images ranks
-
my $countFF = 1; # use fixed field for counter
my $countStart = 1; # Start value for counter
my $countStep = 1; # Step for counter
@@ -155,12 +189,6 @@ my @excludeList = (); # files that will be excluded from list
my $extToProcess = ''; # the extension of files to work with
my $gen_thm = 0; # to not to generate ThumbnailImage if empty
-my $keywords; # whether or not to fill Keywords tag
-my $keywordsReplace; # whether to add keywords to the existent ones or replace them
-my $keywordsFile; # file with keyword set
-
-my $mtime; # mtime taken from CLI
-my $nameTemplate; # template for the filename taken from CLI
my $noRename = 0; # no rename needed, default is to rename to the YYYYmmddHHMMSS.ext
my $noRotation = 0; # no rotation needed, default is to rotate
my $noTags = 0; # no tags writing needed
@@ -172,9 +200,6 @@ my $rotateThumbnail; # define the angle to rotate on 90, 180 or 270
my $subFileSet = ''; # subset of files to process, given in file rather than in commandline
my %tagsFromCli = (); # tags are got from CLI
my @tag_to_name = (); # tags for name building, theirs values to be used (in theory any EXIF)
-my $trim; # jpegtran -trim
-my $useColor; # colorized output
-my $useIPC; # rotate thumbnail via pipe
my $userComment; # text to put into UserComment tag
my $verbose = 0; # verbosity of output
my $workDir = './'; # we'll work ONLY in current directory
@@ -272,7 +297,7 @@ my %colors = (
sub printColored {
my $facility = shift;
- if ($cfgOpts{'use color'} != 0) {
+ if (get_cfg_value($co_g, 'use color') != 0) {
if (defined $facility and defined $colors{$facility}) {
# Put process and info messages to StdOut, otherwise to StdErr
if ($facility eq "process" or $facility eq "info") {
@@ -345,6 +370,32 @@ sub ldbg3 {
};
########################################################################################
+#
+# ldbg3opts() prints option values from given hash
+#
+sub ldbg3opts {
+ my $hash = shift;
+ my $option = shift;
+ foreach my $key (keys %{$hash->{$option}}) {
+ next if (not defined $hash->{$option}{$key}{value});
+ my ($value, $default);
+ my $type = defined $hash->{$option}{$key}{type} ? $hash->{$option}{$key}{type} : "s";
+ if ($type ne "!") {
+ $value = $hash->{$option}{$key}{value};
+ $default = $hash->{$option}{$key}{default};
+ } else {
+ $value = boolConv($hash->{$option}{$key}{value});
+ $default = boolConv($hash->{$option}{$key}{default});
+ }
+ if (not defined $default) {
+ ldbg3("--> '$option $key': $value");
+ } else {
+ ldbg3("--> '$option $key': $value (default: $default)");
+ }
+ }
+}
+
+########################################################################################
### COMMON HELPERS ###
########################################################################################
@@ -427,96 +478,124 @@ sub getOptions {
my $showVersion = 0; # need version
my $showHelp = 0; # need help
my @tmpTags = ();
+
+ # For 'aggregation'
+ my $s_aggr_opts;
+ my %h_aggr_opts;
+
+ # For 'contact sheet'
+ my $s_cs_opts;
+ my %h_cs_opts;
+
+ # For 'general'
+ my %h_g_opts;
+
+ # For 'keywords'
+ my $s_kw_opts;
+ my %h_kw_opts;
+
+ my $ll_opts = {
+ 'aggregation' => { 's' => \$s_aggr_opts, 'h' => \%h_aggr_opts },
+ 'contact sheet' => { 's' => \$s_cs_opts, 'h' => \%h_cs_opts },
+ 'keywords' => { 's' => \$s_kw_opts, 'h' => \%h_kw_opts },
+ };
+
my $getOptions = GetOptions (
- "aggr-delta=i" => \$aggrDelta,
- "aggr-directory=s" => \$aggrDir,
- "aggr-mode=s" => \$aggrMode,
- "aggr-template|a=s" => \$aggrTemplate,
- "aggr-virtual!" => \$aggrVirtual,
-
- "backup!" => \$backup,
- "comment-file=s" => \$comfile,
- "config-file|c=s" => \$configFile,
-
- "contact-sheet|cs!" => \$contactSheet,
- "contact-sheet-tile|cs-tile=s" => \$contactSheetTile,
- "contact-sheet-title|cs-title=s" => \$contactSheetTitle,
- "contact-sheet-file|cs-file=s" => \$contactSheetFile,
- "contact-sheet-dir|cs-dir=s" => \$contactSheetDir,
- "contact-sheet-thm|cs-thm" => \$contactSheetThm,
- "contact-sheet-bg|cs-bg=s" => \$contactSheetBg,
- "contact-sheet-bd|cs-bd=s" => \$contactSheetBd,
- "contact-sheet-mt|cs-mt=s" => \$contactSheetMt,
- "contact-sheet-fl|cs-fl=s" => \$contactSheetFl,
- "contact-sheet-fn|cs-fn=s" => \$contactSheetFn,
- "contact-sheet-lb|cs-lb=s" => \$contactSheetLb,
- "contact-sheet-fr|cs-fr=s" => \$contactSheetFr,
- "contact-sheet-pntsz|cs-pntsz=i" => \$contactSheetPntSz,
- "contact-sheet-shadow|cs-shadow" => \$contactSheetShadow,
- "contact-sheet-thm-fl|cs-thm-fl=s" => \$contactSheetThmFl,
- "contact-sheet-thm-fn|cs-thm-fn=s" => \$contactSheetThmFn,
- "contact-sheet-thm-grfr|cs-thm-grfr=s" => \$contactSheetThmGrFr,
- "contact-sheet-thm-grto|cs-thm-grto=s" => \$contactSheetThmGrTo,
- "contact-sheet-thm-text|cs-thm-text=s" => \$contactSheetThmText,
- "contact-sheet-rank|cs-rank!" => \$contactSheetRank,
- "contact-sheet-rank-file|cs-rank-file=s" => \$contactSheetRankFile,
+ # AGGREGATION
+ "aggr-opts=s" => \$s_aggr_opts,
+ "aggr-delta=i" => \$h_aggr_opts{'delta'},
+ "aggr-directory=s" => \$h_aggr_opts{'directory'},
+ "aggr-mode=s" => \$h_aggr_opts{'mode'},
+ "aggr-template|a=s" => \$h_aggr_opts{'template'},
+ "aggr-virtual!" => \$h_aggr_opts{'virtual'},
+
+ # CONTACT SHEET
+ "contact-sheet-opts|cs-opts=s" => \$s_cs_opts,
+ "contact-sheet-bg|cs-bg=s" => \$h_cs_opts{'background'},
+ "contact-sheet-bd|cs-bd=s" => \$h_cs_opts{'bordercolor'},
+ "contact-sheet-dir|cs-dir=s" => \$h_cs_opts{'dir'},
+ "contact-sheet|cs!" => \$h_cs_opts{'enabled'},
+ "contact-sheet-file|cs-file=s" => \$h_cs_opts{'file'},
+ "contact-sheet-fl|cs-fl=s" => \$h_cs_opts{'fill'},
+ "contact-sheet-fn|cs-fn=s" => \$h_cs_opts{'font'},
+ "contact-sheet-fr|cs-fr=s" => \$h_cs_opts{'frame'},
+ "contact-sheet-lb|cs-lb=s" => \$h_cs_opts{'label'},
+ "contact-sheet-mt|cs-mt=s" => \$h_cs_opts{'mattecolor'},
+ "contact-sheet-pntsz|cs-pntsz=i" => \$h_cs_opts{'pointsize'},
+ "contact-sheet-rank|cs-rank!" => \$h_cs_opts{'rank'},
+ "contact-sheet-rank-file|cs-rank-file=s" => \$h_cs_opts{'rank file'},
+ "contact-sheet-shadow|cs-shadow" => \$h_cs_opts{'shadow'},
+ "contact-sheet-thm|cs-thm" => \$h_cs_opts{'thm'},
+ "contact-sheet-thm-fl|cs-thm-fl=s" => \$h_cs_opts{'thm fill'},
+ "contact-sheet-thm-fn|cs-thm-fn=s" => \$h_cs_opts{'thm font'},
+ "contact-sheet-thm-grfr|cs-thm-grfr=s" => \$h_cs_opts{'thm grad fr'},
+ "contact-sheet-thm-grto|cs-thm-grto=s" => \$h_cs_opts{'thm grad to'},
+ "contact-sheet-thm-text|cs-thm-text=s" => \$h_cs_opts{'thm text'},
+ "contact-sheet-tile|cs-tile=s" => \$h_cs_opts{'tile'},
+ "contact-sheet-title|cs-title=s" => \$h_cs_opts{'title'},
+
+ # GENERAL
+ "mtime!" => \$h_g_opts{'mtime'},
+ "name-template|n=s" => \$h_g_opts{'name template'},
+ "trim!" => \$h_g_opts{'trim'},
+ "use-color!" => \$h_g_opts{'use color'},
+ "use-ipc!" => \$h_g_opts{'use ipc'},
+
+ # KEYWORDIZER
+ "kw-opts=s" => \$s_kw_opts,
+ "keywords!" => \$h_kw_opts{'enabled'},
+ "keywords-file|k=s" => \$h_kw_opts{'file'},
+ "keywords-replace!" => \$h_kw_opts{'replace'},
+
+ # OTHERS
+ "backup!" => \$backup,
+ "comment-file=s" => \$comfile,
+ "config-file|c=s" => \$configFile,
"counter-fixed-field!" => \$countFF,
- "counter-start=i" => \$countStart,
- "counter-step=i" => \$countStep,
- "dry-run" => \$dryRun,
- "exclude=s" => \@excludeList,
- "extension|e=s" => \$extToProcess,
- "generate-thumb|g" => \$gen_thm,
- "help|?" => \$showHelp,
- "keywords!" => \$keywords,
- "keywords-file|k=s" => \$keywordsFile,
- "keywords-replace!" => \$keywordsReplace,
- "mtime!" => \$mtime,
- "name-template|n=s" => \$nameTemplate,
- "no-rename|norename" => \$noRename,
- "no-rotate|norotate" => \$noRotation,
- "no-tags|notags" => \$noTags,
- "no-renrot|nochg" => \$noRenRoTagMtm,
- "only-orientation" => \$orientTag,
- "quiet|q" => \$quiet,
- "rotate-angle|r=i" => \$rotateAngle,
- "rotate-thumb=i" => \$rotateThumbnail,
- "sub-fileset=s" => \$subFileSet,
- "tag|t=s" => \@tmpTags,
- "trim!" => \$trim,
- "use-color!" => \$useColor,
- "use-ipc!" => \$useIPC,
- "user-comment=s" => \$userComment,
- "v+" => \$verbose,
- "version" => \$showVersion,
- "work-directory|d=s" => \$workDir,
+ "counter-start=i" => \$countStart,
+ "counter-step=i" => \$countStep,
+ "dry-run" => \$dryRun,
+ "exclude=s" => \@excludeList,
+ "extension|e=s" => \$extToProcess,
+ "generate-thumb|g" => \$gen_thm,
+ "help|?" => \$showHelp,
+ "no-rename|norename" => \$noRename,
+ "no-rotate|norotate" => \$noRotation,
+ "no-tags|notags" => \$noTags,
+ "no-renrot|nochg" => \$noRenRoTagMtm,
+ "only-orientation" => \$orientTag,
+ "quiet|q" => \$quiet,
+ "rotate-angle|r=i" => \$rotateAngle,
+ "rotate-thumb=i" => \$rotateThumbnail,
+ "sub-fileset=s" => \$subFileSet,
+ "tag|t=s" => \@tmpTags,
+ "user-comment=s" => \$userComment,
+ "v+" => \$verbose,
+ "version" => \$showVersion,
+ "work-directory|d=s" => \$workDir,
);
my $fileCount = scalar(@ARGV);
- ldbg3("--aggr-delta: $aggrDelta") if (defined $aggrDelta);
- ldbg3("--aggr-directory: $aggrDir") if (defined $aggrDir);
- ldbg3("--aggr-mode: $aggrMode") if (defined $aggrMode);
- ldbg3("--aggr-template: $aggrTemplate") if (defined $aggrTemplate);
- ldbg3("--aggr-virtual: ", boolConv($aggrVirtual)) if (defined $aggrVirtual);
+ foreach my $key (keys %$ll_opts) {
+ # Parse long list option
+ if (defined ${$ll_opts->{$key}{'s'}}) {
+ update_config_option_value($config_opts->{$key}{'enabled'}, 1);
+ parse_many_pairs(${$ll_opts->{$key}{'s'}}, $config_opts, $key);
+ }
+ # Override long list option by set of standalone ones before any other action
+ assign_hash_values($config_opts, $key, $ll_opts->{$key}{'h'});
+ # Debug result
+ ldbg3opts($config_opts, $key);
+ }
+
+ # For 'general' section
+ assign_hash_values($config_opts, 'general', \%h_g_opts);
+ ldbg3opts($config_opts, 'general');
+
ldbg3("--backup: ", boolConv($backup));
ldbg3("--comment-file: $comfile") if (defined $comfile);
ldbg3("--config-file: $configFile") if (defined $configFile);
- ldbg3("--contact-sheet: ", boolConv($contactSheet)) if (defined $contactSheet);
- ldbg3("--contact-sheet-tile: $contactSheetTile") if (defined $contactSheetTile);
- ldbg3("--contact-sheet-title: $contactSheetTitle") if (defined $contactSheetTitle);
- ldbg3("--contact-sheet-file: $contactSheetFile") if (defined $contactSheetFile);
- ldbg3("--contact-sheet-dir: $contactSheetDir") if (defined $contactSheetDir);
- ldbg3("--generate-thumb: ", boolConv($gen_thm));
- ldbg3("--contact-sheet-thm: ", boolConv($contactSheetThm));
- ldbg3("--contact-sheet-bg: $contactSheetBg") if (defined $contactSheetBg);
- ldbg3("--contact-sheet-bd: $contactSheetBd") if (defined $contactSheetBd);
- ldbg3("--contact-sheet-mt: $contactSheetMt") if (defined $contactSheetMt);
- ldbg3("--contact-sheet-fn: $contactSheetFn") if (defined $contactSheetFn);
- ldbg3("--contact-sheet-lb: $contactSheetLb") if (defined $contactSheetLb);
- ldbg3("--contact-sheet-fr: $contactSheetFr") if (defined $contactSheetFr);
- ldbg3("--contact-sheet-rank: ", boolConv($contactSheetRank)) if (defined $contactSheetRank);
- ldbg3("--contact-sheet-rank-file: $contactSheetRankFile") if (defined $contactSheetRankFile);
ldbg3("--counter-start: $countStart",
" --counter-step: $countStep",
@@ -526,12 +605,6 @@ sub getOptions {
ldbg3("--extension: '$extToProcess'");
ldbg3("--generate-thumb: ", boolConv($gen_thm));
- ldbg3("--keywords: ", boolConv($keywords)) if (defined $keywords);
- ldbg3("--keywords-replace: ", boolConv($keywordsReplace)) if (defined $keywordsReplace);
- ldbg3("--keywords-file: $keywordsFile") if (defined $keywordsFile);
-
- ldbg3("--mtime: ", boolConv($mtime)) if (defined $mtime);
- ldbg3("--name-template: $nameTemplate") if (defined $nameTemplate);
ldbg3("--no-rename: ", boolConv($noRename),
" --no-rotate: ", boolConv($noRotation),
" --no-tags: ", boolConv($noTags),
@@ -541,9 +614,6 @@ sub getOptions {
ldbg3("--rotate-thumb: $rotateThumbnail") if (defined $rotateThumbnail);
ldbg3("--sub-fileset: $subFileSet") if ($subFileSet ne "");
ldbg3("--tag:\n", join("\n", @tmpTags)) if (scalar(@tmpTags) > 0);
- ldbg3("--trim: ", boolConv($trim)) if (defined $trim);
- ldbg3("--use-color: ", boolConv($useColor)) if (defined $useColor);
- ldbg3("--use-ipc: ", boolConv($useIPC)) if (defined $useIPC);
ldbg3("--work-directory: $workDir");
ldbg3("ARGV:\n", join("\n", @ARGV)) if ($fileCount > 0);
@@ -573,13 +643,13 @@ sub getOptions {
if ($noRenRoTagMtm != 0) {
$noRename = $noRotation = $noTags = 1;
- $mtime = 0;
+ update_config_option_value($config_opts->{'general'}{'mtime'}, 0);
}
# is there ImageMagick?
if ($isThereIM == 1) {
dbgmsg (1, "We have Image::Magick package and could proceed with --contact-sheet related functionality.\n");
- } elsif ($cfgOpts{'contact sheet'} == 1 or defined $contactSheet) {
+ } elsif (get_cfg_value($co_cs, 'enabled') == 1) {
errmsg ("To use --contact-sheet related functionality you need Image::Magick package!\n",
"Contact Sheet generation disabled.\n");
} elsif ($gen_thm != 0) {
@@ -651,6 +721,73 @@ sub parsePair {
########################################################################################
#
+# update_config_option_value()
+#
+sub update_config_option_value {
+ my $hash = shift;
+ my $value = shift;
+ return if (not defined $value);
+ if (not defined $hash->{default}) {
+ $hash->{default} = $hash->{value};
+ }
+ $hash->{value} = $value;
+}
+
+########################################################################################
+# Usage : parse_many_pairs() gets hash with (key, value) pairs from the string like
+# : key1="value1":key2="value2":...:keyM="valueN"
+# Purpose : parses pairs of data
+# Returns : filled hash %hash
+# Parameters : $str [str] string like key1="value1":key2="value2":...:keyM="valueN"
+# $hash [ref] reference to hash
+# $option [str] subtree in the hash
+# Throws : no exceptions
+# Comments : "value1", "value2", ..., "valueN" should not contain ':' symbol
+# See Also : parsePair()
+sub parse_many_pairs {
+ my $str = shift;
+ my $hash = shift;
+ my $sect = shift;
+ return if (not defined $str);
+ my @k = keys %{$hash->{$sect}};
+ foreach my $pair (split(/:/, $str)) {
+ my ($key, $value) = parsePair($pair);
+ next if (not defined $key);
+ if (not grep (/^$key$/, @k)) {
+ warnmsg ("Invalid key '$key' in '$sect'. Skiping...\n");
+ next;
+ }
+ $value = boolConverter($value) if ($hash->{$sect}{$key}{type} eq "!");
+ update_config_option_value($hash->{$sect}{$key}, $value);
+ dbgmsg (4, "Parsed: '$sect' -> '$key': '$value'\n");
+ }
+}
+
+########################################################################################
+#
+# assign_hash_values() assignes given values to a hash
+#
+sub assign_hash_values {
+ my $hash = shift;
+ my $sect = shift;
+ my $values = shift;
+ return if (not defined $values);
+ map { update_config_option_value($hash->{$sect}{$_}, $values->{$_}) } keys %$values;
+}
+
+########################################################################################
+#
+# get_cfg_value() returnes value of the given configuration option
+#
+sub get_cfg_value {
+ my $hash = shift;
+ my $key = shift;
+ return $hash->{$key}{value} if (defined $hash->{$key}{value});
+ return $hash->{$key}{default};
+}
+
+########################################################################################
+#
# strToHash() parses given string to a hash
#
sub strToHash {
@@ -704,6 +841,7 @@ sub getConfig {
parseConfigFile($fc, $value, $hash);
}
$key .= sprintf("#%d#%d", $fc, $i) if (grep (/^$key$/, @multOpts));
+ $key .= ' ' . 'enabled' if (grep (/^$key$/, @config_sections));
$hash->{$key} = boolConverter($value);
dbgmsg (3, "Parsed line($i): '$key' <- '$hash->{$key}'\n");
} else {
@@ -767,13 +905,53 @@ sub parseConfig {
########################################################################################
#
+# apply_config_values() applies values by priority:
+# default -> config -> CLI new -> CLI old
+#
+sub apply_config_values {
+ my $hash = shift;
+ my $value;
+
+ foreach my $option (keys %$hash) {
+ next if (ref($hash->{$option}) ne ""); # Skip non-SCALAR
+ next if ($option =~ m/^[^#]+#\d+#\d+$/); # Skip multi-option
+
+ my ($sect, $key) = undef;
+ foreach my $s (@config_sections) {
+ if ($option =~ m/^$s(.*)/) {
+ ($sect, $key) = ($s, trim_value($1));
+ last;
+ }
+ }
+ ($sect, $key) = ('general', $option) if (not defined $sect);
+ next if (not defined $hash->{$sect}{$key});
+
+ dbgmsg (4, "Option '$option' will be put into '$sect'\n");
+
+ # Get default value
+ $value = $hash->{$sect}{$key}{default};
+ my $vdef = (defined $value) ? $value : "undef"; # For debug message
+
+ # Apply value from configuration file
+ $value = $hash->{$option} if (defined $hash->{$option});
+ my $vcfg = (defined $hash->{$option}) ? $value : "undef"; # For debug message
+
+ # Apply value from command line
+ $hash->{$sect}{$key}{value} = $value if (not defined $hash->{$sect}{$key}{value});
+
+ dbgmsg (4, "'$vdef' -> '$vcfg' -> '$hash->{$sect}{$key}{value}'\n");
+ }
+}
+
+########################################################################################
+#
# switchColor() switches to user defined color scheme
#
sub switchColor {
# Parse configuration file color set
- foreach my $cKey (keys %cfgOpts) {
+ foreach my $cKey (keys %$config_opts) {
next if ($cKey !~ m/^color#\d+#\d+$/); # skip not a color
- my %color = strToHash($cfgOpts{$cKey}, 'reset');
+ my %color = strToHash($config_opts->{$cKey}, 'reset');
map { $colors{$_} = $color{$_} } keys %color;
}
dbgmsg (1, "Switch to user defined color scheme.\n");
@@ -818,14 +996,14 @@ sub renRotProcess {
my $info; # ImageInfo object
my @keywordArr = (); # array for keywords
- if ($cfgOpts{'keywords'} != 0) {
- @keywordArr = keywordizer ($cfgOpts{'keywords file'});
- errmsg ("Keywords file doesn't exist!\n") if (not -e $cfgOpts{'keywords file'});
+ if (get_cfg_value($co_kw, 'enabled') != 0) {
+ @keywordArr = keywordizer (get_cfg_value($co_kw, 'file'));
+ errmsg ("Keywords file doesn't exist!\n") if (not -e get_cfg_value($co_kw, 'file'));
}
if (scalar(@keywordArr) > 0) {
dbgmsg (2, "Keywords count: ", scalar(@keywordArr), "\n");
- if ($cfgOpts{'keywords replace'} != 0) {
+ if (get_cfg_value($co_kw, 'replace') != 0) {
$exifToolObj->SetNewValue(Keywords => \@keywordArr);
} else {
$exifToolObj->SetNewValue(Keywords => \@keywordArr, AddValue => 1);
@@ -833,7 +1011,7 @@ sub renRotProcess {
}
# Convert trim boolean value to string
- my $trimStr = (not defined $cfgOpts{'trim'} or $cfgOpts{'trim'}) ? '-trim' : '';
+ my $trimStr = get_cfg_value($co_g, 'trim') ? '-trim' : '';
dbgmsg (1, "Trim string: '$trimStr'\n");
dbgmsg (1, "Initializing tags...\n");
@@ -978,7 +1156,7 @@ sub renameFile {
$newFileName = template2name (
$exifToolObj,
$infoObj,
- $cfgOpts{'name template'},
+ get_cfg_value($co_g, 'name template'),
$fileCounter,
$file,
$counterSize,
@@ -1088,7 +1266,7 @@ sub mtimeSet {
my $exifToolObj = shift;
my $infoObj = shift;
my $file = shift;
- if ($cfgOpts{'mtime'} != 0) {
+ if (get_cfg_value($co_g, 'mtime') != 0) {
my $mTime = getUnixTime(getTimestamp($exifToolObj, $infoObj));
if ($dryRun == 0) { utime $mTime, $mTime, $file; }
else { procmsg ("Setting mtime.\n"); }
@@ -1141,13 +1319,13 @@ sub exifWriter {
# aggregationProcess() aggregates files to separate directories by request
#
sub aggregationProcess {
- return if ($cfgOpts{'aggregation mode'} eq "none");
+ return if (get_cfg_value($co_aggr, 'mode') eq "none");
my $exifToolObj = shift;
my $counterSize = shift;
my $file;
my $info;
- my $BaseDir = $cfgOpts{'aggregation directory'};
+ my $BaseDir = get_cfg_value($co_aggr, 'directory');
my $NewDir;
my $file_num = scalar(keys(%filenameshash));
my $file_rem = 0;
@@ -1157,8 +1335,8 @@ sub aggregationProcess {
makeDir($BaseDir) if ($dryRun == 0);
- if ($cfgOpts{'aggregation mode'} eq "template") {
- dbgmsg (1, "Template: $cfgOpts{'aggregation template'}\n");
+ if (get_cfg_value($co_aggr, 'mode') eq "template") {
+ dbgmsg (1, "Template: ", get_cfg_value($co_aggr, 'template'), "\n");
my $fileCounter = $countStart;
foreach $file (sort (keys %filenameshash)) {
@@ -1167,7 +1345,7 @@ sub aggregationProcess {
$NewDir = template2name (
$exifToolObj,
$info,
- $cfgOpts{'aggregation template'},
+ get_cfg_value($co_aggr, 'template'),
$fileCounter,
$file,
$counterSize,
@@ -1178,7 +1356,7 @@ sub aggregationProcess {
procmsg ("Aggregate: ($file_rem of $file_num) $file -> $NewDir\n", "\n");
$fileCounter += $countStep;
}
- } elsif ($cfgOpts{'aggregation mode'} eq "delta") {
+ } elsif (get_cfg_value($co_aggr, 'mode') eq "delta") {
my $DirCounter = 1;
my $timestampPrev;
my $filePrev;
@@ -1196,7 +1374,7 @@ sub aggregationProcess {
aggregateFile($file, $NewDir) if ($dryRun == 0);
} else {
# Check for new direcroty creation
- if (($filenameshash{$filetmp} - $timestampPrev) > $cfgOpts{'aggregation delta'}) {
+ if (($filenameshash{$filetmp} - $timestampPrev) > get_cfg_value($co_aggr, 'delta')) {
$NewDir = $BaseDir . "." . sprintf($counterSize, $DirCounter);
$DirCounter++;
}
@@ -1206,7 +1384,7 @@ sub aggregationProcess {
procmsg ("Aggregate: ($file_rem of $file_num) $file -> $NewDir\n", "\n");
}
} else {
- errmsg ("Aggregation mode $cfgOpts{'aggregation mode'} isn't implemented!\n");
+ errmsg ("Aggregation mode ", get_cfg_value($co_aggr, 'mode'), " isn't implemented!\n");
}
}
@@ -1219,12 +1397,12 @@ sub aggregationProcess {
# Comments : requires --ext; --counter-start is valid
# See Also : template2name()
sub contactSheetGenerator {
- return if (not $cfgOpts{'contact sheet'});
+ return if (not get_cfg_value($co_cs, 'enabled'));
use File::Copy;
my $exifToolObj = shift;
- my $workdir = $cfgOpts{'contact sheet dir'};
+ my $workdir = get_cfg_value($co_cs, 'dir');
my $file;
my $info;
my $infothm;
@@ -1239,8 +1417,8 @@ sub contactSheetGenerator {
my $ranks; # reference to the hash of files ranks
# ranks file processing
- if ($cfgOpts{'contact sheet rank'} == 1 and -f $cfgOpts{'contact sheet rank file'}) {
- $ranks = getFileDatLns($cfgOpts{'contact sheet rank file'});
+ if (get_cfg_value($co_cs, 'rank') == 1 and -f get_cfg_value($co_cs, 'rank file')) {
+ $ranks = getFileDatLns(get_cfg_value($co_cs, 'rank file'));
if ($ranks != 0) {
dbgmsg (3, "Ranks successfully processed.\n");
} else {
@@ -1260,7 +1438,7 @@ sub contactSheetGenerator {
$filefull = $file;
- if ($contactSheetThm != 0 and defined $orientation) {
+ if (get_cfg_value($co_cs, 'thm') != 0 and defined $orientation) {
if ($orientation > 1) {
$filefull = rot_thm_cs ($file, $rotorient{$orientation}, $workdir);
} elsif ($orientation == 1) {
@@ -1272,7 +1450,7 @@ sub contactSheetGenerator {
}
$filefull = $ThumbnailOriginal;
}
- } elsif ($contactSheetThm == 0) {
+ } elsif (get_cfg_value($co_cs, 'thm') == 0) {
if (defined ${$$info{ThumbnailImage}}) {
$ThumbnailOriginal = File::Spec->catfile($workdir, $file);
if ($dryRun == 0) {
@@ -1320,19 +1498,8 @@ sub contactSheetGenerator {
}
@thumbnailes_sorted = sort {$a cmp $b} @thumbnailes;
- ldbg3("contact sheet background = \"$cfgOpts{'contact sheet background'}\"");
- ldbg3("contact sheet bordercolor = \"$cfgOpts{'contact sheet bordercolor'}\"");
- ldbg3("contact sheet mattecolor = \"$cfgOpts{'contact sheet mattecolor'}\"");
- ldbg3("contact sheet font = \"$cfgOpts{'contact sheet font'}\"");
- ldbg3("contact sheet label = \"$cfgOpts{'contact sheet label'}\"");
- ldbg3("contact sheet frame = \"$cfgOpts{'contact sheet frame'}\"");
- ldbg3("contact sheet pointsize = \"$cfgOpts{'contact sheet pointsize'}\"");
- ldbg3("contact sheet shadow = \"$cfgOpts{'contact sheet shadow'}\"");
- ldbg3("contact sheet title = \"$cfgOpts{'contact sheet title'}\"");
- ldbg3("contact sheet tile = \"$cfgOpts{'contact sheet tile'}\"");
-
# here it's iteration by tile
- my ($tileX, $tileY) = split ("x", $cfgOpts{'contact sheet tile'});
+ my ($tileX, $tileY) = split ("x", get_cfg_value($co_cs, 'tile'));
my $tileMul = $tileX * $tileY;
my $csIterationNumber = scalar @thumbnailes_sorted;
my $csFullIterations = int($csIterationNumber/$tileMul);
@@ -1370,7 +1537,7 @@ sub contactSheetGenerator {
$montagename = template2name (
$exifToolObj,
$info,
- $cfgOpts{'contact sheet file'},
+ get_cfg_value($co_cs, 'file'),
$fileCounter,
"stub",
$counter_size,
@@ -1383,27 +1550,27 @@ sub contactSheetGenerator {
} else { errmsg ("Image::Magick error: $readres\n"); }
# ranking
- $substrFile = substr($thumbnailes_sorted[$csIter], length($cfgOpts{'contact sheet dir'}) + 1);
+ $substrFile = substr($thumbnailes_sorted[$csIter], length(get_cfg_value($co_cs, 'dir')) + 1);
if (defined $ranks->{$substrFile}->[1]) {
dbgmsg (4, "$substrFile mattecolor is \"$ranks->{$substrFile}->[1]\"\n");
$image->[$readIndex]->Set(mattecolor => $ranks->{$substrFile}->[1]);
} else {
- dbgmsg (4, "$substrFile mattecolor is undefined, using \"$cfgOpts{'contact sheet mattecolor'}\" from config\n");
- $image->[$readIndex]->Set(mattecolor => normalize_color($cfgOpts{'contact sheet mattecolor'}));
+ dbgmsg (4, "$substrFile mattecolor is undefined, using \"", get_cfg_value($co_cs, 'mattecolor'), "\" from config\n");
+ $image->[$readIndex]->Set(mattecolor => normalize_color(get_cfg_value($co_cs, 'mattecolor')));
}
}
dbgmsg (1, "$csIterator montage is started, wait a bit please...\n");
- $montage = $image->Montage(background => normalize_color($cfgOpts{'contact sheet background'}),
- bordercolor => normalize_color($cfgOpts{'contact sheet bordercolor'}),
- font => $cfgOpts{'contact sheet font'},
- fill => normalize_color($cfgOpts{'contact sheet fill'}),
- label => $cfgOpts{'contact sheet label'},
- frame => $cfgOpts{'contact sheet frame'},
+ $montage = $image->Montage(background => normalize_color(get_cfg_value($co_cs, 'background')),
+ bordercolor => normalize_color(get_cfg_value($co_cs, 'bordercolor')),
+ font => get_cfg_value($co_cs, 'font'),
+ fill => normalize_color(get_cfg_value($co_cs, 'fill')),
+ label => get_cfg_value($co_cs, 'label'),
+ frame => get_cfg_value($co_cs, 'frame'),
geometry => $size . "x" . $size . "+4+4",
- pointsize => $cfgOpts{'contact sheet pointsize'},
- shadow => $cfgOpts{'contact sheet shadow'},
- title => $cfgOpts{'contact sheet title'},
- tile => $cfgOpts{'contact sheet tile'},
+ pointsize => get_cfg_value($co_cs, 'pointsize'),
+ shadow => get_cfg_value($co_cs, 'shadow'),
+ title => get_cfg_value($co_cs, 'title'),
+ tile => get_cfg_value($co_cs, 'tile'),
stroke => 'none',
);
@@ -1418,7 +1585,7 @@ sub contactSheetGenerator {
stroke => 'none',
);
$montage->Annotate (
- font => $cfgOpts{'contact sheet font'},
+ font => get_cfg_value($co_cs, 'font'),
pointsize => 9,
x => 5,
y => 13,
@@ -1426,7 +1593,7 @@ sub contactSheetGenerator {
text => $left_up_row[0],
);
$montage->Annotate (
- font => $cfgOpts{'contact sheet font'},
+ font => get_cfg_value($co_cs, 'font'),
pointsize => 9,
x => 5,
y => 23,
@@ -1457,7 +1624,7 @@ sub contactSheetGenerator {
$montagename = template2name (
$exifToolObj,
$info,
- $cfgOpts{'contact sheet file'},
+ get_cfg_value($co_cs, 'file'),
$fileCounter,
"stub",
$counter_size,
@@ -1470,13 +1637,13 @@ sub contactSheetGenerator {
else { errmsg ("Image::Magick error: $readres\n"); }