burak / CPAN-GD-SecurityImage

Security image (captcha) generator for Perl

Changed (Δ10.9 KB):

raw changeset »

Build.PL (5 lines added, 0 lines removed)

Changes (3 lines added, 0 lines removed)

MANIFEST (1 lines added, 1 lines removed)

SPEC (7 lines added, 2 lines removed)

eg/demo.pl (82 lines added, 72 lines removed)

lib/GD/SecurityImage.pm (181 lines added, 155 lines removed)

lib/GD/SecurityImage/GD.pm (245 lines added, 165 lines removed)

lib/GD/SecurityImage/Magick.pm (43 lines added, 55 lines removed)

lib/GD/SecurityImage/Styles.pm (18 lines added, 27 lines removed)

t/03-info_text.t (3 lines added, 4 lines removed)

t/04-backend.t (25 lines added, 19 lines removed)

t/05-version.t (9 lines added, 8 lines removed)

t/06-version_magick.t (15 lines added, 12 lines removed)

t/98-gd.t (14 lines added, 5 lines removed)

t/99-magick.t (16 lines added, 7 lines removed)

t/lib/Test/GDSI.pm (209 lines added, 0 lines removed)

t/magick.pl (12 lines added, 8 lines removed)

t/t.api

Up to file-list Build.PL:

1
1
use strict;
2
use warnings;
2
3
use lib qw( builder );
3
4
use Build;
4
5
5
6
my $mb = Build->new;
6
7
$mb->change_versions(1);
8
$mb->copyright_first_year( '2004' );
9
$mb->add_pod_author_copyright_license(1);
7
10
$mb->create_build_script;
11
12
1;

Up to file-list Changes:

@@ -2,6 +2,9 @@ Revision history for Perl extension GD::
2
2
3
3
Time zone is GMT+2.
4
4
5
1.71 Fri Oct  2 05:50:46 2009
6
    => Major Perl::Critic refactoring.
7
5
8
1.70 Thu Apr 30 16:56:32 2009
6
9
    => Made a mistake. version checking test is really gone now.
7
10

Up to file-list MANIFEST:

@@ -9,7 +9,7 @@ t/06-version_magick.t
9
9
t/98-gd.t
10
10
t/99-magick.t
11
11
t/magick.pl
12
t/t.api
12
t/lib/Test/GDSI.pm
13
13
eg/demo.pl
14
14
Changes
15
15
Build.PL

Up to file-list SPEC:

@@ -15,8 +15,13 @@ print qq~
15
15
16
16
{
17
17
    module_name    => 'GD::SecurityImage',
18
    requires       => { 'GD'            => 0      },
19
    recommends     => { 'Image::Magick' => '6.0.4'},
18
    requires       => {
19
        'GD' => 0,
20
        ( $] < 5.006 ? ( 'warnings::compat' => 0 ) : ()),
21
    },
22
    recommends => {
23
        'Image::Magick' => '6.0.4',
24
    },
20
25
    meta_merge => {
21
26
        resources => {
22
27
            repository => 'http://bitbucket.org/burak/cpan-gd-securityimage/',

Up to file-list eg/demo.pl:

2
2
# -> GD::SecurityImage demo program
3
3
4
4
# See the document section after "__END__" for license and other information.
5
package demo;
5
package Demo;
6
6
use strict;
7
use vars qw( $VERSION %config  );
7
use warnings;
8
use vars qw( $VERSION  );
8
9
use CGI  qw( header escapeHTML );
9
10
use Cwd;
11
use Carp qw( croak );
12
use constant SALT_RANDOM   => 100;
13
use constant MAGICK_PTSIZE => 12;
14
use constant GD_PTSIZE     =>  8;
10
15
11
%config = (
16
my %config = (
12
17
   database   => 'gdsi',                 # database name (for session storage)
13
18
   table_name => 'sessions',             # only change this value, if you *really* have to use another table name. Also change the SQL code below.
14
19
   user       => 'root',                 # database user name
15
   pass       => '',                     # database user's password
16
   font       => getcwd."/StayPuft.ttf", # ttf font. change this to an absolute path if getcwd is failing
20
   pass       => q{},                    # database user's password
21
   font       => getcwd.'/StayPuft.ttf', # ttf font. change this to an absolute path if getcwd is failing
17
22
   itype      => 'png',                  # image format. set this to gif or png or jpeg
18
23
   use_magick => 0,                      # use Image::Magick or GD
19
24
   img_stat   => 1,                      # display statistics on the image?
20
   program    => '',                     # if CGI.pm fails to locate program url, set this value.
25
   program    => q{},                    # if CGI.pm fails to locate program url, set this value.
21
26
);
22
27
23
28
# You'll need this to create the sessions table. 
@@ -25,7 +30,7 @@ use Cwd;
25
30
26
31
# - - - - - - - - - - - - - - > S T A R T   P R O G R A M < - - - - - - - - - - - - - - #
27
32
28
$VERSION = '1.42';
33
$VERSION = '1.50';
29
34
30
35
use constant REQUIREDMODS => qw(
31
36
   DBI
@@ -44,46 +49,49 @@ BEGIN {
44
49
      local $SIG{__DIE__};
45
50
      local $@;
46
51
      my $mod = shift;
47
      eval "require $mod";
48
      push @errors, { module => $mod, error  => $@ } if $@;
52
      my $eok = eval "require $mod; 1;";
53
      push @errors, { module => $mod, error  => $@ } if $@ || ! $eok;
49
54
   };
50
55
   $test->($_) foreach REQUIREDMODS;
51
56
   if ( @errors ) {
52
57
      my $err = qq{<pre>This demo program needs several CPAN modules to run:\n\n};
53
58
      foreach my $e ( @errors ) {
54
         $err .= qq~<b><span style="color:red">[FAILED]</span>~
59
         $err .= q~<b><span style="color:red">[FAILED]</span>~
55
60
               . qq~ $e->{module}</b>: $e->{error}<br />~;
56
61
      }
57
      print header . $err . '</pre>';
62
      print header . $err . '</pre>' or croak "Can not print to STDOUT: $!";
58
63
      exit;
59
64
   }
60
   $SIG{__DIE__} = sub {
61
      print header . qq~
62
         <h1 style="color:red;font-weight:bold"
63
            >FATAL ERROR</h1>
64
         @_
65
      ~;
66
      exit;
67
   };
68
65
}
69
66
70
my $NOT_EXISTS = quotemeta "Object does not exist in the data store";
67
local $SIG{__DIE__} = sub {
68
   print header . <<"ERROR" or croak "Can not print to STDOUT: $!";
69
      <h1 style="color:red;font-weight:bold"
70
         >FATAL ERROR</h1>
71
      @_
72
ERROR
73
   exit;
74
};
75
76
my $NOT_EXISTS = quotemeta 'Object does not exist in the data store';
71
77
72
78
run() if not caller; # if you require this, you'll need to call demo::run()
73
79
74
80
sub TEST_FONT_EXISTENCE {
75
81
   if ( not $config{use_magick} ) {
76
      if ( $config{font} =~ m[\s]s ) {
77
         die "The font path '$config{font}' has a space in it. GD hates spaces!";
82
      if ( $config{font} =~ m{\s}xms ) {
83
         croak "The font path '$config{font}' has a space in it. GD hates spaces!";
78
84
      }
79
85
   }
80
   local *FONTFILE;
81
   if ( open FONTFILE, $config{font} ) {
82
      close FONTFILE;
86
   require IO::File;
87
   my $FONTFILE = IO::File->new;
88
   if ( $FONTFILE->open( $config{font} ) ) {
89
      $FONTFILE->close;
83
90
   }
84
91
   else {
85
      die qq~I can not open/find the font file in '$config{font}': $!~;
92
      croak qq~I can not open/find the font file in '$config{font}': $!~;
86
93
   }
94
   return;
87
95
}
88
96
89
97
sub new {
@@ -92,11 +100,11 @@ sub new {
92
100
   my $self  = {
93
101
      ISDISPLAY => 0,
94
102
      SID       => undef,
95
      CPAN      => "http://search.cpan.org/dist",
103
      CPAN      => 'http://search.cpan.org/dist',
96
104
      IS_GD     => 0,
97
105
   };
98
106
   bless $self, $class;
99
   $self;
107
   return $self;
100
108
}
101
109
102
110
sub run {
@@ -110,7 +118,7 @@ sub run {
110
118
   $self->{program} = $config{program};
111
119
   if ( ! $self->{program} ){
112
120
      # it is possible to get the url as "demo.pl??foo=bar"
113
      ($self->{program}, my @jp) = split /\?/, $self->{cgi}->url;
121
      ($self->{program}, my @jp) = split m{\?}xms, $self->{cgi}->url;
114
122
   }
115
123
   my %options      = $self->all_options;
116
124
   my %styles       = $self->all_styles;
@@ -132,14 +140,14 @@ sub run {
132
140
   my %session;
133
141
   my $create_ses = sub { # fetch/create session
134
142
      my $sid = @_ ? undef : $self->{cgi}->cookie('GDSI_ID');
135
      tie %session, 'Apache::Session::MySQL', $sid, {
143
      tie %session, 'Apache::Session::MySQL', $sid, { ## no critic (Miscellanea::ProhibitTies)
136
144
         Handle     => $dbh,
137
145
         LockHandle => $dbh,
138
146
         TableName  => $config{table_name},
139
147
      };
140
148
   };
141
149
142
   eval { $create_ses->() };
150
   my $eok = eval { $create_ses->() 1; };
143
151
144
152
   # I'm doing a little trick to by-pass exceptions if the session id
145
153
   # coming from the user no longer exists in the database. 
@@ -151,13 +159,13 @@ sub run {
151
159
      $create_ses->('new');
152
160
   }
153
161
154
   if ( not $session{security_code} ) {
162
   if ( ! $session{security_code} ) {
155
163
      $session{security_code} = $self->_random; # initialize random code
156
164
   }
157
165
158
166
   $self->{ISDISPLAY} = $self->{cgi}->param('display') || 0;
159
167
   $self->{SID}       = $session{_session_id};
160
   my $output         = ''; # output buffer
168
   my $output         = q{}; # output buffer
161
169
162
170
   if ( $self->{ISDISPLAY} ) {
163
171
      $START = Time::HiRes::time();
@@ -178,14 +186,14 @@ sub run {
178
186
179
187
   untie %session;
180
188
   $dbh->disconnect;
181
   print $output;
189
   print $output or croak "Can not print to STDOUT: $!";
182
190
   exit;
183
191
}
184
192
185
193
sub process {
186
194
   my $self = shift;
187
   my $ses  = shift || die "security_code from session is missing";
188
   my $code = $self->{cgi}->param('code') || '';
195
   my $ses  = shift || croak 'Security_code from session is missing';
196
   my $code = $self->{cgi}->param('code') || q{};
189
197
   my $pass = $self->iseq( $code, $ses );
190
198
   my $meth = $pass ? '_congrats' : '_failure';
191
199
   return $self->$meth( $code, $ses );
@@ -193,35 +201,36 @@ sub process {
193
201
194
202
sub backenduri {
195
203
   my $self = shift;
196
   my $rv   = qq{Security image generated with <b>};
204
   my $rv   = q{Security image generated with <b>};
197
205
      $rv  .= $self->{IS_GD}
198
            ? qq~<a href="$self->{CPAN}/GD"         target="_blank">GD</a> v$GD::VERSION~ 
206
            ? qq~<a href="$self->{CPAN}/GD"         target="_blank">GD</a> v$GD::VERSION~
199
207
            : qq~<a href="$self->{CPAN}/PerlMagick" target="_blank">Image::Magick</a> v$Image::Magick::VERSION~;
200
208
   return $rv . '</b>';
201
209
}
202
210
203
sub _random { String::Random->new->randregex('\d\d\d\d\d\d') }
211
sub _random { return String::Random->new->randregex('\d\d\d\d\d\d') }
204
212
205
213
sub _failure {
206
214
   my $self = shift;
207
   my $code = CGI::escapeHTML(shift || '');
208
   my $ses  = shift || '';
209
   my $rv   = qq~
215
   my $code = CGI::escapeHTML(shift || q{});
216
   my $ses  = shift || q{};
217
   my $rv   = <<"FAIL";
210
218
      <b>'${code}' != '${ses}'</b>
211
219
      <br />
212
220
      <span style="color:red;font-weight:bold">
213
221
      You have failed to identify yourself as a human!
214
222
      </span>
215
      <br />~;
223
      <br />
224
FAIL
216
225
   $rv .= $self->form();
217
226
   return $rv;
218
227
}
219
228
220
229
sub _congrats {
221
230
   my $self = shift;
222
   my $form = shift || '';
223
   my $ses  = shift || '';
224
   return qq~
231
   my $form = shift || q{};
232
   my $ses  = shift || q{};
233
   return <<"PASS";
225
234
      <b>'$form' == '$ses'</b>
226
235
      <br />
227
236
      <span style="color:#009700;font-weight:bold">
@@ -230,20 +239,19 @@ sub _congrats {
230
239
      <br />
231
240
      <br />
232
241
      <a href="$self->{program}">Try again</a>
233
   ~;
242
PASS
234
243
}
235
244
236
245
sub iseq {
237
246
   my $self = shift;
238
247
   my $form = shift || return;
239
248
   my $ses  = shift || return;
240
   return if $form =~ m{[^0-9]};
249
   return if $form =~ m{[^0-9]}xms;
241
250
   return $form eq $ses;
242
251
}
243
252
244
253
sub myheader {
245
   my $self    = shift;
246
   my %o       = @_;
254
   my($self, %o) = @_;
247
255
   my $display = $self->{ISDISPLAY};
248
256
   my $type    = $o{type} ? $o{type}
249
257
               : $display ? 'image/'.$config{itype}
@@ -253,7 +261,7 @@ sub myheader {
253
261
                    -value => $self->{SID},
254
262
                 );
255
263
   return $self->{cgi}->header(
256
      -type   => $type, 
264
      -type   => $type,
257
265
      -cookie => $c
258
266
   );
259
267
}
@@ -262,7 +270,7 @@ sub myheader {
262
270
263
271
sub help {
264
272
   my $self = shift;
265
   qq~
273
   return <<"HELP";
266
274
267
275
If you want to change the image generation options, open this file with
268
276
a text editor and search for the <b>%config</b> hash.
@@ -352,14 +360,14 @@ used for session data storage.
352
360
353
361
</table>
354
362
355
   ~;
363
HELP
356
364
}
357
365
358
366
sub form {
359
367
   my $self = shift;
360
368
   # by-pass browser cache with this random fake value
361
   my $salt = '&salt=' . $$ . time . rand(100);
362
   return qq~
369
   my $salt = '&salt=' . $$ . time . rand SALT_RANDOM;
370
   return <<"FORM";
363
371
   <form action="$self->{program}" method="post">
364
372
    <table border="0" cellpadding="2" cellspacing="1">
365
373
     <tr>
@@ -377,12 +385,13 @@ sub form {
377
385
     </tr>
378
386
    </table>
379
387
   </form>
380
   ~
388
FORM
381
389
}
382
390
383
391
sub html_head {
384
392
   my $self = shift;
385
   qq~<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
393
   return <<"HTML_HEAD";
394
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
386
395
"http://www.w3.org/TR/html4/loose.dtd">
387
396
<html>
388
397
   <head>
@@ -414,7 +423,7 @@ sub html_head {
414
423
    <h2><a href   = "$self->{CPAN}/GD-SecurityImage"
415
424
           target = "_blank"
416
425
           >GD::SecurityImage</a> v$GD::SecurityImage::VERSION - DEMO v$VERSION</h2>
417
   ~
426
HTML_HEAD
418
427
}
419
428
420
429
sub html_foot {
@@ -441,14 +450,14 @@ sub create_image { # create a security i
441
450
      lines   => $s->{lines},
442
451
      bgcolor => $s->{bgcolor},
443
452
      %{ $self->{rnd_opt} },
444
   )
445
   ->random  ($code)
446
   ->create  (ttf => $s->{name}, $s->{text_color}, $s->{line_color})
447
   ->particle($s->{dots} ? ($s->{particle}, $s->{dots}) 
448
                         : ($s->{particle})
449
453
   );
454
   $i->random   ($code)
455
      ->create  (ttf => $s->{name}, $s->{text_color}, $s->{line_color})
456
      ->particle($s->{dots} ? ($s->{particle}, $s->{dots})
457
                            : ($s->{particle})
458
      );
450
459
   if ($i->gdbox_empty) {
451
      die qq~An error occurred while opening the font file '$config{font}'. ~
460
      croak qq~An error occurred while opening the font file '$config{font}'. ~
452
461
         .qq~Please set font option to an "exact" path, not relative. Error: $@~;
453
462
   }
454
463
   if ($config{img_stat}) {
@@ -457,13 +466,13 @@ sub create_image { # create a security i
457
466
         y      => 'up',
458
467
         gd     => 1,
459
468
         strip  => 1,
460
         color  => "#000000",
461
         scolor => "#FFFFFF",
469
         color  => '#000000',
470
         scolor => '#FFFFFF',
462
471
         # low-level access to an object table is not a good thing,
463
472
         # since the author can change/delete it without notification 
464
473
         # in later releases ;)
465
         ptsize => $i->{IS_MAGICK} ? 12 : 8,
466
         text   => sprintf("Security Image generated at %.3f seconds",
474
         ptsize => $i->{IS_MAGICK} ? MAGICK_PTSIZE : GD_PTSIZE,
475
         text   => sprintf('Security Image generated at %.3f seconds',
467
476
                           Time::HiRes::time() - $START),
468
477
      );
469
478
   }
@@ -531,6 +540,7 @@ sub all_options {
531
540
}
532
541
533
542
sub all_styles {
543
   ## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
534
544
   return ec => {
535
545
      name       => 'ec',
536
546
      lines      => 16,
@@ -541,7 +551,7 @@ sub all_styles {
541
551
   },
542
552
   ellipse => {
543
553
      name       => 'ellipse',
544
      lines      => 15, 
554
      lines      => 15,
545
555
      bgcolor    => [208, 202, 206],
546
556
      text_color => [184,  20, 180],
547
557
      line_color => [184,  20, 180],
@@ -549,9 +559,9 @@ sub all_styles {
549
559
   },
550
560
   circle => {
551
561
      name       => 'circle',
552
      lines      => 40, 
562
      lines      => 40,
553
563
      bgcolor    => [210, 215, 196],
554
      text_color => [ 63, 143, 167], 
564
      text_color => [ 63, 143, 167],
555
565
      line_color => [210, 215, 196],
556
566
      particle   => 3500,
557
567
   },
@@ -566,7 +576,7 @@ sub all_styles {
566
576
   rect => {
567
577
      name       => 'rect',
568
578
      lines      => 30,
569
      text_color => [ 63, 143, 167], 
579
      text_color => [ 63, 143, 167],
570
580
      line_color => [226, 223, 169],
571
581
      particle   => 2000,
572
582
   },

Up to file-list lib/GD/SecurityImage.pm:

1
1
package GD::SecurityImage;
2
2
use strict;
3
use vars qw[@ISA $AUTOLOAD $VERSION $BACKEND];
3
use warnings;
4
use vars qw[@ISA $VERSION $BACKEND];
4
5
use GD::SecurityImage::Styles;
5
6
use Carp qw(croak);
7
use constant RGB_WHITE   => ( 255, 255, 255 );
8
use constant RGB_BLACK   => ( 0, 0, 0 );
9
use constant RANDOM_DATA => ( 0..9 );
10
use constant FULL_CIRCLE => 360;
11
use constant DEFAULT_ANGLES => (0,5,8,15,22,26,29,33,35,36,40,43,45,53,56);
6
12
7
$VERSION = '1.70';
13
use constant DEFAULT_WIDTH  => 80;
14
use constant DEFAULT_HEIGHT => 30;
15
use constant DEFAULT_PTSIZE => 20;
16
use constant DEFAULT_LINES  => 10;
17
18
use constant MAX_RGB_VALUE  => 255;
19
use constant PARTICLE_MULTIPLIER => 20;
20
use constant MAX_RGB_PARAMS => 3;
21
22
$VERSION = '1.71';
8
23
9
24
sub import {
10
   my $class   = shift;
11
   my %opt     = scalar(@_) % 2 ? () : (@_);
25
   my($class, @args) = @_;
26
   my %opt     = @args % 2 ? () : @args;
12
27
   # init/reset globals
13
   $BACKEND    = ''; # name of the back-end
14
   @ISA        = ();
28
   $BACKEND    = q{}; # name of the back-end
29
   @ISA        = (); ## no critic (ClassHierarchies::ProhibitExplicitISA)
15
30
   # load the drawing interface
16
31
   if ( exists $opt{use_magick} && $opt{use_magick} ) {
17
32
      require GD::SecurityImage::Magick;
18
33
      $BACKEND = 'Magick';
19
34
   }
20
35
   elsif ( exists $opt{backend} && $opt{backend} ) {
21
      my $be = __PACKAGE__.'::'.$opt{backend};
22
      eval "require $be";
36
      my $be  = __PACKAGE__.q{::}.$opt{backend};
37
      my $eok = eval "require $be";
23
38
      croak "Unable to locate the $class back-end $be: $@" if $@;
24
39
      $BACKEND = $opt{backend} eq 'AC' ? 'GD' : $opt{backend};
25
40
   }
@@ -27,15 +42,15 @@ sub import {
27
42
      require GD::SecurityImage::GD;
28
43
      $BACKEND = 'GD';
29
44
   }
30
   push @ISA, 'GD::SecurityImage::' . $BACKEND;
31
   push @ISA, qw(GD::SecurityImage::Styles); # load styles
45
   push @ISA, 'GD::SecurityImage::' . $BACKEND, ## no critic (ClassHierarchies::ProhibitExplicitISA)
46
              qw(GD::SecurityImage::Styles); # load styles
32
47
   return;
33
48
}
34
49
35
50
sub new {
36
   my $class = shift;
51
   my($class, @args) = @_;
37
52
      $BACKEND || croak "You didn't import $class!";
38
   my %opt   = scalar @_ % 2 ? () : (@_);
53
   my %opt   = @args % 2 ? () : @args;
39
54
40
55
   my $self  = {
41
56
      IS_MAGICK       => $BACKEND eq 'Magick',
@@ -44,7 +59,7 @@ sub new {
44
59
      DISABLED        => {}, # list of methods that a backend (or some older version of backend) can't do
45
60
      MAGICK          => {}, # Image::Magick configuration options
46
61
      GDBOX_EMPTY     => 0,  # GD::SecurityImage::GD::insert_text() failed?
47
      _RANDOM_NUMBER_ => '', # random security code
62
      _RANDOM_NUMBER_ => q{}, # random security code
48
63
      _RNDMAX_        => 6,  # maximum number of characters in a random string.
49
64
      _COLOR_         => {}, # text and line colors
50
65
      _CREATECALLED_  => 0,  # create() called? (check for particle())
@@ -52,16 +67,59 @@ sub new {
52
67
   };
53
68
   bless $self, $class;
54
69
70
   my %options = $self->_new_options( %opt );
71
72
   if ( $opt{text_location}
73
      && ref $opt{text_location}
74
      && ref $opt{text_location} eq 'HASH' ) {
75
      $self->{_TEXT_LOCATION_} = { %{$opt{text_location}}, _place_ => 1 };
76
   }
77
   else {
78
      $self->{_TEXT_LOCATION_}{_place_} = 0;
79
   }
80
81
   $self->{_RNDMAX_} = $options{rndmax};
82
83
   $self->{$_} = $options{$_} foreach keys %options;
84
85
   if ( $self->{angle} ) { # validate angle
86
      $self->{angle} = FULL_CIRCLE + $self->{angle} if $self->{angle} < 0;
87
      if ( $self->{angle} > FULL_CIRCLE ) {
88
         croak 'Angle parameter can take values in the range -360..360';
89
      }
90
   }
91
92
   if ( $self->{scramble} ) {
93
      if ( $self->{angle} ) {
94
         # Does the user want a fixed angle?
95
         push @{ $self->{_ANGLES_} }, $self->{angle};
96
      }
97
      else {
98
         # Generate angle range. The reason for hardcoding these is; 
99
         # it'll be less random for 0..60 range
100
         push @{ $self->{_ANGLES_} }, DEFAULT_ANGLES;
101
         # push negatives
102
         push @{ $self->{_ANGLES_} },
103
              map {FULL_CIRCLE - $_} @{ $self->{_ANGLES_} };
104
      }
105
   }
106
107
   $self->init;
108
   return $self;
109
}
110
111
sub _new_options {
112
   my($self, %opt) = @_;
55
113
   my %options = (
56
      width      => $opt{width}               || 80,
57
      height     => $opt{height}              || 30,
58
      ptsize     => $opt{ptsize}              || 20,
59
      lines      => $opt{lines}               || 10,
114
      width      => $opt{width}               || DEFAULT_WIDTH,
115
      height     => $opt{height}              || DEFAULT_HEIGHT,
116
      ptsize     => $opt{ptsize}              || DEFAULT_PTSIZE,
117
      lines      => $opt{lines}               || DEFAULT_LINES,
60
118
      rndmax     => $opt{rndmax}              || $self->{_RNDMAX_},
61
      rnd_data   => $opt{rnd_data}            || [0..9],
62
      font       => $opt{font}                || '',
63
      gd_font    => $self->gdf($opt{gd_font}) || '',
64
      bgcolor    => $opt{bgcolor}             || [255, 255, 255],
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 ],
65
123
      send_ctobg => $opt{send_ctobg}          || 0,
66
124
      frame      => defined($opt{frame}) ? $opt{frame} : 1,
67
125
      scramble   => $opt{scramble}            || 0,
@@ -69,76 +127,46 @@ sub new {
69
127
      thickness  => $opt{thickness}           || 0,
70
128
      _ANGLES_   => [], # angle list for scrambled images
71
129
   );
72
73
   if($opt{text_location} && ref $opt{text_location} && ref $opt{text_location} eq 'HASH') {
74
      $self->{_TEXT_LOCATION_} = { %{$opt{text_location}}, _place_ => 1 };
75
   }
76
   else {
77
      $self->{_TEXT_LOCATION_}{_place_} = 0;
78
   }
79
   $self->{_RNDMAX_} = $options{rndmax}; 
80
81
   $self->{$_} = $options{$_} foreach keys %options;
82
   if($self->{angle}) { # validate angle
83
      $self->{angle} = 360 + $self->{angle} if $self->{angle} < 0;
84
      if($self->{angle} > 360) {
85
         croak "Angle parameter can take values in the range -360..360";
86
      }
87
   }
88
89
   if ($self->{scramble}) {
90
      if ($self->{angle}) {
91
         # Does the user want a fixed angle?
92
         push @{ $self->{_ANGLES_} }, $self->{angle};
93
      }
94
      else {
95
         # Generate angle range. The reason for hardcoding these is; 
96
         # it'll be less random for 0..60 range
97
         push @{ $self->{_ANGLES_} }, (0,5,8,15,22,26,29,33,35,36,40,43,45,53,56);
98
         push @{ $self->{_ANGLES_} }, map {360 - $_} @{ $self->{_ANGLES_} }; # push negatives
99
      }
100
   }
101
102
   $self->init;
103
   return $self;
130
   return %options;
104
131
}
105
132
106
133
sub backends {
107
134
   my $self  = shift;
108
135
   my $class = ref($self) || $self;
109
136
   my(@list, @dir_list);
137
   require Symbol;
110
138
   foreach my $inc (@INC) {
111
139
      my $dir = "$inc/GD/SecurityImage";
112
140
      next unless -d $dir;
113
      local  *DIR;
114
      opendir DIR, $dir or croak "opendir($dir) failed: $!";
115
      my @dir = readdir DIR;
116
      closedir DIR;
141
      my $DIR = Symbol::gensym();
142
      opendir $DIR, $dir or croak "opendir($dir) failed: $!";
143
      my @dir = readdir $DIR;
144
      closedir $DIR;
117
145
      push @dir_list, $dir;
118
146
      foreach my $file (@dir) {
119
147
         next if -d $file;
120
         next if $file =~ m[^\.];
121
         next if $file =~ m[^(Styles|AC|Handler)\.pm$];
122
         $file =~ s[\.pm$][];
148
         next if $file =~ m{ \A [.] }xms;
149
         next if $file =~ m{ \A (Styles|AC|Handler)[.]pm \z}xms;
150
         $file =~ s{ [.]pm \z}{}xms;
123
151
         push @list, $file;
124
152
      }
125
153
   }
126
   if (defined wantarray) {
127
      return @list;
128
   }
129
   else {
130
      print "Available back-ends in $class v$VERSION are:\n\t"
131
            .join("\n\t", @list)
132
            ."\n\n"
133
            ."Search directories:\n\t"
134
            .join("\n\t", @dir_list);
135
   }
154
155
   return @list if defined wantarray;
156
157
   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
   print $report or croak "Unable to print to STDOUT: $!";
163
   return;
136
164
}
137
165
138
166
sub gdf {
139
   my $self = shift;
167
   my($self, @args) = @_;
140
168
   return if not $self->{IS_GD};
141
   return $self->gdfx(@_);
169
   return $self->gdfx( @args );
142
170
}
143
171
144
172
sub random_angle {
@@ -149,7 +177,7 @@ sub random_angle {
149
177
   return $r[int rand @r];
150
178
}
151
179
152
sub random_str { shift->{_RANDOM_NUMBER_} }
180
sub random_str { return shift->{_RANDOM_NUMBER_} }
153
181
154
182
sub random {
155
183
   my $self = shift;
@@ -164,24 +192,24 @@ sub random {
164
192
         $random .= $keys[int rand $lk] for 1..$self->{rndmax};
165
193
         $self->{_RANDOM_NUMBER_} = $random;
166
194
   }
167
   return $self if defined wantarray;
195
   return defined wantarray ? $self : undef;
168
196
}
169
197
170
198
sub cconvert { # convert color codes
171
199
   # GD           : return color index number
172
200
   # Image::Magick: return hex color code
173
201
   my $self   = shift;
174
   my $data   = shift || croak "Empty parameter passed to cconvert!";
202
   my $data   = shift || croak 'Empty parameter passed to cconvert';
175
203
   return $self->backend_cconvert($data) if not $self->{IS_CORE};
176
204
177
205
   my $is_hex    = $self->is_hex($data);
178
206
   my $magick_ok = $self->{IS_MAGICK} && $data && $is_hex;
179
207
   # data is a hex color code and Image::Magick has hex support
180
208
   return $data if $magick_ok;
181
   my $color_code = $data              &&
182
                    ! $is_hex          &&
183
                    ! ref($data)       &&
184
                    $data !~ m{[^0-9]} &&
209
   my $color_code = $data                 &&
210
                    ! $is_hex             &&
211
                    ! ref($data)          &&
212
                    $data !~ m{[^0-9]}xms &&
185
213
                    $data >= 0;
186
214
187
215
   if( $color_code ) {
@@ -195,15 +223,20 @@ sub cconvert { # convert color codes
195
223
   }
196
224
197
225
   my @rgb = $self->h2r($data);
198
   return $data if @rgb && $self->{IS_MAGICK};
226
   return @rgb && $self->{IS_MAGICK}
227
         ? $data
228
         : $self->_cconvert_new( $data, @rgb );
229
}
199
230
231
sub _cconvert_new {
232
   my($self, $data, @rgb) = @_;
200
233
   $data = [@rgb] if @rgb;
201
234
   # initialize if not valid
202
   if(not $data || not ref $data || ref $data ne 'ARRAY' || $#{$data} != 2) {
235
   if(! $data || ! ref $data || ref $data ne 'ARRAY' || $#{$data} != 2) {
203
236
      $data = [0, 0, 0];
204
237
   }
205
238
   foreach my $i (0..$#{$data}) { # check for bad values
206
      if ($data->[$i] > 255 or $data->[$i] < 0) {
239
      if ( $data->[$i] > MAX_RGB_VALUE || $data->[$i] < 0 ) {
207
240
         $data->[$i] = 0;
208
241
      }
209
242
   }
@@ -227,10 +260,10 @@ sub create {
227
260
228
261
   # be a smart module and auto-disable ttf if we are under a prehistoric GD
229
262
   if ( not $self->{IS_MAGICK} ) {
230
      $method = 'normal' if $self->_versionlt(1.20);
263
      $method = 'normal' if $self->_versionlt( '1.20' );
231
264
   }
232
265
233
   if($method eq 'normal' and not $self->{gd_font}) {
266
   if ( $method eq 'normal' && ! $self->{gd_font} ) {
234
267
      $self->{gd_font} = $self->gdf('giant');
235
268
   }
236
269
@@ -248,37 +281,36 @@ sub create {
248
281
   }
249
282
250
283
   $self->{_CREATECALLED_}++;
251
   return $self if defined wantarray;
284
   return defined wantarray ? $self : undef;
252
285
}
253
286
254
287
sub particle {
255
288
   # Create random dots. They'll cover all over the surface
256
289
   my $self = shift;
257
   croak "particle() must be called 'after' create()" if not $self->{_CREATECALLED_};
290
   croak q{particle() must be called 'after' create()} if !$self->{_CREATECALLED_};
258
291
   my $big  = $self->{height} > $self->{width} ? $self->{height} : $self->{width};
259
   my $f    = shift || $big * 20; # particle density
292
   my $f    = shift || $big * PARTICLE_MULTIPLIER; # particle density
260
293
   my $dots = shift || 1; # number of multiple dots
261
   my $int  = int $big / 20;
294
   my $int  = int $big / PARTICLE_MULTIPLIER;
262
295
263
296
   if ( ! $int ) { # RT#33629
264
      warn "particle(): image dimension is so small to add particles";
297
      warn "particle(): image dimension is so small to add particles\n";
265
298
      return;
266
299
   }
267
300
268
301
   my @random;
269
   for (my $x = $int; $x <= $big; $x += $int) {
302
   for (my $x = $int; $x <= $big; $x += $int) { ## no critic (ControlStructures::ProhibitCStyleForLoops)
270
303
      push @random, $x;
271
304
   }
272
305
273
306
   my $tc  = $self->{_COLOR_}{text};
274
307
   my $len = @random;
275
308
   my $r   = sub { $random[ int rand $len ] };
276
   my($x, $y, $z);
277
309
278
   for (1..$f) {
279
      $x = int rand $self->{width};
280
      $y = int rand $self->{height};
281
      foreach $z (1..$dots) {
310
   for ( 1..$f ) {
311
      my $x = int rand $self->{width};
312
      my $y = int rand $self->{height};
313
      foreach my $z (1..$dots) {
282
314
         $self->setPixel($x + $z         , $y + $z         , $tc);
283
315
         $self->setPixel($x + $z + $r->(), $y + $z + $r->(), $tc);
284
316
      }
@@ -286,10 +318,10 @@ sub particle {
286
318
   undef @random;
287
319
   undef $r;
288
320
289
   return $self if defined wantarray;
321
   return defined wantarray ? $self : undef;
290
322
}
291
323
292
sub raw { $_[0]->{image} } # raw image object
324
sub raw { return shift->{image} } # raw image object
293
325
294
326
sub info_text { # set text location
295
327
   # x      => 'left|right',  # text-X
@@ -300,34 +332,49 @@ sub info_text { # set text location
300
332
   # color  => '#000000',     # text color
301
333
   # scolor => '#FFFFFF',     # strip color
302
334
   # text   => 'blah',        # modifies random code
303
   my $self = shift;
304
   croak "info_text() must be called 'after' create()" if not $self->{_CREATECALLED_};
305
   my %o = scalar(@_) % 2 ? () : ( qw/ x right y up strip 1 /, @_ );
335
   my($self, @args) = @_;
336
   croak q{info_text() must be called 'after' create()} if ! $self->{_CREATECALLED_};
337
   my %o = @args % 2 ? () : ( qw/ x right y up strip 1 /, @args );
306
338
   return if not %o;
307
339
308
340
   $self->{_TEXT_LOCATION_}{_place_} = 1;
309
341
   $o{scolor}                        = $self->cconvert($o{scolor})       if $o{scolor};
310
   local $self->{_RANDOM_NUMBER_}    = delete $o{text}                   if $o{text};
311
   local $self->{_COLOR_}{text}      = $self->cconvert(delete $o{color}) if $o{color};
312
   local $self->{ptsize}             = delete $o{ptsize}                 if $o{ptsize};
313
342
314
   local $self->{scramble} = 0; # disable. we need a straight text
315
   local $self->{angle}    = 0; # disable. RT:14618
343
   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
   $self->{_RANDOM_NUMBER_}    = delete $o{text}                   if $o{text};
352
   $self->{_COLOR_}{text}      = $self->cconvert(delete $o{color}) if $o{color};
353
   $self->{ptsize}             = delete $o{ptsize}                 if $o{ptsize};
354
   $self->{scramble}           = 0; # disable. we need a straight text
355
   $self->{angle}              = 0; # disable. RT:14618
316
356
317
357
   $self->{_TEXT_LOCATION_}->{$_} = $o{$_} foreach keys %o;
318
358
   $self->insert_text('ttf');
319
   $self;
359
360
   # restore
361
   $self->{_RANDOM_NUMBER_}    = $restore{random};
362
   $self->{_COLOR_}{text}      = $restore{color};
363
   $self->{ptsize}             = $restore{ptsize};
364
   $self->{scramble}           = $restore{scramble};
365
   $self->{angle}              = $restore{angle};
366
367
   return $self;
320
368
}
321
369
322
370
#--------------------[ PRIVATE ]--------------------#
323
371
324
372
sub add_strip { # adds a strip to the background of the text
325
   my $self = shift;
326
   my($x, $y, $box_w, $box_h) = @_;
373
   my($self, $x, $y, $box_w, $box_h) = @_;
327
374
   my $tl    = $self->{_TEXT_LOCATION_};
328
375
   my $c     = $self->{_COLOR_} || {};
329
   my $black = $self->cconvert( $c->{text}    ? $c->{text}    : [   0,   0,   0 ] );
330
   my $white = $self->cconvert( $tl->{scolor} ? $tl->{scolor} : [ 255, 255, 255 ] );
376
   my $black = $self->cconvert( $c->{text}    ? $c->{text}    : [ RGB_BLACK ] );
377
   my $white = $self->cconvert( $tl->{scolor} ? $tl->{scolor} : [ RGB_WHITE ] );
331
378
   my $x2    = $tl->{x} eq 'left' ? $box_w : $self->{width};
332
379
   my $y2    = $self->{height} - $box_h;
333
380
   my $i     = $self->{IS_MAGICK} ? $self  : $self->{image};
@@ -340,11 +387,11 @@ sub add_strip { # adds a strip to the ba
340
387
341
388
sub r2h {
342
389
   # Convert RGB to Hex
343
   my $self = shift;
344
   @_ == 3 || return;
345
   my $color  = '#';
346
      $color .= sprintf("%02x", $_) foreach @_;
347
      $color;
390
   my($self, @args) = @_;
391
   return if @args != MAX_RGB_PARAMS;
392
   my $color  = q{#};
393
      $color .= sprintf '%02x', $_ foreach @args;
394
   return $color;
348
395
}
349
396
350
397
sub h2r {
@@ -352,27 +399,16 @@ sub h2r {
352
399
   my $self  = shift;
353
400
   my $color = shift;
354
401
   return if ref $color;
355
   my @rgb   = $color =~ m[^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$]i;
402
   my @rgb   = $color =~ m/\A \#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2}) \z/xmsi;
356
403
   return @rgb ? map { hex $_ } @rgb : undef;
357
404
}
358
405
359
406
sub is_hex {
360
407
   my $self = shift;
361
408
   my $data = shift;
362
   return $data =~ m[^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$]i;
409
   return $data =~ m/ \A \#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2}) \z /xmsi;
363
410
}
364
411
365
sub AUTOLOAD {
366
   my $self  = shift;
367
   my $class = ref $self;
368
   (my $name = $AUTOLOAD) =~ s,.*:,,;
369
   # fake method for GD compatibility. only GD has this
370
   return 0 if $name eq 'gdbox_empty';
371
   croak "Unknown $class method '$name'";
372
}
373
374
sub DESTROY {}
375
376
412
1;
377
413
378
414
__END__
@@ -386,24 +422,28 @@ GD::SecurityImage - Security image (capt
386
422
   use GD::SecurityImage;
387
423
388
424
   # Create a normal image
389
   my $image = GD::SecurityImage->new(width   => 80,
390
                                      height  => 30,
391
                                      lines   => 10,
392
                                      gd_font => 'giant');
393
      $image->random($your_random_str);
394
      $image->create(normal => 'rect');
425
   my $image = GD::SecurityImage->new(
426
                  width   => 80,
427
                  height  => 30,
428
                  lines   => 10,
429
                  gd_font => 'giant',
430
               );
431
      $image->random( $your_random_str );
432
      $image->create( normal => 'rect' );
395
433
   my($image_data, $mime_type, $random_number) = $image->out;
396
434
397
435
or
398
436
399
437
   # use external ttf font
400
   my $image = GD::SecurityImage->new(width    => 100,
401
                                      height   => 40,
402
                                      lines    => 10,
403
                                      font     => "/absolute/path/to/your.ttf",
404
                                      scramble => 1);
405
      $image->random($your_random_str);
406
      $image->create(ttf => 'default');
438
   my $image = GD::SecurityImage->new(
439
                  width    => 100,
440
                  height   => 40,
441
                  lines    => 10,
442
                  font     => "/absolute/path/to/your.ttf",
443
                  scramble => 1,
444
               );
445
      $image->random( $your_random_str );
446
      $image->create( ttf => 'default' );
407
447
      $image->particle;
408
448
   my($image_data, $mime_type, $random_number) = $image->out;
409
449
@@ -1371,18 +1411,4 @@ C<GD::SecurityImage>, you can comment/ra
1371
1411
the C<CPAN Ratings> system: 
1372
1412
L<http://cpanratings.perl.org/dist/GD-SecurityImage>.
1373
1413
1374
=head1 AUTHOR
1375
1376
Burak GE<252>rsoy, E<lt>burakE<64>cpan.orgE<gt>
1377
1378
=head1 COPYRIGHT
1379
1380
Copyright 2004-2008 Burak GE<252>rsoy. All rights reserved.
1381
1382
=head1 LICENSE
1383
1384
This library is free software; you can redistribute it and/or modify 
1385
it under the same terms as Perl itself, either Perl version 5.8.8 or, 
1386
at your option, any later version of Perl 5 you may have available.
1387
1388
1414
=cut

Up to file-list lib/GD/SecurityImage/GD.pm:

1
1
package GD::SecurityImage::GD;
2
2
use strict;
3
use warnings;
3
4
use vars qw( $VERSION );
4
5
5
6
use constant LOWLEFTX    => 0; # Lower left  corner x
@@ -23,12 +24,21 @@ use constant NEWSTUFF => qw( ellipse
23
24
use constant FORMATS     => qw( png gif jpeg );
24
25
use constant GDFONTS     => qw( Small Large MediumBold Tiny Giant );
25
26
27
use constant RGB_WHITE   => (255, 255, 255);
28
use constant BOX_SIZE    => 7;
29
30
use constant ROTATE_NONE             =>   0;
31
use constant ROTATE_COUNTERCLOCKWISE =>  90;
32
use constant ROTATE_UPSIDEDOWN       => 180;
33
use constant ROTATE_CLOCKWISE        => 270;
34
use constant FULL_CIRCLE             => 360;
35
26
36
use GD;
27
37
28
$VERSION = '1.50';
38
$VERSION = '1.71';
29
39
30
40
# define the tff drawing method.
31
my $TTF = __PACKAGE__->_versiongt( 1.31 ) ? 'stringFT' : 'stringTTF';
41
my $TTF = __PACKAGE__->_versiongt( '1.31' ) ? 'stringFT' : 'stringTTF';
32
42
33
43
sub init {
34
44
   # Create the image object
@@ -36,17 +46,18 @@ sub init {
36
46
   $self->{image} = GD::Image->new($self->{width}, $self->{height});
37
47
   $self->cconvert($self->{bgcolor}); # set background color
38
48
   $self->setThickness($self->{thickness}) if $self->{thickness};
39
   if ( $self->_versionlt(2.07) ) {
49
   if ( $self->_versionlt( '2.07' ) ) {
40
50
      foreach my $prop ( NEWSTUFF ) {
41
51
         $self->{DISABLED}{$prop} = 1;
42
52
      }
43
53
   }
54
   return;
44
55
}
45
56
46
57
sub out {
47
58
   # return $image_data, $image_mime_type, $random_number
48
   my $self = shift;
49
   my %opt  = scalar @_ % 2 ? () : (@_);
59
   my($self, @args) = @_;
60
   my %opt  = @args % 2 ? () : @args;
50
61
   my $i    = $self->{image};
51
62
   my $type;
52
63
   if ( $opt{force} && $i->can($opt{force}) ){
@@ -61,15 +72,16 @@ sub out {
61
72
         }
62
73
      }
63
74
   }
64
   my @args = ();
75
76
   my @iargs = ();
65
77
   if ( $opt{'compress'} ) {
66
      push @args, MAXCOMPRESS      if $type eq 'png' and not $self->{DISABLED}{_png_compression};
67
      push @args, $opt{'compress'} if $type eq 'jpeg';
78
      push @iargs, MAXCOMPRESS      if $type eq 'png' and not $self->{DISABLED}{_png_compression};
79
      push @iargs, $opt{'compress'} if $type eq 'jpeg';
68
80
   }
69
   return $i->$type(@args), $type, $self->{_RANDOM_NUMBER_};
81
   return $i->$type(@iargs), $type, $self->{_RANDOM_NUMBER_};
70
82
}
71
83
72
sub gdbox_empty { $_[0]->{GDBOX_EMPTY} }
84
sub gdbox_empty { return shift->{GDBOX_EMPTY} }
73
85
74
86
sub gdfx {
75
87
   # Sets the font for simple GD usage. 
@@ -85,37 +97,20 @@ sub gdfx {
85
97
   }
86
98
}
87
99
88
sub insert_text {
89
   # Draw text using GD
90
   my $self   = shift;
91
   my $method = shift;
92
   my $key    = $self->{_RANDOM_NUMBER_}; # random string
93
   my $ctext  = $self->{_COLOR_}{text};
94
   if ($method eq 'ttf') {
95
      require Math::Trig;
96
      # don' t draw. we just need info...
97
      my $info = sub {
98
         my $txt = shift;
99
         my $ang = shift || 0;
100
            $ang = Math::Trig::deg2rad($ang) if $ang;
101
         my @box = GD::Image->$TTF( $ctext, $self->{font}, $self->{ptsize}, $ang, 0, 0, $txt );
102
         if ( not @box ) { # use fake values instead of die-ing
103
            $self->{GDBOX_EMPTY} = 1; # set this for error checking.
104
            $#box    = 7;
105
            # lets initialize to silence the warnings
106
            $box[$_] = 1 for 0..$#box;
107
         }
108
         return @box;
109
      };
110
      if ( $self->{scramble} ) {
100
sub _insert_text_ttf_scramble {
101
   my($self, $key, $ctext) = @_;
102
   require Math::Trig;
103
111
104
         my @char;
112
105
         my $anglex;
113
106
         my $total = 0;
114
         my $space = [$self->ttf_info(0, 'A'),0,'  '];
107
         my $space = [ $self->ttf_info( 0, 'A' ), 0, q{  } ];
115
108
         my @randomy;
116
109
         my $sy = $space->[CHY] || 1;
117
         push(@randomy,  $_, - $_) foreach $sy*1.2,$sy, $sy/2, $sy/4, $sy/8;
118
         foreach (split //, $key) { # get char parameters
110
         ## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
111
         push @randomy,  $_, - $_ foreach $sy*1.2,$sy, $sy/2, $sy/4, $sy/8;
112
         ## use critic
113
         foreach (split m{}xms, $key) { # get char parameters
119
114
            $anglex = $self->random_angle;
120
115
            $total += $space->[CHX];
121
116
            push @char, [$self->ttf_info($anglex, $_), $anglex, $_], $space, $space, $space;
@@ -130,87 +125,132 @@ sub insert_text {
130
125
            $self->{image}->$TTF(@config, Math::Trig::deg2rad($box->[CHAR]), $x, $y, $box->[ANGLE]);
131
126
            $total -= $space->[CHX];
132
127
         }
128
   return;
129
}
130
131
sub _insert_text_ttf_normal {
132
   my($self, $key, $ctext) = @_;
133
   require Math::Trig;
134
   # don' t draw. we just need info...
135
   my $info = sub {
136
      my $txt = shift;
137
      my $ang = shift || 0;
138
         $ang = Math::Trig::deg2rad($ang) if $ang;
139
      my @box = GD::Image->$TTF(
140
                  $ctext, $self->{font}, $self->{ptsize}, $ang, 0, 0, $txt
141
               );
142
      if ( not @box ) { # use fake values instead of die-ing
143
         $self->{GDBOX_EMPTY} = 1; # set this for error checking.
144
         $#box = BOX_SIZE;
145
         # lets initialize to silence the warnings
146
         $box[$_] = 1 for 0..$#box;
147
      }
148
      return @box;
149
   };
150
151
   my(@box, $x, $y);
152
   my $tl = $self->{_TEXT_LOCATION_};
153
   if ( $tl->{_place_} ) {
154
      # put the text to one of the four corners in the image
155
      my $white = $self->cconvert( [ RGB_WHITE ] );
156
      my $black = $self->cconvert($ctext);
157
      if ( $tl->{gd} ) { # draw with standard gd fonts
158
         $self->place_gd($key, $tl->{x}, $tl->{y});
159
         return; # by-pass ttf method call...
133
160
      }
134
161
      else {
135
         my(@box,$x,$y);
136
         my $tl = $self->{_TEXT_LOCATION_};
137
         if ($tl->{_place_}) {
138
            # put the text to one of the four corners in the image
139
            my $white = $self->cconvert([255,255,255]);
140
            my $black = $self->cconvert($ctext);
141
            if ( $tl->{gd} ) { # draw with standard gd fonts
142
               $self->place_gd($key, $tl->{x}, $tl->{y});
143
               return; # by-pass ttf method call...
144
            }
145
            else {
146
               @box = $info->($key);
147
               $x   = $tl->{x} eq 'left'? 0                                : ($self->{width}  - ($box[LOWRIGHTX] - $box[LOWLEFTX]));
148
               $y   = $tl->{y} eq 'up'  ? ($box[LOWLEFTY] - $box[UPLEFTY]) :  $self->{height}-2;
149
               if ($tl->{strip}) {
150
                  $self->add_strip($x, $y, $box[LOWRIGHTX] - $box[LOWLEFTX], $box[LOWLEFTY] - $box[UPLEFTY]);
151
               }
152
            }
162
         @box = $info->($key);
163
         $x   = $tl->{x} eq 'left'
164
               ? 0
165
               : ( $self->{width} - ($box[LOWRIGHTX] - $box[LOWLEFTX]) )
166
               ;
167
         $y   = $tl->{y} eq 'up'
168
               ? ( $box[LOWLEFTY] - $box[UPLEFTY] )
169
               :  $self->{height} - 2
170
               ;
171
         if ($tl->{strip}) {
172
            $self->add_strip(
173
               $x, $y, $box[LOWRIGHTX] - $box[LOWLEFTX], $box[LOWLEFTY] - $box[UPLEFTY]
174
            );
153
175
         }
154
         else {
155
            @box = $info->($key);
156
            $x = ($self->{width}  - ($box[LOWRIGHTX] - $box[LOWLEFTX])) / 2;
157
            $y = ($self->{height} - ($box[UPLEFTY]   - $box[LOWLEFTY])) / 2;
158
         }
159
         # this needs a fix. adjust x,y
160
         if ($self->{angle}) {
161
            require Math::Trig;
162
            $self->{angle} = Math::Trig::deg2rad($self->{angle});
163
         }
164
         else {
165
            $self->{angle} = 0;
166
         }
167
         $self->{image}->$TTF($ctext, $self->{font}, $self->{ptsize}, $self->{angle}, $x, $y, $key);
168
176
      }
169
177
   }
170
178
   else {
171
      if ($self->{scramble}) {
172
         # without ttf, we can only have 0 and 90 degrees.
173
         my @char;
174
         my @styles = qw(string stringUp);
175
         my $style  = $styles[int rand @styles];
176
         foreach (split //, $key) { # get char parameters
177
            push @char, [$_, $style], [' ','string'];
178
            $style = $style eq 'string' ? 'stringUp' : 'string';
179
         }
180
         my $sw = $self->{gd_font}->width;
181
         my $sh = $self->{gd_font}->height;
182
         my($x, $y, $m);
183
         my $total = $sw * @char;
184
         foreach my $c (@char) {
185
            $m = $c->[1];
186
            $x = ($self->{width}  - $total) / 2;
187
            $y = $self->{height}/2 + ($m eq 'string' ? -$sh : $sh/2) / 2;
188
            $total -= $sw * 2;
189
            $self->{image}->$m($self->{gd_font}, $x, $y, $c->[0], $ctext);
190
         }
191
      }
192
      else {
193
         my $sw = $self->{gd_font}->width * length($key);
194
         my $sh = $self->{gd_font}->height;
195
         my $x  = ($self->{width}  - $sw) / 2;
196
         my $y  = ($self->{height} - $sh) / 2;
197
         $self->{image}->string($self->{gd_font}, $x, $y, $key, $ctext);
198
      }
179
      @box = $info->($key);
180
      $x   = ($self->{width}  - ($box[LOWRIGHTX] - $box[LOWLEFTX])) / 2;
181
      $y   = ($self->{height} - ($box[UPLEFTY]   - $box[LOWLEFTY])) / 2;
199
182
   }
183
184
   # this needs a fix. adjust x,y
185
   $self->{angle} = $self->{angle} ? Math::Trig::deg2rad($self->{angle}) : 0;
186
   $self->{image}->$TTF( $ctext, $self->{font}, $self->{ptsize}, $self->{angle}, $x, $y, $key );
187
   return;
188
}
189
190
sub _insert_text_gd_scramble {
191
   my($self, $key, $ctext) = @_;
192
   # without ttf, we can only have 0 and 90 degrees.
193
   my @char;
194
   my @styles = qw(string stringUp);
195
   my $style  = $styles[int rand @styles];
196
   foreach (split m{}xms, $key) { # get char parameters
197
      push @char, [ $_, $style ], [ q{ }, 'string' ];
198
      $style = $style eq 'string' ? 'stringUp' : 'string';
199
   }
200
   my $sw = $self->{gd_font}->width;
201
   my $sh = $self->{gd_font}->height;
202
   my($x, $y, $m);
203
   my $total = $sw * @char;
204
   foreach my $c (@char) {
205
      $m = $c->[1];
206
      $x = ($self->{width}  - $total) / 2;
207
      $y = $self->{height}/2 + ($m eq 'string' ? -$sh : $sh/2) / 2;
208
      $total -= $sw * 2;
209
      $self->{image}->$m($self->{gd_font}, $x, $y, $c->[0], $ctext);
210
   }
211
   return;
212
}
213
214
sub _insert_text_gd_normal {
215
   my($self, $key, $ctext) = @_;
216
   my $sw = $self->{gd_font}->width * length $key;
217
   my $sh = $self->{gd_font}->height;
218
   my $x  = ($self->{width}  - $sw) / 2;
219
   my $y  = ($self->{height} - $sh) / 2;
220
   $self->{image}->string($self->{gd_font}, $x, $y, $key, $ctext);
221
   return;
222
}
223
224
sub insert_text {
225
   # Draw text using GD
226
   my $self   = shift;
227
   my $method = shift;
228
   my $key    = $self->{_RANDOM_NUMBER_};
229
   my $ctext  = $self->{_COLOR_}{text};
230
   if ($method eq 'ttf') {
231
      $self->{scramble} ? $self->_insert_text_ttf_scramble( $key, $ctext )
232
                        : $self->_insert_text_ttf_normal(   $key, $ctext )
233
                        ;
234
   }
235
   else {
236
      $self->{scramble} ? $self->_insert_text_gd_scramble( $key, $ctext )
237
                        : $self->_insert_text_gd_normal(   $key, $ctext )
238
                        ;
239
   }
240
   return;
200
241
}
201
242
202
243
sub place_gd {
203
   my $self  = shift;
204
   my($key, $tX, $tY) = @_;
244
   my($self, $key, $tx, $ty) = @_;
205
245
   my $tl    = $self->{_TEXT_LOCATION_};
206
246
   my $black = $self->cconvert($self->{_COLOR_}{text});
207
247
   my $white = $self->cconvert($tl->{scolor});
208
248
   my $font  = GD::Font->Tiny;
209
249
   my $fx    = (length($key)+1)*$font->width;
210
250
   my $x1    = $self->{width} - $fx;
211
   my $y1    = $tY eq 'up' ? 0 : $self->{height} - $font->height;
212
   if ($tY eq 'up') {
213
      if($tX eq 'left') {
251
   my $y1    = $ty eq 'up' ? 0 : $self->{height} - $font->height;
252
   if ($ty eq 'up') {
253
      if($tx eq 'left') {
214
254
         $self->filledRectangle(0, $y1  , $fx  , $font->height+2, $black);
215
255
         $self->filledRectangle(1, $y1+1, $fx-1, $font->height+1, $white);
216
256
      }
@@ -220,7 +260,7 @@ sub place_gd {
220
260
      }
221
261
   }
222
262
   else {
223
      if($tX eq 'left') {
263
      if($tx eq 'left') {
224
264
         $self->filledRectangle(0, $y1-2, $fx  , $self->{height}  , $black);
225
265
         $self->filledRectangle(1    , $y1-1, $fx-1, $self->{height}-2, $white);
226
266
      }
@@ -229,73 +269,127 @@ sub place_gd {
229
269
         $self->filledRectangle($x1-$font->width    , $y1-1, $self->{width}-2, $self->{height}-2, $white);
230
270
      }
231
271
   }
232
   $self->{image}->string($font, $tX eq 'left' ? 2 : $x1, $tY eq 'up' ? $y1+1 : $y1-1, $key, $self->{_COLOR_}{text});
272
   return $self->{image}->string(
273
            $font,
274
            $tx eq 'left' ? 2     : $x1,
275
            $ty eq 'up'   ? $y1+1 : $y1-1,
276
            $key,
277
            $self->{_COLOR_}{text}
278
         );
233
279
}
234
280
235
281
sub ttf_info {
236
282
   my $self  = shift;
237
283
   my $angle = shift || 0;
238
284
   my $text  = shift;
239
   my $x     = 0;
240
   my $y     = 0;
241
   my @box   = GD::Image->$TTF(
242
      $self->{_COLOR_}{text},
243
      $self->{font},
244
      $self->{ptsize},
245
      Math::Trig::deg2rad($angle),
246
      0,
247
      0,
248
      $text
249
   );
285
   require Math::Trig;
286
   my @box = GD::Image->$TTF(
287
               $self->{_COLOR_}{text},
288
               $self->{font},
289
               $self->{ptsize},
290
               Math::Trig::deg2rad($angle),
291
               0,
292
               0,
293
               $text
294
            );
250
295
   if ( not @box ) { # use fake values instead of die-ing
251
296
      $self->{GDBOX_EMPTY} = 1; # set this for error checking.
252
      $#box    = 7;
297
      $#box = BOX_SIZE;
253
298
      # lets initialize to silence the warnings
254
299
      $box[$_] = 1 for 0..$#box;
255
300
   }
256
   my $bx    = $box[LOWLEFTX] - $box[LOWRIGHTX];
257
   my $by    = $box[LOWLEFTY] - $box[LOWRIGHTY];
258
301
259
   if($angle == 0 or $angle == 180 or $angle == 360) {
260
      $by  = $box[  UPLEFTY ] - $box[LOWLEFTY ];
261
   } elsif ($angle == 90 or $angle == 270) {
262
      $bx  = $box[  UPLEFTX ] - $box[LOWLEFTX ];
263
   } elsif($angle > 270 and $angle < 360) {
264
      $bx  = $box[ LOWLEFTX ] - $box[ UPLEFTX ];
265
   } elsif ($angle > 180 and $angle < 270) {
266
      $by  = $box[ LOWLEFTY ] - $box[LOWRIGHTY];
267
      $bx  = $box[ LOWRIGHTX] - $box[ UPRIGHTX];
268
   } elsif($angle > 90 and $angle < 180) {
269
      $bx  = $box[ LOWRIGHTX] - $box[ LOWLEFTX];
270
      $by  = $box[ LOWRIGHTY] - $box[ UPRIGHTY];
271
   } elsif ($angle > 0 and $angle < 90) {
272
      $by  = $box[  UPLEFTY ] - $box[ LOWLEFTY];
273
   } else {}
302
   return $self->_ttf_info_xy( $angle, \@box );
303
}
274
304
275
      if ($angle ==   0                 ) { $x += $bx/2; $y -= $by/2; }
276
   elsif ($angle >    0 and $angle < 90 ) { $x += $bx/2; $y -= $by/2; }
277
   elsif ($angle ==  90                 ) { $x -= $bx/2; $y += $by/2; }
278
   elsif ($angle >   90 and $angle < 180) { $x -= $bx/2; $y += $by/2; }
279
   elsif ($angle == 180                 ) { $x += $bx/2; $y -= $by/2; }
280
   elsif ($angle >  180 and $angle < 270) { $x += $bx/2; $y += $by/2; }
281
   elsif ($angle == 270                 ) { $x -= $bx/2; $y += $by/2; }
282
   elsif ($angle >  270 and $angle < 360) { $x += $bx/2; $y += $by/2; }
283
   elsif ($angle == 360                 ) { $x += $bx/2; $y -= $by/2; }
305
sub _ttf_info_xy {
306
   my($self, $angle, $box) = @_;
307
   my $rnone = ROTATE_NONE;
308
   my $rccw  = ROTATE_COUNTERCLOCKWISE;
309
   my $rusd  = ROTATE_UPSIDEDOWN;
310
   my $rcw   = ROTATE_CLOCKWISE;
311
   my $fc    = FULL_CIRCLE;
312
313
   my $x     = 0;
314
   my $y     = 0;
315
316
   my($bx, $by) = $self->_ttf_info_box_xy( $angle, $box );
317
318
     $angle == $rnone                   ? do { $x += $bx/2; $y -= $by/2; }
319
   : $angle >  $rnone && $angle < $rccw ? do { $x += $bx/2; $y -= $by/2; }
320
   : $angle == $rccw                    ? do { $x -= $bx/2; $y += $by/2; }
321
   : $angle >  $rccw  && $angle < $rusd ? do { $x -= $bx/2; $y += $by/2; }
322
   : $angle == $rusd                    ? do { $x += $bx/2; $y -= $by/2; }
323
   : $angle >  $rusd  && $angle < $rcw  ? do { $x += $bx/2; $y += $by/2; }
324
   : $angle == $rcw                     ? do { $x -= $bx/2; $y += $by/2; }
325
   : $angle >  $rcw   && $angle < $fc   ? do { $x += $bx/2; $y += $by/2; }
326
   : $angle == $fc                      ? do { $x += $bx/2; $y -= $by/2; }
327
   :                                      do {}
328
   ;
284
329
   return $x, $y;
285
330
}
286
331
287
sub setPixel        { shift->{image}->setPixel(@_)        }
288
sub line            { shift->{image}->line(@_)            }
289
sub rectangle       { shift->{image}->rectangle(@_)       }
290
sub filledRectangle { shift->{image}->filledRectangle(@_) }
291
sub ellipse         { shift->{image}->ellipse(@_)         }
292
sub arc             { shift->{image}->arc(@_)             }
332
sub _ttf_info_box_xy {
333
   my($self, $angle, $box) = @_;
334
   my $bx    = $box->[LOWLEFTX] - $box->[LOWRIGHTX];
335
   my $by    = $box->[LOWLEFTY] - $box->[LOWRIGHTY];
293
336
294
sub setThickness {
295
   my $self = shift;
296
   if($self->{image}->can('setThickness')) { # $GD::VERSION >= 2.07
297
      $self->{image}->setThickness(@_);
337
   my $rnone = ROTATE_NONE;
338
   my $rccw  = ROTATE_COUNTERCLOCKWISE;
339
   my $rusd  = ROTATE_UPSIDEDOWN;
340
   my $rcw   = ROTATE_CLOCKWISE;
341
   my $fc    = FULL_CIRCLE;
342
343
   my $is_perp = $angle == $rnone || $angle == $rusd || $angle == $fc;
344
345
     $is_perp                             ? do { $by = $box->[  UPLEFTY ] - $box->[LOWLEFTY ]; }
346
   : $angle == $rccw  || $angle == $rcw   ? do { $bx = $box->[  UPLEFTX ] - $box->[LOWLEFTX ]; }
347
   : $angle >  $rcw   && $angle <  $fc    ? do { $bx = $box->[ LOWLEFTX ] - $box->[ UPLEFTX ]; }
348
   : $angle >  $rusd  && $angle <  $rcw   ? do { $bx = $box->[ LOWRIGHTX] - $box->[ UPRIGHTX]; $by = $box->[ LOWLEFTY ] - $box->[LOWRIGHTY]; }
349
   : $angle >  $rccw  && $angle <  $rusd  ? do { $bx = $box->[ LOWRIGHTX] - $box->[ LOWLEFTX]; $by = $box->[ LOWRIGHTY] - $box->[ UPRIGHTY]; }
350
   : $angle >  $rnone && $angle <  $rccw  ? do { $by = $box->[  UPLEFTY ] - $box->[ LOWLEFTY]; }
351
   :                                        do {}
352
   ;
353
354
   return $bx, $by;
355
}
356
357
sub setPixel { ## no critic (NamingConventions::Capitalization)
358
   my($self, @args) = @_;
359
   return $self->{image}->setPixel(@args);
360
}
361
362
sub line {
363
   my($self, @args) = @_;
364
   return $self->{image}->line(@args);
365
}
366
367
sub rectangle {
368
   my($self, @args) = @_;
369
   return $self->{image}->rectangle(@args);
370
}
371
372
sub filledRectangle { ## no critic (NamingConventions::Capitalization)
373
   my($self, @args) = @_;
374
   return $self->{image}->filledRectangle(@args);
375
}
376
377
sub ellipse {
378
   my($self, @args) = @_;
379
   return $self->{image}->ellipse(@args);
380
}
381
382
sub arc {
383
   my($self, @args) = @_;
384
   return $self->{image}->arc(@args);
385
}
386
387
sub setThickness { ## no critic (NamingConventions::Capitalization)
388
   my($self, @args) = @_;
389
   if( $self->{image}->can('setThickness') ) { # $GD::VERSION >= 2.07
390
      $self->{image}->setThickness( @args );
298
391
   }
392
   return;
299
393
}
300
394
301
395
sub _versiongt {
@@ -362,18 +456,4 @@ Used internally by L<GD::SecurityImage>.
362
456
363
457
L<GD::SecurityImage>.
364
458
365
=head1 AUTHOR
366
367
Burak GE<252>rsoy, E<lt>burakE<64>cpan.orgE<gt>
368
369
=head1 COPYRIGHT
370
371
Copyright 2004-2008 Burak GE<252>rsoy. All rights reserved.
372
373
=head1 LICENSE
374
375
This library is free software; you can redistribute it and/or modify 
376
it under the same terms as Perl itself, either Perl version 5.8.8 or, 
377
at your option, any later version of Perl 5 you may have available.
378
379
459
=cut

Up to file-list lib/GD/SecurityImage/Magick.pm:

1
1
package GD::SecurityImage::Magick;
2
2
# GD method emulation class for Image::Magick
3
3
use strict;
4
use warnings;
4
5
use vars qw($VERSION);
5
6
# Magick related
6
7
use constant XPPEM        => 0; # character width 
@@ -15,15 +16,16 @@ use constant ANGLE => -2;
15
16
use constant CHAR         => -1;
16
17
# image data
17
18
use constant MAX_COMPRESS => 100;
19
use constant FULL_CIRCLE  => 360;
18
20
19
21
use Image::Magick;
20
22
21
$VERSION = '1.38';
23
$VERSION = '1.71';
22
24
23
25
sub init {
24
26
   # Create the image object
25
27
   my $self        = shift;
26
   my $bg          = $self->cconvert( $self->{bgcolor} ); 
28
   my $bg          = $self->cconvert( $self->{bgcolor} );
27
29
   $self->{image}  = Image::Magick->new;
28
30
   $self->{image}->Set(  size=> "$self->{width}x$self->{height}" );
29
31
   $self->{image}->Read( 'null:' . $bg );
@@ -34,15 +36,15 @@ sub init {
34
36
}
35
37
36
38
sub out {
37
   my $self = shift;
38
   my %opt  = scalar @_ % 2 ? () : (@_);
39
   my($self, @args) = @_;
40
   my %opt  = @args % 2 ? () : @args;
39
41
   my $type = 'gif'; # default format
40
42
   if ($opt{force}) {
41
      my %g = map { $_, 1 } $self->{image}->QueryFormat;
43
      my %g = map { $_ => 1 } $self->{image}->QueryFormat;
42
44
      $type = $opt{force} if exists $g{$opt{force}};
43
45
   }
44
46
   $self->{image}->Set( magick => $type );
45
   if ( $opt{'compress'} && $type =~ m[^(png|jpeg)$] ) {
47
   if ( $opt{'compress'} && ( $type eq 'png' || $type eq 'jpeg' ) ) {
46
48
      if($type eq 'png') {
47
49
         $opt{'compress'} = MAX_COMPRESS;
48
50
         $self->{image}->Set( compression => 'Zip' );
@@ -72,12 +74,14 @@ sub insert_text {
72
74
   );
73
75
74
76
   if ($self->{scramble}) {
75
      my $space = [$info->(' '), 0, ' ']; # get " " parameters
77
      my $space = [$info->(q{ }), 0, q{ }]; # get " " parameters
76
78
      my @randomy;
77
79
      my $sy    = $space->[ASCENDER] || 1;
78
      push(@randomy,  $_, - $_) foreach $sy/2, $sy/4, $sy/8;
80
      ## no critic (ValuesAndExpressions::ProhibitMagicNumbers)
81
      push @randomy,  $_, - $_ foreach $sy/2, $sy/4, $sy/8;
82
      ## use critic
79
83
      my @char;
80
      foreach ( split //, $key ) {
84
      foreach ( split m{}xms, $key ) {
81
85
         push @char, [$info->($_), $self->random_angle, $_], $space, $space, $space;
82
86
      }
83
87
      my $total = 0;
@@ -99,7 +103,7 @@ sub insert_text {
99
103
      my $tl = $self->{_TEXT_LOCATION_};
100
104
      if ($tl->{_place_}) {
101
105
         # put the text to one of the four corners in the image
102
         $x = $tl->{x} eq 'left' ? 2                   : $self->{width}-$metric[WIDTH]-2;
106
         $x = $tl->{x} eq 'left' ? 2                   : $self->{width}-$metric[WIDTH] - 2;
103
107
         $y = $tl->{y} eq 'up'   ? $metric[ASCENDER]+1 : $self->{height}-2;
104
108
         $self->add_strip($x, $y, $metric[WIDTH], $metric[ASCENDER]) if $tl->{strip};
105
109
      }
@@ -108,27 +112,25 @@ sub insert_text {
108
112
         $y = ($self->{height} + $metric[ASCENDER]) / 2;
109
113
      }
110
114
      $self->{image}->Annotate(
111
         text   => $key, 
112
         x      => $x, 
115
         text   => $key,
116
         x      => $x,
113
117
         y      => $y,
114
         rotate => $self->{angle} ? 360 - $self->{angle} : 0,
118
         rotate => $self->{angle} ? FULL_CIRCLE - $self->{angle} : 0,
115
119
         %same,
116
120
      );
117
121
   }
118
122
   return;
119
123
}
120
124
121
sub setPixel {
122
   my $self = shift;
123
   my($x, $y, $color) = @_;
124
   $self->{image}->Set( "pixel[$x,$y]" => $self->cconvert($color) );
125
sub setPixel { ## no critic (NamingConventions::Capitalization)
126
   my($self, $x, $y, $color) = @_;
127
   return $self->{image}->Set( "pixel[$x,$y]" => $self->cconvert($color) );
125
128
}
126
129
127
130
sub line {
128
   my $self = shift;
129
   my($x1, $y1, $x2, $y2, $color) = @_;
130
   $self->{image}->Draw(
131
      primitive   => "line",
131
   my($self, $x1, $y1, $x2, $y2, $color) = @_;
132
   return $self->{image}->Draw(
133
      primitive   => 'line',
132
134
      points      => "$x1,$y1 $x2,$y2",
133
135
      stroke      => $self->cconvert($color),
134
136
      strokewidth => $self->{MAGICK}{strokewidth},
@@ -136,10 +138,9 @@ sub line {
136
138
}
137
139
138
140
sub rectangle {
139
   my $self = shift;
140
   my($x1,$y1,$x2,$y2,$color) = @_;
141
   $self->{image}->Draw(
142
      primitive   => "rectangle",
141
   my($self, $x1,$y1,$x2,$y2,$color) = @_;
142
   return $self->{image}->Draw(
143
      primitive   => 'rectangle',
143
144
      points      => "$x1,$y1 $x2,$y2",
144
145
      stroke      => $self->cconvert($color),
145
146
      strokewidth => $self->{MAGICK}{strokewidth},
@@ -147,11 +148,10 @@ sub rectangle {
147
148
   );
148
149
}
149
150
150
sub filledRectangle {
151
   my $self = shift;
152
   my($x1,$y1,$x2,$y2,$color) = @_;
153
   $self->{image}->Draw(
154
      primitive   => "rectangle",
151
sub filledRectangle { ## no critic (NamingConventions::Capitalization)
152
   my($self, $x1, $y1, $x2, $y2, $color) = @_;
153
   return $self->{image}->Draw(
154
      primitive   => 'rectangle',
155
155
      points      => "$x1,$y1 $x2,$y2",
156
156
      fill        => $self->cconvert($color),
157
157
      stroke      => $self->cconvert($color),
@@ -160,10 +160,9 @@ sub filledRectangle {
160
160
}
161
161
162
162
sub ellipse {
163
   my $self = shift;
164
   my($cx,$cy,$width,$height,$color) = @_;
165
   $self->{image}->Draw(
166
      primitive   => "ellipse",
163
   my($self, $cx, $cy, $width, $height, $color) = @_;
164
   return $self->{image}->Draw(
165
      primitive   => 'ellipse',
167
166
      points      => "$cx,$cy $width,$height 0,360",
168
167
      stroke      => $self->cconvert($color),
169
168
      strokewidth => $self->{MAGICK}{strokewidth},
@@ -172,12 +171,11 @@ sub ellipse {
172
171
}
173
172
174
173
sub arc {
175
   my $self = shift;
176
   my($cx,$cy,$width,$height,$start,$end,$color) = @_;
174
   my($self, $cx, $cy, $width, $height, $start, $end, $color) = @_;
177
175
   # I couldn't do that with "arc" primitive. 
178
176
   # Patches are welcome, but this seems to work :)
179
   $self->{image}->Draw(
180
      primitive   => "ellipse",
177
   return $self->{image}->Draw(
178
      primitive   => 'ellipse',
181
179
      points      => "$cx,$cy $width,$height $start,$end",
182
180
      stroke      => $self->cconvert($color),
183
181
      strokewidth => $self->{MAGICK}{strokewidth},
@@ -185,7 +183,7 @@ sub arc {
185
183
   );
186
184
}
187
185
188
sub setThickness {
186
sub setThickness { ## no critic (NamingConventions::Capitalization)
189
187
   my $self = shift;
190
188
   my $thickness = shift || return;
191
189
   $self->{MAGICK}{strokewidth} *= $thickness;
@@ -211,8 +209,8 @@ sub _versionlt {
211
209
sub _tovstr {
212
210
   my $self  = shift;
213
211
   my $thing = shift || return '0.0.0';
214
   my @j     = split /\./, $thing;
215
   my $rv    = join '.',
212
   my @j     = split m{[.]}xms, $thing;
213
   my $rv    = join q{.},
216
214
                    shift(@j) || 0,
217
215
                    shift(@j) || 0,
218
216
                    shift(@j) || 0,
@@ -220,6 +218,8 @@ sub _tovstr {
220
218
   return $rv;
221
219
}
222
220
221
sub gdbox_empty { return 0 }
222
223
223
1;
224
224
225
225
__END__
@@ -260,22 +260,10 @@ Used internally by L<GD::SecurityImage>.
260
260
261
261
=head2 setThickness
262
262
263
=head2 gdbox_empty
264
263
265
=head1 SEE ALSO
264
266
265
267
L<GD::SecurityImage>.
266
268
267
=head1 AUTHOR
268
269
Burak GE<252>rsoy, E<lt>burakE<64>cpan.orgE<gt>
270
271
=head1 COPYRIGHT
272
273
Copyright 2004-2008 Burak GE<252>rsoy. All rights reserved.
274
275
=head1 LICENSE
276
277
This library is free software; you can redistribute it and/or modify 
278
it under the same terms as Perl itself, either Perl version 5.8.8 or, 
279
at your option, any later version of Perl 5 you may have available.
280
281
269
=cut

Up to file-list lib/GD/SecurityImage/Styles.pm:

1
1
package GD::SecurityImage::Styles;
2
2
use strict;
3
use warnings;
3
4
use vars qw[$VERSION];
5
use constant ARC_END_DEGREES => 360;
4
6
5
$VERSION = '1.21';
7
$VERSION = '1.71';
6
8
7
9
sub style_default {
8
   $_[0]->_drcommon(" \ lines will be drawn ");
10
   return shift->_drcommon(' \\ lines will be drawn ');
9
11
}
10
12
11
13
sub style_rect {
12
   $_[0]->_drcommon;
14
   return shift->_drcommon;
13
15
}
14
16
15
17
sub style_box {
@@ -21,6 +23,7 @@ sub style_box {
21
23
   my $h    = $self->{height};
22
24
   $self->filledRectangle(  0,  0, $w         , $h         , $ct );
23
25
   $self->filledRectangle( $n, $n, $w - $n - 1, $h - $n - 1, $cl );
26
   return;
24
27
}
25
28
26
29
sub style_circle {
@@ -32,11 +35,11 @@ sub style_circle {
32
35
   my $max   = int $self->{width} / $n;
33
36
      $max++;
34
37
35
   my( $i, $mi );
36
   for $i ( 1..$n ) {
37
      $mi = $max * $i;
38
      $self->arc( $cx, $cy, $mi, $mi, 0, 360, $cl );
38
   for my $i ( 1..$n ) {
39
      my $mi = $max * $i;
40
      $self->arc( $cx, $cy, $mi, $mi, 0, ARC_END_DEGREES, $cl );
39
41
   }
42
   return;
40
43
}
41
44
42
45
sub style_ellipse {
@@ -49,17 +52,18 @@ sub style_ellipse {
49
52
   my $max   = int $self->{width} / $n;
50
53
      $max++;
51
54
52
   my( $i, $mi );
53
   for $i ( 1..$n ) {
54
      $mi = $max * $i;
55
   for my $i ( 1..$n ) {
56
      my $mi = $max * $i;
55
57
      $self->ellipse( $cx, $cy, $mi * 2, $mi, $cl );
56
58
   }
59
   return;
57
60
}
58
61
59
62
sub style_ec {
60
   my $self = shift;
61
      $self->style_ellipse(@_) if not $self->{DISABLED}{ellipse}; # GD < 2.07
62
      $self->style_circle(@_);
63
   my($self, @args) = @_;
64
   $self->style_ellipse(@args) if ! $self->{DISABLED}{ellipse}; # GD < 2.07
65
   $self->style_circle(@args);
66
   return;
63
67
}
64
68
65
69
sub style_blank {}
@@ -87,6 +91,7 @@ sub _drcommon {
87
91
      $ify = $i * $fy;
88
92
      $self->line( 0, $ify, $w, $ify, $cl ); # - line
89
93
   }
94
   return;
90
95
}
91
96
92
97
1;
@@ -127,18 +132,4 @@ Used internally by L<GD::SecurityImage>.
127
132
128
133
L<GD::SecurityImage>.
129
134
130
=head1 AUTHOR
131
132
Burak GE<252>rsoy, E<lt>burakE<64>cpan.orgE<gt>
133
134
=head1 COPYRIGHT
135
136
Copyright 2004-2008 Burak GE<252>rsoy. All rights reserved.
137
138
=head1 LICENSE
139
140
This library is free software; you can redistribute it and/or modify 
141
it under the same terms as Perl itself, either Perl version 5.8.8 or, 
142
at your option, any later version of Perl 5 you may have available.
143
144
135
=cut

Up to file-list t/03-info_text.t:

1
1
#!/usr/bin/env perl -w
2
2
use strict;
3
use Test;
3
use warnings;
4
use Test::More qw(no_plan);
4
5
use Cwd;
5
6
use GD::SecurityImage;
6
7
7
plan tests => 1;
8
9
8
my $i      = GD::SecurityImage->new->random;
10
9
my $random = $i->random_str;
11
10
$i->create;
@@ -19,4 +18,4 @@ my $random = $i->random_str;
19
18
20
19
my( $image, $mime, $random2 ) = $i->out;
21
20
22
ok( $random eq $random2 ); # info_text must not affect random string
21
ok( $random eq $random2, 'info_text must not affect random string' );

Up to file-list t/04-backend.t:

1
1
#!/usr/bin/env perl -w
2
2
use strict;
3
use warnings;
3
4
use vars qw( $MAGICK_SKIP );
4
use Test;
5
use Test::More;
5
6
use Cwd;
7
use Carp qw( croak );
8
use lib  qw( .. );
6
9
7
10
BEGIN {
8
   do 't/magick.pl' || die "Can not include t/magick.pl: $!";
11
   do 't/magick.pl' || croak "Can not include t/magick.pl: $!";
9
12
10
13
   my %total = (
11
14
      magick => 2,
@@ -15,29 +18,32 @@ BEGIN {
15
18
16
19
   my $total  = 0;
17
20
      $total += $total{$_} foreach keys %total;
18
   my $class = 'GD::SecurityImage';
21
   my $class  = 'GD::SecurityImage';
19
22
20
23
   plan tests => $total;
21
24
22
25
   require GD::SecurityImage;
23
26
24
   eval { $class->new };
25
   ok($@); # if there is an error == OK [since we didn't import() so far]
27
   my $eok = eval { $class->new };
28
   ok( $@, q{If there is an error == OK [since we didn't import() so far]} );
26
29
27
30
   # test if we've loaded the right library
28
   gd();
29
   $MAGICK_SKIP ? skip_magick() : magick();
30
   exit;
31
   GD_TEST: {
32
      $class->import( use_magick => 0 );
33
      ok( $class->new->raw->isa('GD::Image' ), 'Loaded GD [1]' );
34
      $class->import( backend => 'GD' );
35
      ok( $class->new->raw->isa('GD::Image' ), 'Loaded GD [2]' );
36
   }
31
37
32
   sub gd {
33
      $class->import( use_magick => 0        ); ok( $class->new->raw->isa('GD::Image'    ) );
34
      $class->import( backend    => 'GD'     ); ok( $class->new->raw->isa('GD::Image'    ) );
35
   }
36
   sub magick {
37
      $class->import( use_magick => 1        ); ok( $class->new->raw->isa('Image::Magick') );
38
      $class->import( backend    => 'Magick' ); ok( $class->new->raw->isa('Image::Magick') );
39
   }
40
   sub skip_magick {
41
      skip( $MAGICK_SKIP . " Skipping...", sub{1}) for 1..$total{magick};
42
   }
38
   $MAGICK_SKIP
39
   ?  do {
40
         skip( $MAGICK_SKIP . ' Skipping...', sub{1}) for 1..$total{magick};
41
      }
42
   : do {
43
         $class->import( use_magick => 1        );
44
         ok( $class->new->raw->isa('Image::Magick'), 'Loaded Magick [1]' );
45
         $class->import( backend    => 'Magick' );
46
         ok( $class->new->raw->isa('Image::Magick'), 'Loaded Magick [2]' );
47
      }
48
   ;
43
49
}

Up to file-list t/05-version.t:

1
1
#!/usr/bin/env perl -w
2
2
use strict;
3
use Test;
3
use warnings;
4
use Test::More;
4
5
use Cwd;
5
6
use GD::SecurityImage;
6
7
@@ -8,14 +9,14 @@ plan tests => 5;
8
9
9
10
my $i = GD::SecurityImage->new;
10
11
11
my $gt = $i->_versiongt(2.0);
12
my $lt = $i->_versionlt(3.0);
13
ok( defined $gt );
14
ok( defined $lt );
12
my $gt = $i->_versiongt('2.0');
13
my $lt = $i->_versionlt('3.0');
14
ok( defined $gt, 'GT defined' );
15
ok( defined $lt, 'LT defined' );
15
16
16
17
GT: {
17
18
   local $GD::VERSION = '1.19';
18
   ok( $i->_versiongt(1.18) );
19
   ok( $i->_versiongt(1.19) ); # ok. _versiongt() if greater or equal to 
20
   ok( $i->_versionlt(3.0)  ); # but this means "smaller than"
19
   ok( $i->_versiongt('1.18'), 'GT 1.18' );
20
   ok( $i->_versiongt('1.19'), 'ok. _versiongt() if greater or equal to 1.19' );
21
   ok( $i->_versionlt('3.0' ), 'but this means "smaller than"' );
21
22
}

Up to file-list t/06-version_magick.t:

1
1
#!/usr/bin/env perl -w
2
2
use strict;
3
use warnings;
3
4
use vars qw( $MAGICK_SKIP );
4
use Test;
5
use Test::More;
5
6
use Cwd;
7
use Carp qw( croak );
8
use lib  qw( .. );
9
use constant TOTAL_TESTS => 6;
6
10
7
11
BEGIN {
8
   do 't/magick.pl' || die "Can not include t/magick.pl: $!";
12
   do 't/magick.pl' || croak "Can not include t/magick.pl: $!";
9
13
10
   my $TOTAL = 6;
11
   plan tests => $TOTAL;
14
   plan tests => TOTAL_TESTS;
12
15
13
16
   if ( $MAGICK_SKIP ) {
14
      skip( $MAGICK_SKIP . " Skipping...", sub{1}) for 1..$TOTAL;
17
      skip( $MAGICK_SKIP . ' Skipping...', sub{1}) for 1..TOTAL_TESTS;
15
18
      exit;
16
19
   }
17
20
   else {
@@ -22,15 +25,15 @@ BEGIN {
22
25
23
26
my $i = GD::SecurityImage->new;
24
27
25
my $gt = $i->_versiongt(6.0);
28
my $gt = $i->_versiongt('6.0');
26
29
my $lt = $i->_versionlt('6.4.3');
27
ok( defined $gt );
28
ok( defined $lt );
30
ok( defined $gt, 'GT defined' );
31
ok( defined $lt, 'LT defined' );
29
32
30
33
GT: {
31
34
   local $Image::Magick::VERSION = '6.0.3';
32
   ok( $i->_versiongt(  6.0    ) );
33
   ok( $i->_versiongt( '6.0.3' ) );
34
   ok( $i->_versionlt(  6.2    ) );
35
   ok( $i->_versionlt( '6.2.6' ) );
35
   ok( $i->_versiongt( '6.0'   ), 'GT 6.0'   );
36
   ok( $i->_versiongt( '6.0.3' ), 'GT 6.0.3' );
37
   ok( $i->_versionlt( '6.2'   ), 'LT 6.2'   );
38
   ok( $i->_versionlt( '6.2.6' ), 'LT 6.2.6' );
36
39
}

Up to file-list t/98-gd.t:

1
1
#!/usr/bin/env perl -w
2
2
use strict;
3
use warnings;
3
4
use vars qw( %API );
4
use Test;
5
use Test::More;
5
6
use Cwd;
7
use Carp qw(croak);
8
use lib qw(
9
   ..
10
   ../t/lib
11
      t/lib
12
);
6
13
7
14
BEGIN {
8
15
   %API = (
@@ -24,8 +31,9 @@ BEGIN {
24
31
   import  GD::SecurityImage;
25
32
}
26
33
27
require 't/t.api';
28
my $tapi = 'tapi';
34
use Test::GDSI;
35
36
my $tapi = 'Test::GDSI';
29
37
   $tapi->clear;
30
38
31
39
my $font = getcwd.'/StayPuft.ttf';
@@ -50,7 +58,8 @@ foreach my $api (keys %API) {
50
58
            $style,
51
59
            $api,
52
60
            $c++
53
         )
61
         ),
62
         "$style - $api - $c++"
54
63
      );
55
64
   }
56
65
   $tapi->clear;
@@ -118,6 +127,6 @@ sub args {
118
127
     (my $tmp = $name) =~ s{ _info_text }{}xms;
119
128
      $o = $options{$tmp};
120
129
   }
121
   die "Bogus arg name $name!" if not $o;
130
   croak "Bogus arg name $name!" if not $o;
122
131
   return %{$o}
123
132
}

Up to file-list t/99-magick.t:

1
1
#!/usr/bin/env perl -w
2
2
use strict;
3
use warnings;
3
4
use vars qw( %API $MAGICK_SKIP );
4
use Test;
5
use Test::More;
5
6
use Cwd;
7
use Carp qw(croak);
8
use lib qw(
9
   ..
10
   ../t/lib
11
      t/lib
12
);
6
13
7
14
BEGIN {
8
   do 't/magick.pl' || die "Can not include t/magick.pl: $!";
15
   do 't/magick.pl' || croak "Can not include t/magick.pl: $!";
9
16
10
17
   %API = (
11
18
      magick                          => 6,
@@ -22,7 +29,7 @@ BEGIN {
22
29
   plan tests => $total;
23
30
24
31
   if ( $MAGICK_SKIP ) {
25
      skip( $MAGICK_SKIP . " Skipping...", sub{1}) for 1..$total;
32
      skip( $MAGICK_SKIP . ' Skipping...', sub{1}) for 1..$total;
26
33
      exit;
27
34
   }
28
35
   else {
@@ -31,8 +38,9 @@ BEGIN {
31
38
   }
32
39
}
33
40
34
require 't/t.api';
35
my $tapi = 'tapi';
41
use Test::GDSI;
42
43
my $tapi = 'Test::GDSI';
36
44
   $tapi->clear;
37
45
38
46
my $font = getcwd.'/StayPuft.ttf';
@@ -57,7 +65,8 @@ foreach my $api (keys %API) {
57
65
            $style,
58
66
            $api,
59
67
            $c++
60
         )
68
         ),
69
         "$style - $api - $c++"
61
70
      );
62
71
   }
63
72
   $tapi->clear;
@@ -104,6 +113,6 @@ sub args {
104
113
     (my $tmp = $name) =~ s{ _info_text }{}xms;
105
114
      $o = $options{$tmp};
106
115
   }
107
   die "Bogus arg name $name!" if not $o;
116
   croak "Bogus arg name $name!" if not $o;
108
117
   return %{ $o }
109
118
}

Up to file-list t/lib/Test/GDSI.pm:

1
## no critic (NamingConventions::Capitalization, ValuesAndExpressions::ProhibitMagicNumbers)
2
package Test::GDSI;
3
use strict;
4
use warnings;
5
use vars qw( $VERSION );
6
7
$VERSION = '0.40';
8
9
use constant GD      => defined($GD::VERSION)            ? $GD::VERSION            : 0;
10
use constant MAGICK  => defined($Image::Magick::VERSION) ? $Image::Magick::VERSION : '0.0.0';
11
use constant PROBLEM => GD && GD < 2.07 ? 1 : 0;
12
use Carp qw(croak);
13
14
my(%options, %info_text);
15
16
sub the_info_text { return 'GD::SecurityImage' }
17
18
sub GD::SecurityImage::CIT { # __check_info_text
19
    my $self = shift;
20
    $self->info_text( %info_text ) if %info_text;
21
    return $self;
22
}
23
24
sub styles {
25
    return qw( default rect box circle ellipse ec );
26
}
27
28
sub options {
29
    my($class, @args) = @_;
30
    %options = @args if @args;
31
    if ( $options{info_text} ) {
32
        %info_text = %{ delete $options{info_text} };
33
    }
34
    return %options;
35
}
36
37
sub has_method {
38
    my $self = shift;
39
    my $name = shift || q{};
40
    if ( PROBLEM && ($name eq 'ellipse' or $name eq 'ec') ) {
41
        return 'circle';
42
    }
43
    return $name;
44
}
45
46
sub clear {
47
    %options   = ();
48
    %info_text = ();
49
    return;
50
}
51
52
sub set_options {
53
    my($class, @args) = @_;
54
    my %o = @args % 2 ? () : @args;
55
    foreach ( keys %o ) {
56
        next if $_ eq 'thickness' && PROBLEM;
57
        $options{$_} = $o{$_};
58
    }
59
    return $class;
60
}
61
62
sub random {
63
    return {
64
        ec      => 'EC0123',
65
        ellipse => 'ELLIPS',
66
        circle  => 'CIRCLE',
67
        box     => 'BOX012',
68
        rect    => 'RECT01',
69
        default => 'DFAULT',
70
    }
71
}
72
73
sub save {
74
    my($class, $image, $mime, $random, $style, $ID, $counter) = @_;
75
    my $name = sprintf '%s_%02d_%s.%s', $ID, $counter, $style, $mime;
76
    require IO::File;
77
    my $SI = IO::File->new;
78
    $SI->open( $name, '>' ) or croak "Error writing the image '$name' to disk: $!";
79
    binmode $SI;
80
    print {$SI} $image or croak "Unable to print to $name";
81
    close $SI or croak "Unable to close $name";
82
    print  "[OK] $name\n" or croak 'Unable to print to STDOUT';
83
    return 'SUCCESS';
84
}
85
86
package gd_normal;
87
88
sub ec {
89
    return GD::SecurityImage
90
            ->new(
91
                lines   => 5,
92
                bgcolor => [0,0,0],
93
                Test::GDSI->options,
94
            )
95
            ->random( Test::GDSI->random->{ec} )
96
            ->create( qw( normal ec ), [84, 207, 112], [0,0,0] )
97
            ->particle( 100 )
98
            ->CIT
99
}
100
101
sub ellipse {
102
    return GD::SecurityImage
103
            ->new(lines => 10, bgcolor => [208, 202, 206], Test::GDSI->options)
104
            ->random(Test::GDSI->random->{ellipse})
105
            ->create(normal => Test::GDSI->has_method('ellipse'), [31,219,180], [231,219,180])
106
            ->particle(100)->CIT
107
}
108
109
sub circle {
110
    return GD::SecurityImage
111
            ->new(lines => 5, bgcolor => [210, 215, 196], Test::GDSI->options)
112
            ->random(Test::GDSI->random->{circle})
113
            ->create(normal => 'circle', [63, 143, 167], [90, 195, 176])
114
            ->particle(250, 2)->CIT
115
}
116
117
sub box {
118
    return GD::SecurityImage
119
            ->new(lines => 5, Test::GDSI->options)
120
            ->random(Test::GDSI->random->{box})
121
            ->create(normal => 'box', [63, 143, 167], [226, 223, 169])
122
            ->particle(150, 4)->CIT
123
}
124
125
sub rect {
126
    return GD::SecurityImage
127
            ->new(lines => 10, Test::GDSI->options)
128
            ->random(Test::GDSI->random->{rect})
129
            ->create(normal => 'rect', [63, 143, 167], [226, 223, 169])
130
            ->particle(100)->CIT
131
}
132
133
sub default { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
134
    return GD::SecurityImage
135
            ->new(lines => 10, Test::GDSI->options, send_ctobg => 0)
136
            ->random(Test::GDSI->random->{default})
137
            ->create(normal => 'default', [68,150,125], [255,0,0])
138
            ->particle(500)->CIT
139
}
140
141
package gd_ttf;
142
143
sub ec {
144
    return GD::SecurityImage
145
            ->new(lines => 16, bgcolor => [0,0,0], Test::GDSI->set_options(thickness => 1)->options)
146
            ->random(Test::GDSI->random->{ec})
147
            ->create(ttf => 'ec', [84, 207, 112], [0,0,0])
148
            ->particle(1000)->CIT
149
}
150
151
sub ellipse {
152
    return GD::SecurityImage
153
            ->new(lines => 15, bgcolor => [208, 202, 206], Test::GDSI->set_options(thickness => 2)->options)
154
            ->random(Test::GDSI->random->{ellipse})
155
            ->create(ttf => Test::GDSI->has_method('ellipse'), [184,20,180], [184,20,180])
156
            ->particle(2000)->CIT
157
}
158
159
sub circle {
160
    return GD::SecurityImage
161
            ->new(lines => 50, bgcolor => [210, 215, 196],Test::GDSI->set_options(thickness => 1)->options)
162
            ->random(Test::GDSI->random->{circle})
163
            ->create(ttf => 'circle', [63, 143, 167], [210, 215, 196])
164
            ->particle(3500)->CIT
165
}
166
167
sub box {
168
    return GD::SecurityImage
169
            ->new(lines => 6, Test::GDSI->set_options(thickness => 1)->options, frame => 0)
170
            ->random(Test::GDSI->random->{box})
171
            ->create(ttf => 'box', [245,240,220], [115, 115, 115])
172
            ->particle(3000, 2)->CIT
173
}
174
175
sub rect {
176
    return GD::SecurityImage
177
            ->new(lines => 30, Test::GDSI->set_options(thickness => 1)->options)
178
            ->random(Test::GDSI->random->{rect})
179
            ->create(ttf => 'rect', [63, 143, 167], [226, 223, 169])
180
            ->particle(2000)->CIT
181
}
182
183
sub default { ## no critic (ProhibitBuiltinHomonyms)
184
    return GD::SecurityImage
185
            ->new(lines => 10, Test::GDSI->set_options(thickness => 2)->options)
186
            ->random(Test::GDSI->random->{default})
187
            ->create(ttf => 'default', [68,150,125], [255,0,0])
188
            ->particle(5000)->CIT
189
}
190
191
package gd_normal_scramble;              use base qw(gd_normal);
192
package gd_ttf_scramble;                 use base qw(gd_ttf);
193
package gd_ttf_scramble_fixed;           use base qw(gd_ttf);
194
package gd_normal_info_text;             use base qw(gd_normal);
195
package gd_ttf_info_text;                use base qw(gd_ttf);
196
package gd_normal_scramble_info_text;    use base qw(gd_normal);
197
package gd_ttf_scramble_info_text;       use base qw(gd_ttf);
198
package gd_ttf_scramble_fixed_info_text; use base qw(gd_ttf);
199
200
package magick;                          use base qw(gd_ttf);
201
package magick_scramble;                 use base qw(gd_ttf);
202
package magick_scramble_fixed;           use base qw(gd_ttf);
203
package magick_info_text;                use base qw(gd_ttf);
204
package magick_scramble_info_text;       use base qw(gd_ttf);
205
package magick_scramble_fixed_info_text; use base qw(gd_ttf);
206
207
1;
208
209
__END__

Up to file-list t/magick.pl:

1
1
use strict;
2
use vars qw($MAGICK_SKIP);
2
use warnings;
3
use vars qw( $MAGICK_SKIP );
4
3
5
BEGIN {
4
   eval "require Image::Magick;";
5
   if ( $@ ) {
6
      $MAGICK_SKIP  = "You don't have Image::Magick installed.";
7
      $MAGICK_SKIP .= " $@";
6
   my $eok = eval {
7
      require Image::Magick;
8
      1;
9
   };
10
   if ( $@ || ! $eok ) {
11
      $MAGICK_SKIP  = "You don't have Image::Magick installed. $@";
8
12
   }
9
13
   elsif ( $Image::Magick::VERSION lt '6.0.4') {
10
      $MAGICK_SKIP = "There may be a bug in your PerlMagick version's "
14
      $MAGICK_SKIP = q{There may be a bug in your PerlMagick version's }
11
15
                   . "($Image::Magick::VERSION) QueryFontMetrics() method. "
12
                   . "Please upgrade to 6.0.4 or newer.";
16
                   . q{Please upgrade to 6.0.4 or newer.};
13
17
   }
14
18
   else {
15
      $MAGICK_SKIP = '';
19
      $MAGICK_SKIP = q{};
16
20
   }
17
21
}
18
22