File Coverage

lib/Image/Info.pm
Criterion Covered Total %
statement 95 107 88.7
branch 61 80 76.2
condition 7 11 63.6
subroutine 16 16 100.0
pod 5 5 100.0
total 184 219 84.0


line stmt bran cond sub pod time code
1              
2             #############################################################################
3             #
4             # ATTENTION! This file is autogenerated from dev/Info.pm.tmpl - DO NOT EDIT!
5             #
6             #############################################################################
7              
8             package Image::Info;
9              
10             # Copyright 1999-2004, Gisle Aas.
11             #
12             # This library is free software; you can redistribute it and/or
13             # modify it under the same terms as Perl v5.8.8 itself.
14             #
15             # Previously maintained by Tels - (c) 2006 - 2008.
16             # Currently maintained by Slaven Rezic - (c) 2008 - 2023.
17              
18 21     21   2192849 use strict;
  21         290  
  21         720  
19 21     21   111 use vars qw($VERSION @EXPORT_OK);
  21         30  
  21         7546  
20              
21             $VERSION = '1.44';
22              
23             require Exporter;
24             *import = \&Exporter::import;
25              
26             @EXPORT_OK = qw(image_info dim html_dim image_type determine_file_format);
27              
28             # already required and failed sub-modules are remembered here
29             my %mod_failure;
30              
31             sub image_info
32             {
33 80     80 1 139924 my $source = _source(shift);
34 80 100       279 return $source if ref $source eq 'HASH'; # Pass on errors
35              
36             # What sort of file is it?
37 79         170 my $head = _head($source);
38              
39 79 50       213 return $head if ref($head) eq 'HASH'; # error?
40              
41 79 50       473 my $format = determine_file_format($head)
42             or return { error => 'Unrecognized file format' };
43              
44 79         223 return _image_info_for_format($format, $source);
45             }
46              
47             # Note: this function is private, but may be used by Image::Info::*
48             # implementations (i.e. the WBMP implementation)
49             sub _image_info_for_format
50             {
51 80     80   163 my($format, $source) = @_;
52              
53 80         212 my $mod = "Image::Info::$format";
54 80         165 my $sub = "$mod\::process_file";
55 80         340 my $info = bless [], "Image::Info::Result";
56 80         138 eval {
57 80 100       351 unless (defined &$sub) {
58             # already required and failed?
59 31 50       102 if (my $fail = $mod_failure{$mod}) {
60 0         0 die $fail;
61             }
62 31         1962 eval "require $mod";
63 31 50       200 if ($@) {
64 0         0 $mod_failure{$mod} = $@;
65 0         0 die $@;
66             }
67 31 50       198 die "$mod did not define &$sub" unless defined &$sub;
68             }
69              
70 80         245 my %cnf = @_;
71             {
72             # call process_file()
73 21     21   163 no strict 'refs';
  21         46  
  21         26814  
  80         119  
74 80         325 &$sub($info, $source, \%cnf);
75             }
76 79         413 $info->clean_up;
77             };
78 80 100       217 return { error => $@ } if $@;
79 79 100       1375 return wantarray ? @$info : $info->[0];
80             }
81              
82             sub image_type
83             {
84 2     2 1 1262 my $source = _source(shift);
85 2 100       9 return $source if ref $source eq 'HASH'; # Pass on errors
86              
87             # What sort of file is it?
88 1 50       3 my $head = _head($source) or return _os_err("Can't read head");
89 1 50       2 my $format = determine_file_format($head)
90             or return { error => "Unrecognized file format" };
91              
92 1         17 return { file_type => $format };
93             }
94              
95             # Note: this function is private, but may be used by Image::Info::*
96             # implementations (i.e. the WBMP implementation)
97             sub _source
98             {
99 83     83   163 my $source = shift;
100 83 100       324 if (!ref $source) {
    50          
101 57         84 my $fh;
102 57 50       143 if ($] < 5.006) {
103 0         0 require Symbol;
104 0         0 $fh = Symbol::gensym();
105 0 0       0 open($fh, $source) || return _os_err("Can't open $source");
106             }
107             else {
108 57 100       2976 open $fh, '<', $source
109             or return _os_err("Can't open $source");
110             }
111 55         172 ${*$fh} = $source; # keep filename in case somebody wants to know
  55         273  
112 55         200 binmode($fh);
113 55         106 $source = $fh;
114             }
115             elsif (ref($source) eq "SCALAR") {
116             # Earlier PerlIO::scalar versions may segfault or consume lots
117             # of memory for some invalid images, see
118             # RT #100847 and img/segfault.tif
119 26 50 33     48 if (eval { require PerlIO::scalar; PerlIO::scalar->VERSION(0.21) } ||
  26         1991  
  26         1721  
120 0         0 !eval { require IO::Scalar; 1 }) {
  0         0  
121 26 50       292 open(my $s, "<", $source) or return _os_err("Can't open string");
122 26         59 $source = $s;
123             }
124             else {
125 0         0 $source = IO::Scalar->new($source);
126             }
127             }
128             else {
129 0 0       0 seek($source, 0, 0) or return _os_err("Can't rewind");
130             }
131              
132 81         158 $source;
133             }
134              
135             sub _head
136             {
137 80     80   130 my $source = shift;
138 80         111 my $head;
139              
140             # Originally was 32 bytes.
141             # In the meantime lowered to 11 bytes.
142             # But XBM probably need more because of a leading comment.
143 80         112 my $to_read = 64;
144 80         1867 my $read = read($source, $head, $to_read);
145              
146 80 50       285 return _os_err("Couldn't read any bytes") if !$read;
147              
148 80 50       211 if (ref($source) eq "IO::String") {
149             # XXX workaround until we can trap seek() with a tied file handle
150 0         0 $source->setpos(0);
151             }
152             else {
153 80 50       758 seek($source, 0, 0) or return _os_err("Can't rewind");
154             }
155 80         259 $head;
156             }
157              
158             sub _os_err
159             {
160 2     2   31 return { error => "$_[0]: $!",
161             Errno => $!+0,
162             };
163             }
164              
165             sub determine_file_format
166             {
167 81     81 1 1537 local($_) = @_;
168 81 100       347 return "JPEG" if /^\xFF\xD8/;
169 64 100       197 return "PNG" if /^\x89PNG\x0d\x0a\x1a\x0a/;
170 56 100       177 return "GIF" if /^GIF8[79]a/;
171 47 100       130 return "TIFF" if /^MM\x00\x2a/;
172 46 100       131 return "TIFF" if /^II\x2a\x00/;
173 41 100       114 return "BMP" if /^BM/;
174 37 100       81 return "ICO" if /^\000\000\001\000/;
175 34 100       103 return "PPM" if /^P[1-6]/;
176 26 100       315 return "XPM" if /(^\/\* XPM \*\/)|(static\s+char\s+\*\w+\[\]\s*=\s*{\s*"\d+)/;
177 23 100       111 return "XBM" if /^(?:\/\*.*\*\/\n)?#define\s/;
178 18 100       61 return "AVIF" if /\A....ftypavif/s;
179 15 100       69 return "SVG" if /^(<\?xml|[\012\015\t ]*
180 10 50       68 return "WEBP" if /^RIFF.{4}WEBP/s;
181 0         0 return undef;
182             }
183              
184             sub dim
185             {
186 18   50 18 1 37931 my $img = shift || return;
187 18   100     73 my $x = $img->{width} || return;
188 17   50     48 my $y = $img->{height} || return;
189 17 100       107 wantarray ? ($x, $y) : "${x}x$y";
190             }
191              
192             sub html_dim
193             {
194 2     2 1 5 my($x, $y) = dim(@_);
195 2 100       8 return "" unless $x;
196 1         10 "width=\"$x\" height=\"$y\"";
197             }
198              
199             #############################################################################
200             package Image::Info::Result;
201              
202             sub push_info
203             {
204 1961     1961   3546 my($self, $n, $key) = splice(@_, 0, 3);
205 1961         2012 push(@{$self->[$n]{$key}}, @_);
  1961         6152  
206             }
207              
208             sub replace_info
209             {
210 77     77   178 my($self, $n, $key) = splice(@_, 0, 3);
211 77         221 $self->[$n]{$key}[0] = $_[0];
212             }
213              
214             sub clean_up
215             {
216 79     79   127 my $self = shift;
217 79         174 for (@$self) {
218 102         549 for my $k (keys %$_) {
219 1738         1936 my $a = $_->{$k};
220 1738 100       3513 $_->{$k} = $a->[0] if @$a <= 1;
221             }
222             }
223             }
224              
225             sub get_info {
226 188     188   337 my($self, $n, $key, $delete) = @_;
227 188 100       413 my $v = $delete ? delete $self->[$n]{$key} : $self->[$n]{$key};
228 188   100     483 $v ||= [];
229 188         563 @$v;
230             }
231              
232             1;
233              
234             __END__