📄 size.pm
字号:
################################################################################# This file copyright (c) 2000 by Randy J. Ray, all rights reserved## Copying and distribution are permitted under the terms of the Artistic# License as distributed with Perl versions 5.005 and later.################################################################################## Once upon a time, this code was lifted almost verbatim from wwwis by Alex# Knowles, alex@ed.ac.uk. Since then, even I barely recognize it. It has# contributions, fixes, additions and enhancements from all over the world.## See the file README for change history.################################################################################package Image::Size;require 5.002;use strict;use Cwd 'cwd';use File::Spec;use Symbol;use Exporter;use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $revision $VERSION $read_in $last_pos);@ISA = qw(Exporter);@EXPORT = qw(imgsize);@EXPORT_OK = qw(imgsize html_imgsize attr_imgsize);%EXPORT_TAGS = ('all' => [@EXPORT_OK]);$revision = q$Id: Size.pm,v 1.24 2001/04/13 08:52:41 rjray Exp $;$VERSION = "2.93";# Package lexicals - invisible to outside world, used only in imgsize## Cache of files seen, and mapping of patterns to the sizing routinemy %cache = ();my %type_map = ( '^GIF8[7,9]a' => \&gifsize, "^\xFF\xD8" => \&jpegsize, "^\x89PNG\x0d\x0a\x1a\x0a" => \&pngsize, "^P[1-7]" => \&ppmsize, # also XVpics '\#define\s+\S+\s+\d+' => \&xbmsize, '\/\* XPM \*\/' => \&xpmsize, '^MM\x00\x2a' => \&tiffsize, '^II\x2a\x00' => \&tiffsize, '^BM' => \&bmpsize, '^8BPS' => \&psdsize, '^FWS' => \&swfsize);## These are lexically-scoped anonymous subroutines for reading the three# types of input streams. When the input to imgsize() is typed, then the# lexical "read_in" is assigned one of these, thus allowing the individual# routines to operate on these streams abstractly.#my $read_io = sub { my $handle = shift; my ($length, $offset) = @_; if (defined($offset) && ($offset != $last_pos)) { $last_pos = $offset; return '' if (! seek($handle, $offset, 0)); } my ($data, $rtn) = ('', 0); $rtn = read $handle, $data, $length; $data = '' unless ($rtn); $last_pos = tell $handle; $data;};my $read_buf = sub { my $buf = shift; my ($length, $offset) = @_; if (defined($offset) && ($offset != $last_pos)) { $last_pos = $offset; return '' if ($last_pos > length($$buf)); } my $data = substr($$buf, $last_pos, $length); $last_pos += length($data); $data;};1;sub imgsize{ my $stream = shift; my ($handle, $header); my ($x, $y, $id, $mtime, @list); # These only used if $stream is an existant open FH my ($save_pos, $need_restore) = (0, 0); # This is for when $stream is a locally-opened file my $need_close = 0; $header = ''; if (ref($stream) eq "SCALAR") { $handle = $stream; $read_in = $read_buf; $header = substr($$handle, 0, 256); } elsif (ref $stream) { # # I no longer require $stream to be in the IO::* space. So I'm assuming # you don't hose yourself by passing a ref that can't do fileops. If # you do, you fix it. # $handle = $stream; $read_in = $read_io; $save_pos = tell $handle; $need_restore = 1; # # First alteration (didn't wait long, did I?) to the existant 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 { $stream = File::Spec->catfile(cwd(),$stream) unless File::Spec->file_name_is_absolute($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. return @list[1 .. 3] unless ($list[0] < $mtime); # In fact, clear it delete $cache{$stream}; } #first try to open the stream $handle = gensym; open($handle, "< $stream") or 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; } $last_pos = 0; # # Oh pessimism... set the values of $x and $y to the error condition. If # the grep() below matches the data to one of the known types, then the # called subroutine will override these... # $id = "Data stream is not a known image file format"; $x = undef; $y = undef; grep($header =~ /$_/ && (($x, $y, $id) = &{$type_map{$_}}($handle)), keys %type_map); # # 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: # $cache{$stream} = join(',', $mtime, $x, $y, $id) unless (ref $stream or (! defined $x)); # # If we were passed an existant file handle, we need to restore the # old filepos: # seek($handle, $save_pos, 0) if $need_restore; # ...and if we opened the file ourselves, we need to close it close($handle) if $need_close; # results: return (wantarray) ? ($x, $y, $id) : ();}sub html_imgsize{ my @args = imgsize(@_); # Use lowercase and quotes so that it works with xhtml. return ((defined $args[0]) ? sprintf('width="%d" height="%d"', @args) : undef);}sub attr_imgsize{ my @args = imgsize(@_); return ((defined $args[0]) ? (('-width', '-height', @args)[0, 2, 1, 3]) : undef);}# This used only in gifsize:sub img_eof{ my $stream = shift; return ($last_pos >= length($$stream)) if (ref($stream) eq "SCALAR"); eof $stream;}############################################################################ Subroutine gets the size of the specified GIF###########################################################################sub gifsize{ my $stream = shift; my ($cmapsize, $buf, $h, $w, $x, $y, $type); my $gif_blockskip = sub { my ($skip, $type) = @_; my ($lbuf); &$read_in($stream, $skip); # Skip header (if any) while (1) { if (&img_eof($stream)) { return (undef, undef, "Invalid/Corrupted GIF (at EOF in GIF $type)"); } $lbuf = &$read_in($stream, 1); # Block size last if ord($lbuf) == 0; # Block terminator &$read_in($stream, ord($lbuf)); # Skip data } }; $type = &$read_in($stream, 6); if (length($buf = &$read_in($stream, 7)) != 7 ) { return (undef, undef, "Invalid/Corrupted GIF (bad header)"); } ($x) = unpack("x4 C", $buf); if ($x & 0x80) { $cmapsize = 3 * (2**(($x & 0x07) + 1)); if (! &$read_in($stream, $cmapsize)) { return (undef, undef, "Invalid/Corrupted GIF (global color map too small?)"); } } FINDIMAGE: while (1) { if (&img_eof($stream)) { return (undef, undef, "Invalid/Corrupted GIF (at EOF w/o Image Descriptors)"); } $buf = &$read_in($stream, 1); ($x) = unpack("C", $buf); if ($x == 0x2c) { # Image Descriptor (GIF87a, GIF89a 20.c.i) if (length($buf = &$read_in($stream, 8)) != 8) { return (undef, undef, "Invalid/Corrupted GIF (missing image header?)"); } ($x, $w, $y, $h) = unpack("x4 C4", $buf); $x += $w * 256; $y += $h * 256; return ($x, $y, 'GIF'); } if ($x == 0x21) { # Extension Introducer (GIF89a 23.c.i, could also be in GIF87a) $buf = &$read_in($stream, 1); ($x) = unpack("C", $buf); if ($x == 0xF9) { # Graphic Control Extension (GIF89a 23.c.ii) &$read_in($stream, 6); # Skip it next FINDIMAGE; # Look again for Image Descriptor } elsif ($x == 0xFE) { # Comment Extension (GIF89a 24.c.ii) &$gif_blockskip(0, "Comment"); next FINDIMAGE; # Look again for Image Descriptor } elsif ($x == 0x01) { # Plain Text Label (GIF89a 25.c.ii) &$gif_blockskip(13, "text data"); next FINDIMAGE; # Look again for Image Descriptor } elsif ($x == 0xFF) { # Application Extension Label (GIF89a 26.c.ii) &$gif_blockskip(12, "application data"); next FINDIMAGE; # Look again for Image Descriptor } else { return (undef, undef, sprintf("Invalid/Corrupted GIF (Unknown " . "extension %#x)", $x)); } } else { return (undef, undef, sprintf("Invalid/Corrupted GIF (Unknown code %#x)", $x)); } }}sub xbmsize{ my $stream = shift; my $input; my ($x, $y, $id) = (undef, undef, "Could not determine XBM size"); $input = &$read_in($stream, 1024); if ($input =~ /^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)/si) { ($x, $y) = ($1, $2); $id = 'XBM'; } ($x, $y, $id);}# Added by Randy J. Ray, 30 Jul 1996# Size an XPM file by looking for the "X Y N W" line, where X and Y are# dimensions, N is the total number of colors defined, and W is the width of# a color in the ASCII representation, in characters. We only care about X & Y.sub xpmsize{ my $stream = shift; my $line; my ($x, $y, $id) = (undef, undef, "Could not determine XPM size"); while ($line = &$read_in($stream, 1024)) { next unless ($line =~ /"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"/s); ($x, $y) = ($1, $2); $id = 'XPM'; last; } ($x, $y, $id);}# pngsize : gets the width & height (in pixels) of a png file# cor this program is on the cutting edge of technology! (pity it's blunt!)## Re-written and tested by tmetro@vl.comsub pngsize{ my $stream = shift; my ($x, $y, $id) = (undef, undef, "could not determine PNG size"); my ($offset, $length); # Offset to first Chunk Type code = 8-byte ident + 4-byte chunk length + 1 $offset = 12; $length = 4; if (&$read_in($stream, $length, $offset) eq 'IHDR') { # IHDR = Image Header $length = 8; ($x, $y) = unpack("NN", &$read_in($stream, $length)); $id = 'PNG'; } ($x, $y, $id);}# jpegsize: gets the width and height (in pixels) of a jpeg file# Andrew Tong, werdna@ugcs.caltech.edu February 14, 1995# modified slightly by alex@ed.ac.uk# and further still by rjray@tsoft.com# optimization and general re-write from tmetro@vl.com
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -