home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / TIFF.pm < prev    next >
Encoding:
Perl POD Document  |  2004-01-07  |  4.8 KB  |  200 lines

  1. package Image::Info::TIFF;
  2.  
  3. =begin register
  4.  
  5. MAGIC: /^MM\x00\x2a/
  6. MAGIC: /^II\x2a\x00/
  7.  
  8. The C<TIFF> spec can be found at:
  9. http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf
  10.  
  11. Also good writeup on exif spec at:
  12. http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
  13.  
  14. =end register
  15.  
  16. =cut
  17.  
  18. use strict;
  19. use Config;
  20. use Image::TIFF;
  21.  
  22. sub my_read
  23. {
  24.     my($source, $len) = @_;
  25.     my $buf;
  26.     my $n = read($source, $buf, $len);
  27.     die "read failed: $!" unless defined $n;
  28.     die "short read ($len/$n)" unless $n == $len;
  29.     $buf;
  30. }
  31. sub my_readbytes
  32. {
  33.     my ($fh,$offset,$len) = @_;
  34.     my $curoffset = tell($fh);
  35.     my $buf;
  36.     seek($fh,$offset,0);
  37.     my $n = read($fh,$buf,$len);
  38.     die "short read($len/$n)" unless $n == $len;
  39.     # back to before.
  40.     seek($fh,$curoffset,0);
  41.     return $buf;
  42. }
  43.  
  44. sub my_readrational
  45. {
  46.     my ($fh,$offset,$byteorder,$count,$ar,$signed) = @_;
  47.     my $curoffset = tell($fh);
  48.     my $buf;
  49.     seek($fh,$offset,0);
  50.     while ($count > 0) {
  51.     my $num;
  52.     my $denom;
  53.     if ($signed) {
  54.         $num = unpack("l",my_read_order($fh,4,$byteorder));
  55.         $denom = unpack("l",my_read_order($fh,4,$byteorder));
  56.     } else {
  57.         $num = unpack("L",my_read_order($fh,4,$byteorder));
  58.         $denom = unpack("L",my_read_order($fh,4,$byteorder));
  59.     }
  60.     push(@{$ar},new Image::TIFF::Rational($num,$denom));
  61.     $count--;
  62.     }
  63.     # back to before.
  64.     seek($fh,$curoffset,0);
  65. }
  66.  
  67. sub my_read_order
  68. {
  69.     my($source, $len,$byteorder) = @_;
  70.     my $buf;
  71.     my $n = read($source, $buf, $len);
  72.     # maybe reverse
  73.     if ($byteorder ne $Config{byteorder}) {
  74.     my @bytes = unpack("C$len",$buf);
  75.     my @newbytes;
  76.     # swap bytes
  77.     for (my $i = $len-1; $i >= 0; $i--) {
  78.         push(@newbytes,$bytes[$i]);
  79.     }
  80.     $buf = pack("C$len",@newbytes);
  81.     }
  82.     die "read failed: $!" unless defined $n;
  83.     die "short read ($len/$n)" unless $n == $len;
  84.     $buf;
  85. }
  86.  
  87. my %order = (
  88.          "MM\x00\x2a" => '4321',
  89.          "II\x2a\x00" => '1234',
  90.          );
  91.  
  92. sub process_file
  93. {
  94.     my($info, $fh) = @_;
  95.  
  96.     my $soi = my_read($fh, 4);
  97.     die "SOI missing" unless (defined($order{$soi}));
  98.     # XXX: should put this info in all pages?
  99.     $info->push_info(0, "file_media_type" => "image/tiff");
  100.     $info->push_info(0, "file_ext" => "tif");
  101.  
  102.     my $byteorder = $order{$soi};
  103.     #print "TIFF byte order $byteorder, our byte order: $Config{byteorder}\n";
  104.     my $ifdoff = unpack("L",my_read_order($fh,4,$byteorder));
  105.     #print "first dir at $ifdoff\n";
  106.     &process_ifds($info,$fh,0,0,$byteorder,$ifdoff);
  107. }
  108.  
  109. sub process_ifds {
  110.     my($info, $fh,$page, $tagsseen, $byteorder,$offset) = @_;
  111.     my $curpos = tell($fh);
  112.     seek($fh,$offset,0);
  113.  
  114.     my $n = unpack("S",my_read_order($fh, 2, $byteorder));
  115.     my $i = 1;
  116.     while ($n > 0) {
  117.     # process one IFD entry
  118.     my $tag = unpack("S",my_read_order($fh,2,$byteorder));
  119.     my $fieldtype = unpack("S",my_read_order($fh,2,$byteorder));
  120.     my $count = unpack("L",my_read_order($fh,4,$byteorder));
  121.     my $offset;
  122.     if ($fieldtype == 3 && $count <= 1) {
  123.         $offset = unpack("S",my_read_order($fh,2,$byteorder));
  124.         # skip rest
  125.         my_read_order($fh,2,$byteorder);
  126.     } else {        # fieldtype == 4
  127.         $offset = unpack("L",my_read_order($fh,4,$byteorder));
  128.     }
  129.     my $val = "";
  130.     if ($fieldtype == 2) {
  131.         $val = my_readbytes($fh,$offset,$count);
  132.     } elsif (($fieldtype == 3 || $fieldtype == 4) &&
  133.         $count == 1) {
  134.         $val = $offset;
  135.     } elsif ($fieldtype == 3 && $count == 2) {
  136.         # array
  137.         $val = [];
  138.         push(@$val,$offset & 0xffff);
  139.         push(@$val,$offset >> 16);
  140.     } elsif ($fieldtype == 4 && $count > 1) {
  141.         $val = [];
  142.         my $n = $count;
  143.         my $curoffset = tell($fh);
  144.         seek($fh,$offset,0);
  145.         while ($n > 0) {
  146.         $offset = unpack("L",my_read_order($fh,4,$byteorder));
  147.         push(@$val,$offset);
  148.         $n--;
  149.         }
  150.         seek($fh,$curoffset,0);
  151.     } elsif ($fieldtype == 5 || $fieldtype == 10) {
  152.         # rational
  153.         my $num;
  154.         my $denom;
  155.         $val = [];
  156.         if ($fieldtype == 5) {
  157.         my_readrational($fh,$offset,$byteorder,$count,$val,0);
  158.         } else {
  159.         #signed rational
  160.         my_readrational($fh,$offset,$byteorder,$count,$val,1);
  161.         }
  162.         # get rid of singleton array.
  163.         if ($#{$val} == 0) {
  164.         $val = $$val[0];
  165.         }
  166.     }
  167.     #look up tag
  168.     my $tn =  Image::TIFF->exif_tagname($tag);
  169.     if (ref($tn)) {
  170.         $val = $$tn{$offset};
  171.         $tn = $$tn{__TAG__};
  172.     }
  173.     if ($tn eq "NewSubfileType") {
  174.         # start new page if necessary
  175.         if ($tagsseen) {
  176.         $page++;
  177.         $tagsseen = 0;
  178.         }
  179.     } else {
  180.         $tagsseen = 1;
  181.     }
  182.     #print "$i/$page: tag: $tag ($tn), fieldtype: $fieldtype, count: $count, offset: $offset ($val)\n";
  183.     if ($tn eq "ExifOffset") {
  184.         # parse ExifSubIFD
  185.         &process_ifds($info,$fh,$byteorder,$offset);
  186.     }
  187.     $info->push_info($page, $tn => $val);
  188.     $n--;
  189.     $i++;
  190.     }
  191.     my $ifdoff = unpack("L",my_read_order($fh,4,$byteorder));
  192.     #print "next dir at $ifdoff\n";
  193.     if ($ifdoff) {
  194.     &process_ifds($info,$fh,$page, $tagsseen, $byteorder,$ifdoff);
  195.     }
  196.     # back to before
  197.     seek($fh,$curpos,0);
  198. }
  199. 1;
  200.