in reply to Image size in pure perl

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.

Replies are listed 'Best First'.
Re: Re: Image size in pure perl
by tachyon (Chancellor) on Mar 07, 2003 at 01:29 UTC

    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