File Coverage

blib/lib/Imager/Simple.pm
Criterion Covered Total %
statement 18 92 19.5
branch 0 64 0.0
condition 0 16 0.0
subroutine 6 12 50.0
pod 5 6 83.3
total 29 190 15.2


line stmt bran cond sub pod time code
1             package Imager::Simple;
2              
3 1     1   29744 use warnings;
  1         3  
  1         30  
4 1     1   5 use strict;
  1         2  
  1         36  
5              
6 1     1   6 use base 'Class::Accessor::Fast';
  1         6  
  1         1381  
7              
8 1     1   4675 use Carp ();
  1         3  
  1         22  
9 1     1   7 use Scalar::Util 'blessed';
  1         2  
  1         102  
10              
11 1     1   1526 use Imager;
  1         120760  
  1         16  
12              
13             __PACKAGE__->mk_accessors(qw(frames format));
14              
15             =head1 NAME
16              
17             Imager::Simple - Make easy things easy with Imager
18              
19             =head1 VERSION
20              
21             Version 0.010003
22              
23             =cut
24              
25             our $VERSION = '0.010003';
26              
27             =head1 SYNOPSIS
28              
29             C simplyfies common tasks with L.
30              
31             use Imager::Simple;
32              
33             # scale image "anim.gif" and assign output to a variable
34             $scaled_data = eval {
35             Imager::Simple->read('anim.gif')->scale(100, 100, 'min')->data;
36             };
37             if ($@) {
38             die "error from Imager::Simple: $@";
39             }
40              
41             =head1 DESCRIPTION
42              
43             L is a powerful module for processing image data, but it is the
44             power that makes it sometimes hard to use for simple tasks, like for
45             example read an image, scale it, convert it to another format and save it
46             somewhere. This module tries to DWIM with as little effort as possible.
47              
48             =head1 METHODS
49              
50             =cut
51              
52             # internal - get the first defined value
53 0 0   0 0   sub first_defined ($;@) { for (@_) { return $_ if defined } }
  0            
54              
55             =head2 read
56              
57             $img = Imager::Simple->read($source, $type);
58              
59             A constructor method that reads an image and returns an C
60             object. C<$source> can be
61              
62             =over
63              
64             =item a scalar
65              
66             which is taken as a name of a file, that contains the image;
67              
68             =item a reference to a scalar
69              
70             that contains the image data itself;
71              
72             =item a file handle
73              
74             of an opened file from which the image data can be read.
75              
76             =back
77              
78             The C<$type> is optional. If given it must be an image type known by
79             L like C or C. If not given L tries to guess the
80             image type.
81              
82             Image data is read by L.
83             The returned object provides the individual images through the L
84             method. For most images C<< $img->frames >> is a reference to an array
85             with one element (C<< @{$img->frames} == 1 >>).
86              
87             =cut
88              
89             sub read {
90 0     0 1   my ($self, $d, $type) = @_;
91 0           my @args;
92 0           my $ref = ref $d;
93              
94 0 0         $self = bless {}, $self unless ref $self;
95 0 0         if ($ref) {
96             # read through supplied code
97 0 0 0       if ($ref eq 'CODE') {
    0 0        
    0          
98 0           @args = (callback => $d);
99             }
100             # get data from a filehandle
101             elsif ($ref eq 'GLOB' or blessed($d) and $d->can('read')) {
102 0           @args = (fh => $d);
103             }
104             # read from scalar
105             elsif ($ref eq 'SCALAR') {
106 0           @args = (data => $$d);
107             }
108             }
109             else {
110 0           @args = (file => $d);
111             }
112 0 0         push @args, 'type', $type if defined $type;
113 0 0         @{$self->{frames}} = Imager->read_multi(@args)
  0            
114             or Carp::croak(Imager->errstr);
115              
116 0           $self->{format} = $self->{frames}->[0]->tags(name => 'i_format');
117              
118 0           $self;
119             }
120              
121             =head2 format
122              
123             $img->format('gif');
124              
125             Accessor to the image's output format.
126              
127             =head2 frames
128              
129             C supports multi-image files, e.g. GIF animations.
130             The individual images are stored in an array of L objects,
131             that is available through the C method.
132              
133             =head2 clone
134              
135             TODO
136              
137             =cut
138              
139             sub clone {
140 0     0 1   Carp::croak("not implemented yet");
141             }
142              
143             =head2 scale
144              
145             $scaled_img = $img->scale(100);
146             $scaled_img = $img->scale({y => 100});
147             $scaled_img = $img->scale(100, 100, 'min');
148             $scaled_img = $img->scale(100, 100, {type => 'min'});
149             $scaled_img = $img->scale('min', {height => 100, width => 100});
150              
151             Scale the image in place.
152              
153             Accepts absolute and named arguments. Named arguments must be supplied
154             a hash reference as last argument. The order of absolute argument
155             positions is C, C, C. All other arguments can only
156             be supplied as named arguments.
157             Possible names for the image width are C, C and C -
158             names for the image height are C, C and C - and
159             finally the type must be named C. For all other known named
160             arguments see L.
161              
162             Absolute and named arguments can be mixed, whereas absolute arguments
163             supersede named ones.
164              
165             Image tags are copied from the old image(s) where applicable.
166              
167             =cut
168              
169             sub scale {
170 0     0 1   my $self = shift;
171 0 0         my $opt = ref $_[-1] eq 'HASH' ? pop : {};
172 0           my (%args, %scale, @out, $out, $tag, $factor_x, $factor_y, $t);
173 0 0         my @frames = @{$self->{frames}}
  0            
174             or return $self;
175 0           my ($screen_width, $screen_height);
176 0           my ($width, $height);
177              
178 0           for (shift, $opt->{x}, $opt->{xpixels}, $opt->{width}) {
179 0 0         $width = $_, last if defined;
180             }
181 0           for (shift, $opt->{y}, $opt->{ypixels}, $opt->{height}) {
182 0 0         $height = $_, last if defined;
183             }
184 0           for (shift, $opt->{type}) {
185 0 0         $args{type} = $_, last if defined;
186             }
187 0           for (qw(constrain qtype)) {
188 0 0         $args{$_} = $t, last if defined($t = $opt->{$_});
189             }
190 0           for (qw(scalefactor xscalefactor yscalefactor)) {
191 0 0         $scale{$_} = $t, last if defined($t = $opt->{$_});
192             }
193 0           for (my $i = 0; my $frame = $frames[$i]; ++$i) {
194              
195 0 0         if ($i == 0) {
196 0 0         if ($frame->tags(name => 'i_format') eq 'gif') {
197 0 0         $args{xscalefactor} = $factor_x =
198             defined $width ?
199             $width / $frame->tags(name => 'gif_screen_width') :
200             first_defined $scale{xscalefactor}, $scale{scalefactor};
201 0 0 0       $args{yscalefactor} = $factor_y =
202             defined $height ?
203             $height / $frame->tags(name => 'gif_screen_height') :
204             first_defined $scale{yscalefactor}, $scale{scalefactor} || $factor_x || 1;
205             }
206             else {
207 0 0         $args{xscalefactor} = $factor_x =
208             defined $width ?
209             $width / $frame->getwidth :
210             first_defined $scale{xscalefactor}, $scale{scalefactor};
211 0 0 0       $args{yscalefactor} = $factor_y =
212             defined $height ?
213             $height / $frame->getheight :
214             first_defined $scale{yscalefactor}, $scale{scalefactor} || $factor_x || 1;
215             }
216 0 0         $args{xscalefactor} = $factor_x = $factor_y
217             unless defined $factor_x;
218             }
219              
220 0 0         $out = $frame->scale(%args)
221             or Carp::croak($frame->errstr);
222              
223 0 0         if ($frame->tags(name => 'i_format') eq 'gif') {
224 0           $out->settag(name => 'gif_left', value => int($factor_x * $frame->tags(name => 'gif_left')));
225 0           $out->settag(name => 'gif_top', value => int($factor_y * $frame->tags(name => 'gif_top')));
226              
227 0           $out->settag(name => 'gif_screen_width', value => ceil($factor_x * $frame->tags(name => 'gif_screen_width')));
228 0           $out->settag(name => 'gif_screen_height', value => ceil($factor_y * $frame->tags(name => 'gif_screen_height')));
229              
230 0           for $tag (qw/gif_delay gif_user_input gif_loop gif_disposal/) {
231 0           $out->settag(name => $tag, value => $frame->tags(name => $tag));
232             }
233              
234 0 0         if ($frame->tags(name => 'gif_local_map')) {
235 0           $out->settag(name => 'gif_local_map', value => 1);
236             }
237             }
238              
239 0           push @out, $out;
240             }
241 0           $self->{frames} = \@out;
242              
243 0           $self;
244             }
245              
246             =head2 write
247              
248             $img->write($destination);
249              
250             Write image data to given destination.
251              
252             C<$destination> can be:
253              
254             =over 4
255              
256             =item A scalar
257              
258             is taken as a filename.
259              
260             =item File handle or L object
261              
262             that must be opened in write mode and should be set to C.
263              
264             =item A scalar reference
265              
266             points to a buffer where the image data has to be stored.
267              
268             =item not given
269              
270             in what case write acts like L by returning
271             the image buffer.
272              
273             =back
274              
275             =cut
276              
277             sub write {
278 0     0 1   my ($self, $d) = @_;
279              
280 0 0         return $self->data unless defined $d; # for convenience
281 0           my $key;
282 0           my $ref = ref $d;
283              
284 0 0         if ($ref) {
285             # read through supplied code
286 0 0 0       if ($ref eq 'CODE') {
    0 0        
    0          
287 0           $key = 'callback';
288             }
289             # get data from a filehandle
290             elsif ($ref eq 'GLOB' or blessed($d) and $d->can('read')) {
291 0           $key = 'fh';
292             }
293             # read from scalar
294             elsif ($ref eq 'SCALAR') {
295 0           $key = 'data';
296             }
297             }
298             else {
299 0           $key = 'file';
300             }
301              
302 0           Imager->write_multi(
303             {
304             $key => $d,
305             type => $self->format,
306             transp => 'threshold',
307             tr_threshold => 50
308             },
309 0 0         @{$self->frames})
310             or Carp::croak(Imager->errstr);
311              
312 0           $self;
313             }
314              
315             =head2 data
316              
317             Returns the raw image data.
318              
319             =cut
320              
321             sub data {
322 0     0 1   my $self = shift;
323 0           my $data;
324            
325 0           Imager->write_multi(
326             {
327             data => \$data,
328             type => $self->format,
329             transp => 'threshold',
330             tr_threshold => 50
331             },
332 0 0         @{$self->frames})
333             or Carp::croak(Imager->errstr);
334              
335 0           $data;
336             }
337              
338             1;
339              
340             __END__