File Coverage

blib/lib/CGI/Uploader/Transform/ImageMagick.pm
Criterion Covered Total %
statement 15 66 22.7
branch 0 30 0.0
condition 0 11 0.0
subroutine 5 10 50.0
pod 1 1 100.0
total 21 118 17.8


line stmt bran cond sub pod time code
1             package CGI::Uploader::Transform::ImageMagick;
2              
3 1     1   1113 use base 'Exporter';
  1         3  
  1         125  
4 1     1   6 use File::Temp 'tempfile';
  1         2  
  1         50  
5 1     1   6 use Params::Validate ':all';
  1         2  
  1         230  
6 1     1   6 use Carp::Assert;
  1         2  
  1         12  
7              
8             our $VERSION = 2.18;
9             our @EXPORT = qw(&gen_thumb);
10              
11             =head2 gen_thumb()
12              
13             use CGI::Uploader::Transform::ImageMagick;
14              
15             As a class method:
16              
17             ($thumb_tmp_filename) = CGI::Uploader::Transform::ImageMagick->gen_thumb({
18             filename => $orig_filename,
19             w => $width,
20             h => $height
21             });
22              
23             Within a CGI::Uploader C:
24              
25             gen_files => {
26             my_thumb => gen_thumb({ w => $width, h => $height }),
27             }
28              
29             Looking for a different syntax? See L
30              
31             This function creates a copy of given image file and resizes the copy to the
32             provided width and height.
33              
34             C can be called as object or class method. As a class method,
35             there there is no need to call C before calling this method.
36              
37             L is used as the first choice image service module.
38             L is tried next.
39              
40             Input:
41              
42             filename - filename of source image
43             w - max width of thumbnail
44             h - max height of thumbnail
45              
46             One or both of C or C is required.
47              
48             Output:
49             - filename of generated tmp file for the thumbnail
50             - the initialized image generation object. (You generally shouldn't need this)
51              
52             =cut
53              
54             sub gen_thumb {
55             # If the first arg is an object, we have really work to do right now
56 0     0 1   my $first_arg = $_[0];
57 1     1   214 use Scalar::Util (qw/blessed/);
  1         3  
  1         917  
58 0 0 0       if ((blessed $first_arg) or (eval {$first_arg->can('gen_thumb')})) {
  0            
59 0           return _really_gen_thumb(@_);
60             }
61             # Otherwise, just generate a closure pass back a code ref for later use
62             else {
63             # require a single hashref as input
64 0           my ($args_href) = validate_pos(@_, { type => HASHREF });
65             return sub {
66 0     0     my $self = shift;
67 0           my $filename = shift;
68 0           _really_gen_thumb($self, {
69             filename => $filename,
70             %$args_href,
71             });
72             }
73 0           }
74             }
75              
76             sub _really_gen_thumb {
77 0   0 0     my $self = shift || die "gen_thumb needs object";
78 0           my (%p,$orig_filename,$params);
79             # If we have the new hashref API
80 0 0         if (ref $_[0] eq 'HASH') {
81 0           %p = validate(@_,{
82             filename => { type => SCALAR },
83             w => { type => SCALAR | UNDEF, regex => qr/^\d*$/, optional => 1, },
84             h => { type => SCALAR | UNDEF, regex => qr/^\d*$/, optional => 1 },
85             });
86 0           $orig_filename = $p{filename};
87             }
88             # we have the old ugly style API
89             else {
90 0           ($orig_filename, $params) = validate_pos(@_,1,{ type => ARRAYREF });
91             # validate handles a hash or hashref transparently
92 0           %p = validate(@$params,{
93             w => { type => SCALAR | UNDEF, regex => qr/^\d*$/, optional => 1, },
94             h => { type => SCALAR | UNDEF, regex => qr/^\d*$/, optional => 1 },
95             });
96             }
97 0 0 0       die "must supply 'w' or 'h'" unless (defined $p{w} or defined $p{h});
98              
99             # Having both Graphics::Magick and Image::Magick loaded at the same time
100             # can cause very strange problems, so we take care to avoid that
101             # First see if we have already loaded Graphics::Magick or Image::Magick
102             # If so, just use whichever one is already loaded.
103 0           my $magick_module;
104 0 0         if (exists $INC{'Graphics/Magick.pm'}) {
    0          
    0          
    0          
105 0           $magick_module = 'Graphics::Magick';
106             }
107             elsif (exists $INC{'Image/Magick.pm'}) {
108 0           $magick_module = 'Image::Magick';
109             }
110              
111             # If neither are already loaded, try loading either one.
112             elsif ( _load_magick_module('Graphics::Magick') ) {
113 0           $magick_module = 'Graphics::Magick';
114             }
115             elsif ( _load_magick_module('Image::Magick') ) {
116 0           $magick_module = 'Image::Magick';
117             }
118             else {
119 0           die "No graphics module found for image resizing. Install Graphics::Magick or Image::Magick: $@ "
120             }
121              
122 0           my ($thumb_tmp_fh, $thumb_tmp_filename) = tempfile('CGIuploaderXXXXX', UNLINK => 1, DIR => $self->{'temp_dir'});
123 0           binmode($thumb_tmp_fh);
124              
125 0           my $img = $magick_module->new();
126              
127 0           my $err;
128 0           eval {
129 0           $err = $img->Read(filename=>$orig_filename);
130 0 0         die "Error while reading $orig_filename: $err" if $err;
131              
132 0           my ($target_w,$target_h) = _calc_target_size($img,$p{w},$p{h});
133              
134 0           $err = $img->Resize($target_w.'x'.$target_h);
135 0 0         die "Error while resizing $orig_filename: $err" if $err;
136 0           $err = $img->Write($thumb_tmp_filename);
137 0 0         die "Error while writing $orig_filename: $err" if $err;
138             };
139 0 0         if ($@) {
140 0           warn $@;
141 0           my $code;
142             # codes > 400 are fatal
143 0 0 0       die $err if ((($code) = $err =~ /(\d+)/) and ($code > 400));
144             }
145              
146 0           assert ($thumb_tmp_filename, 'thumbnail tmp file created');
147 0 0         return wantarray ? ($thumb_tmp_filename, $img ) : $thumb_tmp_filename;
148              
149             }
150              
151              
152             # Calculate the target with height
153             #
154             # my ($target_w,$target_h) = _calc_target_size($img,$p{w},$p{h})
155             #
156             # Input:
157             #
158             # - Magick object, pre-opened with the original file
159             # - provided width
160             # - provided height
161              
162             sub _calc_target_size {
163 0     0     my ($img,$w,$h) = @_;
164              
165 0           my $target_h = $h;
166 0           my $target_w = $w;
167 0           my ($orig_w,$orig_h) = $img->Get('width','height');
168              
169 0 0         $target_h = sprintf("%.1d", ($orig_h * $target_w) / $orig_w) unless $target_h;
170 0 0         $target_w = sprintf("%.1d", ($orig_w * $target_h) / $orig_h) unless $target_w;
171              
172 0           return ($target_w,$target_h);
173              
174             }
175              
176              
177              
178              
179             # load Graphics::Magick or Image::Magick if one is not already loaded.
180             sub _load_magick_module {
181 0     0     my $module_name = shift;
182 0           return eval "require $module_name";
183             }
184              
185             =head2 BACKWARDS COMPATIBILITY
186              
187             These older, more awkward syntaxes are still supported:
188              
189             As a class method:
190              
191             ($thumb_tmp_filename) = CGI::Uploader::Transform::ImageMagick->gen_thumb(
192             $orig_filename,
193             [ w => $width, h => $height ]
194             );
195              
196             In a C C:
197              
198             'my_img_field_name' => {
199             transform_method => \&gen_thumb,
200             params => [ w => 100, h => 100 ],
201             }
202              
203              
204             1;