Image-Size
view release on metacpan or search on metacpan
lib/Image/Size.pm view on Meta::CPAN
$need_restore = 1;
# First alteration (didn't wait long, did I?) to the existing handle:
#
# assist dain-bramaged operating systems -- SWD
# SWD: I'm a bit uncomfortable with changing the mode on a file
# that something else "owns" ... the change is global, and there
# is no way to reverse it.
# But image files ought to be handled as binary anyway.
binmode $handle;
seek $handle, 0, 0;
read $handle, $header, 256;
seek $handle, 0, 0;
}
else
{
if (! $NO_CACHE)
{
require Cwd;
require File::Spec;
if (! File::Spec->file_name_is_absolute($stream))
{
$stream = File::Spec->catfile(Cwd::cwd(), $stream);
}
$mtime = (stat $stream)[9];
if (-e "$stream" and exists $CACHE{$stream})
{
@list = split /,/, $CACHE{$stream}, 4;
# Don't return the cache if the file is newer.
if ($mtime <= $list[0])
{
return @list[1 .. 3];
}
# In fact, clear it
delete $CACHE{$stream};
}
}
# first try to open the stream
require Symbol;
$handle = Symbol::gensym();
if (! open $handle, '<', $stream)
{
return (undef, undef, "Can't open image file $stream: $!");
}
$need_close = 1;
# assist dain-bramaged operating systems -- SWD
binmode $handle;
read $handle, $header, 256;
seek $handle, 0, 0;
$READ_IN = $read_io;
$file_name = $stream;
}
$LAST_POS = 0;
# Right now, $x, $y and $id are undef. If the while-loop below doesn't
# match the header to a file-type and call a subroutine, then the later
# block that tried Image::Magick will default to setting the id/error to
# "unknown file type".
my $tm_idx = 0;
while ($tm_idx < @TYPE_MAP)
{
if ($header =~ $TYPE_MAP[$tm_idx])
{
($x, $y, $id) = $TYPE_MAP[$tm_idx + 1]->($handle);
last;
}
$tm_idx += 2;
}
# Added as an afterthought: I'm probably not the only one who uses the
# same shaded-sphere image for several items on a bulleted list:
if (! ($NO_CACHE or (ref $stream) or (! defined $x)))
{
$CACHE{$stream} = join q{,}, $mtime, $x, $y, $id;
}
# If we were passed an existing file handle, we need to restore the
# old filepos:
if ($need_restore)
{
seek $handle, $save_pos, 0;
}
# ...and if we opened the file ourselves, we need to close it
if ($need_close)
{
close $handle; ## no critic(RequireCheckedClose)
}
if (! defined $id)
{
if ($file_name)
{
# Image::Magick operates on file names.
($x, $y, $id) = imagemagick_size($file_name);
}
else
{
$id = 'Data stream is not a known image file format';
}
}
# results:
return (wantarray) ? ($x, $y, $id) : ();
}
sub imagemagick_size
{
my $file_name = shift;
my $module_name;
# First see if we have already loaded Graphics::Magick or Image::Magick
# If so, just use whichever one is already loaded.
if (exists $INC{'Graphics/Magick.pm'})
{
$module_name = 'Graphics::Magick';
}
elsif (exists $INC{'Image/Magick.pm'})
{
$module_name = 'Image::Magick';
}
# If neither are already loaded, try loading either one.
elsif (_load_magick_module('Graphics::Magick'))
{
$module_name = 'Graphics::Magick';
}
elsif (_load_magick_module('Image::Magick'))
{
$module_name = 'Image::Magick';
}
if ($module_name)
{
my $img = $module_name->new();
my $x = $img->Read($file_name);
# Image::Magick error handling is a bit weird, see
# <http://www.simplesystems.org/ImageMagick/www/perl.html#erro>
if("$x") {
return (undef, undef, "$x");
} else {
return ($img->Get('width', 'height', 'format'));
}
}
else {
return (undef, undef, 'Data stream is not a known image file format');
}
}
# load Graphics::Magick or Image::Magick if one is not already loaded.
sub _load_magick_module {
my $module_name = shift;
my $retval = eval {
local $SIG{__DIE__} = q{};
require $module_name;
1;
};
return $retval ? 1 : 0;
}
sub html_imgsize
{
my @args = @_;
@args = imgsize(@args);
# Use lowercase and quotes so that it works with xhtml.
return ((defined $args[0]) ?
sprintf('width="%d" height="%d"', @args[0,1]) :
undef);
}
sub attr_imgsize
{
my @args = @_;
@args = imgsize(@args);
return ((defined $args[0]) ?
(('-width', '-height', @args)[0, 2, 1, 3]) :
undef);
}
# This used only in gifsize:
sub img_eof
{
my $stream = shift;
if (ref($stream) eq 'SCALAR')
{
return ($LAST_POS >= length ${$stream});
}
return eof $stream;
}
# Simple converter-routine used by SWF and CWS code
sub _bin2int
{
my $val = shift;
# "no critic" because I want it clear which args are being used by
# substr() versus unpack().
## no critic (ProhibitParensWithBuiltins)
return unpack 'N', pack 'B32', substr(('0' x 32) . $val, -32);
}
###########################################################################
# Subroutine gets the size of the specified GIF
###########################################################################
sub gifsize ## no critic(ProhibitExcessComplexity)
{
lib/Image/Size.pm view on Meta::CPAN
($x, $y, $id) = imgsize(\$img);
# $x and $y are dimensions, $id is the type of the image
=item Open file handle
The third option is to pass in an open filehandle (such as an object of
the C<IO::File> class, for example) that has already been associated with
the target image file. The file pointer will necessarily move, but will be
restored to its original position before subroutine end.
# $fh was passed in, is IO::File reference:
($x, $y, $id) = imgsize($fh);
# Same as calling with filename, but more abstract.
=back
=head2 Recognized Formats
Image::Size natively understands and sizes data in the following formats:
=over 4
=item GIF
=item JPG
=item XBM
=item XPM
=item PPM family (PPM/PGM/PBM)
=item XV thumbnails
=item PNG
=item MNG
=item TIF
=item BMP
=item PSD (Adobe PhotoShop)
=item SWF (ShockWave/Flash)
=item CWS (FlashMX, compressed SWF, Flash 6)
=item PCD (Kodak PhotoCD, see notes below)
=item EMF (Windows Enhanced Metafile Format)
=item WEBP
=item ICO (Microsoft icon format)
=item CUR (Microsoft mouse cursor format)
=back
Additionally, if the B<Image::Magick> module is present, the file types
supported by it are also supported by Image::Size. See also L<"CAVEATS">.
When using the C<imgsize> interface, there is a third, unused value returned
if the programmer wishes to save and examine it. This value is the identity of
the data type, expressed as a 2-3 letter abbreviation as listed above. This is
useful when operating on open file handles or in-memory data, where the type
is as unknown as the size. The two support routines ignore this third return
value, so those wishing to use it must use the base C<imgsize> routine.
Note that when the B<Image::Magick> fallback is used (for all non-natively
supported files), the data type identity comes directly from the 'format'
parameter reported by B<Image::Magick>, so it may not meet the 2-3 letter
abbreviation format. For example, a WBMP file might be reported as
'Wireless Bitmap (level 0) image' in this case.
=head2 Information Caching and C<$NO_CACHE>
When a filename is passed to any of the sizing routines, the default behavior
of the library is to cache the resulting information. The modification-time of
the file is also recorded, to determine whether the cache should be purged and
updated. This was originally added due to the fact that a number of CGI
applications were using this library to generate attributes for pages that
often used the same graphical element many times over.
However, the caching can lead to problems when the files are generated
dynamically, at a rate that exceeds the resolution of the modification-time
value on the filesystem. Thus, the optionally-importable control variable
C<$NO_CACHE> has been introduced. If this value is anything that evaluates to a
non-false value (be that the value 1, any non-null string, etc.) then the
cacheing is disabled until such time as the program re-enables it by setting
the value to false.
The parameter C<$NO_CACHE> may be imported as with the B<imgsize> routine, and
is also imported when using the import tag B<C<:all>>. If the programmer
chooses not to import it, it is still accessible by the fully-qualified package
name, B<$Image::Size::NO_CACHE>.
=head2 Sharing the Cache Between Processes
If you are using B<Image::Size> in a multi-thread or multi-process environment,
you may wish to enable sharing of the cached information between the
processes (or threads). Image::Size does not natively provide any facility
for this, as it would add to the list of dependencies.
To make it possible for users to do this themselves, the C<%CACHE> hash-table
that B<Image::Size> uses internally for storage may be imported in the B<use>
statement. The user may then make use of packages such as B<IPC::MMA>
(L<IPC::MMA|IPC::MMA>) that can C<tie> a hash to a shared-memory segment:
use Image::Size qw(imgsize %CACHE);
use IPC::MMA;
...
tie %CACHE, 'IPC::MM::Hash', $mmHash; # $mmHash via mm_make_hash
# Now, forked processes will share any changes made to the cache
=head2 Sizing PhotoCD Images
With version 2.95, support for the Kodak PhotoCD image format is
included. However, these image files are not quite like the others. One file
is the source of the image in any of a range of pre-set resolutions (all with
the same aspect ratio). Supporting this here is tricky, since there is nothing
inherent in the file to limit it to a specific resolution.
The library addresses this by using a scale mapping, and requiring the user
(you) to specify which scale is preferred for return. Like the C<$NO_CACHE>
setting described earlier, this is an importable scalar variable that may be
used within the application that uses B<Image::Size>. This parameter is called
C<$PCD_SCALE>, and is imported by the same name. It, too, is also imported
when using the tag B<C<:all>> or may be referenced as
B<$Image::Size::PCD_SCALE>.
lib/Image/Size.pm view on Meta::CPAN
L<IPC::MMA|IPC::MMA>), which provides shared memory management via the I<mm>
library from Ralf Engelschall (details available in the documentation for
B<IPC::MMA>):
use IPC::MMA;
use Image::Size qw(%CACHE);
my $mm = mm_create(65536, '/tmp/test_lockfile');
my $mmHash = mm_make_hash($mm);
tie %CACHE, 'IPC::MM::Hash', $mmHash;
As before, this is done in the start-up phase of the webserver. As the
child processes are created, they inherit the pointer to the existing shared
segment.
=head1 MORE EXAMPLES
The B<attr_imgsize> interface is also well-suited to use with the Tk
extension:
$image = $widget->Photo(-file => $img_path, attr_imgsize($img_path));
Since the C<Tk::Image> classes use dashed option names as C<CGI> does, no
further translation is needed.
This package is also well-suited for use within an Apache web server context.
File sizes are cached upon read (with a check against the modified time of
the file, in case of changes), a useful feature for a B<mod_perl> environment
in which a child process endures beyond the lifetime of a single request.
Other aspects of the B<mod_perl> environment cooperate nicely with this
module, such as the ability to use a sub-request to fetch the full pathname
for a file within the server space. This complements the HTML generation
capabilities of the B<CGI> module, in which C<CGI::img> wants a URL but
C<attr_imgsize> needs a file path:
# Assume $Q is an object of class CGI, $r is an Apache request object.
# $imgpath is a URL for something like "/img/redball.gif".
$r->print($Q->img({ -src => $imgpath,
attr_imgsize($r->lookup_uri($imgpath)->filename) }));
The advantage here, besides not having to hard-code the server document root,
is that Apache passes the sub-request through the usual request lifecycle,
including any stages that would re-write the URL or otherwise modify it.
=head1 DIAGNOSTICS
The base routine, C<imgsize>, returns B<undef> as the first value in its list
when an error has occurred. The third element contains a descriptive
error message.
The other two routines simply return B<undef> in the case of error.
=head1 CAVEATS
Caching of size data can only be done on inputs that are file names. Open
file handles and scalar references cannot be reliably transformed into a
unique key for the table of cache data. Buffers could be cached using the
MD5 module, and perhaps in the future I will make that an option. I do not,
however, wish to lengthen the dependency list by another item at this time.
As B<Image::Magick> operates on file names, not handles, the use of it is
restricted to cases where the input to C<imgsize> is provided as file name.
=head1 SEE ALSO
L<Image::Magick|Image::Magick> and L<Image::Info|Image::Info> Perl modules at
CPAN. The B<Graphics::Magick> Perl API at
L<http://www.graphicsmagick.org/perl.html>.
=head1 CONTRIBUTORS
Perl module interface by Randy J. Ray I<(rjray@blackperl.com)>, original
image-sizing code by Alex Knowles I<(alex@ed.ac.uk)> and Andrew Tong
I<(werdna@ugcs.caltech.edu)>, used with their joint permission.
Some bug fixes submitted by Bernd Leibing I<(bernd.leibing@rz.uni-ulm.de)>.
PPM/PGM/PBM sizing code contributed by Carsten Dominik
I<(dominik@strw.LeidenUniv.nl)>. Tom Metro I<(tmetro@vl.com)> re-wrote the JPG
and PNG code, and also provided a PNG image for the test suite. Dan Klein
I<(dvk@lonewolf.com)> contributed a re-write of the GIF code. Cloyce Spradling
I<(cloyce@headgear.org)> contributed TIFF sizing code and test images. Aldo
Calpini I<(a.calpini@romagiubileo.it)> suggested support of BMP images (which
I I<really> should have already thought of :-) and provided code to work
with. A patch to allow html_imgsize to produce valid output for XHTML, as
well as some documentation fixes was provided by Charles Levert
I<(charles@comm.polymtl.ca)>. The ShockWave/Flash support was provided by
Dmitry Dorofeev I<(dima@yasp.com)>. Though I neglected to take note of who
supplied the PSD (PhotoShop) code, a bug was identified by Alex Weslowski
<aweslowski@rpinteractive.com>, who also provided a test image. PCD support
was adapted from a script made available by Phil Greenspun, as guided to my
attention by Matt Mueller I<mueller@wetafx.co.nz>. A thorough read of the
documentation and source by Philip Newton I<Philip.Newton@datenrevision.de>
found several typos and a small buglet. Ville Skytt� I<(ville.skytta@iki.fi)>
provided the MNG and the Image::Magick fallback code. Craig MacKenna
I<(mackenna@animalhead.com)> suggested making the cache available so that it
could be used with shared memory, and helped test my change before release.
=head1 BUGS
Please report any bugs or feature requests to
C<bug-image-size at rt.cpan.org>, or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Image-Size>. I will be
notified, and then you'll automatically be notified of progress on
your bug as I make changes.
=head1 SUPPORT
=over 4
=item * RT: CPAN's request tracker
L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Image-Size>
=item * AnnoCPAN: Annotated CPAN documentation
L<http://annocpan.org/dist/Image-Size>
=item * CPAN Ratings
L<http://cpanratings.perl.org/d/Image-Size>
=item * Search CPAN
L<http://search.cpan.org/dist/Image-Size>
=item * Project page on GitHub
L<http://github.com/rjray/image-size>
=back
=head1 REPOSITORY
L<https://github.com/rjray/image-size>
=head1 LICENSE AND COPYRIGHT
This file and the code within are copyright (c) 1996-2009 by Randy J. Ray.
Copying and distribution are permitted under the terms of the Artistic
License 2.0 (L<http://www.opensource.org/licenses/artistic-license-2.0.php>) or
the GNU LGPL 2.1 (L<http://www.opensource.org/licenses/lgpl-2.1.php>).
=head1 AUTHOR
Randy J. Ray C<< <rjray@blackperl.com> >>
=cut
( run in 1.211 second using v1.01-cache-2.11-cpan-39bf76dae61 )