| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package GD::SecurityImage; |
|
2
|
4
|
|
|
4
|
|
65127
|
use strict; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
127
|
|
|
3
|
4
|
|
|
4
|
|
17
|
use warnings; |
|
|
4
|
|
|
|
|
4
|
|
|
|
4
|
|
|
|
|
126
|
|
|
4
|
4
|
|
|
4
|
|
16
|
use vars qw[@ISA $VERSION $BACKEND]; |
|
|
4
|
|
|
|
|
13
|
|
|
|
4
|
|
|
|
|
215
|
|
|
5
|
4
|
|
|
4
|
|
1305
|
use GD::SecurityImage::Styles; |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
100
|
|
|
6
|
4
|
|
|
4
|
|
20
|
use Carp qw(croak); |
|
|
4
|
|
|
|
|
22
|
|
|
|
4
|
|
|
|
|
192
|
|
|
7
|
4
|
|
|
4
|
|
17
|
use constant RGB_WHITE => ( 255, 255, 255 ); |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
227
|
|
|
8
|
4
|
|
|
4
|
|
15
|
use constant RGB_BLACK => ( 0, 0, 0 ); |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
164
|
|
|
9
|
4
|
|
|
4
|
|
15
|
use constant RANDOM_DATA => ( 0..9 ); |
|
|
4
|
|
|
|
|
3
|
|
|
|
4
|
|
|
|
|
150
|
|
|
10
|
4
|
|
|
4
|
|
19
|
use constant FULL_CIRCLE => 360; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
164
|
|
|
11
|
4
|
|
|
4
|
|
14
|
use constant DEFAULT_ANGLES => (0,5,8,15,22,26,29,33,35,36,40,43,45,53,56); |
|
|
4
|
|
|
|
|
4
|
|
|
|
4
|
|
|
|
|
207
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
4
|
|
|
4
|
|
19
|
use constant DEFAULT_WIDTH => 80; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
154
|
|
|
14
|
4
|
|
|
4
|
|
16
|
use constant DEFAULT_HEIGHT => 30; |
|
|
4
|
|
|
|
|
3
|
|
|
|
4
|
|
|
|
|
135
|
|
|
15
|
4
|
|
|
4
|
|
15
|
use constant DEFAULT_PTSIZE => 20; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
136
|
|
|
16
|
4
|
|
|
4
|
|
18
|
use constant DEFAULT_LINES => 10; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
127
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
4
|
|
|
4
|
|
13
|
use constant MAX_RGB_VALUE => 255; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
142
|
|
|
19
|
4
|
|
|
4
|
|
13
|
use constant PARTICLE_MULTIPLIER => 20; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
127
|
|
|
20
|
4
|
|
|
4
|
|
16
|
use constant MAX_RGB_PARAMS => 3; |
|
|
4
|
|
|
|
|
3
|
|
|
|
4
|
|
|
|
|
8584
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$VERSION = '1.73'; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub import { |
|
25
|
4
|
|
|
4
|
|
2221
|
my($class, @args) = @_; |
|
26
|
4
|
50
|
|
|
|
21
|
my %opt = @args % 2 ? () : @args; |
|
27
|
|
|
|
|
|
|
# init/reset globals |
|
28
|
4
|
|
|
|
|
5
|
$BACKEND = q{}; # name of the back-end |
|
29
|
4
|
|
|
|
|
20
|
@ISA = (); ## no critic (ClassHierarchies::ProhibitExplicitISA) |
|
30
|
|
|
|
|
|
|
# load the drawing interface |
|
31
|
4
|
50
|
66
|
|
|
29
|
if ( exists $opt{use_magick} && $opt{use_magick} ) { |
|
|
|
50
|
33
|
|
|
|
|
|
32
|
0
|
|
|
|
|
0
|
require GD::SecurityImage::Magick; |
|
33
|
0
|
|
|
|
|
0
|
$BACKEND = 'Magick'; |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
elsif ( exists $opt{backend} && $opt{backend} ) { |
|
36
|
0
|
|
|
|
|
0
|
my $be = __PACKAGE__.q{::}.$opt{backend}; |
|
37
|
0
|
|
|
|
|
0
|
my $eok = eval "require $be"; |
|
38
|
0
|
0
|
|
|
|
0
|
croak "Unable to locate the $class back-end $be: $@" if $@; |
|
39
|
0
|
0
|
|
|
|
0
|
$BACKEND = $opt{backend} eq 'AC' ? 'GD' : $opt{backend}; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
else { |
|
42
|
4
|
|
|
|
|
1551
|
require GD::SecurityImage::GD; |
|
43
|
0
|
|
|
|
|
0
|
$BACKEND = 'GD'; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
0
|
|
|
|
|
0
|
push @ISA, 'GD::SecurityImage::' . $BACKEND, ## no critic (ClassHierarchies::ProhibitExplicitISA) |
|
46
|
|
|
|
|
|
|
qw(GD::SecurityImage::Styles); # load styles |
|
47
|
0
|
|
|
|
|
0
|
return; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub new { |
|
51
|
1
|
|
|
1
|
1
|
6
|
my($class, @args) = @_; |
|
52
|
1
|
50
|
|
|
|
236
|
$BACKEND || croak "You didn't import $class!"; |
|
53
|
0
|
0
|
|
|
|
|
my %opt = @args % 2 ? () : @args; |
|
54
|
|
|
|
|
|
|
|
|
55
|
0
|
|
0
|
|
|
|
my $self = { |
|
56
|
|
|
|
|
|
|
IS_MAGICK => $BACKEND eq 'Magick', |
|
57
|
|
|
|
|
|
|
IS_GD => $BACKEND eq 'GD', |
|
58
|
|
|
|
|
|
|
IS_CORE => $BACKEND eq 'GD' || $BACKEND eq 'Magick', |
|
59
|
|
|
|
|
|
|
DISABLED => {}, # list of methods that a backend (or some older version of backend) can't do |
|
60
|
|
|
|
|
|
|
MAGICK => {}, # Image::Magick configuration options |
|
61
|
|
|
|
|
|
|
GDBOX_EMPTY => 0, # GD::SecurityImage::GD::insert_text() failed? |
|
62
|
|
|
|
|
|
|
_RANDOM_NUMBER_ => q{}, # random security code |
|
63
|
|
|
|
|
|
|
_RNDMAX_ => 6, # maximum number of characters in a random string. |
|
64
|
|
|
|
|
|
|
_COLOR_ => {}, # text and line colors |
|
65
|
|
|
|
|
|
|
_CREATECALLED_ => 0, # create() called? (check for particle()) |
|
66
|
|
|
|
|
|
|
_TEXT_LOCATION_ => {}, # see info_text |
|
67
|
|
|
|
|
|
|
}; |
|
68
|
0
|
|
|
|
|
|
bless $self, $class; |
|
69
|
|
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
|
my %options = $self->_new_options( %opt ); |
|
71
|
|
|
|
|
|
|
|
|
72
|
0
|
0
|
0
|
|
|
|
if ( $opt{text_location} |
|
|
|
|
0
|
|
|
|
|
|
73
|
|
|
|
|
|
|
&& ref $opt{text_location} |
|
74
|
|
|
|
|
|
|
&& ref $opt{text_location} eq 'HASH' ) { |
|
75
|
0
|
|
|
|
|
|
$self->{_TEXT_LOCATION_} = { %{$opt{text_location}}, _place_ => 1 }; |
|
|
0
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
else { |
|
78
|
0
|
|
|
|
|
|
$self->{_TEXT_LOCATION_}{_place_} = 0; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
$self->{_RNDMAX_} = $options{rndmax}; |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
$self->{$_} = $options{$_} foreach keys %options; |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
0
|
|
|
|
|
if ( $self->{angle} ) { # validate angle |
|
86
|
0
|
0
|
|
|
|
|
$self->{angle} = FULL_CIRCLE + $self->{angle} if $self->{angle} < 0; |
|
87
|
0
|
0
|
|
|
|
|
if ( $self->{angle} > FULL_CIRCLE ) { |
|
88
|
0
|
|
|
|
|
|
croak 'Angle parameter can take values in the range -360..360'; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
0
|
0
|
|
|
|
|
if ( $self->{scramble} ) { |
|
93
|
0
|
0
|
|
|
|
|
if ( $self->{angle} ) { |
|
94
|
|
|
|
|
|
|
# Does the user want a fixed angle? |
|
95
|
0
|
|
|
|
|
|
push @{ $self->{_ANGLES_} }, $self->{angle}; |
|
|
0
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
else { |
|
98
|
|
|
|
|
|
|
# Generate angle range. The reason for hardcoding these is; |
|
99
|
|
|
|
|
|
|
# it'll be less random for 0..60 range |
|
100
|
0
|
|
|
|
|
|
push @{ $self->{_ANGLES_} }, DEFAULT_ANGLES; |
|
|
0
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# push negatives |
|
102
|
0
|
|
|
|
|
|
push @{ $self->{_ANGLES_} }, |
|
|
0
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
map {FULL_CIRCLE - $_} @{ $self->{_ANGLES_} }; |
|
|
0
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
$self->init; |
|
108
|
0
|
|
|
|
|
|
return $self; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub _new_options { |
|
112
|
0
|
|
|
0
|
|
|
my($self, %opt) = @_; |
|
113
|
0
|
0
|
0
|
|
|
|
my %options = ( |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
114
|
|
|
|
|
|
|
width => $opt{width} || DEFAULT_WIDTH, |
|
115
|
|
|
|
|
|
|
height => $opt{height} || DEFAULT_HEIGHT, |
|
116
|
|
|
|
|
|
|
ptsize => $opt{ptsize} || DEFAULT_PTSIZE, |
|
117
|
|
|
|
|
|
|
lines => $opt{lines} || DEFAULT_LINES, |
|
118
|
|
|
|
|
|
|
rndmax => $opt{rndmax} || $self->{_RNDMAX_}, |
|
119
|
|
|
|
|
|
|
rnd_data => $opt{rnd_data} || [ RANDOM_DATA ], |
|
120
|
|
|
|
|
|
|
font => $opt{font} || q{}, |
|
121
|
|
|
|
|
|
|
gd_font => $self->gdf($opt{gd_font}) || q{}, |
|
122
|
|
|
|
|
|
|
bgcolor => $opt{bgcolor} || [ RGB_WHITE ], |
|
123
|
|
|
|
|
|
|
send_ctobg => $opt{send_ctobg} || 0, |
|
124
|
|
|
|
|
|
|
frame => defined($opt{frame}) ? $opt{frame} : 1, |
|
125
|
|
|
|
|
|
|
scramble => $opt{scramble} || 0, |
|
126
|
|
|
|
|
|
|
angle => $opt{angle} || 0, |
|
127
|
|
|
|
|
|
|
thickness => $opt{thickness} || 0, |
|
128
|
|
|
|
|
|
|
_ANGLES_ => [], # angle list for scrambled images |
|
129
|
|
|
|
|
|
|
); |
|
130
|
0
|
|
|
|
|
|
return %options; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub backends { |
|
134
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
135
|
0
|
|
0
|
|
|
|
my $class = ref($self) || $self; |
|
136
|
0
|
|
|
|
|
|
my(@list, @dir_list); |
|
137
|
0
|
|
|
|
|
|
require Symbol; |
|
138
|
0
|
|
|
|
|
|
foreach my $inc (@INC) { |
|
139
|
0
|
|
|
|
|
|
my $dir = "$inc/GD/SecurityImage"; |
|
140
|
0
|
0
|
|
|
|
|
next unless -d $dir; |
|
141
|
0
|
|
|
|
|
|
my $DIR = Symbol::gensym(); |
|
142
|
0
|
0
|
|
|
|
|
opendir $DIR, $dir or croak "opendir($dir) failed: $!"; |
|
143
|
0
|
|
|
|
|
|
my @dir = readdir $DIR; |
|
144
|
0
|
|
|
|
|
|
closedir $DIR; |
|
145
|
0
|
|
|
|
|
|
push @dir_list, $dir; |
|
146
|
0
|
|
|
|
|
|
foreach my $file (@dir) { |
|
147
|
0
|
0
|
|
|
|
|
next if -d $file; |
|
148
|
0
|
0
|
|
|
|
|
next if $file =~ m{ \A [.] }xms; |
|
149
|
0
|
0
|
|
|
|
|
next if $file =~ m{ \A (Styles|AC|Handler)[.]pm \z}xms; |
|
150
|
0
|
|
|
|
|
|
$file =~ s{ [.]pm \z}{}xms; |
|
151
|
0
|
|
|
|
|
|
push @list, $file; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
0
|
|
|
|
|
return @list if defined wantarray; |
|
156
|
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
|
my $report = "Available back-ends in $class v$VERSION are:\n\t" |
|
158
|
|
|
|
|
|
|
. join("\n\t", @list) |
|
159
|
|
|
|
|
|
|
. "\n\n" |
|
160
|
|
|
|
|
|
|
. "Search directories:\n\t" |
|
161
|
|
|
|
|
|
|
. join "\n\t", @dir_list; |
|
162
|
0
|
0
|
|
|
|
|
print $report or croak "Unable to print to STDOUT: $!"; |
|
163
|
0
|
|
|
|
|
|
return; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub gdf { |
|
167
|
0
|
|
|
0
|
1
|
|
my($self, @args) = @_; |
|
168
|
0
|
0
|
|
|
|
|
return if not $self->{IS_GD}; |
|
169
|
0
|
|
|
|
|
|
return $self->gdfx( @args ); |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub random_angle { |
|
173
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
174
|
0
|
|
|
|
|
|
my @angles = @{ $self->{_ANGLES_} }; |
|
|
0
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
my @r; |
|
176
|
0
|
|
|
|
|
|
push @r, $angles[int rand @angles] for 0..$#angles; |
|
177
|
0
|
|
|
|
|
|
return $r[int rand @r]; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
0
|
|
|
0
|
1
|
|
sub random_str { return shift->{_RANDOM_NUMBER_} } |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub random { |
|
183
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
184
|
0
|
|
|
|
|
|
my $user = shift; |
|
185
|
0
|
0
|
0
|
|
|
|
if($user and length($user) >= $self->{_RNDMAX_}) { |
|
186
|
0
|
|
|
|
|
|
$self->{_RANDOM_NUMBER_} = $user; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
else { |
|
189
|
0
|
|
|
|
|
|
my @keys = @{ $self->{rnd_data} }; |
|
|
0
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
my $lk = scalar @keys; |
|
191
|
0
|
|
|
|
|
|
my $random; |
|
192
|
0
|
|
|
|
|
|
$random .= $keys[int rand $lk] for 1..$self->{rndmax}; |
|
193
|
0
|
|
|
|
|
|
$self->{_RANDOM_NUMBER_} = $random; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
0
|
0
|
|
|
|
|
return defined wantarray ? $self : undef; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub cconvert { # convert color codes |
|
199
|
|
|
|
|
|
|
# GD : return color index number |
|
200
|
|
|
|
|
|
|
# Image::Magick: return hex color code |
|
201
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
202
|
0
|
|
0
|
|
|
|
my $data = shift || croak 'Empty parameter passed to cconvert'; |
|
203
|
0
|
0
|
|
|
|
|
return $self->backend_cconvert($data) if not $self->{IS_CORE}; |
|
204
|
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
|
my $is_hex = $self->is_hex($data); |
|
206
|
0
|
|
0
|
|
|
|
my $magick_ok = $self->{IS_MAGICK} && $data && $is_hex; |
|
207
|
|
|
|
|
|
|
# data is a hex color code and Image::Magick has hex support |
|
208
|
0
|
0
|
|
|
|
|
return $data if $magick_ok; |
|
209
|
0
|
|
0
|
|
|
|
my $color_code = $data && |
|
210
|
|
|
|
|
|
|
! $is_hex && |
|
211
|
|
|
|
|
|
|
! ref($data) && |
|
212
|
|
|
|
|
|
|
$data !~ m{[^0-9]}xms && |
|
213
|
|
|
|
|
|
|
$data >= 0; |
|
214
|
|
|
|
|
|
|
|
|
215
|
0
|
0
|
|
|
|
|
if( $color_code ) { |
|
216
|
0
|
0
|
|
|
|
|
if ( $self->{IS_MAGICK} ) { |
|
217
|
0
|
|
|
|
|
|
croak "The number '$data' can not be transformed to a color code!"; |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
# data is a GD color index number ... |
|
220
|
|
|
|
|
|
|
# ... or it is any number! since there is no way to determine this. |
|
221
|
|
|
|
|
|
|
# GD object' s rgb() method returns 0,0,0 upon failure... |
|
222
|
0
|
|
|
|
|
|
return $data; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
my @rgb = $self->h2r($data); |
|
226
|
0
|
0
|
0
|
|
|
|
return @rgb && $self->{IS_MAGICK} |
|
227
|
|
|
|
|
|
|
? $data |
|
228
|
|
|
|
|
|
|
: $self->_cconvert_new( $data, @rgb ); |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub _cconvert_new { |
|
232
|
0
|
|
|
0
|
|
|
my($self, $data, @rgb) = @_; |
|
233
|
0
|
0
|
|
|
|
|
$data = [@rgb] if @rgb; |
|
234
|
|
|
|
|
|
|
# initialize if not valid |
|
235
|
0
|
0
|
0
|
|
|
|
if(! $data || ! ref $data || ref $data ne 'ARRAY' || $#{$data} != 2) { |
|
|
0
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
236
|
0
|
|
|
|
|
|
$data = [0, 0, 0]; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
0
|
|
|
|
|
|
foreach my $i (0..$#{$data}) { # check for bad values |
|
|
0
|
|
|
|
|
|
|
|
239
|
0
|
0
|
0
|
|
|
|
if ( $data->[$i] > MAX_RGB_VALUE || $data->[$i] < 0 ) { |
|
240
|
0
|
|
|
|
|
|
$data->[$i] = 0; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
|
return $self->{IS_MAGICK} ? $self->r2h(@{$data}) # convert to hex |
|
|
0
|
|
|
|
|
|
|
|
245
|
0
|
0
|
|
|
|
|
: $self->{image}->colorAllocate(@{$data}); |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub create { |
|
249
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
250
|
0
|
|
0
|
|
|
|
my $method = shift || 'normal'; # ttf or normal |
|
251
|
0
|
|
0
|
|
|
|
my $style = shift || 'default'; # default or rect or box |
|
252
|
0
|
|
0
|
|
|
|
my $col1 = shift || [ 0, 0, 0]; # text color |
|
253
|
0
|
|
0
|
|
|
|
my $col2 = shift || [ 0, 0, 0]; # line/box color |
|
254
|
|
|
|
|
|
|
|
|
255
|
0
|
0
|
|
|
|
|
$self->{send_ctobg} = 0 if $style eq 'box'; # disable for that style |
|
256
|
0
|
|
|
|
|
|
$self->{_COLOR_} = { # set the color hash |
|
257
|
|
|
|
|
|
|
text => $self->cconvert($col1), |
|
258
|
|
|
|
|
|
|
lines => $self->cconvert($col2), |
|
259
|
|
|
|
|
|
|
}; |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# be a smart module and auto-disable ttf if we are under a prehistoric GD |
|
262
|
0
|
0
|
|
|
|
|
if ( not $self->{IS_MAGICK} ) { |
|
263
|
0
|
0
|
|
|
|
|
$method = 'normal' if $self->_versionlt( '1.20' ); |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
|
|
266
|
0
|
0
|
0
|
|
|
|
if ( $method eq 'normal' && ! $self->{gd_font} ) { |
|
267
|
0
|
|
|
|
|
|
$self->{gd_font} = $self->gdf('giant'); |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
0
|
0
|
|
|
|
|
$style = $self->can('style_'.$style) ? 'style_'.$style : 'style_default'; |
|
271
|
|
|
|
|
|
|
|
|
272
|
0
|
0
|
|
|
|
|
$self->$style() if not $self->{send_ctobg}; |
|
273
|
0
|
|
|
|
|
|
$self->insert_text($method); |
|
274
|
0
|
0
|
|
|
|
|
$self->$style() if $self->{send_ctobg}; |
|
275
|
|
|
|
|
|
|
|
|
276
|
0
|
0
|
|
|
|
|
if ( $self->{frame} ) { |
|
277
|
|
|
|
|
|
|
# put a frame around the image |
|
278
|
0
|
|
|
|
|
|
my $w = $self->{width} - 1; |
|
279
|
0
|
|
|
|
|
|
my $h = $self->{height} - 1; |
|
280
|
0
|
|
|
|
|
|
$self->rectangle( 0, 0, $w, $h, $self->{_COLOR_}{lines} ); |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
$self->{_CREATECALLED_}++; |
|
284
|
0
|
0
|
|
|
|
|
return defined wantarray ? $self : undef; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub particle { |
|
288
|
|
|
|
|
|
|
# Create random dots. They'll cover all over the surface |
|
289
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
290
|
0
|
0
|
|
|
|
|
croak q{particle() must be called 'after' create()} if !$self->{_CREATECALLED_}; |
|
291
|
0
|
0
|
|
|
|
|
my $big = $self->{height} > $self->{width} ? $self->{height} : $self->{width}; |
|
292
|
0
|
|
0
|
|
|
|
my $f = shift || $big * PARTICLE_MULTIPLIER; # particle density |
|
293
|
0
|
|
0
|
|
|
|
my $dots = shift || 1; # number of multiple dots |
|
294
|
0
|
|
|
|
|
|
my $int = int $big / PARTICLE_MULTIPLIER; |
|
295
|
|
|
|
|
|
|
|
|
296
|
0
|
0
|
|
|
|
|
if ( ! $int ) { # RT#33629 |
|
297
|
0
|
|
|
|
|
|
warn "particle(): image dimension is so small to add particles\n"; |
|
298
|
0
|
|
|
|
|
|
return; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
|
my @random; |
|
302
|
0
|
|
|
|
|
|
for (my $x = $int; $x <= $big; $x += $int) { ## no critic (ControlStructures::ProhibitCStyleForLoops) |
|
303
|
0
|
|
|
|
|
|
push @random, $x; |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
|
|
306
|
0
|
|
|
|
|
|
my $tc = $self->{_COLOR_}{text}; |
|
307
|
0
|
|
|
|
|
|
my $len = @random; |
|
308
|
0
|
|
|
0
|
|
|
my $r = sub { $random[ int rand $len ] }; |
|
|
0
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
|
|
310
|
0
|
|
|
|
|
|
for ( 1..$f ) { |
|
311
|
0
|
|
|
|
|
|
my $x = int rand $self->{width}; |
|
312
|
0
|
|
|
|
|
|
my $y = int rand $self->{height}; |
|
313
|
0
|
|
|
|
|
|
foreach my $z (1..$dots) { |
|
314
|
0
|
|
|
|
|
|
$self->setPixel($x + $z , $y + $z , $tc); |
|
315
|
0
|
|
|
|
|
|
$self->setPixel($x + $z + $r->(), $y + $z + $r->(), $tc); |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
} |
|
318
|
0
|
|
|
|
|
|
undef @random; |
|
319
|
0
|
|
|
|
|
|
undef $r; |
|
320
|
|
|
|
|
|
|
|
|
321
|
0
|
0
|
|
|
|
|
return defined wantarray ? $self : undef; |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
0
|
|
|
0
|
1
|
|
sub raw { return shift->{image} } # raw image object |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub info_text { # set text location |
|
327
|
|
|
|
|
|
|
# x => 'left|right', # text-X |
|
328
|
|
|
|
|
|
|
# y => 'up|low|down', # text-Y |
|
329
|
|
|
|
|
|
|
# strip => 1|0, # add strip? |
|
330
|
|
|
|
|
|
|
# gd => 1|0, # use default GD font? |
|
331
|
|
|
|
|
|
|
# ptsize => 10, # point size |
|
332
|
|
|
|
|
|
|
# color => '#000000', # text color |
|
333
|
|
|
|
|
|
|
# scolor => '#FFFFFF', # strip color |
|
334
|
|
|
|
|
|
|
# text => 'blah', # modifies random code |
|
335
|
0
|
|
|
0
|
1
|
|
my($self, @args) = @_; |
|
336
|
0
|
0
|
|
|
|
|
croak q{info_text() must be called 'after' create()} if ! $self->{_CREATECALLED_}; |
|
337
|
0
|
0
|
|
|
|
|
my %o = @args % 2 ? () : ( qw/ x right y up strip 1 /, @args ); |
|
338
|
0
|
0
|
|
|
|
|
return if not %o; |
|
339
|
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
$self->{_TEXT_LOCATION_}{_place_} = 1; |
|
341
|
0
|
0
|
|
|
|
|
$o{scolor} = $self->cconvert($o{scolor}) if $o{scolor}; |
|
342
|
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
my %restore = ( |
|
344
|
|
|
|
|
|
|
random => $self->{_RANDOM_NUMBER_}, |
|
345
|
|
|
|
|
|
|
color => $self->{_COLOR_}{text}, |
|
346
|
|
|
|
|
|
|
ptsize => $self->{ptsize}, |
|
347
|
|
|
|
|
|
|
scramble => $self->{scramble}, |
|
348
|
|
|
|
|
|
|
angle => $self->{angle}, |
|
349
|
|
|
|
|
|
|
); |
|
350
|
|
|
|
|
|
|
|
|
351
|
0
|
0
|
|
|
|
|
$self->{_RANDOM_NUMBER_} = delete $o{text} if $o{text}; |
|
352
|
0
|
0
|
|
|
|
|
$self->{_COLOR_}{text} = $self->cconvert(delete $o{color}) if $o{color}; |
|
353
|
0
|
0
|
|
|
|
|
$self->{ptsize} = delete $o{ptsize} if $o{ptsize}; |
|
354
|
0
|
|
|
|
|
|
$self->{scramble} = 0; # disable. we need a straight text |
|
355
|
0
|
|
|
|
|
|
$self->{angle} = 0; # disable. RT:14618 |
|
356
|
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
|
$self->{_TEXT_LOCATION_}->{$_} = $o{$_} foreach keys %o; |
|
358
|
0
|
|
|
|
|
|
$self->insert_text('ttf'); |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# restore |
|
361
|
0
|
|
|
|
|
|
$self->{_RANDOM_NUMBER_} = $restore{random}; |
|
362
|
0
|
|
|
|
|
|
$self->{_COLOR_}{text} = $restore{color}; |
|
363
|
0
|
|
|
|
|
|
$self->{ptsize} = $restore{ptsize}; |
|
364
|
0
|
|
|
|
|
|
$self->{scramble} = $restore{scramble}; |
|
365
|
0
|
|
|
|
|
|
$self->{angle} = $restore{angle}; |
|
366
|
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
|
return $self; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
#--------------------[ PRIVATE ]--------------------# |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub add_strip { # adds a strip to the background of the text |
|
373
|
0
|
|
|
0
|
1
|
|
my($self, $x, $y, $box_w, $box_h) = @_; |
|
374
|
0
|
|
|
|
|
|
my $tl = $self->{_TEXT_LOCATION_}; |
|
375
|
0
|
|
0
|
|
|
|
my $c = $self->{_COLOR_} || {}; |
|
376
|
0
|
0
|
|
|
|
|
my $black = $self->cconvert( $c->{text} ? $c->{text} : [ RGB_BLACK ] ); |
|
377
|
0
|
0
|
|
|
|
|
my $white = $self->cconvert( $tl->{scolor} ? $tl->{scolor} : [ RGB_WHITE ] ); |
|
378
|
0
|
0
|
|
|
|
|
my $x2 = $tl->{x} eq 'left' ? $box_w : $self->{width}; |
|
379
|
0
|
|
|
|
|
|
my $y2 = $self->{height} - $box_h; |
|
380
|
0
|
0
|
|
|
|
|
my $i = $self->{IS_MAGICK} ? $self : $self->{image}; |
|
381
|
0
|
|
|
|
|
|
my $up = $tl->{y} eq 'up'; |
|
382
|
0
|
|
|
|
|
|
my $h = $self->{height}; |
|
383
|
0
|
0
|
|
|
|
|
$i->filledRectangle($up ? ($x-1, 0, $x2, $y+1) : ($x-1, $y2-1, $x2 , $h ), $black); |
|
384
|
0
|
0
|
|
|
|
|
$i->filledRectangle($up ? ($x , 1, $x2-2, $y) : ($x , $y2 , $x2-2, $h-2), $white); |
|
385
|
0
|
|
|
|
|
|
return; |
|
386
|
|
|
|
|
|
|
} |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub r2h { |
|
389
|
|
|
|
|
|
|
# Convert RGB to Hex |
|
390
|
0
|
|
|
0
|
1
|
|
my($self, @args) = @_; |
|
391
|
0
|
0
|
|
|
|
|
return if @args != MAX_RGB_PARAMS; |
|
392
|
0
|
|
|
|
|
|
my $color = q{#}; |
|
393
|
0
|
|
|
|
|
|
$color .= sprintf '%02x', $_ foreach @args; |
|
394
|
0
|
|
|
|
|
|
return $color; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub h2r { |
|
398
|
|
|
|
|
|
|
# Convert Hex to RGB |
|
399
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
400
|
0
|
|
|
|
|
|
my $color = shift; |
|
401
|
0
|
0
|
|
|
|
|
return if ref $color; |
|
402
|
0
|
|
|
|
|
|
my @rgb = $color =~ m/\A \#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2}) \z/xmsi; |
|
403
|
0
|
0
|
|
|
|
|
return @rgb ? map { hex $_ } @rgb : undef; |
|
|
0
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub is_hex { |
|
407
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
408
|
0
|
|
|
|
|
|
my $data = shift; |
|
409
|
0
|
|
|
|
|
|
return $data =~ m/ \A \#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2}) \z /xmsi; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
1; |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
__END__ |