home *** CD-ROM | disk | FTP | other *** search
- package Image::Info::TIFF;
-
- =begin register
-
- MAGIC: /^MM\x00\x2a/
- MAGIC: /^II\x2a\x00/
-
- The C<TIFF> spec can be found at:
- http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf
-
- Also good writeup on exif spec at:
- http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
-
- =end register
-
- =cut
-
- use strict;
- use Config;
- use Image::TIFF;
-
- sub my_read
- {
- my($source, $len) = @_;
- my $buf;
- my $n = read($source, $buf, $len);
- die "read failed: $!" unless defined $n;
- die "short read ($len/$n)" unless $n == $len;
- $buf;
- }
- sub my_readbytes
- {
- my ($fh,$offset,$len) = @_;
- my $curoffset = tell($fh);
- my $buf;
- seek($fh,$offset,0);
- my $n = read($fh,$buf,$len);
- die "short read($len/$n)" unless $n == $len;
- # back to before.
- seek($fh,$curoffset,0);
- return $buf;
- }
-
- sub my_readrational
- {
- my ($fh,$offset,$byteorder,$count,$ar,$signed) = @_;
- my $curoffset = tell($fh);
- my $buf;
- seek($fh,$offset,0);
- while ($count > 0) {
- my $num;
- my $denom;
- if ($signed) {
- $num = unpack("l",my_read_order($fh,4,$byteorder));
- $denom = unpack("l",my_read_order($fh,4,$byteorder));
- } else {
- $num = unpack("L",my_read_order($fh,4,$byteorder));
- $denom = unpack("L",my_read_order($fh,4,$byteorder));
- }
- push(@{$ar},new Image::TIFF::Rational($num,$denom));
- $count--;
- }
- # back to before.
- seek($fh,$curoffset,0);
- }
-
- sub my_read_order
- {
- my($source, $len,$byteorder) = @_;
- my $buf;
- my $n = read($source, $buf, $len);
- # maybe reverse
- if ($byteorder ne $Config{byteorder}) {
- my @bytes = unpack("C$len",$buf);
- my @newbytes;
- # swap bytes
- for (my $i = $len-1; $i >= 0; $i--) {
- push(@newbytes,$bytes[$i]);
- }
- $buf = pack("C$len",@newbytes);
- }
- die "read failed: $!" unless defined $n;
- die "short read ($len/$n)" unless $n == $len;
- $buf;
- }
-
- my %order = (
- "MM\x00\x2a" => '4321',
- "II\x2a\x00" => '1234',
- );
-
- sub process_file
- {
- my($info, $fh) = @_;
-
- my $soi = my_read($fh, 4);
- die "SOI missing" unless (defined($order{$soi}));
- # XXX: should put this info in all pages?
- $info->push_info(0, "file_media_type" => "image/tiff");
- $info->push_info(0, "file_ext" => "tif");
-
- my $byteorder = $order{$soi};
- #print "TIFF byte order $byteorder, our byte order: $Config{byteorder}\n";
- my $ifdoff = unpack("L",my_read_order($fh,4,$byteorder));
- #print "first dir at $ifdoff\n";
- &process_ifds($info,$fh,0,0,$byteorder,$ifdoff);
- }
-
- sub process_ifds {
- my($info, $fh,$page, $tagsseen, $byteorder,$offset) = @_;
- my $curpos = tell($fh);
- seek($fh,$offset,0);
-
- my $n = unpack("S",my_read_order($fh, 2, $byteorder));
- my $i = 1;
- while ($n > 0) {
- # process one IFD entry
- my $tag = unpack("S",my_read_order($fh,2,$byteorder));
- my $fieldtype = unpack("S",my_read_order($fh,2,$byteorder));
- my $count = unpack("L",my_read_order($fh,4,$byteorder));
- my $offset;
- if ($fieldtype == 3 && $count <= 1) {
- $offset = unpack("S",my_read_order($fh,2,$byteorder));
- # skip rest
- my_read_order($fh,2,$byteorder);
- } else { # fieldtype == 4
- $offset = unpack("L",my_read_order($fh,4,$byteorder));
- }
- my $val = "";
- if ($fieldtype == 2) {
- $val = my_readbytes($fh,$offset,$count);
- } elsif (($fieldtype == 3 || $fieldtype == 4) &&
- $count == 1) {
- $val = $offset;
- } elsif ($fieldtype == 3 && $count == 2) {
- # array
- $val = [];
- push(@$val,$offset & 0xffff);
- push(@$val,$offset >> 16);
- } elsif ($fieldtype == 4 && $count > 1) {
- $val = [];
- my $n = $count;
- my $curoffset = tell($fh);
- seek($fh,$offset,0);
- while ($n > 0) {
- $offset = unpack("L",my_read_order($fh,4,$byteorder));
- push(@$val,$offset);
- $n--;
- }
- seek($fh,$curoffset,0);
- } elsif ($fieldtype == 5 || $fieldtype == 10) {
- # rational
- my $num;
- my $denom;
- $val = [];
- if ($fieldtype == 5) {
- my_readrational($fh,$offset,$byteorder,$count,$val,0);
- } else {
- #signed rational
- my_readrational($fh,$offset,$byteorder,$count,$val,1);
- }
- # get rid of singleton array.
- if ($#{$val} == 0) {
- $val = $$val[0];
- }
- }
- #look up tag
- my $tn = Image::TIFF->exif_tagname($tag);
- if (ref($tn)) {
- $val = $$tn{$offset};
- $tn = $$tn{__TAG__};
- }
- if ($tn eq "NewSubfileType") {
- # start new page if necessary
- if ($tagsseen) {
- $page++;
- $tagsseen = 0;
- }
- } else {
- $tagsseen = 1;
- }
- #print "$i/$page: tag: $tag ($tn), fieldtype: $fieldtype, count: $count, offset: $offset ($val)\n";
- if ($tn eq "ExifOffset") {
- # parse ExifSubIFD
- &process_ifds($info,$fh,$byteorder,$offset);
- }
- $info->push_info($page, $tn => $val);
- $n--;
- $i++;
- }
- my $ifdoff = unpack("L",my_read_order($fh,4,$byteorder));
- #print "next dir at $ifdoff\n";
- if ($ifdoff) {
- &process_ifds($info,$fh,$page, $tagsseen, $byteorder,$ifdoff);
- }
- # back to before
- seek($fh,$curpos,0);
- }
- 1;
-