cvsimport
[fvwm-themes.git] / bin / fvwm-themes-images.in
blob476a254c688d1419bd974060458a026a5aaec1f9
1 #!@PERL@ -w
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 #-----------------------------------------------------------------------------
19 # Copyright 2000, Olivier Chapuis
20 #-----------------------------------------------------------------------------
22 # Filter this script to pod2man to get a man page:
23 #   pod2man -c "Fvwm Utility" fvwm-themes-images | nroff -man | less -e
25 use strict;
26 use Getopt::Long;
28 my $prefix = '@prefix@';
29 my $ROOT_PREFIX = '@ROOT_PREFIX@';
30 $ROOT_PREFIX = $ENV{'DESTDIR'} if $ENV{'DESTDIR'};
31 my $datadir = "@datadir@";
33 my $version = '@VERSION@';
34 my $fvwmVersion = '@FVWM_VERSION@';
35 my $ftDataDir = "@FT_DATADIR@";
36 my @xlibPath = qw(@X_LIBS@ @X_EXTRA_LIBS@);
37 my $scriptName = ($0 =~ m:([^/]+)$:, $1);
38 my $ftImagesDir = "$ftDataDir/images";
40 my $userHome = $ENV{'HOME'} || "./.";
41 # default directory for "transformed" icons
42 my $siteTransformOutDir = "$ftDataDir/tr-images";
43 my $userTransformOutDir = "$userHome/tr-images";
45 my @pathDirs = split(':',$ENV{PATH});
46 my $userName = $ENV{USER} || "unknown";
48 # global options
49 my $inDir = "";
50 my $outDir = "";
51 my $inFile = "";
52 my $outFile = "";
54 # for storing the rgb.txt file
55 my %rgb;
57 # convert options
58 my $convert = 0;
59 my $gnome = 0;
60 my $kde2 = 0;
61 my $kde2Hi = 0;
62 my $postfix = "";
63 my $transFilter = 1;
64 my @types = ();
65 my $preserve = 0;
66 my %build = (
67         '48x48' => 1,
68         '16x16' => 1,
69         '56x56' => 0,
70         '32x32' => 0,
71         'tiles' => 0,
73 my %tileOpt = (
74         '48x48' => "",
75         '16x16' => "",
76         '56x56' => "",
77         '32x32' => "",
78         'tiles' => "",
80 my %addBorderOpt = (
81         '48x48' => "",
82         '16x16' => "",
83         '56x56' => "",
84         '32x32' => "",
85         'tiles' => "",
87 my %size = (
88         '48x48' => "48x48",
89         '16x16' => "17x17",  # huh?
90         '56x56' => "56x56",
91         '32x32' => "32x32",
92         'tiles' => "",
95 # tile options
96 my $tile = "";
98 # add border
99 my $addBorder = "";
101 # ImageMagick options
102 my $magickColors = 256;
103 my $magickColorspace = "Transparent";
104 # depends if ImageMagick is compiled with 16bits per pixels enabled!
105 # if yes percentage is taken with 65535 if no 255 is used
106 my $threshold = 70;
107 my $magickPath = "";
108 my $magickBpp = 0;
110 # cde-like sky options
111 my $sky = 0;
112 my $skyColorsOpt = "";
113 my $skyComp = "linear";
114 my $patternFile = "$ftDataDir/themes/cde/background/pattern";
115 my $patternType = "";
116 my $patternXpm = "";
117 my $patternGap = 1;
118 my $patternY = "";
120 # set the background
121 my $setRoot = 0;
122 my $setRootProg = "fvwm-root --retain-pixmap";
123 #my $setRootProg = "fvwm-root";
124 my $setRootTmpFile = "/tmp/$userName-ft-back.xpm";
126 # rotate
127 my $rotate = 0;
129 # colorize
130 my $colorize = 0;
131 my $rizeColorsOpt = "gray40,gray60";
132 my $transColor = "";
133 my $rizeComp = "l";
134 my $rizeRule = "max";
136 # Info
137 my $xcolorsInfo = 0;
138 my $xcolorsetsInfo = 0;
139 my $colorToShow = undef;
141 # colors shemes
142 my $colorSchemes = 0;
143 my $colorSchemesFores = "";
144 my $colorSchemesExt = "dp";
146 # others
147 my $verbose = 1;
148 my $verboseOpt = -1;
149 my $site = 0;
150 my $createSymLink = "";
151 my $install = 0;
152 my $update = 0;
153 my $debug = "";
154 my $beFast = 0;
156 # constant (these constant are in main:: because this speed the code)
157 my @Hex=(0 .. 9, "a" .. "f");
158 my $singleIdList =
159         q( .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk) .
160         q(lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|);
161 # ` <- stupid fix for my stupid Xemacs! olicha
163 GetOptions(
164         "help"               => \&showHelp,
165         "version"            => \&showVersion,
166         "in-dir=s"           => \$inDir,
167         "out-dir=s"          => \$outDir,
168         "in-file=s"          => \$inFile,
169         "out-file=s"         => \$outFile,
170         "magick-path=s"      => \$magickPath,
171         "magick-bpp=i"       => \$magickBpp,
172         "magick-colors=i"    => \$magickColors,
173         "magick-colorspace=s" => \$magickColorspace,
174         "convert"            => \$convert,
175         "gnome"              => \$gnome,
176         "kde2"               => \$kde2,
177         "kde2-hi"            => \$kde2Hi,
178         "postfix"            => \$postfix,
179         "trans-filter!"      => \$transFilter,
180         "size-48x48=s"       => \$size{"48x48"},
181         "size-56x56=s"       => \$size{"56x56"},
182         "size-32x32=s"       => \$size{"32x32"},
183         "size-16x16=s"       => \$size{"16x16"},
184         "size-tiles=s"       => \$size{"tiles"},
185         "build-16x16!"       => \$build{"16x16"},
186         "build-48x48!"       => \$build{"48x48"},
187         "build-56x56!"       => \$build{"56x56"},
188         "build-32x32!"       => \$build{"32x32"},
189         "build-tiles!"       => \$build{"tiles"},
190         "preserve"           => \$preserve,
191         "tile=s"             => \$tile,
192         "tile-48x48=s"       => \$tileOpt{"48x48"},
193         "tile-16x16=s"       => \$tileOpt{"16x16"},
194         "tile-56x56=s"       => \$tileOpt{"56x56"},
195         "tile-32x32=s"       => \$tileOpt{"32x32"},
196         "tile-tiles=s"       => \$tileOpt{"tiles"},
197         "border=s"           => \$addBorder,
198         "border-48x48=s"     => \$addBorderOpt{"48x48"},
199         "border-16x16=s"     => \$addBorderOpt{"16x16"},
200         "border-56x56=s"     => \$addBorderOpt{"56x56"},
201         "border-32x32=s"     => \$addBorderOpt{"32x32"},
202         "border-tiles=s"     => \$addBorderOpt{"tiles"},
203         "threshold=i"        => \$threshold,
204         "colorize-colors=s"  => \$rizeColorsOpt,
205         "colorize"           => \$colorize,
206         "trans-color=s"      => \$transColor,
207         "colorize-comp=s"    => \$rizeComp,
208         "colorize-rule=s"    => \$rizeRule,
209         "sky"                => \$sky,
210         "sky-colors=s"       => \$skyColorsOpt,
211         "pattern-file=s"     => \$patternFile,
212         "pattern-type=s"     => \$patternType,
213         "pattern-xpm=s"      => \$patternXpm,
214         "pattern-gap=s"      => \$patternGap,
215         "pattern-y=i"        => \$patternY,
216         "sky-comp=s"         => \$skyComp,
217         "setroot"            => \$setRoot,
218         "setroot-prog=s"     => \$setRootProg,
219         "rotate=s"           => \$rotate,
220         "show-xcolors"       => \$xcolorsInfo,
221         "show-xcolorsets"    => \$xcolorsetsInfo,
222         "show-color-info=s"  => \$colorToShow,
223         "verbose=i"          => \$verboseOpt,
224         "site"               => \$site,
225         "create-symlink=s"   => \$createSymLink,
226         "update"             => \$update,
227         "ft-install"         => \$install,
228         "be-fast"            => \$beFast,
229         "colorschemes"       => \$colorSchemes,
230         "colorschemes-fores=s" => \$colorSchemesFores,
231         "colorschemes-ext=s" => \$colorSchemesExt,
233         # for compatibility only (to be removed)
234         "cde-sky"            => \$sky,
235         "set-background"     => \$setRoot,
236         "set-back-prog=s"    => \$setRootProg,
237         "magick-space=s"     => \$magickColorspace,
238         "add-border-48x48=s" => \$addBorderOpt{"48x48"},
239         "add-border-16x16=s" => \$addBorderOpt{"16x16"},
240         "add-border-56x56=s" => \$addBorderOpt{"56x56"},
241         "add-border-32x32=s" => \$addBorderOpt{"32x32"},
242         "add-border-tiles=s" => \$addBorderOpt{"tiles"},
243         "add-border=s"       => \$addBorder,
244         "48x48-size=s"       => \$size{"48x48"},
245         "56x56-size=s"       => \$size{"56x56"},
246         "32x32-size=s"       => \$size{"32x32"},
247         "16x16-size=s"       => \$size{"16x16"},
248         "tiles-size=s"       => \$size{"tiles"},
249 ) || wrongUsage();
251 # compute verbosity!
252 if ($setRoot) {
253         $verbose = 0;
255 if ($verboseOpt != -1) {
256         $verbose = $verboseOpt;
259 if ($install) {
260         $site = 1;
261         $convert = 1;
262         $update = 1;
263         $createSymLink = "48x48,16x16";
264         die "$scriptName: --install needs --gnome or --kde2 (but not both)\n"
265                 unless $gnome xor $kde2;
268 die "$scriptName: --convert and --setroot are incompatible\n"
269         if $convert && $setRoot;
271 die "$scriptName: --gnome and --kde2 are incompatible\n"
272         if $gnome && $kde2;
274 if ($xcolorsInfo || $xcolorsetsInfo) {
275         &showXcolorsInfo($xcolorsetsInfo);
276         exit;
279 if (defined $colorToShow) {
280         &showColorInfo($colorToShow);
281         exit;
284 if ($sky) {
285         &processSky();
286         exit;
289 $convert = 1 if $gnome || $kde2;
291 # see if we have to check magic:
292 if ($convert || $tile =~ /expand/) {
293         ($magickPath,$magickBpp) = checkMagick();
296 if ($convert) {
297         foreach (keys %build) {
298                 push @types, $_ if $build{$_};
299         }
300         @types = ("preserve") if $preserve;
301         &transform();
302         exit;
305 if ($tile || $addBorder || $colorize || $rotate ne "0") {
306         @types = ("preserve");
307         &transform();
308         exit;
311 if ($createSymLink ne "") {
312         @types = ();
313         &transform();
314         exit;
317 if ($colorSchemes || $colorSchemesFores ne "") {
318         &processColorSchemes();
319         exit;
322 if ($setRoot && $inFile) {
323         &setRoot($inFile);
324         exit;
327 wrongUsage();
329 #------------------------------------------------------------------------------
330 # Transform, main "convert" procedure
331 #------------------------------------------------------------------------------
333 sub transform {
334         my $type;
335         my $dirtype;
336         my $dir;
337         my $sizeOpt;
339         if ($gnome) {
340                 my $testExecFile = 'gnome-session';
341                 my $defaultGnomeInstallDir = '/usr';
343                 my $gnomeInstallDir = getExecFileDir($testExecFile);
344                 $gnomeInstallDir =~ s,/$,,;
345                 $gnomeInstallDir =~     s,/[-A-Za-z]+$,,;
346                 $gnomeInstallDir =~ s,/$,,;
347                 $gnomeInstallDir = $defaultGnomeInstallDir
348                         if $gnomeInstallDir eq 'not found';
349                 $inDir = "$gnomeInstallDir/share/pixmaps";
350                 $postfix = "gnome";
351                 $inFile = "";
352                 $outFile = "";
353         }
355         if ($kde2) {
356                 $postfix = "kde2";
357                 $inDir = "";
358                 my $kdeDir = $ENV{'KDEDIR'} || "";
359                 die "KDEDIR must be set for --kde2" if $kdeDir eq "";
360                 $inDir = "$kdeDir/share/icons";
361         }
363         $inDir = "$inDir/" unless $inDir =~ /\/$/ || $inDir eq "";
364         if ($inDir !~ /^\// && $inFile !~ /^\//) {
365                 my $tmp =`pwd`;
366                 chomp($tmp);
367                 $inDir ="$tmp/$inDir";
368         }
370         if ($inFile ne "") {
371                 if ($inFile =~ /\//) {
372                         my $index = rindex($inFile,"/");
373                         if ($inFile =~ /^\//) {
374                                 $inDir = substr($inFile,0,$index);
375                         } else {
376                                 $inDir = "$inDir" . substr($inFile,0,$index);
377                         }
378                         $inFile = substr($inFile,$index+1);
379                 }
380                 die "No such file: $inDir/$inFile !" unless -f "$inDir/$inFile";
381         }
382         $inDir =~ s/\/$//;
384         my $transformOutDir = $userTransformOutDir;
385         $transformOutDir = $siteTransformOutDir if $site;
386         $outDir = "$transformOutDir/$outDir" if ($outDir eq "");
388         if ($inFile ne "" && $outFile eq "" && !$convert) {
389                 if ($setRoot) { $outFile = $setRootTmpFile; }
390                 else {
391                         die "If you specify an in-file you must specify an out-file\n" .
392                                 "(except for --setroot and --convert)\n";
393                 }
394         }
396         if ($outDir !~ /^\// && $outFile !~ /^\//) {
397                 my $tmp =`pwd`;
398                 chomp($tmp);
399                 $outDir ="$tmp/$outDir";
400         }
401         $outDir = "$outDir/" unless $outDir =~ /\/$/ || $outDir eq "";
402         if ($outFile ne "") {
403                 if ($outFile =~ /\//) {
404                         my $index = rindex($outFile,"/");
405                         if ($outFile =~ /^\//) { $outDir = substr($outFile,0,$index); }
406                         else { $outDir = "$outDir" . substr($outFile,0,$index);}
407                         $outFile = substr($outFile,$index+1);
408                 }
409         }
410         $outDir =~ s/\/$//;
412         -d $outDir || mkdir("$outDir", 0775) ||
413                 die "impossible to create $outDir \n\t (we do not create more than one".
414                         " level of directory).\n";
417         # compute the threshold:
418         if ($convert && $transFilter) {
419                 if ($threshold > 100) { $threshold = 100; }
420                 if ($threshold < 0) { $threshold = 0; }
421                 $threshold = int(((2**$magickBpp)-1)*($threshold/100));
422         }
424         # compute the postfix
425         $postfix = "-".$postfix if $postfix ne "";
427         for $type (@types) {
429                 if ($type eq "preserve") {
430                         $dirtype = "";
431                         $sizeOpt = "";
432                         $dir = $inDir;
433                 } elsif ($type eq "tiles") {
434                         $dir = "$inDir/tiles";
435                         $dirtype = "/$type$postfix";
436                         $sizeOpt = "-geometry $size{$type}" if $size{$type} ne "";
437                 } else {
438                         $dir = $inDir;
439                         if ($kde2) {
440                                 if ($kde2Hi && -d "$inDir/hicolor/$type/apps") {
441                                         $dir = "$inDir/hicolor/$type/apps";
442                                 }
443                                 elsif (-d "$inDir/locolor/$type/apps") {
444                                         $dir = "$inDir/locolor/$type/apps";
445                                 }
446                                 elsif (-d "$inDir/hicolor/$type/apps") {
447                                         $dir = "$inDir/hicolor/$type/apps";
448                                 }
449                                 else {
450                                         next 
451                                 }
452                         }
453                         $dirtype = "/$type$postfix";
454                         $sizeOpt = "-geometry $size{$type}" if $size{$type} ne "";
455                         $sizeOpt = "" if ($kde2);
456                 }
458                 -d "$outDir$dirtype" || mkdir("$outDir$dirtype", 0775) ||
459                         die "impossible to create $outDir$dirtype";
461                 # tile ?
462                 my $haveToTile = 0;
463                 my $tileXpm; my $tileType;
464                 my ($xTile,$yTile) = (0, 0);
465                 if ($convert && $tileOpt{$type} ne "") {
466                         ($tileXpm,$tileType,$xTile,$yTile) = getTile("$tileOpt{$type}");
467                         $haveToTile = 1;
468                 } elsif ($tile ne "") {
469                         ($tileXpm,$tileType,$xTile,$yTile) = getTile("$tile");
470                         $haveToTile = 1;
471                 }
473                 # add border ?
474                 my $haveToAddBorder = 0;
475                 my ($xBorder, $yBorder) = (0, 0);
476                 my $borderColor = "Gray0";
477                 if ($convert && $addBorderOpt{$type} =~ /^\+(\d+)\+(\d+)[,]*(.*)/) {
478                         $xBorder = $1; $yBorder = $2;
479                         $borderColor = $3; $haveToAddBorder = 1;
480                 } elsif ($addBorder =~ /^\+(\d+)\+(\d+)[,]*(.*)/) {
481                         $xBorder = $1; $yBorder = $2;
482                         $borderColor = $3; $haveToAddBorder = 1;
483                 }
485                 my $unlinkmask = 0;
487                 my $info = "";
488                 my $infoType = "";
489                 if ($convert) {
490                         $info .= "convert ";
491                         $infoType .= "$type xpm";
492                 }
493                 $info .= "rotate " if ($rotate);
494                 $info .= "colorize " if ($colorize);
495                 $info .= "tile " if ($haveToTile);
496                 $info .= "borderize " if ($haveToAddBorder);
497                 $info .= " (update) " if ($update);
498                 if ($inFile eq "") {
499                         myPrint (2,"-------------------------------------------\n");
500                         myPrint (1,"$info images in $dir\ninto $type xpm images " .
501                           "in $outDir$dirtype\n");
502                         myPrint (2,"\n");
503                 }
505                 my @fileList;
506                 if ($inFile eq "") { @fileList = scanDir($dir);}
507                 else { @fileList = ("$inFile"); }
508                 
509                 # bad hack:
510                 if ($kde2) {
511                         my @others = qw(filesystems actions devices mimetypes);
512                         if ($kde2Hi) {
513                                 push @others, ("../../locolor/$type/apps",
514                                                                         "../../locolor/$type/filesystems",
515                                                                         "../../locolor/$type/actions",
516                                                                         "../../locolor/$type/devices",
517                                                                         "../../locolor/$type/mimetypes");
518                         } else {
519                                 push @others, ("../../hicolor/$type/apps",
520                                                                         "../../hicolor/$type/filesystems",
521                                                                         "../../hicolor/$type/actions",
522                                                                         "../../hicolor/$type/devices",
523                                                                         "../../hicolor/$type/mimetypes");
524                         }
525                         my $o;
526                         foreach $o (@others) {
527                                 if (-d "$dir/../$o/") {
528                                         my @l = scanDir("$dir/../$o/");
529                                         push @fileList, map {"../$o/$_"} @l;
530                                 }
531                         }
532                 }
533                 my $file = "";
535                 foreach $file (@fileList) {
536                         my $xpmFile = "";
537                         my $mainXpm = 0;
538                         my $xpmdir = $dir;
540                         if ($convert) {
541                                 $xpmFile = changeIconFilename($file);
542                                 # the back hack continued:
543                                 if ($xpmFile =~ /^\.\./) {
544                                         $xpmFile = substr($xpmFile,rindex($xpmFile,"/"));
545                                         next if -f "$outDir$dirtype/$xpmFile";
546                                 }
547                                 next if $update && -f "$outDir$dirtype/$xpmFile";
548                         }
549                         if ($convert) {
550                                 myPrint (1,"transform $file ...");
551                                 myPrint(2,"\n\t convert to $type xpm ... ");
552                                 system("$magickPath/convert -colors $magickColors $sizeOpt ".
553                                         "-colorspace $magickColorspace ".
554                                         "$dir/$file $outDir$dirtype/$xpmFile");
555                                 $xpmdir = "$outDir$dirtype";
556                                 myPrint(2,"done");
557                         } elsif ($colorize || $tile || $addBorder || $rotate) {
558                                 next unless $file =~ /.xpm$/;
559                                 $xpmFile = $file;
560                                 next if ($update && -f "$outDir$dirtype/$xpmFile");
561                                 myPrint (1,"transform $file ...");
562                         }
564                         if ($convert && $file !~ /.xpm$/ && hasMatte("$dir/$file")
565                                 && $transFilter) {
566                                 myPrint(2,"\n\t transparent filter ... ");
567                                 system("$magickPath/convert -mono -colorspace $magickColorspace ".
568                                         "-layers Matte $sizeOpt -threshold $threshold ".
569                                         "$dir/$file $outDir$dirtype/.mask.xpm");
570                                 $unlinkmask = 1;
571                                 $mainXpm = loadXpm("$outDir$dirtype/$xpmFile");
572                                 my $maskXpm = loadXpm("$outDir$dirtype/.mask.xpm");
573                                 applyTrans($mainXpm, $maskXpm,"None");
574                                 myPrint(2,"done");
575                         }
577                         if ($rotate ne "0") {
578                                 myPrint(2,"\n\t rotate ... ");
579                                 $mainXpm = loadXpm("$xpmdir/$xpmFile")
580                                         if ref($mainXpm) ne "HASH";
581                                 rotateXpm($mainXpm,$rotate);
582                                 myPrint(2,"done");
583                         }
585                         if ($colorize) {
586                                 myPrint(2,"\n\t colorize ... ");
587                                 $mainXpm = loadXpm("$xpmdir/$xpmFile")
588                                         if ref($mainXpm) ne "HASH";
589                                 colorizeXpm($mainXpm);
590                                 myPrint(2,"done");
591                         }
593                         if ($haveToTile) {
594                                 myPrint(2,"\n\t tile ... ");
595                                 $mainXpm = loadXpm("$xpmdir/$xpmFile")
596                                         if ref($mainXpm) ne "HASH";
597                                 applyTile($mainXpm,$tileXpm,$tileType,$xTile,$yTile);
598                                 myPrint(2,"done");
599                         }
601                         if ($haveToAddBorder) {
602                                 myPrint(2,"\n\t add border ... ");
603                                 $mainXpm = loadXpm("$xpmdir/$xpmFile")
604                                         if ref($mainXpm) ne "HASH";
605                                 addBorder($mainXpm,$xBorder,$xBorder,$yBorder,$yBorder,
606                                         $borderColor);
607                                 myPrint(2,"done");
608                         }
611                         $xpmFile = $outFile if ($inFile ne "" && $outFile ne "");
612                         writeXpm($mainXpm,"$outDir$dirtype/$xpmFile")
613                                 if $mainXpm && ref($mainXpm->{'def'}) eq "ARRAY";
615                         myPrint(2,"\n");
616                         myPrint(1, "done\n");
617                         myPrint(2,"\n");
618                 }
619                 unlink("$outDir$dirtype/.mask.xpm") if $unlinkmask;
620         }
622         if ($setRoot && $outFile ne "") {
623                 &setRoot("$outDir/$outFile");
624         }
626         if ($createSymLink ne "") {
627                 createSymLink();
628         }
632 #-----------------------------------------------------------------------------
633 # useful func for transform
635 # parse a tile option and return the good xpm
636 sub getTile($) {
637         my $tile = shift;
638         my $xpm;
639         my $type = "tile";
640         my ($x,$y) = (0, 0);
642         if ($tile =~ /^\s*color:(.*)\s*/) {
643                 my $color = $1;
644                 if ($color =~ /^\+(\d+)\+(\d+)[,](.*)/) {
645                         $color = encode16bpp($3);
646                         $x=$1; $y=$2;
647                 }
648                 $xpm = createMonoXpm(1,1,$color);
649         } elsif ($tile =~ /^\s*expand:(.*)\s*/) {
650                 $xpm = $1;
651                 if ($xpm =~ /^\+(\d+)\+(\d+)[,](.*)/) {
652                         $xpm = $3;
653                         $x=$1; $y=$2;
654                 }
655                 die "no tile xpm $tile" unless -f $xpm;
656                 $type = "expand";
657         } elsif ($tile =~ /^\s*center:(.*)\s*/) {
658                 $tile = $1;
659                 if ($tile =~ /^\+(\d+)\+(\d+)[,](.*)/) {
660                         $tile = $3;
661                 }
662                 die "no tile xpm $tile" unless -f $tile;
663                 $xpm = loadXpm($tile);
664                 $type = "center";
665         }  elsif ($tile =~ /^\s*tile:(.*)\s*/) {
666                 $tile = $1;
667                 if ($tile =~ /^\+(\d+)\+(\d+)[,](.*)/) {
668                         $tile = $3;
669                         $x=$1; $y=$2;
670                 }
671                 die "no tile xpm $tile" unless -f $tile;
672                 $xpm = loadXpm($tile);
673         } else {
674                 if ($tile =~ /^\+(\d+)\+(\d+)[,](.*)/) {
675                         $tile = $3;
676                         $x=$1; $y=$2;
677                 }
678                 die "no tile xpm $tile" unless -f $tile;
679                 $xpm = loadXpm($tile);
680         }
681         return ($xpm,$type,$x,$y);
684 #-------------------------------------
685 # FROM fvwm2gnome
686 sub changeIconFilename {
687         my ($iconName) = @_;
688         my $xpmString = "xpm";
690         my $choppedIconName = substr($iconName, 0, -3);
691         $iconName = "$choppedIconName$xpmString";
692         return $iconName;
695 sub scanDir {
696         my ($scanPath) = @_;
697         my  @dirList = ();
698         opendir(DIR, "$scanPath") || die "cannot open dir $scanPath\n";
699         foreach (readdir(DIR)) {
700                 # must be fixed one day: found all the formats supported
701                 # by ImageMagick ...
702                 push @dirList, $_
703                         if (/.png$/ || /.xpm$/ || /.jpg$/ || /.gif$/);
704         }
705         closedir(DIR);
706         return(@dirList);
709 #-------------------------------------
712 sub getExecFileDir($) {
713         my $execFile = shift;
714         my $done = 0;
715         my $return = 'not found';
716         foreach (@pathDirs) {
717                 my $test = "$_/$execFile";
718                 return $_ if -x  $test;
719         }
720         return $return;
723 #-------------------------------------
724 # create the symlink: need more work
726 sub createSymLink {
727         my $i = 0;
728         my $type;
729         my @dest = split(",", $createSymLink);
730         @dest = map { "$outDir/$_$postfix" } @dest;
731         die "No directory to link!\n"
732                 unless -d $dest[0] && -d $dest[1];
733         myPrint(1,"Create symbolic link\n");
734         foreach $type ("norm", "mini") {
735                 unlink("$ftImagesDir/$type$postfix");
736                 symlink("$dest[$i]","$ftImagesDir/$type$postfix") ||
737                         die "Can't symlink $dest[$i] to $ftImagesDir/$type$postfix";
738                 myPrint(2,"symlink $dest[$i] to $ftImagesDir/$type$postfix\n");
739                 $i++;
740         }
743 #-------------------------------------
744 # check for Image Magick: there is now a Magick-config, but
745 # old (and very good) version of ImageMagick does not have it.
747 sub checkMagick {
748         my $dir  = "";
749         my $bpp = $magickBpp;
751         myPrint(2,"\n");
752         myPrint(1,"Check for ImageMagick ...");
753         if ($magickPath eq "") {
754                 $dir = getExecFileDir("convert");
755                 $dir =~ s/\/$//;
756                 if      ($dir eq 'not found') {
757                         die "Gasp\nconvert from ImageMagick was not found!!\n".
758                                 "\t use the --magick-path option or install ImageMagick.\n"
759                 }
760         } else {
761                 $dir = $magickPath;
762                 $dir =~ s/\/$//;
763                 if (! -x "$dir/convert") {
764                         die "Gasp\nconvert from ImageMagick was not found in:\n".
765                                 "\t$dir, check the --magick-path option\n";
766                 }
767         }
768         myPrint(1," Ok\n");
770         open(VER,"$dir/convert|");
771         my @version = <VER>;
772         close(VER);
773         my $verLine = $version[0];
774         myPrint(2, "$verLine");
775         if ($magickBpp == 0 && $verLine =~ /Q:([0-9][0-9]*)/) {
776                 $bpp = "$1";
777                 myPrint(2, "QuantumLeap: $bpp\n");
778         } elsif ($magickBpp == 0) {
779                 $bpp = 16;
780                 myPrint(1,"WARN: QuantumLeap: no indication from ImageMagick\n".
781                         "\t 16 is assumed (see the -magick-bpp option)\n");
782         }
784         return ($dir,$bpp);
787 #------------------------------------------------------------------------------
788 # cde-like sky (from jos-cdeskylike)
789 #------------------------------------------------------------------------------
791 sub processSky() {
792         my @pattern=();
793         my $coef;
794         if ($patternType ne "") { @pattern = createPattern() }
795         elsif ($patternXpm ne "") { @pattern = createPatternXpm() }
796         else {
797                 die "pattern file $patternFile not found\n" unless -f $patternFile;
798                 open(INFILE,$patternFile);
799                 @pattern = <INFILE>;
800                 close(INFILE);
801         }
803         if ($patternY !~ /^\d+$/) {
804                 my ($ScreenX, $ScreenY) = `xdpyinfo|grep dimensions:` =~ / (\d+)x(\d+)/;
805                 $patternY = $rotate =~ /90/ ? $ScreenX:$ScreenY;
806         }
808         my @consPar = ();
809         my $p; my $W=0; my $test = -1; my $Y=0;
810         $patternGap = 1 if ($patternGap <= 0 || $patternGap !~ /^\d+$/);
811         foreach $p (@pattern) {
812                 $test++;
813                 next if ($test % $patternGap != 0);
814                 chomp($p);
815                 push @consPar, split("",$p);
816                 $Y=$Y+1;
817         }
818         $W=length($pattern[0]);
820         my $nbrColors = 0;
821         my $skyColors = [];
823         ## evaluate the second gradient color ourselves if only one is given
824         ## this is hilightColor() with a different factor...
825         if ($skyColorsOpt && $skyColorsOpt !~ /[,]/) {
826                 my $color = encode16bpp($skyColorsOpt);
827                 my $a = bppTo3intArray($color);
828                 my $i;
829                 for ($i = 0; $i < 3; $i++) {
830                         $a->[$i] = max(255/5, $a->[$i]);
831                         $a->[$i] = min(255, ($a->[$i] * 180) / 100);  # was 110
832                         $a->[$i] = int($a->[$i]);
833                 }
834                 $skyColorsOpt = encode16bpp($a) . ",$skyColorsOpt";
835         }
837         my @tmp = split('[,]', $skyColorsOpt);
838         my $c;
839         foreach $c (@tmp) {
840                 $skyColors->[$nbrColors] = bppTo3intArray(encode16bpp($c));
841                 $nbrColors++;
842         }
844         my $NY = int($patternY/$Y)+1;
845         my $dx = $NY;
847         my $xpm = createMonoXpm($W,1,"None");
848         my $def = $xpm->{'def'};
849         my $pixels = $xpm->{'pixels'};
850         my ($i,$k) = (0, 0);
851         my $id; my $nextId;
853         while ($i < $NY) {
854                 my $t; my $j = 0; my $done = 0; my $l = 0;
855                 if ($i == 0) {
856                         $t=interpolateColors($skyColors,$nbrColors,$i/$dx,$skyComp,$i);
857                         $id = addColor($xpm,encode16bpp($t));
858                 } else { $id = $nextId; }
859                 $t=interpolateColors($skyColors,$nbrColors,($i+1)/$dx,$skyComp,$i+1);
860                 $nextId=addColor($xpm,encode16bpp($t));
861                 $id .= " " if length($id) < length($nextId);
862                 while (defined $consPar[$l] && !$done) {
863                         $pixels->[$k]->[$j] = $consPar[$l] eq "+" ? $id:$nextId;
864                         $j++; $l++;
865                         if ($j == $W) {
866                                 $k++; $j=0; $def->[1] = $k;
867                                 if ($k == $patternY) { $done = 1; $i=$NY;}
868                         }
869                 }
870                 $i++;
871         }
873         rotateXpm($xpm,$rotate) if $rotate ne "0";
875         $outFile = $setRootTmpFile if $outFile eq "";
876         writeXpm($xpm,$outFile);
878         &setRoot($outFile) if $setRoot;
881 #-------------------------------------
882 # create some pattern. Any other idea?
883 # Can one create the "cde-like" like pattern?
885 sub createPattern () {
886         my $type = "uniform";
887         my @pattern = ();
888         my ($i, $n);
889         my $coef = 1;
890         my $coef2 = undef;
891         my @coefs = ();
893         # perl: '?:' may be ommited, but then $2 should be $3.
894         if ($patternType =~ /^random:(\d+)(?::(\d+))?$/) {
895                 $type = "rand";
896                 $coef = $1;
897                 $coef2 = $2 || 8;
898         } elsif ($patternType =~ /^uniform:(\d+)(?::(\d+))?$/) {
899                 $type = "uniform";
900                 $coef = $1;
901                 $coef2 = $2 || 8;
902         } elsif ($patternType =~ /^square:(\d+)(?::(\d+))?$/) {
903                 $type = "square";
904                 $coef = $1;
905                 $coef2 = $2 || $coef;
906         } elsif ($patternType =~ /^altern:(\d+(?:,\d+)*)(?::(\d+))?$/) {
907                 $type = "altern";
908                 @coefs = split(/,/, $1);
909                 push @coefs, $coefs[0] if @coefs == 1;  # for backward compatibility
910                 $coef2 = $2 || 8;
911         } elsif ($patternType =~ /^(\d+)(?:[:,](\d+))?$/) {
912                 $type = "uniform";
913                 $coef = $1;
914                 $coef2 = $2 || 8;
915         } else {
916                 die "Bad --pattern-type argument\n";
917         }
919         if ($type eq "uniform") {
920                 my $p = "+" x $coef2 ."\n";
921                 for ($i=0; $i < $coef; $i++) { push @pattern, $p }
922         }
923         elsif ($type eq "altern") {
924                 my @v = ("+", "-");
925                 for ($n = 0; $n < @coefs; $n++) {
926                         my $p = $v[$n % 2] x $coef2 . "\n";
927                         for ($i = 0; $i < $coefs[$n]; $i++) { push @pattern, $p }
928                 }
929         }
930         elsif ($type eq "square") {
931                 my $p = "+" x $coef2 . "-"x$coef2 ."\n";
932                 for ($i=0; $i < $coef; $i++) { push @pattern, $p }
933         }
934         elsif ($type eq "rand") {
935                 for ($i=0;$i<$coef;$i++) {
936                         my $p = ""; my $j; my $r;
937                         for ($j=0; $j<$coef2; $j++) { $r= rand 1; $p .= $r > 0.5 ? "+" : "-" }
938                         push @pattern, "$p\n";
939                 }
940         }
941         return @pattern;
944 #-------------------------------------
945 # create pattern from an xpm
947 sub createPatternXpm () {
948         my $xpm = loadXpm($patternXpm);
949         my ($c,$r,$nc) = ($xpm->{'def'}->[0],$xpm->{'def'}->[1],$xpm->{'def'}->[2]);
950         my $colors = $xpm->{colors};
951         my $pixels = $xpm->{pixels};
952         my $ids = $xpm->{ids};
953         my $id = "";
954         my @pattern = ();
956         # found the transparent id
957         my $i = 0; my $done =0;
958         while($i < $nc && !$done) {
959                 if ($colors->[$i] eq "None") {
960                         $id = $ids->[$i];
961                         $done = 1;
962                 }
963                 $i++;
964         }
965         for ($i=0; $i<$r; $i++) {
966                 my $pm = ""; my $j;
967                 for ($j=0;$j<$c;$j++) { $pm .= $pixels->[$i]->[$j] eq $id ? "+" :"-"; }
968                 push @pattern, "$pm\n";
969         }
970         return @pattern;
973 #------------------------------------------------------------------------------
974 # evaluating foreground from background in color shemes
975 #------------------------------------------------------------------------------
977 sub processColorSchemes () {
978         my ($lines, $value, $white, $black) = ("","","","");
979         my $evalFores = 0;
980         my @files = ();
981         my $file;
983         $inDir = "$inDir/" unless $inDir =~ /\/$/ || $inDir eq "";
984         if ($inDir !~ /^\//) {
985                 my $tmp =`pwd`;
986                 chomp($tmp);
987                 $inDir ="$tmp/$inDir";
988         }
989         $inDir =~ s/\/$//;
991         if ($outDir !~ /^\//) {
992                 my $tmp =`pwd`;
993                 chomp($tmp);
994                 $outDir ="$tmp/$outDir";
995         }
996         $outDir =~ s/\/$// unless $outDir eq "/";
998         -d $outDir || mkdir("$outDir", 0775) ||
999                 die "Cannot make dir $outDir: [$!]\n"
1000                 . "\t(we do not create more than one level of directories).\n";
1002         opendir(DIR, "$inDir") || die "Cannot open dir $inDir\n";
1003         foreach (readdir(DIR)) {
1004                 push @files, $_ if  /\.$colorSchemesExt$/;
1005         }
1007         if ($colorSchemesFores ne "") {
1008                 $evalFores = 1;
1009                 ($lines, $value, $white, $black) = split(",", $colorSchemesFores);
1010                 die "Bad --colorschemes-fores parameters"
1011                         if ($lines !~ /^\d+$/ || (defined $value && $value !~ /^\d+$/));
1012                 $value = 128 if !defined $value  || $value eq "";
1013                 $white = "white" if !defined $white || $white eq "";
1014                 $black = "black" if !defined $black || $black eq "";
1015         }
1017         myPrint(1,"\ntransform color schemes *.$colorSchemesExt in\n".
1018                 "\t$inDir into\n\t$outDir\n\n");
1020         foreach $file (@files) {
1021                 myPrint(2,"transform $file ... ");
1022                 open(FILE, "$inDir/$file") || die "Cannot open $inDir/$file: [$!]\n";
1023                 my @f = <FILE>;
1024                 close(FILE);
1025                 foreach (@f) { chomp }
1026                 my @g = ();
1028                 if ($evalFores) {
1029                         my $i = 0;
1030                         while (defined $f[$i] && $i < $lines) {
1031                                 #chomp($f[$i]);
1032                                 $g[$i] = $f[$i];
1033                                 my $t = bppTo3intArray(encode16bpp($f[$i]));
1034                                 my $grey = greyval($t);
1035                                 if ($grey >= $value) { $g[$i+$lines] = $black }
1036                                 else { $g[$i+$lines] = $white }
1037                                 $i++;
1038                         }
1039                 } 
1040                 else { @g = @f; }
1042                 open(OUT,">$outDir/$file") || die "Cannot write to $outDir/$file: [$!]\n";
1043                 foreach (@g) { print OUT "$_\n" }
1044                 close(OUT);
1045                 myPrint(2,"done\n");
1046         }
1049 #------------------------------------------------------------------------------
1050 # set the root image
1051 #------------------------------------------------------------------------------
1053 sub setRoot ($) {
1054         my $file = shift || "*none*";
1055         die "No file $file to set root\n" unless -f $file;
1056         system("$setRootProg $file");
1057         unlink($file) if $file eq $setRootTmpFile;
1060 #------------------------------------------------------------------------------
1061 # Info
1062 #------------------------------------------------------------------------------
1064 sub formatColorInfoLine ($$$) {
1065         my $colorName = shift;
1066         my $colorRgb = encode16bpp(shift);
1067         my $base = shift;
1069         my ($r, $g, $b) = ($colorRgb =~ /^#(..)..(..)..(..)..$/);
1070         my $trio = bppTo3intArray($colorRgb);
1071         return sprintf("%-${base}s  %7s    %3d %3d %3d",
1072                 "$colorName:", "#$r$g$b", @{$trio});
1075 sub formatColorInfoHeadLine ($) {
1076         my $base = shift;
1077         return sprintf("%-${base}s  %8s   %s",
1078         "Color name", "8bpp RGB", "Decimal RGB");
1081 sub showXcolorsInfo ($) {
1082         my $set = shift;
1083         my $base = $set ? 25 : 17;
1084         my $nbr;
1085         my $key;
1087         loadRGB();
1088         print formatColorInfoHeadLine($base), "\n\n";
1090         foreach $key (sort keys %rgb) {
1091                 $nbr = $rgb{"$key"};
1092                 print formatColorInfoLine($key, $nbr, $base), "\n";
1093                 if ($set) {
1094                         my $prefix;
1095                         foreach $prefix ("shadow","hilight","random","top255","top50") {
1096                                 print formatColorInfoLine("$prefix $key", "$prefix$nbr", $base),
1097                                         "\n";
1098                         }
1099                         print "\n";
1100                 }
1101         }
1104 sub showColorInfo {
1105         my $color = shift;
1106         my $base = 25;
1107         loadRGB();
1108         my $nbr = encode16bpp("$color");
1109         my $a = bppTo3intArray($nbr);
1111         print "Information on $color:\n\n";
1113         my $best = 256;
1114         my $t;
1115         my @x =();
1116         my $key;
1117         foreach $key (sort keys %rgb) {
1118                 my $b = bppTo3intArray($rgb{"$key"});
1119                 $t =
1120                   sqrt(($$a[0]-$$b[0])**2+($$a[1]-$$b[1])**2+($$a[2]-$$b[2])**2)/sqrt(3);
1121                 push @x, $key if $t == $best;
1122                 if ($t < $best) { $best = $t; @x = ("$key"); }
1123         }
1125         if ($best == 0) {
1126                 print "\tX color name(s): @x\n";
1127         } else {
1128                 print "\tClosest X color name(s): ", join(', ',@x), " (".int($best).")\n";
1129         }
1130         print "\n";
1131         print "\t", formatColorInfoHeadLine($base), "\n\n";
1132         print "\t", formatColorInfoLine("$color", "$nbr", $base), "\n";
1134         my $prefix;
1135         foreach $prefix ("shadow", "hilight", "random", "top255", "top200",
1136                 "top150", "top100", "top50") {
1137                 print "\t", formatColorInfoLine("$prefix $color", "$prefix$nbr", $base),
1138                         "\n";
1139         }
1140         print "\n";
1144 #------------------------------------------------------------------------------
1145 # an xpm lib
1146 #------------------------------------------------------------------------------
1148 sub loadXpm ($) {
1150         my $file = shift;
1151         my $xpm;
1153         open(XPM, $file) || die "Impossible to load $file";
1154         my $count = -1;
1155         my ($isColors,$isPixels) = (0, 0);
1156         my ($pixCount, $inComment) = (0, 0);
1157         my ($nc,$cpp);
1158         my ($i,$re);
1159         my $def = [];
1160         my $pixels = [];
1161         my $colors = [];
1162         my $ids = [];
1164         while(<XPM>) {
1165                 # "in comment" need amelioration ...
1166                 $inComment = 1 if (/^\s*\/\*/);
1167                 if ($inComment) {
1168                         $inComment = 0 if /\*\//;
1169                         next;
1170                 }
1171                 s/^\s*//;
1172                 next if $_ !~ /^\"/;
1173                 chomp;
1174                 s/^\"//;
1175                 s/\"*,*\}*;*\s*$//;
1176                 my $line = $_;
1177                 if ($isPixels) {
1178                         # can we do this faster ?
1179                         $pixels->[$pixCount] = [ $line =~ /$re/ ];
1180                         #die "bad number of columns in xpm file $file\n"
1181                         #       if ($#{@{$pixels->[$pixCount]}} != $def->[0]);
1182                         $pixCount++;
1183                 }
1184                 elsif ($isColors) {
1185                         $ids->[$count] = substr($line,0,$cpp);
1186                         $line = substr($line,$cpp+1);
1187                         $line =~ s/^\s*//;
1188                         # suppress these stupids "s None"
1189                         $line =~ s/s\s+none$//i;
1190                         $line =~ s/^\s*c\s+//;
1191                         $line =~ s/\s*$//;
1192                         # encode in 16 bits per pixels ...
1193                         die "bad color definition in $file" if ($line eq "");
1194                         $colors->[$count]=encode16bpp($line);
1195                         $count++;
1196                         if ($count == $nc) {
1197                                 $isColors = 0;
1198                                 $isPixels = 1;
1199                         }
1200                 }
1201                 else {
1202                         $isColors = 1;
1203                         $def = [ $line =~ /\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/ ];
1204                         for ($i=0;$i<4;$i++) {
1205                                 die "it does not seem that $file is an xpm (definition)"
1206                                         unless (defined($def->[$i]));
1207                         }
1208                         $nc = $def->[2];
1209                         $cpp = $def->[3];
1210                         $re = "(" . "." x $cpp . ")";
1211                         $re = "$re" x $def->[0];
1212                         $count++;
1213                 }
1214         }
1215         close(XPM);
1216         # check if the format is ok:
1217         die "it does not seem that $file is an xpm\n"
1218                 if ($count < 1 || !$isPixels || ($def->[1] != $pixCount));
1220         $xpm->{'def'} = $def;
1221         $xpm->{'colors'} = $colors;
1222         $xpm->{'ids'} = $ids;
1223         $xpm->{'pixels'} = $pixels;
1224         return $xpm;
1227 #-------------------------------------
1228 # write an xpm to a file
1230 sub writeXpm ($;$) {
1231         my $xpm = shift;
1232         my $file = shift || "";
1233         my $out ="";
1234         my $def = $xpm->{'def'};
1235         my $pixels = $xpm->{'pixels'};
1236         my $i;
1238         $out .= qq(/* XPM */\nstatic char *ft_xpm[] = {\n);
1239         $out .= qq(/* columns rows colors chars-per-pixel */\n);
1240         $out .= qq("@{$def}",\n);
1242         for($i = 0; $i < $def->[2]; $i++) {
1243                 $out .= qq("$xpm->{'ids'}->[$i] c $xpm->{'colors'}->[$i]",\n);
1244         }
1245         $out .= "/* pixels */\n";
1247         for ($i=0; $i < $def->[1]; $i++) {
1248                 $out .= qq(");
1249                 $out .= join ("", @{$pixels->[$i]}[0 .. $def->[0]-1]);
1250                 $out .= qq(",\n);
1251         }
1252         chomp($out);
1253         $out .= "\n};\n";
1255         if (defined($file)) {
1256                 # use saveFile() from possible Util::FileSystem lib?
1257                 open(OUT, ">$file") || die "Can't write $file: [$!]";
1258                 print OUT $out;
1259                 close(OUT);
1260         } else {
1261                 print $out;
1262         }
1265 #-------------------------------------
1266 # create a monochrome xpm
1268 sub createMonoXpm($$$) {
1269         my $columns = shift || 1;
1270         my $rows =  shift || 1;
1271         my $color = shift || "None";
1272         my $xpm; my $i; my $j;
1274         $xpm->{'def'} = [$columns, $rows, 1, 1];
1275         $xpm->{'colors'}->[0] = encode16bpp($color);
1276         $xpm->{'ids'}->[0] = " ";
1278         for ($i = 0; $i<$rows; $i++) {
1279                 for ($j = 0; $j<$columns; $j++) { $xpm->{'pixels'}->[$i]->[$j] = " "; }
1280         }
1281         return $xpm;
1284 #-------------------------------------
1285 # get the color id from its nbr.
1286 # we need the reverse function ...
1288 sub getColorId($$) {
1289         my $nbr = shift;
1290         my $cpp = shift;
1291         my $id = "";
1292         my $k;
1294         my $max = 92**$cpp;
1295         return undef if ($max <= $nbr);
1297         for ($k = $cpp-1; $k >= 0; $k--) {
1298                 $a = int($nbr / (92 ** $k));
1299                 $id = substr($singleIdList, $a, 1) . $id;
1300                 $nbr -= $a*(92 ** $k);
1301         }
1303         return $id;
1306 #-------------------------------------
1307 # add a new colors
1309 sub addColor($$) {
1310         my $xpm = shift;
1311         my $color = shift;
1312         my $def = $xpm->{'def'};
1313         my $ids = $xpm->{'ids'};
1314         my $colors = $xpm->{'colors'};
1316         # does the color is already there?
1317         if (!$beFast) {
1318                 my $i;
1319                 for($i = 0; $i < $def->[2]; $i++) {
1320                         return $ids->[$i] if $colors->[$i] eq "$color";
1321                 }
1322         }
1324         # get the id for the new colors
1325         my $id = getColorId($def->[2], $def->[3]);
1327         if (defined($id)) {
1328                 $def->[2]++;
1329         } else {
1330                 $id = addACharPerPix($xpm); # and a dummy color
1331    }
1333         $ids->[$def->[2]-1] = $id;
1334         $colors->[$def->[2]-1] = $color;
1335         return $id;
1338 #-------------------------------------
1339 # add a char per Pixels and a dummy colors
1341 sub addACharPerPix {
1342         my $xpm = shift;
1343         my $def = $xpm->{'def'};
1344         my $colors = $xpm->{'colors'};
1345         my $ids = $xpm->{'ids'};
1346         my $pixels = $xpm->{'pixels'};
1347         my $nc = $def->[2];
1348         my $i;
1350         $def->[3]++;
1351         @{$ids} = map { "$_ " } @{$ids};
1352         # add a dumy colors
1353         $ids->[$nc] = " " x ($def->[3]-1) . ".";
1354         $colors->[$nc] = $colors->[$nc-1];
1355         $def->[2]++;
1357         for ($i = 0; $i < $def->[1]; $i++) {
1358                 @{$pixels->[$i]} = map { "$_ " } @{$pixels->[$i]};
1359         }
1360         return $ids->[$def->[2]-1];
1363 #-------------------------------------
1364 # Take 2 xpm $xpm and $mask of the same size and set the pixel
1365 # of $xpm to $colors if the corresponding pixel of mask is black
1366 # (i.e. #0* or grey0 or black).
1368 sub applyTrans {
1369         my $xpm = shift;
1370         my $mask = shift;
1371         my $color = shift;
1372         my ($mcolors,$mids,$mpixels,$nc) = ($mask->{'colors'}, $mask->{'ids'},
1373                 $mask->{'pixels'},$mask->{'def'}->[2]);
1374         my ($xpixels,$def) = ($xpm->{'pixels'},$xpm->{'def'});
1375         my ($done,$i) = (0, 0);
1376         my $j;
1377         my $t = "";
1379         # found the transparent id
1380         while($i < $nc && !$done) {
1381                 my $tmp = $mask->{'colors'}->[$i];
1382                 if ($mcolors->[$i] =~ /^#0*$/ ||
1383                         $mcolors->[$i] =~ /^gray0$/i ||
1384                         $mcolors->[$i] =~ /^black$/i) {
1385                         $t = $mids->[$i];
1386                         $done = 1;
1387                 }
1388                 $i++;
1389         }
1391         return if $t eq "";
1393         my $id = addColor($xpm,$color);
1395         for ($i=0; $i<$def->[1]; $i++) {
1396                 for ($j=0; $j<$def->[0]; $j++) {
1397                         $xpixels->[$i]->[$j] = $id if $mpixels->[$i]->[$j] eq "$t";
1398                 }
1399         }
1403 #-------------------------------------
1404 # add border to an xpm
1406 sub addBorder($$$$$$) {
1407         my ($xpm,$x1,$x2,$y1,$y2,$color) = @_;
1408         my $id = addColor($xpm,encode16bpp($color));
1409         my $columns = $xpm->{'def'}->[0];
1410         my $rows = $xpm->{'def'}->[1];
1411         my $pixels = $xpm->{'pixels'};
1412         my @addLeft = ();
1413         my @addRight = ();
1414         my $i;
1416         for ($i = 0; $i < $x1; $i++) { $addLeft[$i] = $id; }
1417         for ($i = 0; $i < $x2; $i++) { $addRight[$i] = $id; }
1418         my @new_row = ();
1419         for ($i=0; $i < $columns + $x1 + $x2; $i++) { $new_row[$i] = $id; }
1420         # shift the rows and add left and right border:
1421         for ($i = $rows + $y1 - 1; $i >= $y1; $i--) {
1422                 @{$pixels->[$i]}= (@addLeft,
1423                         @{$pixels->[$i-$y1]}[0..$columns-1],@addRight);
1424         }
1425         # add top border
1426         for ($i = 0; $i < $y1; $i++) { @{$pixels->[$i]} = @new_row; }
1427         # add bottom border
1428         for ($i = $rows + $y1 ; $i < $rows + $y1 + $y2; $i++) {
1429                 @{$pixels->[$i]} = @new_row;
1430         }
1431         $xpm->{'def'}->[0] += $x1 + $x2;
1432         $xpm->{'def'}->[1] += $y1 + $y2;
1435 #-------------------------------------
1436 # tile an xpm
1438 sub applyTile {
1439         my $xpm = shift;
1440         my $tile = shift;
1441         my $type = shift;
1442         my $x = shift || 0;
1443         my $y = shift || 0;
1445         my ($done,$i,$k) = qw(0 0 0);
1446         my $t = "";
1447         my %idConv = ();
1449         if ($type ne "center" && ($x != 0 || $y != 0)) {
1450                 addBorder($xpm,$x,$x,$y,$y,"None");
1451         }
1453         my $columns = $xpm->{'def'}->[0];
1454         my $rows = $xpm->{'def'}->[1];
1456         if ($type eq "expand") {
1457                 system("$magickPath/convert -geomerty $columns" .
1458                         "x$rows" ."! $tile /tmp/ft-tmp-images.xpm");
1459                 $tile = loadXpm("/tmp/ft-tmp-images.xpm");
1460                 unlink("/tmp/ft-tmp-images.xpm");
1461                 $type = "center";
1462         }
1464         # add border to $xpm
1465         if ($type eq "center") {
1466                 my ($x1,$x2,$x3,$x4,$y1,$y2);
1467                 my $tilecol = $tile->{'def'}->[0];
1468                 my $tilerows = $tile->{'def'}->[1];
1469                 my $x = $tilecol > $columns ? $tilecol-$columns : 0;
1470                 my $y = $tilerows > $rows ? $tilerows-$rows : 0;
1472                 if ($x/2 == int($x/2)) { $x1= $x2 = $x/2; }
1473                 else { $x1 = int($x/2) + 1; $x2 = int($x/2); }
1474                 if ($x/2 == int($y/2)) { $y1 =$y2 =$y/2; }
1475                 else { $y1 = int($y/2) + 1; $y2 = int($y/2); }
1477                 addBorder($xpm,$x1,$x2,$y1,$y2,"None");
1478                 $columns = $xpm->{'def'}->[0];
1479                 $rows = $xpm->{'def'}->[1];
1480         }
1482         # add the $tile colors in $xpm
1483         my $tilenc = $tile->{'def'}->[2];
1484         my $tilecolors = $tile->{'colors'};
1485         my $tileids = $tile->{'ids'};
1486         for($i = 0; $i < $tilenc; $i++) {
1487                 $idConv{"$tileids->[$i]"} = addColor($xpm,"$tilecolors->[$i]");
1488         }
1490         # found the transparent id
1491         my $xpmnc = $xpm->{'def'}->[2];
1492         my $colors = $xpm->{'colors'};
1493         my $ids = $xpm->{'ids'};
1494         $i = 0;
1495         while($i < $xpmnc && !$done) {
1496                 if ($colors->[$i] =~ /^none$/i) { $t = $ids->[$i]; $done = 1; }
1497                 $i++;
1498         }
1500         return if $t eq "";
1502         # add some space if need in the id hash
1503         my $xpmcpp = $xpm->{'def'}->[3];
1504         foreach $i (keys %idConv) {
1505                 my $len = length($idConv{"$i"});
1506                 $idConv{"$i"} .= " "x($xpmcpp-$len);
1507         }
1509         # apply the tile:
1510         my $pixels = $xpm->{'pixels'};
1511         my $tpixels = $tile->{'pixels'};
1512         for ($i = 0; $i < $rows; $i++) {
1513                 my($j,$l) = (0, 0);
1514                 for ($j = 0; $j < $columns; $j++) {
1515                         if ($pixels->[$i]->[$j] eq "$t") {
1516                                 $pixels->[$i]->[$j] = $idConv{"$tpixels->[$k]->[$l]"};
1517                         }
1518                         $l = defined $tpixels->[$k]->[$l+1] ? $l+1:0;
1519                 }
1520                 $k = defined $tpixels->[$k+1]->[0] ? $k+1:0;
1521         }
1524 #-------------------------------------
1525 # colorize an xpm from jos-colorizexpm
1527 sub colorizeXpm() {
1529         my $xpm = shift;
1530         my ($min,$max)= qw(255 0);
1531         my @tmp;
1532         my $colors = $xpm->{'colors'};
1534         die "colorize computation does not support polynomial interpolation\n"
1535                 if $rizeComp =~ /^p/;
1537         my $nc = $xpm->{'def'}->[2];
1538         my @GREY = ();
1539         my $i;
1540         for ($i=0;$i<$nc;$i++) {
1541                 next if $colors->[$i] =~ /^None$/i;
1542                 my $t = bppTo3intArray($colors->[$i]);
1543                 $GREY[$i] = greyval($t);
1544                 if ($GREY[$i]<$min) {$min=$GREY[$i]};
1545                 if ($GREY[$i]>$max) {$max=$GREY[$i]};
1546         }
1548         my $dx = 255; my $x1; my $x2;
1549         if ($rizeRule eq "min") {
1550                 $x1=0;$x2=1;
1551         } else {
1552                 # ??:  olicha: there is a problem if $dx < $min or $max ??
1553                 #$dx = $max-$min;
1554                 #$dx = 1 if $dx<=0;
1555                 #$x1=$min/$dx;
1556                 #$x2=$max/$dx;
1557                 # I think this is better ? (see also the modification in interpolate)
1558                 $x1 = $min/$dx;
1559                 $x2 = $max/$dx;
1560         }
1562         my $nbrColors = 0;
1563         my $rizeColors = [];
1564         @tmp = split('[,]', $rizeColorsOpt);
1566         if ($tmp[0] =~ /^\s*top\s*[[#A-Za-z]/) {
1567                 $min = int($min);
1568                 $tmp[0] =~ s/^\s*top\s*/top$min/;
1569         }
1570         if ($tmp[-1] =~ /^top[[#A-Za-z]/) {
1571                 $max = int($max);
1572                 $tmp[-1] =~ s/^\s*top\s*/top$max/;
1573         }
1575         my $c;
1576         foreach $c (@tmp) {
1577                 $rizeColors->[$nbrColors] = bppTo3intArray(encode16bpp($c));
1578                 $nbrColors++;
1579         }
1581         $transColor = encode16bpp("$transColor") if $transColor ne "";
1582         for ($i = 0; $i < $nc; $i++) {
1583                 if ($colors->[$i] =~ /^None$/i) {
1584                         $colors->[$i] = $transColor if $transColor ne "";
1585                         next;
1586                 }
1587                 my $G=$GREY[$i]/$dx;
1588                 # need a better fix
1589                 $G = 1 if $G > 1;
1590                 my $t=interpolateColors($rizeColors,$nbrColors,$G,$rizeComp,$i,$x1,$x2);
1591                 $colors->[$i]=encode16bpp($t);
1592         }
1595 #-------------------------------------
1596 # rotate
1598 sub rotateXpm($$) {
1599         my $xpm = shift;
1600         my $angle = shift || $rotate;
1601         my ($c,$r,$pixels)=($xpm->{'def'}->[0],$xpm->{'def'}->[1],$xpm->{'pixels'});
1602         my ($i,$j);
1603         my $np =[];
1605         if ($angle eq "0m" || $angle eq "-0m") {
1606                 for ($i=0;$i<$r;$i++) { @{$pixels->[$i]}= reverse @{$pixels->[$i]} }
1607         }
1608         elsif ($angle eq "90") {
1609                 for ($i=0;$i<$r;$i++) {
1610                         for ($j=0;$j<$c;$j++) { $np->[$j]->[$i] = $pixels->[$i]->[$c-$j-1] }
1611                 }
1612                 @{$pixels} = @{$np};
1613                 $xpm->{'def'}->[0] = $r; $xpm->{'def'}->[1] = $c;
1614         }
1615         elsif ($angle eq "90m") {
1616                 for ($i=0;$i<$r;$i++) {
1617                         for ($j=0;$j<=$c;$j++) { $np->[$j]->[$i]= $pixels->[$i]->[$j] }
1618                 }
1619                 $pixels = $np;$xpm->{'def'}->[0] = $r; $xpm->{'def'}->[1] = $c;
1620         }
1621         elsif ($angle eq "-90") {
1622                 for ($i=0;$i<$r;$i++) {
1623                         for ($j=0;$j<=$c;$j++) { $np->[$j]->[$i] = $pixels->[$r-$i-1]->[$j] }
1624                 }
1625                 @{$pixels} = @{$np};
1626                 $xpm->{'def'}->[0] = $r; $xpm->{'def'}->[1] = $c;
1627         }
1628         elsif ($angle eq "-90m") {
1629                 for ($i=0;$i<$r;$i++) {
1630                         for ($j=0;$j<=$c;$j++) {
1631                                 $np->[$j]->[$i] = $pixels->[$r-$i-1]->[$c-$j-1]
1632                         }
1633                 }
1634                 @{$pixels} = @{$np};
1635                 $xpm->{'def'}->[0] = $r; $xpm->{'def'}->[1] = $c;
1636         }
1637         elsif ($angle eq "-180m") {
1638                 for ($i=0;$i<$r;$i++) {
1639                         for ($j=0;$j<=$c;$j++) { $np->[$i]->[$j] = $pixels->[$r-$i-1]->[$j] }
1640                 }
1641                 @{$pixels} = @{$np};
1642         }
1643         elsif ($angle eq "-180") {
1644                 for ($i=0;$i<$r;$i++) {
1645                         for ($j=0;$j<=$c;$j++) {
1646                                 $np->[$i]->[$j] = $pixels->[$r-$i-1]->[$c-$j-1]
1647                         }
1648                 }
1649                 @{$pixels} = @{$np};
1650         }
1651         elsif ($angle ne "0" && $angle ne "-0") {
1652                 die "rotate argument must be either 0[m], 90[m], -90[m], 180[m]".
1653                          " or -180[m]\n";
1654         }
1657 #-----------------------------------------------------------------------------
1658 # colors library
1659 #-----------------------------------------------------------------------------
1661 #-------------------------------------
1662 # load the X rgb.txt file
1664 sub loadRGB() {
1666         # return if it is already loaded
1667         return if defined $rgb{'gray0'};
1669         my $rgbFile = "";
1670         my $path = "";
1672         foreach (@xlibPath) {
1673                 s/^-L//;
1674                 $path = $_;
1675                 $path .= "/X11/rgb.txt";
1676                 $rgbFile = $path if -f $path;
1677         }
1679         die "X window rgb.txt file not found under @xlibPath" if $rgbFile eq "";
1681         open(RGB,"$rgbFile") || die "impossible to read $rgbFile";
1682         while(<RGB>) {
1683                 if ( /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.+)\s*$/ ) {
1684                         my $name = lc($4);
1685                         my $a = int2hex($1);
1686                         my $b = int2hex($2);
1687                         my $c = int2hex($3);
1688                         $rgb{"$name"} = "#$a$a$b$b$c$c";
1689                 }
1690         }
1691         close(RGB);
1694 #-------------------------------------
1695 # Encode in 16 bits by pixels: we must be as general as possible
1696 # and this is not a problem for the one which use 8bpp
1697 # so I suggest we use 16 bpp and a 12 digit hex number as
1698 # default encoding for colors. Then, if a function need to
1699 # compute on the colors it will transform to the colors format it
1700 # want and convert back to 16bpp in hex.
1702 sub encode16bpp($) {
1703         my $color = shift;
1705         if (ref($color) eq "ARRAY") {
1706                 # here we must be as fast as possible
1707                 int2hexRef($color);
1708                 return
1709                         "#$color->[0]$color->[0]$color->[1]$color->[1]$color->[2]$color->[2]";
1710         }
1711         $color =~ s/^\s*//;
1712         $color =~ s/\s*$//;
1713         if ($color =~ /^\[?\s*(\d+)\s*\/\s*(\d+)\s*\/\s*(\d+)\s*\]?$/) {
1714                 my ($a,$b,$c);
1715                 $a = int2hex($1);
1716                 $b = int2hex($2);
1717                 $c = int2hex($3);
1718                 return "#$a$a$b$b$c$c";
1719         }
1720         elsif ($color =~ m!^rgb:([a-f\d]{2,4})/([a-f\d]{2,4})/([a-f\d]{2,4})$!i) {
1721                 return "#$1$2$3" if length($1) == 4;
1722                 return "#$1$1$2$2$3$3";
1723         }
1724         elsif ($color =~ /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/) {
1725                 return "#$1$1$2$2$3$3";
1726         }
1727         elsif ($color =~/^#[0-9a-fA-F]{12}$/) {
1728                 return $color;
1729         }
1730         elsif ($color =~ /none/i) {
1731                 return "None";
1732         }
1733         # fixed some bugs in various apps
1734         elsif ($color =~ /transparent/i) {
1735                 return "None";
1736         }
1737         elsif ($color =~ /^random\s*(.*)$/i) {
1738                 return randomColor($1);
1739         }
1740         elsif ($color =~ /^top(\d*)\s*(.+)$/i) {
1741                 my $a;
1742                 $a = $1;
1743                 $a = 255 if $a eq "";
1744                 return topColor($2,$a);
1745         }
1746         elsif ($color =~ /^hilight\s*(.+)$/i) {
1747                 return hilightColor($1);
1748         }
1749         elsif ($color =~ /^shadow\s*(.+)$/i) {
1750                 return shadowColor($1);
1751         }
1752         else {
1753                 loadRGB();
1754                 $color = lc("$color");
1755                 return $rgb{"$color"} if (defined $rgb{"$color"});
1756         }
1758         warn "Unknown color $color, set it to black.\n";
1759         return "#000000000000";
1762 #-------------------------------------
1763 # 16bpp to a ref array (0-255,0-255,0-255)
1765 sub bppTo3intArray($) {
1766         # can we be more fast?
1767         my $color = shift;
1768         my @a = $color =~ /#(..)..(..)..(..)/;
1769         @a=(hex($a[0]),hex($a[1]),hex($a[2]));
1770         return \@a;
1773 #-------------------------------------
1774 # the random color
1776 sub randomColor {
1777         my $color = shift;
1778         my $a;
1780         $a->[0] = int(rand 256);
1781         $a->[1] = int(rand 256);
1782         $a->[2] = int(rand 256);
1784         return encode16bpp($a) if ($color eq "");
1786         # not terrible ... a better idea?
1787         $color = encode16bpp($color);
1788         my $b = bppTo3intArray($color);
1789         my $i;
1790         for ($i=0;$i<3;$i++) {
1791                 $$b[$i] = int(($$a[$i] + 2*$$b[$i]) / 3);
1792         }
1793         return  encode16bpp($b);
1796 #-------------------------------------
1797 # top colors from jos-colorizexpm
1799 sub topColor {
1800         my $color = shift;
1801         my $max = shift;
1803         $color = encode16bpp($color);
1804         my $a = bppTo3intArray($color);
1805         my $CenterG=greyval($a);
1806         $CenterG = 1 if $CenterG == 0;
1807         my $HI = $max/$CenterG;
1808         my $i;
1809         for ($i = 0; $i < 3; $i++) {
1810                 $$a[$i] = int($$a[$i] * $HI);
1811                 $$a[$i] = $$a[$i] > 255 ? 255 : $$a[$i];
1812         }
1813         return  encode16bpp($a);
1816 #-------------------------------------
1817 # from jos-colorset-cdegradient
1818 # an hilight white is white ?
1819 # migo: Yes for GTK style hilighting, no for motif.
1820 # migo: fvwm algorithms are in libs/ColorUtils.c (2.2.4 is better).
1822 sub hilightColor {
1823         my $color = shift;
1825         $color = encode16bpp($color);
1826         my $a = bppTo3intArray($color);
1827         my $i;
1828         for ($i = 0; $i < 3; $i++) {
1829                 $a->[$i] = max(255/5, $a->[$i]);
1830                 $a->[$i] = min(255, ($a->[$i] * 130) / 100);  # was 110
1831                 $a->[$i] = int($a->[$i]);
1832         }
1833         return  encode16bpp($a);
1836 #-------------------------------------
1837 # from jos-colorset-cdegradient
1838 # is this 0.9 official? What about 0.8
1839 # Moreover a shadow black is black ?
1840 # migo: Yes for GTK style hilighting, no for motif.
1842 sub shadowColor {
1843         my $color = shift;
1845         $color = encode16bpp($color);
1846         my $a = bppTo3intArray($color);
1847         my $i;
1848         for ($i = 0; $i < 3; $i++) {
1849                 $a->[$i] *= 0.7;  # was 0.9
1850                 $a->[$i] = int($a->[$i]);
1851         }
1852         return  encode16bpp($a);
1856 #--------------------------------------
1857 # grey value of a ref (\d+,\d+,\d+) colors from jos-colorizexpm
1859 sub greyval {
1860         my $c = shift;
1861         return sqrt($$c[0]**2 + $$c[1]**2 + $$c[2]**2)/sqrt(3);
1864 #-------------------------------------
1865 # interpolate colors
1867 sub interpolateColors {
1868         my $colors = shift;
1869         my $nc = shift;       # nbr of colors
1870         my $x = shift;
1871         my $type = shift;
1872         my $step = shift || 0;
1873         my $x1 = shift || 0; # $x1 and $x2 are used by colorizeXpm
1874         my $x2 = shift || 1;
1875         my @a = qw(0 0 0);
1876         my $c = $nc-1;
1877         my $i; my $j;
1879         die "You need to specify at least two colors in the color list\n"
1880                 if $c <= 0;
1882         if ($type =~ /^t/) {
1883                 for ($i = 0; $i < 3 ; $i++) { $a[$i] = int(rand 256) }
1884                 return \@a;
1885         }
1887         if ($type =~ /^c/) {
1888                 $i= $step%$nc;
1889                 @a = @{$colors->[$i]};
1890                 return \@a;
1891         }
1893         if ($type =~ /^p/) {
1894                 for ($i =0 ; $i < 3; $i++) {
1895                         for ($j = 0; $j < $nc; $j++) {
1896                                 my $inter = 1; my $k;
1897                                 for ($k = 0; $k < $nc; $k++) {
1898                                         next if $k == $j;
1899                                         $inter *= ($x - $k/$c) * ($c/($j-$k));
1900                                 }
1901                                 $a[$i] += $colors->[$j]->[$i] * $inter;
1902                                 $a[$i] = int ($a[$i]);
1903                                 $a[$i] = 255 if ($a[$i] > 255);
1904                                 $a[$i] = 0 if ($a[$i] < 0);
1905                         }
1906                 }
1907                 return \@a;
1908         }
1910         # more reasonable interpolation:
1911         # try to be as fast as possible !
1912         $x *= $c;
1913         $j=0;
1914         while ($x > ($j+1)) { $j++ }
1915         my $t1 = $j == 0 ? $x1 * $c : $j;
1916         my $t2 = $j == $c-1 ? $x2 * $c : $j+1;
1917         my $d = 1 / ($t2-$t1);
1918         my $l = $j + 1;
1919         # faster than a loop?
1920         # in any case doing the int independently is faster. why?
1921         $a[0] = ($colors->[$j]->[0]*($t2-$x) + $colors->[$l]->[0]*($x-$t1)) * $d;
1922         $a[1] = ($colors->[$j]->[1]*($t2-$x) + $colors->[$l]->[1]*($x-$t1)) * $d;
1923         $a[2] = ($colors->[$j]->[2]*($t2-$x) + $colors->[$l]->[2]*($x-$t1)) * $d;
1924         if ($type =~ /^r/) {
1925                 for ($i=0;$i<3;$i++) {
1926                         $a[$i] = $a[$i] + (-(rand)+rand)*25;
1927                         $a[$i] = 255 if ($a[$i] > 255);
1928                         $a[$i] = 0 if ($a[$i] < 0);
1929                 }
1930         }
1931         ($a[0],$a[1],$a[2]) = (int($a[0]),int($a[1]),int($a[2]));
1932         return \@a;
1935 #-------------------------------------
1936 # integer to hexadecimal (from jos-colorfun)
1938 # $h = int2hex(255); -> "ff"
1939 sub int2hex {
1940         my $i= shift;
1941         # modified for speed (olicha)
1942         my $h = $Hex[$i/16] . $Hex[$i%16];
1943         return $h;
1946 sub int2hexRef {
1947         my $a= shift;
1948         my $i;
1949         # must be as fast as possible
1950         $a->[0] = $Hex[$a->[0]/16] . $Hex[$a->[0]%16];
1951         $a->[1] = $Hex[$a->[1]/16] . $Hex[$a->[1]%16];
1952         $a->[2] = $Hex[$a->[2]/16] . $Hex[$a->[2]%16];
1955 #-----------------------------------
1956 # min and max
1958 sub min {
1959         my ($a, $b) = @_;
1960         return ($a < $b) ? $a : $b;
1963 sub max {
1964         my ($a, $b) = @_;
1965         return ($a > $b) ? $a : $b;
1969 #-----------------------------------------------------------------------------
1970 # my !xpm image lib :o)
1971 #-----------------------------------------------------------------------------
1973 sub hasMatte {
1974         my $file = shift;
1975         my $done= 0;
1976         my $r = 0;
1978         open(IDENT,"$magickPath/identify -verbose $file|");
1979         while (<IDENT>) {
1980                 if (/matte/i && /true/i) { $r = 1; }
1981         }
1982         close(IDENT);
1983         return $r;
1986 #-----------------------------------------------------------------------------
1987 # The starndard functions
1990 sub showHelp {
1991         print "The fvwm-themes images utility.\n";
1992         print "Usage: $scriptName [OPTIONS]\n";
1993         print "General Options:\n";
1994         print "\t--help              show this help and exit\n";
1995         print "\t--version           show the version and exit\n";
1996         print "\t--in-dir dir        The input directory\n";
1997         print "\t--out-dir dir       The main directory for output the images\n";
1998         print "\t--gnome             short cut for converting GNOME icons\n";
1999         print "\t--kde2              short cut for converting KDE2 icons\n";
2000         print "\t--kde2-hi           convert hight colors KDE2 icons\n";
2001         print "\t--site              set the out dir to \$FT_DATADIR/tr-image\n";
2002         print "\t--create-symlink n  Create symlink for use with fvwm-themes\n";
2003         print "\t--update            only create images which are needed\n";
2004         print "\t--ft-install        short cut used by fvwm-themes installation\n";
2005         print "\t--verbose int       level of verbosity\n";
2006         print "Convert\n";
2007         print "\t--convert           convert images to XPM images\n";
2008         print "\t--[no]trans-filter  Apply a transparent filter\n";
2009         print "\t--threshold value   percentage of transparisation\n";
2010         print "\t--postfix str       add -str after 16x16, 48x48... to out dirs\n";
2011         print "\t--[no]build-48x48   build or not 48x48 XPM images\n";
2012         print "\t--[no]build-16x16   build or not 16x16 XPM images\n";
2013         print "\t--[no]build-56x56   build or not 56x56 XPM images\n";
2014         print "\t--[no]build-32x32   build or not 32x32 XPM images\n";
2015         print "\t--[no]build-tiles   build or not tiles XPM images\n";
2016         print "\t--preserve          build XPM images without size modification\n";
2017         print "\t--size-48x48 geo    Set the size of the 48x48 XPM icons\n";
2018         print "\t--size-16x16 geo    Set the size of the 16x16 XPM icons\n";
2019         print "\t--size-56x56 geo    Set the size of the 56x56 XPM icons\n";
2020         print "\t--size-32x32 geo    Set the size of the 32x32 XPM icons\n";
2021         print "\t--size-tiles geo    Set the size of the tiles XPM icons\n";
2022         print "\t--tile-48x48 value  tile to the 48x48 XPM icons\n";
2023         print "\t--tile-16x16 value  tile to the 16x16 XPM icons\n";
2024         print "\t--tile-56x56 value  tile to the 32x32 XPM icons\n";
2025         print "\t--tile-32x32 value  tile to the 56x56 XPM icons\n";
2026         print "\t--tile-tiles value  tile to the tiles XPM icons\n";
2027         print "\t--border-48x48      add border to the 48x48 XPM icons\n";
2028         print "\t--border-16x16      add border to the 16x16 XPM icons\n";
2029         print "\t--border-56x56      add border to the 32x32 XPM icons\n";
2030         print "\t--border-32x32      add border to the 56x56 XPM icons\n";
2031         print "\t--border-tiles      add border to the tiles XPM icons\n";
2032         print "ImageMagick\n";
2033         print "\t--magick-bpp value  number of bit per pixel used by ImageMagick\n";
2034         print "\t--magick-path path  Set the path of ImageMagick convert\n";
2035         print "\t--magick-colors n   Number of colors used by ImageMagick\n";
2036         print "\t--magick-colorspace see the ImageMagick convert man page\n";
2037         print "Simple transformations\n";
2038         print "\t--rotate value      rotate and/or mirror an XPM\n";
2039         print "\t--tile value        tile all images\n";
2040         print "\t--border +x+y,col   add border to all images\n";
2041         print "Colorize\n";
2042         print "\t--colorize          colorize an/all image(s)\n";
2043         print "\t--colorize-colors l comma separated list of colors for colorize\n";
2044         print "\t--trans-color col   set the transparent pixels to col pixels\n";
2045         print "\t--colorize-comp t   interpolation computation type for colorize\n";
2046         print "\t--colorize-rule v   colorization procedure\n";
2047         print "CDE like sky\n";
2048         print "\t--sky               produce cde-like gradient and a lot more\n";
2049         print "\t--sky-colors l      comma separated list of colors for sky\n";
2050         print "\t--pattern-file f    use pattern in file f for sky\n";
2051         print "\t--pattern-type t    create some patterns\n";
2052         print "\t--pattern-xpm f     create a pattern from an XPM\n";
2053         print "\t--pattern-gap n     jump into the pattern\n";
2054         print "\t--sky-comp t        interpolation computation type for sky\n";
2055         print "\t--be-fast           try to be faster by using more memory\n";
2056         print "Set Root Image\n";
2057         print "\t--setroot           set the root window with the built XPM\n";
2058         print "\t--setroot-prog prog command to set the root ($setRootProg)\n";
2059         print "Color schemes\n";
2060         print "\t--colorschemes      process color schemes\n";
2061         print "\t--colorschemes-fores evaluate fore from back for colors schemes\n";
2062    print "\t--colorschemes-ext  file extention for color scheme files\n";
2063         print "Color Info\n";
2064         print "\t--show-xcolors      show a list of all xcolors\n";
2065         print "\t--show-xcolorsets   show a list of all xcolor sets\n";
2066         print "\t--show-color-info c show a full info for the specified color\n";
2067         print "Good luck!\n";
2068         exit 0;
2071 sub showVersion {
2072         print "$version\n";
2073         exit 0;
2076 sub wrongUsage {
2077         print STDERR "Try '$scriptName --help' for more information.\n";
2078         exit -1;
2081 sub myPrint {
2082         my $deg = shift;
2083         my $string = shift;
2085         if ($verbose >= $deg) {
2086                 print "$string";
2087         }
2090 sub myDebug {
2092         my $flag = shift;
2093         my $string = shift;
2094         if ($debug =~ /$flag/ || $debug eq "main") {
2095                 print "(".times.")\t[$flag] $string";
2096         }
2097         # note: for time eval it is better to use perl -d:DProf with dprofpp
2100 __END__
2102 # ---------------------------------------------------------------------------
2104 =head1 NAME
2106 fvwm-themes-images - fvwm-themes images and colors utility
2108 =head1 SYNOPSIS
2110 B<fvwm-themes-images>
2111 B<--convert> or/and B<--rotate> value or/and B<--colorize> or/and
2112 B<--tile> or/and B<--border> or B<--sky> or B<--colorschemes>
2113 or B<--show-xcolors> or B<--show-xcolors-set> or B<--show-color-info> color 
2114 or B<--help> or B<--version>
2115 [ B<--in-dir> dir ]
2116 [ B<--out-dir> dir ]
2117 [ B<--in-file> file ]
2118 [ B<--out-file> file ]
2119 [ B<--gnome> ]
2120 [ B<--kde2> ]
2121 [ B<--kde2-hi> ]
2122 [ B<--site> ]
2123 [ B<--create-symlink> name ]
2124 [ B<--update> ]
2125 [ B<--ft-install> ]
2126 [ B<--verbose> int ]
2127 [ B<--[no]trans-filter> ]
2128 [ B<--threshold> int ]
2129 [ B<--postfix> string ]
2130 [ B<--[no]build-48x48> ]
2131 [ B<--[no]build-16x16> ]
2132 [ B<--[no]build-56x56> ]
2133 [ B<--[no]build-32x32> ]
2134 [ B<--[no]build-tiles> ]
2135 [ B<--preserve> ]
2136 [ B<--size-48x48> geo ]
2137 [ B<--size-16x16> geo ]
2138 [ B<--size-56x56> geo ]
2139 [ B<--size-32x32> geo ]
2140 [ B<--size-tiles> geo ]
2141 [ B<--border> +x+y,color ]
2142 [ B<--border-48x48> +x+y,color ]
2143 [ B<--border-16x16> +x+y,color ]
2144 [ B<--border-56x56> +x+y,color ]
2145 [ B<--border-32x32> +x+y,color ]
2146 [ B<--border-tiles> +x+y,color ]
2147 [ B<--tile rule:file> ]
2148 [ B<--tile-48x48> rule:file ]
2149 [ B<--tile-16x16> rule:file ]
2150 [ B<--tile-56x56> rule:file ]
2151 [ B<--tile-32x32> rule:file ]
2152 [ B<--tile-tiles> rule:file ]
2153 [ B<--rotate> value ]
2154 [ B<--magick-bpp> 8/16 ]
2155 [ B<--magick-path> path ]
2156 [ B<--magick-colors> int ]
2157 [ B<--magick-colorspace> value ]
2158 [ B<--colorize-colors> color1,color2... ]
2159 [ B<--trans-color> color ]
2160 [ B<--colorize-comp> value ]
2161 [ B<--colorize-rule> value ]
2162 [ B<--sky-colors> color1,color2... ]
2163 [ B<--pattern-file> file ]
2164 [ B<--pattern-type> value ]
2165 [ B<--pattern-xpm> file ]
2166 [ B<--pattern-gap> value ]
2167 [ B<--pattern-y> value ]
2168 [ B<--sky-comp> value ]
2169 [ B<--be-fast> ]
2170 [ B<--setroot> ]
2171 [ B<--setroot-prog> exec ]
2172 [ B<--text-colors> value ]
2173 [ B<--colorschemes-fores> num,threshold,color1,color2 ]
2174 [ B<--colorschemes-ext> ext ]
2176 =head1 DESCRIPTION
2178 The aim of this script is to build images to be used by fvwm-themes.
2180 =head2 Convert Images to XPM Images
2182 fvwm-themes-images can convert images in various format
2183 (especially PNG GNOME or KDE version 2 icons) into XPM images of various 
2184 sizes. This
2185 use ImageMagick plus some internal XPM manipulations (to get
2186 better results). For example, if you run:
2188     fvwm-themes-images --convert --gnome
2190 then, if GNOME is not installed in an exotic way all icons
2191 in the GNOME images directory will be converted into 48x48 and 16x16
2192 XPM icons under ~/tr-images (if GNOME is not found the
2193 images in /usr/share/pixmaps will be converted). To control the
2194 result of the conversion you can use the --threshold
2195 and --magick-colors option below. If the result is very very bad you must use
2196 the --magick-bpp option.
2198 You can also convert an individual images by using the --in-file and
2199 --out-file option.
2201 =head2 Other transformations
2203 fvwm-themes-images can perform other transformations (which do not require
2204 ImageMagick). You can colorize, rotate, add border and tile an XPM
2205 images. These operations can be done together (and with "convert")
2206 for all images in a directory or for an individual image.
2207 For example, if you want blue/red mirrored gnome icons tiled with
2208 a-48x48-tile.xpm for 48x48 icons and tiled with a-16x16-tile.xpm for
2209 16x16 icons and with a yellow border of 5 pixels for 48x48 icons and of
2210 2 pixels for 16x16 icons just run fvwm-themes-images with the following
2211 options :o)
2213     --gnome --convert --rotate 0m \
2214     --colorize --colorize-colors blue,red \
2215     --tile-48x48 path_to/a-48x48-tile.xpm \
2216     --tile-16x16 path_to/a-16x16-tile.xpm \
2217     --border-48x48 +5+5,yellow \
2218     --border-16x16 +2+2,yellow
2220 =head2 Colorize
2222 fvwm-themes-images can colorize an XPM image (or a family of images
2223 in a directory). The main aim of "colorize" is to produce an infinite
2224 number of backgrounds with only one xpm. For example:
2226     fvwm-themes-images --colorize --colorize-colors black,red \
2227       --trans-color yellow --in-file My.xpm --setroot
2229 will tile your root window with an XPM build from My.xpm, such that
2230 the darkest pixels in My.xpm are replaced by black pixels, the lightest
2231 pixels are replaced by red pixels, the pixels in between are
2232 interpolated between black and red and the transparent pixels are
2233 replaced by yellow pixels. Moreover, you can use more than 2 colors
2234 and some options allows you to control the interpolation.
2235 You can also rotate, tile and borderize your XPM.
2236 By default, fvwm-themes-images uses "fvwm-root" to
2237 set background, you can specify an other program using the --setroot-prog
2238 option, e.g., if you want to use xv just add the option
2240     --setroot-prog "xv -root -quit"
2242 Note that if you do not specify an out-file, the built XPM
2243 is saved in /tmp/$USER-ft-back.xpm and then removed in this case.
2245 =head2 CDE-LIKE SKY
2247 fvwm-themes-images can set the root window to a gradient pattern like
2248 CDE does. CDE has an option to display a gradient on the background,
2249 which consists of a repeated pattern, but along the color
2250 gradient, the color of the pattern varies. Try:
2252     fvwm-themes-images --sky --sky-colors turquoise,darkblue --setroot
2254 in this case the default pattern file is used
2255 ($FT_DATADIR/themes/cde/background/pattern). A pattern file must contain a
2256 rectangular pattern consisting of +es and -es like this:
2258     +++++
2259     +-+-+
2260     -+-+-
2261     -----
2263 and nothing else. This pattern is painted repeatedly over the
2264 screen. However, the colors change in the y direction accordingly
2265 with the --sky-colors and --sky-comp options. fvwm-themes-images
2266 can generate some pattern. If you want a regular gradient add the
2267 option: --pattern-type uniform:1, try also the --pattern-type
2268 option with square:50 or altern:20 and random:50 for examples.
2269 If you want an horizontal gradient just rotate: --rotate 90.
2270 You can also control the gradient computation. Try: --pattern-type
2271 square:64 --sky-comp c for a chess like background, --pattern-type
2272 altern:64,64 --sky-comp c for a band background, --pattern-type 1
2273 --sky-comp r for an irregular gradient, and --pattern-type 1
2274 --sky-comp t for an horrible background.
2275 Note that if your sky contains a lot of coulours you can speed a
2276 lot the construction of you sky by using the --be-fast option
2277 (but this will build a bigger XPM).
2279 =head2 PROCESSING COLOR SCHEMES
2281 A color scheme file is a file constituted of one color by line.
2282 These colors are traditionally background colors.
2283 At the present time fvwm-themes-images can extend such color scheme
2284 file by adding corresponding foreground colors. For example, if there
2285 are several color scheme files with extension .pal in the directory DIR
2286 and you run:
2288     fvwm-themes-images --colorschemes --colorschemes-ext pal \
2289     --colorschemes-fores 8,128,color1,color2 --in-dir DIR --out-dir DIR
2291 then the 8 first colors of the color scheme files will be unchanged
2292 and 8 new colors will be added (if your original color scheme files have
2293 more than 8 colors these colors are ignored/removed). So, you get color
2294 scheme files with 16 colors. The 7-th color is the foreground color,
2295 corresponding to the 1-st background color and so on. The foreground color
2296 is evaluated to be either color1 or color2. It is color1 for the backgrounds
2297 with gray value < 128 and is color2 otherwise. A gray value of 255
2298 corresponds to white color and a gray value of 0 corresponds to black.
2299 So, the idea is to use a light color for color1 (like white) and a dark
2300 color for color2 (like black).
2302 =head2 COLORS
2304 When giving colors to fvwm-themes-image, you can use X colors name
2305 (blue, turquoise, ...etc.), the standard RGB formats rgb:rr/gg/bb
2306 or rgb:rrrr/gggg/bbbb, 8bits hexadecimal number
2307 (#0000ff, #40e0d0, ...etc.), 16bits  hexadecimal number (#00000000ffff,
2308 #0404e0e0d0d0, ...etc) or an array of 3 decimal numbers between 0 and 255
2309 ([0/0/255], [64/224/208], ...etc.). All these numbers represent the
2310 red, green and blue values of the colors. To get the list of your X colors
2311 which have a name with the corresponding value in 8bits and in an array
2312 of 3 integer just type:
2314     fvwm-themes-images --show-xcolors | less
2316 if you use hexadecimal numbers like B<#abcdef> in some shells you must put
2317 these colors in quotes. Note, if you give colors by hexadecimal numbers
2318 fvwm-themes-images is faster, since rgb.txt should not be loaded.
2320 fvwm-themes-images have some generic ways to create colors. You can
2321 give to fvwm-themes-images a color of the form:
2323     typecolor
2325 where type is either top[integer], hilight, shadow, random and
2326 where color is a color encoded as explained above. If you give
2327 such a color fvwm-themes-images compute for you the "type" color
2328 of the "color". To see the result of these computations for
2329 all the colors which have name try:
2331     fvwm-themes-images --show-xcolorsets | less
2333 for any individual color type:
2335     fvwm-themes-images --show-color-info color
2337 You can enter random alone, this try to produce a random color. The only
2338 type which does not have a clear meaning is "top". top may have an integer
2339 between 0 and 255 after it (default is 255). top255 will purify your
2340 color as top0 will destroy it completely to black. Typically, top255blue
2341 will give blue, top255darkblue will give blue, top50blue will give a
2342 very dark blue. The top type (without integer argument) is used in a
2343 special way with the --colorize-colors option: if you want to colorize
2344 an XPM with "color" as a "center color" try the following:
2346     fvwm-themes-images --colorize --colorize-colors topcolor,topcolor \
2347     --in-file My.xpm --setroot
2349 then, fvwm-themes-images will try to compute good integer values
2350 for I<top> to produce two good colors.
2352 =head1 OPTIONS
2354 =head2 General Options
2356 B<--help>    - show the help and exit
2358 B<--version> - show the version and exit
2360 B<--in-dir> dir - The input directory. Default is the working directory
2361 of the shell that will run fvwm-themes-images. You can give either a complete
2362 path or a relative path (relative to the working directory).
2363 With the --gnome option fvwm-themes-images will try to find the GNOME icons
2364 directory, if GNOME is not found the default is /usr/share/pixmaps.
2366 B<--out-dir> dir - The main directory for output the images. Default
2367 is $HOME/tr-images and $FT_DATADIR/tr-images where $FT_DATADIR
2368 is the fvwm-themes installation directory with the --site option.
2369 You can give either a complete path or a relative path (relative
2370 to the working directory).
2372 B<--in-file> file - input file relatively to the --in-dir option
2373 except if you give a complete path.
2375 B<--out-file> file - output file if you use the --in-file option
2376 and not --convert. You can give either a complete
2377 path or a relative path (relative to the --out-dir option, i.e.,
2378 $HOME/tr-images or $FT_DATADIR/tr-images). Yes, this is strange but
2379 this is good. With --convert - this option is ignored, with --setroot -
2380 you do not need to define an outfile, a temporary file is used,
2381 but you can, if you also want to save it.
2383 B<--site> equivalent to --out-dir $FT_DATADIR/tr-images.
2385 B<--update> if the file to be created already exist skip it. This is
2386 useful for example after you have installed some new GNOME applications
2387 and you do not want to rebuild all your xpm icons, with --update only
2388 the new icons are builded.
2390 B<--gnome> imply --convert, --postfix gnome, and try to find the GNOME icons
2391 directory to define the --in-dir, if GNOME is not found --in-dir is set
2392 to /usr/share/pixmaps
2394 B<--kde2> imply --convert, --postfix kde2, and try to find the KDE2 icons
2395 directory to define the internal generalization of --in-dir, if these
2396 directories are not found or if the KDEDIR environement variable is not set
2397 nothing is done. Low colors icons under apps/ filesystems/ actions/ devices/ 
2398 mimetypes/ and hight colors icons under the same directories are converted.
2399 If two icons to be converted have the same name, then the first found is
2400 converted (relatively to the above directories list). You can reverse the
2401 low/hight colors priority by using the next option. Note that there is a
2402 bug here: the only way to really rebuild the KDE2 icons is to remove the
2403 output directory; if not only the low (hight, with --kde2-hi) colors icons
2404 under apps/ will be rebuild.
2406 B<--kde2-hi> if --kde2 is used convert the KDE2 hight color icons before the
2407 low color icons.
2409 B<--ft-install> equivalent to --site --update --create-symlink 48x48,16x16.
2410 This option must be use with --gnome or --kde2 (but not both).
2412 B<--create-symlink> A,B - where A and B are either 48x48, 16x16, 32x32.
2413 Create symbolic link from $FT_DATADIR/images/norm-postfix to OUT/A-postfix
2414 and from $FT_DATADIR/images/mini-postfix to OUT/B-postfix. Where postfix
2415 is defined with the --postfix option and where OUT is the directory
2416 defined by --out-dir.
2418 B<--verbose> int - where int can be 0, 1 or 2. This integer represents
2419 the level of "verbosity". Default is 1, but with --setroot the default is 0.
2421 =head2 Convert
2423 B<--convert> - Will cause fvwm-themes-images to convert all images
2424 in the directory specified by the --in-dir options into XPM icons
2425 of various sizes. By default, XPM icons of sizes 48x48 and 16x16
2426 are build in dir/48x48 and dir/16x16 where dir is he directory specified
2427 by the --out-dir option
2429 B<--[no]trans-filter> - Apply or not the internal "transparent filter".
2430 Default is --trans-filter and this filter can be controlled with the
2431 --threshold option below.
2432 When ImageMagick convert a PNG image into an XPM one the result is not
2433 perfect (or I have not found the good procedure). The problems is that
2434 a PNG image has a "matte" channel which represent the degree of
2435 transparency/opacity of the images. On the other hands, an XPM image has
2436 a binary matte channel (a pixel is either opaque or transparent).
2437 The "transparent filter" extract the matte channel (using ImageMagick),
2438 then "threshold" it (using again ImageMagick) to get  the "good"
2439 transparency zone which is applied to the XPM image using an internal
2440 procedure (Maybe ImageMagick combine can do that but I never found
2441 the good procedure). If you have bad result try to use
2442 the --magick-bpp options.
2444 B<--threshold> value - value must be an integer between 0 and 100
2445 and represent a percentage. This value is used by the "transparent filter"
2446 to compute the transparency zone of the builded XPM icons. More the value
2447 is big more the resulting images are transparent. For GNOME icons you may
2448 try value between 30 to 99 (a value of 100 will give a family of
2449 empty icons as a value of 0 will probably give to you icons with a
2450 black background). Default is 70.
2452 B<--postfix> str - add "-str" to the name of the output directories of the
2453 converted images: OUTDIR/48x48-str, OUTDIR/16x16-str ...etc.
2455 B<--[no]build-48x48> - build or not the 48x48 XPM icons. Default is
2456 --build-48x48.
2458 B<--[no]build-16x16> - build or not the 16x16 XPM icons. Default is
2459 --build-16x16.
2461 B<--[no]build-56x56> - build or not the 56x56 XPM icons (under 56x56/).
2462 Default is --nobuild-56x56.
2464 B<--[no]build-32x32> - build or not the 32x32 XPM icons (under 32x32/).
2465 Default is --nobuild-32x32.
2467 B<--[no]build-tiles> - build or not the tiles XPM icons from the
2468 tiles sub directory of the --in-dir option (under tiles/). Default is
2469 --nobuild-tiles.
2471 B<--preserve> - Set to no all the 5 previous options and convert without
2472 size modifications under the out-dir.
2474 B<--size-48x48> geometry - Set the size of the 48x48 XPM icons via an
2475 ImageMagick size geometry. See the --size option of "man convert".
2476 Default is 48x48.
2478 B<--size-16x16> geometry - As above for the 16x16 XPM icons.
2479 Default is 17x17 :)
2481 B<--size-56x56> geometry - As above for the 56x56 XPM icons. Default is 56x56.
2483 B<--size-32x32> geometry - As above for the 32x32 XPM icons. Default is 32x32.
2485 B<--size-tiles> geometry - As above for the tiles XPM icons. Default is "".
2487 B<--border-48x48> +x+y,color - add border for the 48x48 XPM icons. See
2488 the --border option for details.
2490 B<--border-16x16> +x+y,color - As above for the 16x16 XPM icons.
2492 B<--border-56x56> +x+y,color - As above for the 16x16 XPM icons.
2494 B<--border-32x32> +x+y,color - As above for the 32x32 XPM icons.
2496 B<--border-tiles> +x+y,color - As above for the tiles XPM icons.
2498 B<--tile-48x48> [rule:]file_or_color - tile the 48x48 XPM icons with the xpm file
2499 following the rule "rule". See the ---tile option for details.
2501 B<--tile-16x16> [rule:]file_or_color - As above for the 16x16 XPM icons.
2503 B<--tile-56x56> [rule:]file_or_color - As above for the 56x56 XPM icons.
2505 B<--tile-32x32> [rule:]file_or_color - As above for the 32x32 XPM icons.
2507 B<--tile-tiles> [rule:]file_or_color - As above for the tiles XPM icons.
2509 =head2 ImageMagick Options
2511 B<--magick-colors> value - Number of colors used. Default is 256. If
2512 you use X under 16bpp (xdpyinfo) you can use for example 65536.
2514 B<--magick-colorspace> value - Where value must be GRAY, OHTA, RGB,
2515 Transparent, XYZ, YCbCr, YIQ, YPbPr, YUV, or CMYK. See the -colorspace
2516 option of ImageMagick (man convert). Default is Transparent.
2518 B<--magick-path> path - set the path of the convert ImageMagick executable.
2519 Useful if convert ImageMagick executable is not in your PATH or to test
2520 different versions.
2522 B<--magick-bpp> value - value must be 8 or 16. Set the number of bit per
2523 pixels used by ImageMagick. This is a compile time option of ImageMagick
2524 and fvwm-themes-images will detect it if you use a recent version of
2525 ImageMagick. If fvwm-themes-images does not found this value it is set
2526 to 16. This is very important for the --threshold option above.
2528 =head2 Other Simple Transformations
2530 B<--tile> [rule:][+x+y,]file_or_color - where rule can be "expand",
2531 "center", "color" or nothing, where x and y are integers
2532 and where file_or_color is a
2533 xpm tile file or a color in the "color" case. Without "rule" the
2534 xpm file will be tiled as usual on the background of the image.
2535 With "expand" the tile file will be resized to fit the image.
2536 With "center" the image is centered  on the tile file (your tile
2537 file have to be bigger that your image). With "color" the background
2538 of the image will be colorized by the color. The +x+y option can
2539 be used with all the rules but the "center" rule. This option expand the
2540 zone to tile by x pixels in the left and
2541 the right of the image and y  pixels in the top and
2542 the bottom of the image.
2544 B<--border> +x+y,color - add x color pixels in the left and
2545 the right of the image and y color pixels in the top and
2546 the bottom of the image.
2548 B<--rotate> value - value can be 0m, 90, 90m, 180, 180m. The integer
2549 is the degree of the rotation the "m" says to also mirror the image.
2551 =head2 Colorize
2553 B<--colorize-colors> - Colorize an XPM image such that
2554 the darkest pixels are replaced by pixels with the first color in the
2555 color list below and the lightest pixels are replaced by pixels with
2556 the last color in the list below. The pixels in between are
2557 interpolated between these two colors and the colors in between.
2558 Moreover the transparent pixels can be replaced by opaque pixels
2559 with the --trans-color option. The type of the interpolation can
2560 be changed with the --colorize-comp. If you found that your resulting
2561 XPM is too contrasted you can try the "--colorize-rule min" option
2562 (or change the color list).
2564 B<--colorize-colors> color1,color2... - list of colors for colorization.
2565 The top type (without integer argument) is used in a
2566 special way here. If you use top with the first color and/or the last
2567 color fvwm-themes-images will try to find the good integer values
2568 to top to do so that these colors are "centred" in the colorization.
2570 B<--trans-color> color - set the transparent pixels to color pixels.
2572 B<--colorize-comp> type - type of the computation for the interpolation.
2573 Type can be "l" for linear (this is the default), "r" for perturbed (as
2574 linear but the colors obtained is randomly perturbed), "c" for
2575 circular (the colors in the list are used alternatively), "t" for totally
2576 random (then the list of colors are ignored and the pixels are colorized
2577 randomly ... this is funny).
2579 B<--colorize-rule> value - value can be max or min, default is max. max
2580 does nothing. min changes the way of the colorization: black is "mapped"
2581 to the first color in the list and white  is "mapped" to the last color
2582 in the list.
2584 =head2 CDE-LIKE SKY
2586 B<--sky> -  Create a "gradient" XPM which consists of a repeated
2587 pattern, but along the color gradient, the color of the pattern varies.
2588 A pattern file must contain a rectangular pattern consisting of +es and
2589 -es. This pattern is painted repeatedly over the screen.
2590 However, the colors change in the y direction accordingly
2591 with the --sky-colors and --sky-comp options. By default, the pattern
2592 used is $FT_DATADIR/themes/cde/background/pattern. You can use one
2593 of the --pattern-* option below to load or create other patterns.
2594 Finally, you can rotate your image to get horizontal gradient.
2596 B<--sky-colors> color1,color2... - List of the colors for creating
2597 the sky gradient.
2599 B<--pattern-file> file - use the pattern file "file" as pattern.
2601 B<--pattern-type> type[[:y]:x] - where type can be I<uniform>, I<altern>,
2602 I<square>, I<random> and where y and x are positive integers. If no type
2603 is specified uniform is used, default y is 1 and default x is 8,
2604 for square the default for x is y. I<uniform> creates a pattern with y rows
2605 of x '+'. I<altern> creates a pattern with y rows of x '+' followed
2606 by y rows of x '-' (a comma-separated value for y may be used; altern:10
2607 and altern:10,10,0,0:8 are the same). I<square> creates a pattern of y rows
2608 constituted of x '+' followed by x '-'. I<random> creates a pattern with
2609 y random rows of length x.
2611 B<--pattern-xpm> file - Produce the pattern file from an xpm file.
2612 Set the transparent color to '-' and all other colors to '+'.
2614 B<--pattern-gap> n - where n is a positive integer. Take into account
2615 only every n-th lines of the pattern. Default is 1, so all pattern lines
2616 are taken.
2618 B<--pattern-y> y - where y is a positive integer. By default, the
2619 XPM file produced by --sky has the same height of your screen
2620 to produce complete gradient. You can set this height to a smaller
2621 value with this option to get repeated gradient or to save memory
2622 and time with some patterns and some --sky-comp options.
2624 B<--sky-comp> type - type of the computation for computing the gradient.
2625 The type are the same as for --colorize-comp but you can use also "p"
2626 for a polynomial interpolation.
2628 B<--be-fast> - If your sky contains a lot of colors you can use this
2629 option so that the background appear more rapidly on your root window.
2630 On the other hands, the XPM file builded will be larger.
2632 =head2 Setting the Root Image
2634 B<--setroot> - Set the root image (background) with the XPM file produced.
2635 Of course, this works only for a "transformation" which produces
2636 only one file, i.e., with --sky or with --in-file without --convert.
2638 B<--setroot-prog> I<prog> - a program with arguments to be executed
2639 as "I<prog> out.xpm" that sets the root window.
2640 Default is "fvwm-root".
2642 =head2 Evaluating foregrounds from backgrounds in color schemes
2644 B<--colorschemes> - Process color scheme files in the in-directory in
2645 place or into out-directory. A color scheme file is a file constituted
2646 of one color by line.
2648 B<--colorschemes-fores> num,threshold,color1,color2 - where num and threshold
2649 are integers. Transforms an original color scheme file using the following
2650 rules:
2652   1) the resulting file has 2*num lines of colors
2653   2) the first num colors (background colors) remain as are
2654   3) the last num lines are evaluated to be the foreground colors for the
2655 first num background colors respectively.
2656   4) the foreground color is color1 if the background color has a gray value
2657 which is less than threshold and is color2 otherwise.
2659 B<--colorschemes-ext> ext - consider only files with the trailing ".ext" in
2660 their names as color scheme files. Default is "dp".
2662 =head2 Colors Informations
2664 B<--show-xcolors> - show a list of all colors with an X name.
2666 B<--show-xcolorsets> - show a list of all "xcolors sets"
2668 B<--show-color-info color> - show full informations for the specified color
2670 =head1 AUTHORS
2672 Olivier Chapuis <olivier.chapuis@free.fr> (general design, convert, simple
2673 transformations, internal xpm library, interpolation, amelioration in
2674 "colorize" and cde-sky). 22 July 2000.
2676 Jos van Riswick  <josvanr@xs4all.nl> (Colorize, cde-sky, numerous
2677 functions in the colors "library").
2679 The starting point of this script is the fvwm2gnome script written
2680 by Clarence Smith, Jr
2681 <csmith@staticbomb.com> and Jer Warren <jer@digitalaccess.net>,
2682 where ImageMagick is used to convert GNOME icons into 20x20 XPM icons.
2684 =head1 COPYING
2686 The script is distributed by the same terms as fvwm-themes itself.
2687 See GNU General Public License for details.
2689 =head1 BUGS
2691 The english of this man page have to be fixed.
2693 Report bugs to fvwm-themes-devel@lists.sourceforge.net.
2695 =cut
2697 # ==========================================================================