📄 size.pm
字号:
sub jpegsize{ my $stream = shift; my $MARKER = "\xFF"; # Section marker. my $SIZE_FIRST = 0xC0; # Range of segment identifier codes my $SIZE_LAST = 0xC3; # that hold size info. my ($x, $y, $id) = (undef, undef, "could not determine JPEG size"); my ($marker, $code, $length); my $segheader; # Dummy read to skip header ID &$read_in($stream, 2); while (1) { $length = 4; $segheader = &$read_in($stream, $length); # Extract the segment header. ($marker, $code, $length) = unpack("a a n", $segheader); # Verify that it's a valid segment. if ($marker ne $MARKER) { # Was it there? $id = "JPEG marker not found"; last; } elsif ((ord($code) >= $SIZE_FIRST) && (ord($code) <= $SIZE_LAST)) { # Segments that contain size info $length = 5; ($y, $x) = unpack("xnn", &$read_in($stream, $length)); $id = 'JPG'; last; } else { # Dummy read to skip over data &$read_in($stream, ($length - 2)); } } ($x, $y, $id);}# ppmsize: gets data on the PPM/PGM/PBM family.## Contributed by Carsten Dominik <dominik@strw.LeidenUniv.nl>sub ppmsize{ my $stream = shift; my ($x, $y, $id) = (undef, undef, "Unable to determine size of PPM/PGM/PBM data"); my $n; my $header = &$read_in($stream, 1024); # PPM file of some sort $header =~ s/^\#.*//mg; ($n, $x, $y) = ($header =~ /^(P[1-6])\s+(\d+)\s+(\d+)/s); $id = "PBM" if $n eq "P1" || $n eq "P4"; $id = "PGM" if $n eq "P2" || $n eq "P5"; $id = "PPM" if $n eq "P3" || $n eq "P6"; if ($n eq 'P7') { # John Bradley's XV thumbnail pics (thanks to inwap@jomis.Tymnet.COM) $id = 'XV'; ($x, $y) = ($header =~ /IMGINFO:(\d+)x(\d+)/s); } ($x, $y, $id);}# tiffsize: size a TIFF image## Contributed by Cloyce Spradling <cloyce@headgear.org>sub tiffsize { my $stream = shift; my ($x, $y, $id) = (undef, undef, "Unable to determine size of TIFF data"); my $endian = 'n'; # Default to big-endian; I like it better my $header = &$read_in($stream, 4); $endian = 'v' if ($header =~ /II\x2a\x00/o); # little-endian # Set up an association between data types and their corresponding # pack/unpack specification. Don't take any special pains to deal with # signed numbers; treat them as unsigned because none of the image # dimensions should ever be negative. (I hope.) my @packspec = ( undef, # nothing (shouldn't happen) 'C', # BYTE (8-bit unsigned integer) undef, # ASCII $endian, # SHORT (16-bit unsigned integer) uc($endian), # LONG (32-bit unsigned integer) undef, # RATIONAL 'c', # SBYTE (8-bit signed integer) undef, # UNDEFINED $endian, # SSHORT (16-bit unsigned integer) uc($endian), # SLONG (32-bit unsigned integer) ); my $offset = &$read_in($stream, 4, 4); # Get offset to IFD $offset = unpack(uc($endian), $offset); # Fix it so we can use it my $ifd = &$read_in($stream, 2, $offset); # Get number of directory entries my $num_dirent = unpack($endian, $ifd); # Make it useful $offset += 2; $num_dirent = $offset + ($num_dirent * 12); # Calc. maximum offset of IFD # Do all the work $ifd = ''; my $tag = 0; my $type = 0; while (!defined($x) || !defined($y)) { $ifd = &$read_in($stream, 12, $offset); # Get first directory entry last if (($ifd eq '') || ($offset > $num_dirent)); $offset += 12; $tag = unpack($endian, $ifd); # ...and decode its tag $type = unpack($endian, substr($ifd, 2, 2)); # ...and the data type # Check the type for sanity. next if (($type > @packspec+0) || (!defined($packspec[$type]))); if ($tag == 0x0100) { # ImageWidth (x) # Decode the value $x = unpack($packspec[$type], substr($ifd, 8, 4)); } elsif ($tag == 0x0101) { # ImageLength (y) # Decode the value $y = unpack($packspec[$type], substr($ifd, 8, 4)); } } # Decide if we were successful or not if (defined($x) && defined($y)) { $id = 'TIF'; } else { $id = ''; $id = 'ImageWidth ' if (!defined($x)); if (!defined ($y)) { $id .= 'and ' if ($id ne ''); $id .= 'ImageLength '; } $id .= 'tag(s) could not be found'; } ($x, $y, $id);}# bmpsize: size a Windows-ish BitMaP image## Adapted from code contributed by Aldo Calpini <a.calpini@romagiubileo.it>sub bmpsize{ my ($stream) = shift; my ($x, $y, $id) = (undef, undef, "Unable to determine size of TIFF data"); my ($buffer); $buffer = &$read_in($stream, 26); ($x, $y) = unpack("x18VV", $buffer); $id = 'BMP' if (defined $x and defined $y); ($x, $y, $id);}# psdsize: determine the size of a PhotoShop save-file (*.PSD)sub psdsize{ my ($stream) = shift; my ($x, $y, $id) = (undef, undef, "Unable to determine size of PSD data"); my ($buffer); $buffer = &$read_in($stream, 26); ($x, $y) = unpack("x14NN", $buffer); $id = 'PSD' if (defined $x and defined $y); ($x, $y, $id);}# swfsize: determine size of ShockWave/Flash files. Adapted from code sent by# Dmitry Dorofeev <dima@yasp.com>sub swfsize{ my ($image) = @_; my $header = &$read_in($image, 33); sub _bin2int { unpack("N", pack("B32", substr("0" x 32 . shift, -32))); } my $ver = _bin2int(unpack 'B8', substr($header, 3, 1)); my $bs = unpack 'B133', substr($header, 8, 17); my $bits = _bin2int(substr($bs, 0, 5)); my $x = int(_bin2int(substr($bs, 5+$bits, $bits))/20); my $y = int(_bin2int(substr($bs, 5+$bits*3, $bits))/20); return ($x, $y, 'SWF');}=head1 NAMEImage::Size - read the dimensions of an image in several popular formats=head1 SYNOPSIS use Image::Size; # Get the size of globe.gif ($globe_x, $globe_y) = imgsize("globe.gif"); # Assume X=60 and Y=40 for remaining examples use Image::Size 'html_imgsize'; # Get the size as 'width="X" height="Y"' for HTML generation $size = html_imgsize("globe.gif"); # $size == 'width="60" height="40"' use Image::Size 'attr_imgsize'; # Get the size as a list passable to routines in CGI.pm @attrs = attr_imgsize("globe.gif"); # @attrs == ('-width', 60, '-height', 40) use Image::Size; # Get the size of an in-memory buffer ($buf_x, $buf_y) = imgsize($buf);=head1 DESCRIPTIONThe B<Image::Size> library is based upon the C<wwwis> script written byAlex Knowles I<(alex@ed.ac.uk)>, a tool to examine HTML and add 'width' and'height' parameters to image tags. The sizes are cached internally based onfile name, so multiple calls on the same file name (such as images usedin bulleted lists, for example) do not result in repeated computations.B<Image::Size> provides three interfaces for possible import:=over=item imgsize(I<stream>)Returns a three-item list of the X and Y dimensions (width and height, inthat order) and image type of I<stream>. Errors are noted by undefined(B<undef>) values for the first two elements, and an error string in the third.The third element can be (and usually is) ignored, but is useful whensizing data whose type is unknown.=item html_imgsize(I<stream>)Returns the width and height (X and Y) of I<stream> pre-formatted as a singlestring C<'width="X" height="Y"'> suitable for addition into generated HTML IMGtags. If the underlying call to C<imgsize> fails, B<undef> is returned. Theformat returned should be dually suited to both HTML and XHTML.=item attr_imgsize(I<stream>)Returns the width and height of I<stream> as part of a 4-element list usefulfor routines that use hash tables for the manipulation of named parameters,such as the Tk or CGI libraries. A typical return value looks likeC<("-width", X, "-height", Y)>. If the underlying call to C<imgsize> fails,B<undef> is returned.=backBy default, only C<imgsize()> is imported. Any one orcombination of the three may be imported, or all three may be with thetag B<:all>.=head2 Input TypesThe sort of data passed as I<stream> can be one of three forms:=over=item stringIf an ordinary scalar (string) is passed, it is assumed to be a file name(either absolute or relative to the current working directory of theprocess) and is searched for and opened (if found) as the source of data.Possible error messages (see DIAGNOSTICS below) may include file-accessproblems.=item scalar referenceIf the passed-in stream is a scalar reference, it is interpreted as pointingto an in-memory buffer containing the image data. # Assume that &read_data gets data somewhere (WWW, etc.) $img = &read_data; ($x, $y, $id) = imgsize(\$img); # $x and $y are dimensions, $id is the type of the image=item Open file handleThe third option is to pass in an open filehandle (such as an object ofthe C<IO::File> class, for example) that has already been associated withthe target image file. The file pointer will necessarily move, but will berestored 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 Recognizd FormatsImage::Size 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 PNG=item TIF=item BMP=item PSD (Adobe PhotoShop)=item SWF (ShockWave/Flash)=backWhen using the C<imgsize> interface, there is a third, unused value returnedif the programmer wishes to save and examine it. This value is the three-letter identity of the data type. This is useful when operating on openfile 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 touse it must use the base C<imgsize> routine.=head1 DIAGNOSTICSThe base routine, C<imgsize>, returns B<undef> as the first value in its listwhen an error has occured. The third element contains a descriptiveerror message.The other two routines simply return B<undef> in the case of error.=head1 MORE EXAMPLESThe B<attr_imgsize> interface is also well-suited to use with the Tkextension: $image = $widget->Photo(-file => $img_path, attr_imgsize($img_path));Since the C<Tk::Image> classes use dashed option names as C<CGI> does, nofurther 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 ofthe file, in case of changes), a useful feature for a B<mod_perl> environmentin which a child process endures beyond the lifetime of a single request.Other aspects of the B<mod_perl> environment cooperate nicely with thismodule, such as the ability to use a sub-request to fetch the full pathnamefor a file within the server space. This complements the HTML generationcapabilities of the B<CGI> module, in which C<CGI::img> wants a URL butC<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 CAVEATSCaching of size data can only be done on inputs that are file names. Openfile handles and scalar references cannot be reliably transformed into aunique key for the table of cache data. Buffers could be cached using theMD5 module, and perhaps in the future I will make that an option. I do not,however, wish to lengthen the dependancy list by another item at this time.=head1 SEE ALSOC<http://www.tardis.ed.ac.uk/~ark/wwwis/> for a description of C<wwwis>and how to obtain it.=head1 AUTHORSPerl module interface by Randy J. Ray I<(rjray@tsoft.com)>, originalimage-sizing code by Alex Knowles I<(alex@ed.ac.uk)> and Andrew TongI<(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 DominikI<(dominik@strw.LeidenUniv.nl)>. Tom Metro I<(tmetro@vl.com)> re-wrote the JPGand PNG code, and also provided a PNG image for the test suite. Dan KleinI<(dvk@lonewolf.com)> contributed a re-write of the GIF code. Cloyce SpradlingI<(cloyce@headgear.org)> contributed TIFF sizing code and test images. AldoCalpini I<(a.calpini@romagiubileo.it)> suggested support of BMP images (whichI I<really> should have already thought of :-) and provided code to workwith. A patch to allow html_imgsize to produce valid output for XHTML, aswell as some documentation fixes was provided by Charles LevertI<(charles@comm.polymtl.ca)>. The ShockWave/Flash support was provided byDmitry Dorofeev I<(dima@yasp.com)>.=cut
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -