These short routines will return the size of GIF, JPEG and PNG images without the need for external libraries.

#!/usr/bin/perl -w use strict; sub sizePNG { return unless $_[0]; my ($width, $height); ($width, $height) = unpack( "NN", $1 ) if $_[0] =~ /IHDR(........) +/; return ($width,$height); } sub sizeGIF { return unless $_[0]; my ($width, $height); ($width, $height) = unpack( "SS", $1 ) if $_[0] =~ /^GIF8..(....)/ +; return ($width,$height); } sub sizeJPG { return unless $_[0]; my ($width, $height); ($height,$width) = unpack( "nn", $1 ) if $_[0] =~ /\xFF\xC0...(... +.)/; return ($width,$height); } sub get_file { open FILE, $_[0] or die $!; binmode FILE; local $/; my $data = <FILE>; close FILE; return $data; } my $gif = 'c:/sample.gif'; my $data = get_file($gif); my @res = sizeGIF($data); print "$gif width $res[0] height $res[1]\n"; my $jpg = 'c:/sample.jpg'; $data = get_file($jpg); @res = sizeJPG($data); print "$jpg width $res[0] height $res[1]\n"; my $png = 'c:/sample.png'; $data = get_file($png); @res = sizePNG($data); print "$png width $res[0] height $res[1]\n";

Replies are listed 'Best First'.
Re: Image size in pure perl
by PodMaster (Abbot) on Mar 06, 2003 at 12:55 UTC
    That's neato, but <hat type="merlyn"> Yeah, CPAN already has that ;) </hat> and it is called Image::Size
    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); # Assuming that $buf was the data, imgsize() needed a referenc +e to a scalar


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    I run a Win32 PPM repository for perl 5.6x+5.8x. I take requests.
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      It's also called Image::Info

      --
      I'm not belgian but I play one on TV.

      Image::Size requires Image::Magic which in its turn require the libmagic libraries so this is not a pure Perl solution, nor is it nearly as portable. You can depend on having pack and unpack

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

        No it doesn't. Please examine the Makefile.PL and the documentation.
        Recognized Formats Image::Size natively understands and sizes data in the following formats:
        GIF 
        JPG 
        XBM 
        XPM 
        PPM family (PPM/PGM/PBM) 
        XV thumbnails 
        PNG 
        MNG 
        TIF 
        BMP 
        PSD (Adobe PhotoShop) 
        SWF (ShockWave/Flash) 
        PCD (Kodak PhotoCD, see notes below) 
        
        Additionally, if the Image::Magick module is present, the file types supported by it are also supported by Image::Size. See also "CAVEATS".
        There is a reason I am PodMaster ;D
        # NOTE: Derived from blib\lib\Image\Size.pm. # Changes made here will be lost when autosplit is run again. # See AutoSplit.pm. package Image::Size; #line 741 "blib\lib\Image\Size.pm (autosplit into blib\lib\auto\Image\ +Size\pngsize.al)" # pngsize : gets the width & height (in pixels) of a png file # cor this program is on the cutting edge of technology! (pity it's bl +unt!) # # Re-written and tested by tmetro@vl.com sub 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 le +ngth + 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); } # end of Image::Size::pngsize 1;


        MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
        I run a Win32 PPM repository for perl 5.6x+5.8x. I take requests.
        ** The Third rule of perl club is a statement of fact: pod is sexy.

Re: Image size in pure perl
by bart (Canon) on Mar 06, 2003 at 13:33 UTC
    I expect this to fail "mysteriously" for some values of image sizes, as /./ doesn't match "\n", which is a valid value for a binary byte.

    Also, I wouldn't be too surprised if occasionally, for some images, the regex would match a wrong part of the file.

    In summary: I wouldn't use this code if anybody's life depended on its proper workings.

      The . point is quite valid and cured by a /s. Here is my take which first gets the file type sig then does the deed. As you can see for GIF, and BMP the size info is a set number of bytes from the SOF. This is set down in the spec so there is no reason this should not be very reliable. Similarly the PNG spec has the 'IHDR' sequence denoting the start of the header. In all the PNGs I have seen this sequence is 12 bytes from the SOF but as this does not appear formally in the spec just grabbing the first IHDR seems pretty reasonable to me.

      With JPEG the SOFn sig \xFF\xC0 is followed 3 bytes later (2 for length, 1 for precison) by the size info. 0xFF is the SOF marker and 0xC0 is the (n) baseline marker. This 2 byte sequence should not appear in the header so that should not be a problem. A ?real problem is the ability to embed a thumbnail so you have 2 SOFn sections (one is the thumbnail, the next the image) - with this simplistic approach you will get the first dimension (possibly the thumbnail size not the main image size). Other than that caveat I don't see why this should not be a reliable approach given that all the format specs are set down.

      #!/usr/bin/perl -w use strict; sub image_size { return unless $_[0]; my ($width, $height, $sig); if ( $_[0] =~ m/^GIF8..(....)/s ) { $sig = 'GIF'; # found GIF signature ($width, $height) = unpack( "SS", $1 ); } elsif ( $_[0] =~ m/^^\xFF\xD8.{4}JFIF/s ) { $sig = 'JPEG'; # found JPG signature ($height,$width) = unpack( "nn", $1 ) if $_[0] =~ /\xFF\xC0... +(....)/s; } elsif ( $_[0] =~ /^\x89PNG\x0d\x0a\x1a\x0a/ ) { $sig = 'PNG'; # found PNG signature ($width, $height) = unpack( "NN", $1 ) if $_[0] =~ /IHDR(.{8}) +/s; } elsif ( $_[0] =~ /BM.{16}(.{8})/s ) { $sig = 'BMP'; # found bitmap sig ($width, $height) = unpack( "LL", $1); } return $width, $height, $sig; } sub get_file { open FILE, $_[0] or die $!; binmode FILE; local $/; my $data = <FILE>; close FILE; return $data; } for my $img ( qw( c:/sample.bmp c:/sample.jpg c:/sample.gif c:/sample. +png) ) { my $data = get_file($img); my @res = image_size($data); print "$img $res[2] width $res[0] height $res[1]\n"; } __END__ c:/sample.bmp BMP width 512 height 384 c:/sample.jpg JPEG width 100 height 149 c:/sample.gif GIF width 110 height 58 c:/sample.png PNG width 256 height 192

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Image size in pure perl
by gannett (Novice) on May 26, 2020 at 16:14 UTC
    Just tried this code in May 2020 works for .gif .png but was returning blank results for .jpg files. The file type was recognised but the size marker string was not found.
    $ file sample.jpg sample.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), den +sity 123x123, segment length 16, progressive, precision 8, 1024x1448, + frames 3 $ perl -v This is perl 5, version 22, subversion 1 (v5.22.1) built for darwin-th +read-multi-2level $ hexdump -C sample.jpg | head -30 00000000 ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 7b |......JFI +F.....{| 00000010 00 7b 00 00 ff db 00 43 00 01 01 01 01 01 01 01 |.{.....C. +.......| 00000020 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 |......... +.......|* 00000090 01 01 01 01 01 01 01 01 01 01 01 01 01 01 >>>> ff c2 <<<< + |................| 000000a0 00 11 08 >>> 05 a8 04 00 <<<< 03 01 22 00 02 11 01 03 11 | +........."......| 000000b0 01 ff c4 00 1e 00 01 00 01 04 03 01 01 00 00 00 |......... +.......| 000000c0 00 00 00 00 00 00 00 06 05 07 08 09 03 04 0a 02 |......... +.......|
    Looking for size bytes 05 a8 04 00 and a marker a few bytes before shows the marker to be ff c2 . Changing
    elsif ( $_[0] =~ m/^^\xFF\xD8.{4}JFIF/s ) { $sig = 'JPEG'; # found JPG signature ($height,$width) = unpack( "nn", $1 ) if $_[0] =~ /\xFF\xC0...(....)/s; to elsif ( $_[0] =~ m/^^\xFF\xD8.{4}JFIF/s ) { $sig = 'JPEG'; ($height,$width) = unpack( "nn", $1 ) if $_[0] =~ /\xFF\xC2...(....)/s; along with the driver for my $img ( qw( ./sample.jpg ./sampleC.jpg ) ) { my $data = get_file($img); my @res = image_size($data); print "\nNative $img $res[2] width $res[0] height $res[1]\n"; ($x, $y) = imgsize($img); print "Image::Size ($x, $y)\n"
    gives a working code set. Adding the Image::Size method to test along size gives
    Native ./sample.jpg JPEG width 1024 height 1448 Image::Size (1024, 1448) Native ./sampleC.jpg JPEG width 617 height 1220 Image::Size (617, 1220)
    Not sure what changed or if this is just a mac thing but wanted to leave this testament for following monks.
      Looking at the Wiki page for jpeg I see that the size marker tag is 0xFF 0xCO for baseline images and 0xFF 0xC2 for progressive images. Also marker for a JFIF is 0xFF 0xD8 0xFF Updating complete sub image_size to ...
      sub image_size { return unless $_[0]; my ($width, $height, $sig); if ( $_[0] =~ m/^GIF8..(....)/s ) { $sig = 'GIF'; # found GIF signature ($width, $height) = unpack( "SS", $1 ); } elsif ( $_[0] =~ m/^^\xFF\xD8\xFF.{3}JFIF/s ) { $sig = 'JPEG'; ($height,$width) = unpack( "nn", $1 ) if $_[0] =~ /\xFF\xC0...(....)/s; #Baseline Image ($height,$width) = unpack( "nn", $1 ) if $_[0] =~ /\xFF\xC2...(....)/s; #Pogressive Images } elsif ( $_[0] =~ /^\x89PNG\x0d\x0a\x1a\x0a/ ) { $sig = 'PNG'; # found PNG signature ($width, $height) = unpack( "NN", $1 ) if $_[0] =~ /IHDR(.{8})/s; } elsif ( $_[0] =~ /BM.{16}(.{8})/s ) { $sig = 'BMP'; # found bitmap sig ($width, $height) = unpack( "LL", $1); } return $width, $height, $sig; }
Re: Image size in pure perl
by gmpassos (Priest) on Mar 07, 2003 at 06:12 UTC
    Please, insert the /s in your REGEX, to tell that it's not multi line, or wont work if you have \r\n? in the data!

    Your REGEX need to be:

    if $_[0] =~ /^GIF8..(....)/s;

    Note that width and height generally, like on BMP, are write in byte integer, in other words, they can have any type of byte, from 0 to 255.

    For example, a BMP image with the width of 2570, has the byte integer as "\n\n\0\0".

    Graciliano M. P.
    "The creativity is the expression of the liberty".