File Coverage

blib/lib/App/Greple/subst/dyncmap.pm
Criterion Covered Total %
statement 17 54 31.4
branch 0 18 0.0
condition 0 3 0.0
subroutine 6 13 46.1
pod 0 4 0.0
total 23 92 25.0


line stmt bran cond sub pod time code
1             =encoding utf-8
2              
3             =head1 NAME
4              
5             -Msubst::dyncmap - Getopt::EX Dynamic colormap module
6              
7             =head1 SYNOPSIS
8              
9             option --subst-color-light \
10             -Msubst::dyncmap \
11             --colormap \
12             --dyncmap \
13             range=0-2,except=000:111:222,shift=3,even="555D/%s",odd="I;000/%s"
14              
15             =head1 DESCRIPTION
16              
17             Parameter is given in a form of B<name>=I<value> and connected by
18             comma.
19              
20             =over 7
21              
22             =item B<range>=I<s>-I<e>[:I<s>-I<e>[:I<s>-I<e>]]
23              
24             RGB range. All range can be given like C<0-2:0-2:0-2>, or if the
25             number of range is less than three, last range is repeated.
26              
27             Each RGB value is in the range of 0 to 5, and produces 6x6x6 216
28             colors.
29              
30             =item B<except>
31              
32             Specify exception value, like C<000:111:222>.
33              
34             =item B<even>=I<colormap>
35              
36             =item B<odd>=I<colormap>
37              
38             Colormap string for even and odd index. String is given to C<sprintf>
39             function with RGB parameter.
40              
41             =item B<shift>=I<number>
42              
43             Range is shifted by this value for odd index map. Shifted value have
44             to be in the range of 0 to 5.
45              
46             =item B<sort>=[I<none>,I<average>,I<luminance>]
47              
48             Specify sort algorithm. Default is B<average>.
49              
50             =item B<reverse>=[0,1]
51              
52             If true, map is reversed.
53              
54             =back
55              
56             =head1 SEE ALSO
57              
58             L<Getopt::EX>, L<Getopt::EX::Colormap>
59              
60             L<App::Greple>, L<App::Greple::subst>
61              
62             =head1 AUTHOR
63              
64             Kazumasa Utashiro
65              
66             =head1 LICENSE
67              
68             Copyright 2020-2021 Kazumasa Utashiro.
69              
70             You can redistribute it and/or modify it under the same terms
71             as Perl itself.
72              
73             =cut
74              
75             package App::Greple::subst::dyncmap;
76              
77 1     1   1982 use v5.14;
  1         3  
78 1     1   5 use strict;
  1         22  
  1         24  
79 1     1   5 use warnings;
  1         2  
  1         23  
80              
81 1     1   4 use Carp;
  1         17  
  1         69  
82 1     1   6 use Data::Dumper;
  1         3  
  1         66  
83 1     1   7 use List::Util qw(notall pairmap reduce sum);
  1         2  
  1         995  
84              
85             ##
86             ## Dyamic colormap generator
87             ##
88              
89             sub dyncmap {
90 0     0 0   my %opt = @_;
91 0           for ($opt{range}) {
92 0 0   0     my @range = pairmap { [ $a..$b ] } /([0-5])-([0-5])/g
  0            
93             or die "$_: range format error";
94 0           push @range, $range[-1] while @range < 3;
95 0           $_ = \@range;
96             }
97 0           my @cm = cmap(%opt);
98 0           join ',', @cm;
99             }
100              
101             sub combination {
102             my $c = reduce {
103 0     0     [ map { my @a = @$_; map { [ @a, $_ ] } @$b } @$a ];
  0            
  0            
  0            
104 0     0 0   } [ [] ], @_;
105 0           @$c;
106             }
107              
108             sub rgb {
109 0 0   0 0   if (notall { 0 <= $_ && $_ <= 5 } @_) {
  0 0   0      
110 0           local $" = '';
111 0           die "@_: Invalid RGB value";
112             }
113 0           my($r, $g, $b) = @_;
114 0 0 0       if ($r == $g and $r == $b) {
115 0           qw(L03 L07 L11 L15 L19 L23)[$r];
116             } else {
117 0           "$r$g$b";
118             }
119             }
120              
121             my %sort = (
122             none => undef,
123             average => sub {
124             local $" = '';
125             map { $_->[0] }
126             sort { $a->[1] <=> $b->[1] || $a->[2] cmp $b->[2] }
127             map { [ $_, sum(@$_), "@$_" ] }
128             @_;
129             },
130             luminance => sub {
131             map { $_->[0] }
132             sort { $a->[1] <=> $b->[1] }
133             map { [ $_, $$_[0]*30 + $$_[1]*59 + $$_[2]*11 ] }
134             @_;
135             },
136             );
137              
138             sub cmap {
139 0     0 0   my %opt = (shift => 0, except => '', sort => 'average', @_);
140 0           my @cm = combination @{$opt{range}};
  0            
141 0 0         if (my %except = map { $_ => 1 } $opt{except} =~ /\b(\d\d\d)\b/g) {
  0            
142 0           local $" = '';
143 0           @cm = grep { not $except{"@$_"} } @cm;
  0            
144             }
145 0 0         if (my $algorithm = $opt{sort}) {
146 0 0         exists $sort{$algorithm} or die "$algorithm: unknown algorithm";
147 0 0         if (my $sort = $sort{$algorithm}) {
148 0           @cm = $sort->(@cm);
149             }
150             }
151 0 0         @cm = reverse @cm if $opt{reverse};
152             my @map = map {
153 0           ( sprintf($opt{even}, rgb(@$_) ),
154 0           sprintf($opt{odd}, rgb(map $_ + $opt{shift}, @$_) ) );
155             } @cm;
156             }
157              
158             1;
159              
160             __DATA__
161              
162             mode function
163              
164             option --dyncmap &dyncmap($<shift>)