From owner-FreeBSD-users-jp@jp.FreeBSD.org Wed Jul 16 09:24:58 2003
Received: (from daemon@localhost)
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) id h6G0Oww83312;
	Wed, 16 Jul 2003 09:24:58 +0900 (JST)
	(envelope-from owner-FreeBSD-users-jp@jp.FreeBSD.org)
Received: from mail1.accsnet.ne.jp (mail1.accsnet.ne.jp [211.0.138.69])
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) with ESMTP/inet id h6G0OwT83302
	for <FreeBSD-users-jp@jp.FreeBSD.org>; Wed, 16 Jul 2003 09:24:58 +0900 (JST)
	(envelope-from ushida@msa.biglobe.ne.jp)
Received: from olive.localdomain (215.249.accsnet.ne.jp [202.220.249.215])
	by mail1.accsnet.ne.jp (8.9.3/3.7W-ns) with ESMTP id JAA10820
	for <FreeBSD-users-jp@jp.FreeBSD.org>; Wed, 16 Jul 2003 09:24:53 +0900 (JST)
Received: by olive.localdomain (Postfix, from userid 1000)
	id 2E469101; Wed, 16 Jul 2003 09:24:53 +0900 (JST)
From: Jun USHIDA <ushida@msa.biglobe.ne.jp>
To: FreeBSD-users-jp@jp.FreeBSD.org
In-Reply-To: Your message of "Mon, 14 Jul 2003 07:45:26 +0900".
	<030714074526.M0112521@ns.kobe1995.net>
References: <030714074526.M0112521@ns.kobe1995.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Message-ID: <030716092451.M0146472@ushida.msa.biglobe.ne.jp>
X-Mailer: mnews [version 1.22PL5] 2001-02/07(Wed)
Reply-To: FreeBSD-users-jp@jp.FreeBSD.org
Precedence: list
Date: Wed, 16 Jul 2003 09:24:53 +0900
X-Sequence: FreeBSD-users-jp 75412
Subject: [FreeBSD-users-jp 75412] Re: Exif viewer
Sender: owner-FreeBSD-users-jp@jp.FreeBSD.org
X-Originator: ushida@msa.biglobe.ne.jp
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+030702

<030714074526.M0112521@ns.kobe1995.net>$B$N5-;v$K$*$$$F(B
2003$BG/(B07$B7n(B14$BF|(B($B7n(B) 07$B;~(B45$BJ,(B26$BIC:"!"(Bkaz$B$5$s$O=q$+$l$^$7$?!%(B

|$B%G%8%+%aEy$G;#1F$7$?2hA|%U%!%$%k$N(BExif$B>pJs$r%@%s%W$9$k%D!<%k$H$+!"(B

Olympus C-2040 $B$N(B EXIF $BMQ$K;H$C$F$$$k<+:n%"%J%i%$%6$G$9!%(B
Olympus $BFH<+$N(BTag $B$b0lItBP1~$7$F$^$9$,!$>\:Y$O$o$+$i$J$$$?$a(B
$B2r@O$G$-$F$$$J$$ItJ,$b$"$j$^$9!%3F<RFH<+$N(BTag$B$NItJ,!$(B
$B$I$C$+$K8x3+$5$l$F$l$P$$$$$N$@$1$I(B.
--
Ushida

#!/usr/local/bin/perl -w
#------------------------------------------------------------------------------
#     EXIF analyzer for JPEG file created with Olympus Digital Camera
#
# COPYRIGHT and DISCLAIMER 
#  Copyright 2001 Jun Ushida <ushida@msa.biglobe.ne.jp> All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
###############################################################################
use strict 'subs';
use Getopt::Std;
$|=1;
$debug = 0;
# TAG list that you want to print. Print all if the first element is one(1).
@printlist = (1);
##@printlist = (1);  # print all!
##@printlist = (@printlist,0x010e,0x010f,0x0110,0x011a,0x011b); 
#@printlist = (@printlist,0x011a,0x011b); 
#@printlist = (@printlist,0x0132,0x829a,0x829d,0x8822);
#@printlist = (@printlist,0x8827,0x9204,0x9205,0x9207,0x9208);
#@printlist = (@printlist,0x9209,0x920a,0xa001,0xa002,0xa003);
#@printlist = (@printlist,0x0200,0x0202,0x0204);
#@printlist = (@printlist,0x021);

#--- get name of this script -------------------------------------------------
($command = $0) =~ s#.*/##;

#--- get version of this script from RCS keyword -----------------------------
$rev_tmp = '$Revision: 1.2 $';    # This line is modified when it checks in. 
$rev_tmp =~ s/\$//g;
$rev_tmp =~ /^\Revision:\s(.*)$/o;
$version = $1;

#----- Command line options --------------------------------------------------
getopts('hdo:t:');
Print_Help() if ($#ARGV);
Print_Help(), undef $opt_h if $opt_h;
$debug = 1,   undef $opt_d if $opt_d;
$thumbnailfile = $opt_t if $opt_t;
open(DUMP,">$opt_o") or die "Can't open $opt_o: $!\n" if $opt_o;
$file = $ARGV[0];
#-----------------------------------------------------------------------------
$mean = {
# Olympus Original (MakerNote)
    0x0200 => "Olympus Special Mode",
    0x0201 => "Olympus JpegQual",
    0x0202 => "Olympus Macro",
    0x0203 => "Olympux Unknown",
    0x0204 => "Olympus Digizoom",
    0x0205 => "Olympus Unknown",
    0x0206 => "Olympus Unknown",
    0x0207 => "Olympus SoftwareRelease",
    0x0208 => "Olympus PictInfo",
    0x0209 => "Olympus CameraID",
    0x0300 => "Olympus Unknown",
    0x0301 => "Olympus Unknown",
    0x0302 => "Olympus Unknown",
    0x0303 => "Olympus Unknown",
    0x0304 => "Olympus Unknown",
    0x0f00 => "Olympus Unknown",
#
    0x0100 => "ImageWidth",
    0x0101 => "ImageLength",
    0x0102 => "BitsPerSample",
    0x0103 => "Compression",
    0x0106 => "PhotometricInterpretation",
    0x010e => "ImageDescription",
    0x010f => "Make",
    0x0110 => "Model",
    0x0111 => "StripOffsets",
    0x0112 => "Orientation",
    0x0115 => "SamplesPerPixel",
    0x0116 => "RowsPerStrip",
    0x0117 => "StripByteCounts",
    0x011a => "XResolution",
    0x011b => "YResolution",
    0x011c => "PlanarConfiguration",
    0x0128 => "ResolutionUnit",
    0x012d => "TransferFunction",
    0x0131 => "Software",
    0x0132 => "DateTime",
    0x013b => "Artist",
    0x013e => "WhitePoint",
    0x013f => "PrimaryChromaticities",
#
    '0201' => "Offset to JPEG SOI",
    '0202' => "Bytes of JPEG data",
#
    0x0211 => "YCbCrCoefficients",
    0x0212 => "YCbCrSubSampling",
    0x0213 => "YCbCrPositioning",
    0x0214 => "ReferenceBlackWhite",
    0x8769 => "Exif IFD Pointer",
    0x8298 => "Copyright",
    0x8769 => "Exif IFD Pointer",
    0x8825 => "GPSInfo IFD Pointer",
    0x829a => "ExposureTime",
    0x829d => "FNumber",
    0x8822 => "ExposureProgram",
    0x8824 => "SpectralSensitivity",
    0x8827 => "ISOSpeedRatings",
    0x8828 => "OECF",
    0x9000 => "ExifVersion",
    0x9003 => "DateTimeOriginal",
    0x9004 => "DateTimeDigitized",
    0x9101 => "ComponentsConfiguration",
    0x9102 => "CompressedBitsPerPixel",
    0x9201 => "ShutterSpeedValue",
    0x9202 => "ApertureValue",
    0x9203 => "BrightnessValue",
    0x9204 => "ExposureBiasValue",
    0x9205 => "MaxApertureValue",
    0x9206 => "SubjestDistance",
    0x9207 => "MeteringMode",
    0x9208 => "LightSource",
    0x9209 => "Flash",
    0x920a => "FocalLength",
    0x927c => "MakerNote",
    0x9286 => "UserComment",
    0x9290 => "SubSecTime",
    0x9291 => "SubSecTimeOriginal",
    0x9292 => "SubSecTimeDigitized",
    0xa000 => "FlashPixVersion",
    0xa001 => "ColorSpace",
    0xa002 => "PixelXDimension",
    0xa003 => "PixelYDimension",
    0xa004 => "RelatedSoundFile",
    0xa005 => "Interoperability IFD Pointer",
    0xa20b => "FlashEnergy",
    0xa20c => "SpatialFrequencyResponse",
    0xa20e => "FocalPlaneXResolution",
    0xa20f => "FocalPlaneYResolution",
    0xa210 => "FocalPlaneResolutionUnit",
    0xa214 => "SubjectLocation",
    0xa215 => "ExposureIndex",
    0xa217 => "SensingMethod",
    0xa300 => "FileSource",
    0xa301 => "SceneType",
    0xa302 => "CFAPattern",
    0x0001 => "Interop. Index",
    0x0002 => "Interop. Version",
    };
##############################################################################
sub end
{
    my ($msg) = @_;
    print "Error($command): $msg\n";
    exit 1;
}

#-----------------------------------------------------------------------------
print "Filename : $file\n\n";
print "x"x78,"\n";
printf ("Title       : Analized Data of EXIF file created ");
printf ("by Olympus Digital Camera\n");
printf ("Creator     : $command Version $version ");
printf ("Copyright 2000,2001  Jun Ushida\n");
printf ("CreationDate: %s\n",scalar(localtime));
print "x"x78,"\n\n";
printf ("====== Debugging Information ") if $debug; 
print "="x49,"\n\n" if $debug;
#-----------------------------------------------------------------------------
open(READ, $file) or die "Can't open $file: $!\n";
end("read SOI marker.")        if (read(READ, $soi_marker, 2) != 2);
end("No SOI marker('ff d8').") if ($soi_marker ne "\377\330");
end("read APP1 marker.")       if (read(READ, $app1_marker, 2) != 2);
end("No APP1 marker('ff e1').")if ($app1_marker ne "\377\341");
end("read APP1 size.")         if (read(READ, $app1_size, 2) != 2);
$app1_length = unpack('n', $app1_size);
if (read(READ, $body, $app1_length -2) != $app1_length -2){end("read APP1");}
close(READ);
$buf = $soi_marker . $app1_marker . $app1_size . $body;
#
syswrite(DUMP, $buf, $app1_length + 6 ) if $opt_o;  
##############################################################################
$base_offset = 12;
# Address of First IFD
$add_of_num_of_entries = unpack( "V" , substr( $buf , 16 , 4 ) ) ; 

while($add_of_num_of_entries){
    printf STDERR ("Current address: %08x\n",$add_of_num_of_entries) if $debug;
    $next_add = getdirectory($add_of_num_of_entries);
    printf STDERR ("Next    address: %08x\n\n",$next_add) if $debug;
    $add_of_num_of_entries = $next_add;
}
# Exception !
if (defined $type->{0x0201}){
    printf STDERR ("Shuntting TAG 0x0201: New TAG :(char)0201\n") if $debug;
    $tag=0x0201;
    $newtag='0201'; # Special TAG   decimal value
    ($$type{$newtag}, $$size{$newtag}, $$offset{$newtag}) =
	($$type{$tag}, $$size{$tag}, $$offset{$tag});
    printf STDERR ("%2d tag=%04s , type=%2x , size=%2x , ",
		   0, $newtag ,$type->{$newtag}, $size->{$newtag})if $debug;
    printf STDERR ("offset=%4x , adr=%04x \n\n",
		       $offset->{$newtag}, $offset->{$newtag}+12 ) if $debug;
}
if (defined $type->{0x0202}){
    printf STDERR ("Shuntting TAG 0x0202: New TAG :(char)0202\n") if $debug;
    $tag=0x0202;
    $newtag='0202'; # Special TAG   decimal value
    ($$type{$newtag}, $$size{$newtag}, $$offset{$newtag}) =
	($$type{$tag}, $$size{$tag}, $$offset{$tag});
    printf STDERR ("%2d tag=%04d , type=%2x , size=%2x , ",
		   0, $newtag ,$type->{$newtag}, $size->{$newtag})if $debug;
    printf STDERR ("offset=%4x , adr=%04x \n\n",
		       $offset->{$newtag}, $offset->{$newtag}+12 ) if $debug;
}
##############################################################################
# Exif-specific IFD
if (defined $type->{0x8769}){
    print STDERR "Specific directory (tag is 0x8769) is defined\n" if $debug;
    getdirectory($offset->{0x8769});
    print STDERR "Finish reading Specific directory(tag is 0x8769)\n"if $debug;
    print STDERR "\n" if $debug;
}
if (defined $type->{0xa005}){
    print STDERR "Specific directory (tag is 0xa005) is defined\n" if $debug;
    getdirectory($offset->{0xa005});
    print STDERR "Finish reading Specific directory(tag is 0xa005)\n"if $debug;
    print STDERR "\n" if $debug;
}
if (defined $type->{0x927c}){
    print STDERR "Specific directory (tag is 0x927c) is defined\n" if $debug;
    getdirectory($offset->{0x927c} + 0x8);
    print STDERR "Finish reading Specific directory(tag is 0x927c)\n"if $debug;
    print STDERR "\n" if $debug;
}

#----  Subroutine getdirectory ------------------------------------------------
sub getdirectory{
# Input  : $address = ``Address of Number of Entries''
# Output : ``Address of Number of Entries of Next IFD''
    my($address) = @_;
# Number of Entries of First IFD
    $num_of_entries = unpack("v", substr($buf , $base_offset + $address, 2));
    printf STDERR ( "Number of Entries = %d \n" , $num_of_entries ) if $debug;

# pointer to a entry
    $entry_ptr = $base_offset + $address + 2;
    
    for($n = 0; $n < $num_of_entries; $n++){
	$tag = unpack("v", substr($buf, $entry_ptr, 2));
	($$type{$tag}, $$size{$tag}, $$offset{$tag}) 
	    = unpack("vVV", substr($buf, $entry_ptr + 0x2, 10));
	printf STDERR ("%2d tag=%04x , type=%2x , size=%2x , ",
		       $n+1, $tag ,$type->{$tag}, $size->{$tag}) if $debug;
	printf STDERR ("offset=%4x , adr=%04x \n",
		       $offset->{$tag}, $offset->{$tag}+12 ) if $debug;
	$entry_ptr += 12;
    }
    return unpack( "V", substr($buf, $entry_ptr, 4)); 
}

#----  dump Thumbnail --------------------------------------------------------
if ($opt_t){
    open(THUMB,">$thumbnailfile") or die "Can't open $thumbnailfile: $!\n";
    $thumb=substr($buf , $base_offset + $offset->{'0201'}, $offset->{'0202'});
    syswrite(THUMB, $thumb, $offset->{'0202'} );
    close(THUMB);
}

#------ Get All values pointed by address ------------------------------------
foreach $tag (sort keys %{$type}){
    $type->{$tag} = 0x07 if ($tag == 0x0001);  # Interop. Index Tag
#    printf("%04x ",$tag);
    if ($type->{$tag} == 0x2){ # Type : ASCII
	$value->{$tag} = substr($buf, $base_offset+$offset->{$tag},
				$size->{$tag}-1); # -1 for chomp
    }
    elsif($type->{$tag} == 0x5){ # Type : RATIONAL
	($value->{$tag}->{'numer'},$value->{$tag}->{'denom'}) 
	    = unpack("VV",substr($buf, $base_offset+$offset->{$tag}, 8));
    }
    elsif($type->{$tag} == 0xa){ # Type : Signed RATIONAL
	($value->{$tag}->{'numer'}, $value->{$tag}->{'denom'}) 
	    = unpack("VV", substr($buf, $base_offset+$offset->{$tag}, 8));
    }
}
######## print value #########################################################
print "-"x78,"\n";
printf ("NO  TAG  Description                     Value\n");
print "-"x78,"\n";
$ct = 1;
foreach $tag (sort keys %{$type}){
    $type->{$tag} = 0x07 if ($tag == 0x0001);  # Interop. Index Tag
    if ($printlist[0] == 1){
	$print_flag = 1;
    }else{
	$print_flag = 0;
    }
    foreach $chk (@printlist){
	if ($tag == $chk){
	    $print_flag = 1;
	}
    }
    next if ($print_flag != 1);
  read_data:{
#-----------------------------------------------------------------------------
      if ($type->{$tag} == 0x2){ # Type : ASCII
#	  $value->{$tag} = substr($buf, $base_offset+$offset->{$tag},
#				  $size->{$tag}-1); # -1 for chomp
	  printf("%02d %04x %-30s %-32s\n",$ct,
		 $tag, $mean->{$tag},$value->{$tag});
      }
#-----------------------------------------------------------------------------
      elsif($type->{$tag} == 0x3){ # Type : SHORT
	  if ($tag == 0x0103){  # Compression
	      $char = "No Compression"   if ($offset->{$tag} == 1);
	      $char = "JPEG Compression" if ($offset->{$tag} == 6);
	      printf("%02d %04x %-30s %d: %-20s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	  }
	  elsif ($tag == 0x0112){  # Orientation
	      $char = "Upper Left"  if ($offset->{$tag} == 1);
	      $char = "Lower Right" if ($offset->{$tag} == 3);
	      $char = "Upper Right" if ($offset->{$tag} == 6);
	      $char = "Lower Left"  if ($offset->{$tag} == 8);
	      $char = "Undefined"   if ($offset->{$tag} == 9);
	      printf("%02d %04x %-30s %d: %-15s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	  }
	  elsif($tag == 0x0128){ # ResolutionUnit
	      $char = "Unknown ";
	      $char = "No Unit"    if ($offset->{$tag} == 1);
	      $char = "Inch"       if ($offset->{$tag} == 2);
	      $char = "Centimetre" if ($offset->{$tag} == 3);
	      printf("%02d %04x %-30s %d: %-15s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	  }
	  elsif($tag == 0x8822){ # ExposureProgram
	      $char = "Unknown ";
	      $char = "Manual"            if ($offset->{$tag} == 1);
	      $char = "Program Normal"    if ($offset->{$tag} == 2);
	      $char = "Aperture Priority" if ($offset->{$tag} == 3);
	      $char = "Shutter Priority"  if ($offset->{$tag} == 4);
	      $char = "Program Creative"  if ($offset->{$tag} == 5);
	      $char = "Program Action"    if ($offset->{$tag} == 6);
	      $char = "Portrait Mode"     if ($offset->{$tag} == 7);
	      $char = "Landscape Mode"    if ($offset->{$tag} == 8);
	      printf("%02d %04x %-30s %d: %-20s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("\t(1:Manual,2:Program Normal,");
	      printf("3:Aperture Priority,4:Shutter Priority)\n");
	  }
	  elsif($tag == 0x9207){ # MeteringMode
	      $char = "Unknown ";
	      $char = "Average"                 if ($offset->{$tag} == 1);
	      $char = "Centre Weighted Average" if ($offset->{$tag} == 2);
	      $char = "Spot"                    if ($offset->{$tag} == 3);
	      $char = "Multi-Spot"              if ($offset->{$tag} == 4);
#	      $char = "Multi-Segment"           if ($offset->{$tag} == 5);
	      $char = "Multi-Segment(ESP)"     if ($offset->{$tag} == 5);
	      printf("%02d %04x %-30s %d: %-25s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("\t\t\t\t(3:Spot,5:Multi-Segment(ESP))\n");
	  }
	  elsif($tag == 0x9208){ # LightSource
	      $char = "Unknown ";
	      $char = "Auto"        if ($offset->{$tag} == 0);
	      $char = "Daylight"    if ($offset->{$tag} == 1);
	      $char = "Fluorescent" if ($offset->{$tag} == 2);
	      $char = "Tangsten"    if ($offset->{$tag} == 3);
	      $char = "Flash"       if ($offset->{$tag} == 10);
	      $char = "Cloudy"      if ($offset->{$tag} == 20);
	      printf("%02d %04x %-30s %d: %-20s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("\t(White Balance 0:Auto,1:Daylight,20:Cloudy,");
	      printf("3:Tangsten,2:Fluorescent)\n");
	  }
	  elsif($tag == 0x9209){ # Flash
	      $char = "Unknown ";
	      $char = "Not Fired"   if ($offset->{$tag} == 0);
	      $char = "Fired"       if ($offset->{$tag} == 1);
	      printf("%02d %04x %-30s %d: %-10s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("\t\t\t(0:Not Fired,1:Fired,others:Unknown)\n");
	  }
	  elsif($tag == 0xa001){ # ColorSpace
	      $char = "Unknown ";
	      $char = "sRGB"           if ($offset->{$tag} == 1);
	      $char = "Uncalibrated"   if ($offset->{$tag} == 0xffff);
	      printf("%02d %04x %-30s %d: %-20s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("\t\t\t(1:sRGB,65535(0xffff):");
	      printf("Uncalibrated,others:Unknown)\n")
	  }
	  elsif($tag == 0x0213){ # YCbCrPositioning
	      $char = "Unknown ";
	      $char = "Center"       if ($offset->{$tag} == 1);
	      $char = "Datum Point"  if ($offset->{$tag} == 2);
	      printf("%02d %04x %-30s %d: %-20s\n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("\t\t\t(1:Center,2:Datum Point,others:Unknown)\n");
	  }
	  elsif($tag == 0x8827){ # ISOSpeedRatings
	      printf("%02d %04x %-30s %d ",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag});
	      printf("(auto, 100, 200 or 400)\n");
	  }
	  elsif($tag == 0x0202){ # Olympus Original Macro
	      $char = "Unknown"; 
	      $char = "Normal"  if ($offset->{$tag} == 0);
	      $char = "Macro"   if ($offset->{$tag} == 1);
	      printf("%02d %04x %-30s %d: %s ",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag},$char);
	      printf("(0:Normal,1:Macro)\n");
	  }
	  else{
	      printf("%02d %04x %-30s %d \n",$ct,
		     $tag, $mean->{$tag}, $offset->{$tag});
	  }
      }
#-----------------------------------------------------------------------------
      elsif($type->{$tag} == 0x4){ # Type : LONG
	  if( ($tag == 0xa002) ||($tag == 0xa003) ){
	      printf("%02d %04x %-30s %-4d\n", $ct,  
		     $tag, $mean->{$tag}, $offset->{$tag});
	  }elsif($tag == '0201'){
	      printf("%02d %04s %-30s 0x%04x\n", $ct,  
		     $tag, $mean->{$tag}, $offset->{$tag}+12);
	  }elsif($tag == '0202'){
	      printf("%02d %04s %-30s %4d Bytes\n", $ct,  
		     $tag, $mean->{$tag}, $offset->{$tag});
	  }elsif($tag == 0x0200){
	      ($spmode[1],$spmode[2],$spmode[3])
		  =unpack("VVV",substr($buf, $base_offset+$offset->{$tag},12));
	      printf("%02d %04x %-30s %d %d %d \n", $ct,  
		     $tag, $mean->{$tag}, $spmode[1],$spmode[2],$spmode[3]);
	      printf("\t\t\t1st:(0:normal,1:unknown,2:");
	      printf("continuous,3:panorama)\n");
	      printf("\t\t\t2nd:(Picture Number in mode 2 and 3)\n");
	      printf("\t\t\t3rd:(panorama direction ");
	      printf("1:LtoR,2:RtoL,3:BtoT,4:TtoB)\n");
	  }elsif($tag == 0x8769){
	      printf("%02d %04x %-30s 0x%04x\n", $ct,  
		     $tag, $mean->{$tag}, $offset->{$tag}+12);
	  }elsif($tag == 0xa005){
	      printf("%02d %04x %-30s 0x%04x\n", $ct,  
		     $tag, $mean->{$tag}, $offset->{$tag}+12);
	  }else{
	      printf("%02d %04x %-30s 0x%04x --UNKNOWN in TYPE(0x4)--\n", $ct, 
		     $tag, $mean->{$tag}, $offset->{$tag}+12);
	  }
      }
#-----------------------------------------------------------------------------
      elsif($type->{$tag} == 0x5){ # Type : RATIONAL
#	  ($value->{$tag}->{'numer'},$value->{$tag}->{'denom'}) 
#	      = unpack("VV",substr($buf, $base_offset+$offset->{$tag}, 8));
	  if ($tag == 0x011a || $tag == 0x011b){  # 
	      $tmp = 0x0128; # ResolutionUnit
	      $char = "Unknown "   if ($offset->{$tmp} == 1);
	      $char = "No Unit"    if ($offset->{$tmp} == 1);
	      $char = "Inch"       if ($offset->{$tmp} == 2);
	      $char = "Centimetre" if ($offset->{$tmp} == 3);
	      printf("%02d %04x %-30s %d [pixels per %s]\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'},
		     $char);
	  }
	  elsif ($tag == 0x829a){  # ExposureTime
	      printf("%02d %04x %-30s %d/%-d\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}, $value->{$tag}->{'denom'});
	      printf("\t\t\t\t(1-1/800 [sec], Manual: 16-1/800 [sec])\n");
	  }
	  elsif ($tag == 0x829d){  # FNumber
	      printf("%02d %04x %-30s F%.2f\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'});
	      printf("\t\t\t\t(W:F1.80-F10.00,T:F2.60-F10.00)\n" );
	  }
	  elsif ($tag == 0x9205){  # MaxApertureValue
	      printf("%02d %04x %-30s %.2f\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'});
	      printf("\t\t\t\t(W:F1.80-F10.00,T:F2.60-F10.00)\n" );
	  }
	  elsif ($tag == 0x920a){  # FocalLength
	      $ff = $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'};
	      printf("%02d %04x %-30s f= %6.2f [mm] ",
		     $ct, $tag,$mean->{$tag},$ff);
	      printf("( 7.10- 21.30 [mm])\n");
	      printf("\t(Conversion to that of 35mm :  ");
	      $a = 80.0e0/14.2e0;
	      $b = 120.0e0 - 21.3e0*$a;
	      $conv = $a * $ff + $b;
	      printf("f= %6.2f [mm] (40.00-120.00 [mm]))\n",$conv);
	  }
	  elsif ($tag == 0x0204){  # Digizoom
	      printf("%02d %04x %-30s %.2f ",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'});
	      printf("(1.00 - 2.50 (VGA:1.00-5.00))\n");
	  }
	  else{
	      printf("%02d %04x %-30s %d/%-d\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}, $value->{$tag}->{'denom'});
	  }
      }
#-----------------------------------------------------------------------------
      elsif ($type->{$tag} == 0x7) { # Type : UNDEFINED
	  if ($size->{$tag} <= 4) {
	      $value->{$tag}= pack("V",$offset->{$tag}); # pack it again!
	  }
	  else {
	      $value->{$tag} = substr($buf, $base_offset+$offset->{$tag},
				  $size->{$tag}); # -1 for chomp
	  }

	  if (($tag == 0x927c) or ($tag == 0x9286)){
	      printf("%02d %04x %-30s 0x%04x\n", $ct,  
		     $tag, $mean->{$tag}, $offset->{$tag}+12);
	  }
	  elsif ($tag == 0x0f00){ # 
	      printf ("%02d %04x %-30s ",$ct,$tag, $mean->{$tag});
	      for ($j = 0; $j < $size->{$tag}; $j++){
		  $a = substr($value->{$tag},$j,1);
		  if ((0x20 <= ord($a) ) and (ord($a) <= 0x7e)){
		      printf("%x(%s):",ord($a),$a);
		  }
		  else{
		      printf("%02x(-):",ord($a));
		  }
	      }
	      printf("\n");
	  }
	  else { # Others
	      printf ("%02d %04x %-30s ",$ct,$tag, $mean->{$tag});
	      for ($j = 0; $j < $size->{$tag}; $j++){
		  $a = substr($value->{$tag},$j,1);
		  if ((0x20 <= ord($a) ) and (ord($a) <= 0x7e)){
		      printf("%x(%s):",ord($a),$a);
		  }
		  else{
		      printf("%02x(-):",ord($a));
		  }
	      }
	      printf("\n");
	  }
      }
#-----------------------------------------------------------------------------
      elsif($type->{$tag} == 0xa){ # Type : Signed RATIONAL
#	  ($value->{$tag}->{'numer'}, $value->{$tag}->{'denom'}) 
#	      = unpack("VV", substr($buf, $base_offset+$offset->{$tag}, 8));
	  if ($tag == 0x9204){  # ExposureBiasValue
	      printf("%02d %04x %-30s %.2f\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'});
	  }
	  else{
	      printf("%02d %04x %-30s %d/%-5d\n",
		     $ct, $tag,$mean->{$tag},
		     $value->{$tag}->{'numer'}, $value->{$tag}->{'denom'});
	  }
      }
      $ct++;
  }
}
print "-"x78,"\n";

#---- print EV(Exposure Value) -----------------------------------------------
print "\n";
$tag = 0x829d; # FNumber
#$tag = 0x9205; # FNumber
$f =  $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'};
$av= 2.0e0 * log($f)/log(2.0e0);
printf +("AV(Aperture Value) : %5.1f (%d/%d)\n",$av,
	 $value->{$tag}->{'numer'}, $value->{$tag}->{'denom'});
#
$tag = 0x829a; # ExposureTime
$s =  $value->{$tag}->{'numer'}/$value->{$tag}->{'denom'};
$tv= - log($s)/log(2.0e0);
printf +("TV(Time Value)     : %5.1f (%d/%d)\n",$tv,
 	$value->{$tag}->{'numer'}, $value->{$tag}->{'denom'});
printf +("EV(Exposure Value) : %5.1f\n\n", $av + $tv);

#-----------------------------------------------------------------------------
print "-"x78,"\n";
printf("Header Part is stored in the file       : $opt_o\n") if $opt_o;
printf("Thumbnail picture is stored in the file : $thumbnailfile\n")if $opt_t;
exit(0);

#----- Subroutine to print Help Messages -------------------------------------
sub Print_Help{
    select(STDERR); $| = 1; 
    print <<"Options_HELP";
EXIF analyzer for JPEG file created with Olympus Digital Camera
Version $version Copyright 2000,2001  Jun Ushida

Usage: $command [options] file.jpg
  options: -h         show this messages
           -d         debug mode
           -t file    dump thumbnail picture part into file
           -o file    dump header part info to binary file
Options_HELP
    exit(0);
}
##############################################################################
