source: gsdl/trunk/perllib/cpan/Image/ExifTool/GPS.pm@ 16842

Last change on this file since 16842 was 16842, checked in by davidb, 16 years ago

ExifTool added to cpan area to support metadata extraction from files such as JPEG. Primarily targetted as Image files (hence the Image folder name decided upon by the ExifTool author) it also can handle video such as flash and audio such as Wav

File size: 11.2 KB
Line 
1#------------------------------------------------------------------------------
2# File: GPS.pm
3#
4# Description: EXIF GPS meta information tags
5#
6# Revisions: 12/09/2003 - P. Harvey Created
7#------------------------------------------------------------------------------
8
9package Image::ExifTool::GPS;
10
11use strict;
12use vars qw($VERSION);
13use Image::ExifTool::Exif;
14
15$VERSION = '1.17';
16
17my %coordConv = (
18 ValueConv => 'Image::ExifTool::GPS::ToDegrees($val)',
19 ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val)',
20 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)',
21 PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val)',
22);
23
24%Image::ExifTool::GPS::Main = (
25 GROUPS => { 0 => 'EXIF', 1 => 'GPS', 2 => 'Location' },
26 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
27 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
28 WRITABLE => 1,
29 WRITE_GROUP => 'GPS',
30 NOTES => q{
31 When adding GPS information to an image, it is important to set all of the
32 following tags: GPSLatitude, GPSLatitudeRef, GPSLongitude, GPSLongitudeRef,
33 GPSAltitude and GPSAltitudeRef. ExifTool will write the required
34 GPSVersionID tag automatically if new a GPS IFD is added to an image.
35 },
36 0x0000 => {
37 Name => 'GPSVersionID',
38 Writable => 'int8u',
39 Count => 4,
40 PrintConv => '$val =~ tr/ /./; $val',
41 PrintConvInv => '$val =~ tr/./ /; $val',
42 },
43 0x0001 => {
44 Name => 'GPSLatitudeRef',
45 Writable => 'string',
46 Count => 2,
47 PrintConv => {
48 N => 'North',
49 S => 'South',
50 },
51 },
52 0x0002 => {
53 Name => 'GPSLatitude',
54 Writable => 'rational64u',
55 Count => 3,
56 %coordConv,
57 },
58 0x0003 => {
59 Name => 'GPSLongitudeRef',
60 Writable => 'string',
61 Count => 2,
62 PrintConv => {
63 E => 'East',
64 W => 'West',
65 },
66 },
67 0x0004 => {
68 Name => 'GPSLongitude',
69 Writable => 'rational64u',
70 Count => 3,
71 %coordConv,
72 },
73 0x0005 => {
74 Name => 'GPSAltitudeRef',
75 Writable => 'int8u',
76 PrintConv => {
77 0 => 'Above Sea Level',
78 1 => 'Below Sea Level',
79 },
80 },
81 0x0006 => {
82 Name => 'GPSAltitude',
83 Writable => 'rational64u',
84 PrintConv => '$val eq "inf" ? $val : "$val m"',
85 PrintConvInv => '$val=~s/\s*m$//;$val',
86 },
87 0x0007 => {
88 Name => 'GPSTimeStamp',
89 Groups => { 2 => 'Time' },
90 Writable => 'rational64u',
91 Count => 3,
92 Shift => 'Time',
93 ValueConv => sub {
94 my $val = shift;
95 my ($h,$m,$s) = split ' ', $val;
96 my $f = (($h || 0) * 60 + ($m || 0)) * 60 + ($s || 0);
97 $h = int($f / 3600); $f -= $h * 3600;
98 $m = int($f / 60); $f -= $m * 60;
99 $s = int($f); $f -= $s;
100 $f = int($f * 1000000 + 0.5);
101 if ($f) {
102 ($f = sprintf(".%.6d", $f)) =~ s/0+$//;
103 } else {
104 $f = ''
105 }
106 return sprintf("%.2d:%.2d:%.2d$f",$h,$m,$s);
107 },
108 ValueConvInv => '$val=~tr/:/ /;$val',
109 # pull time out of any format date/time string
110 # (eventually handle timezones? -- timestamp should be UTC)
111 PrintConvInv => sub {
112 my $v = shift;
113 $v =~ s/[-+].*//s; # remove timezone
114 my @a = ($v =~ /((?=\d|\.\d)\d*(?:\.\d*)?)/g);
115 push @a, '00' while @a < 3;
116 return "$a[-3]:$a[-2]:$a[-1]";
117 },
118 },
119 0x0008 => {
120 Name => 'GPSSatellites',
121 Writable => 'string',
122 },
123 0x0009 => {
124 Name => 'GPSStatus',
125 Writable => 'string',
126 Count => 2,
127 PrintConv => {
128 A => 'Measurement In Progress',
129 V => 'Measurement Interoperability',
130 },
131 },
132 0x000A => {
133 Name => 'GPSMeasureMode',
134 Writable => 'string',
135 Count => 2,
136 PrintConv => {
137 2 => '2-Dimensional Measurement',
138 3 => '3-Dimensional Measurement',
139 },
140 },
141 0x000B => {
142 Name => 'GPSDOP',
143 Description => 'GPS Dilution Of Precision',
144 Writable => 'rational64u',
145 },
146 0x000C => {
147 Name => 'GPSSpeedRef',
148 Writable => 'string',
149 Count => 2,
150 PrintConv => {
151 K => 'km/h',
152 M => 'mph',
153 N => 'knots',
154 },
155 },
156 0x000D => {
157 Name => 'GPSSpeed',
158 Writable => 'rational64u',
159 },
160 0x000E => {
161 Name => 'GPSTrackRef',
162 Writable => 'string',
163 Count => 2,
164 PrintConv => {
165 M => 'Magnetic North',
166 T => 'True North',
167 },
168 },
169 0x000F => {
170 Name => 'GPSTrack',
171 Writable => 'rational64u',
172 },
173 0x0010 => {
174 Name => 'GPSImgDirectionRef',
175 Writable => 'string',
176 Count => 2,
177 PrintConv => {
178 M => 'Magnetic North',
179 T => 'True North',
180 },
181 },
182 0x0011 => {
183 Name => 'GPSImgDirection',
184 Writable => 'rational64u',
185 },
186 0x0012 => {
187 Name => 'GPSMapDatum',
188 Writable => 'string',
189 },
190 0x0013 => {
191 Name => 'GPSDestLatitudeRef',
192 Writable => 'string',
193 Count => 2,
194 PrintConv => {
195 N => 'North',
196 S => 'South',
197 },
198 },
199 0x0014 => {
200 Name => 'GPSDestLatitude',
201 Writable => 'rational64u',
202 Count => 3,
203 %coordConv,
204 },
205 0x0015 => {
206 Name => 'GPSDestLongitudeRef',
207 Writable => 'string',
208 Count => 2,
209 PrintConv => {
210 E => 'East',
211 W => 'West',
212 },
213 },
214 0x0016 => {
215 Name => 'GPSDestLongitude',
216 Writable => 'rational64u',
217 Count => 3,
218 %coordConv,
219 },
220 0x0017 => {
221 Name => 'GPSDestBearingRef',
222 Writable => 'string',
223 Count => 2,
224 PrintConv => {
225 M => 'Magnetic North',
226 T => 'True North',
227 },
228 },
229 0x0018 => {
230 Name => 'GPSDestBearing',
231 Writable => 'rational64u',
232 },
233 0x0019 => {
234 Name => 'GPSDestDistanceRef',
235 Writable => 'string',
236 Count => 2,
237 PrintConv => {
238 K => 'Kilometers',
239 M => 'Miles',
240 N => 'Nautical Miles',
241 },
242 },
243 0x001A => {
244 Name => 'GPSDestDistance',
245 Writable => 'rational64u',
246 },
247 0x001B => {
248 Name => 'GPSProcessingMethod',
249 Writable => 'undef',
250 PrintConv => 'Image::ExifTool::Exif::ConvertExifText($self,$val)',
251 PrintConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)',
252 },
253 0x001C => {
254 Name => 'GPSAreaInformation',
255 Writable => 'undef',
256 PrintConv => 'Image::ExifTool::Exif::ConvertExifText($self,$val)',
257 PrintConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)',
258 },
259 0x001D => {
260 Name => 'GPSDateStamp',
261 Groups => { 2 => 'Time' },
262 Writable => 'string',
263 Notes => 'YYYY:MM:DD',
264 Count => 11,
265 Shift => 'Time',
266 ValueConv => 'Image::ExifTool::Exif::ExifDate($val)',
267 ValueConvInv => '$val',
268 # pull date out of any format date/time string
269 PrintConvInv => '$val=~/(\d{4}).*?(\d{2}).*?(\d{2})/ ? "$1:$2:$3" : $val',
270 },
271 0x001E => {
272 Name => 'GPSDifferential',
273 Writable => 'int16u',
274 PrintConv => {
275 0 => 'No Correction',
276 1 => 'Differential Corrected',
277 },
278 },
279);
280
281# Composite GPS tags
282%Image::ExifTool::GPS::Composite = (
283 GPSDateTime => {
284 Description => 'GPS Date/Time',
285 Groups => { 2 => 'Time' },
286 Require => {
287 0 => 'GPSDateStamp',
288 1 => 'GPSTimeStamp',
289 },
290 ValueConv => '"$val[0] $val[1]"',
291 PrintConv => '$self->ConvertDateTime($val)',
292 },
293 GPSLatitude => {
294 Require => {
295 0 => 'GPS:GPSLatitude',
296 1 => 'GPS:GPSLatitudeRef',
297 },
298 ValueConv => '$val[1] =~ /^S/i ? -$val[0] : $val[0]',
299 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
300 },
301 GPSLongitude => {
302 Require => {
303 0 => 'GPS:GPSLongitude',
304 1 => 'GPS:GPSLongitudeRef',
305 },
306 ValueConv => '$val[1] =~ /^W/i ? -$val[0] : $val[0]',
307 PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
308 },
309);
310
311# add our composite tags
312Image::ExifTool::AddCompositeTags('Image::ExifTool::GPS');
313
314#------------------------------------------------------------------------------
315# Convert degrees to DMS, or whatever the current settings are
316# Inputs: 0) ExifTool reference, 1) Value in degrees,
317# 2) format code (0=no format, 1=CoordFormat, 2=XMP format)
318# 3) 'N' or 'E' if sign is significant and N/S/E/W should be added
319# Returns: DMS string
320sub ToDMS($$;$$)
321{
322 my ($exifTool, $val, $doPrintConv, $ref) = @_;
323 my ($fmt, $num);
324
325 if ($ref) {
326 if ($val < 0) {
327 $val = -$val;
328 $ref = {N => 'S', E => 'W'}->{$ref};
329 }
330 $ref = " $ref" unless $doPrintConv and $doPrintConv eq '2';
331 } else {
332 $ref = '';
333 }
334 if ($doPrintConv) {
335 if ($doPrintConv eq '1') {
336 $fmt = ($exifTool->Options('CoordFormat') || q{%d deg %d' %.2f"}) . $ref;
337 } else {
338 $fmt = "%d,%.6f$ref"; # use XMP standard format
339 }
340 # count the number of format specifiers
341 $num = ($fmt =~ tr/%/%/);
342 } else {
343 $num = 3;
344 }
345 my ($d, $m, $s);
346 $d = $val;
347 if ($num > 1) {
348 $d = int($d);
349 $m = ($val - $d) * 60;
350 if ($num > 2) {
351 $m = int($m);
352 $s = ($val - $d - $m / 60) * 3600;
353 }
354 }
355 return $doPrintConv ? sprintf($fmt, $d, $m, $s) : "$d $m $s$ref";
356}
357
358#------------------------------------------------------------------------------
359# Convert to decimal degrees
360# Inputs: 0) a string containing 1-3 decimal numbers and any amount of other garbage
361# 1) true if value should be negative if coordinate ends in 'S' or 'W'
362# Returns: Coordinate in degrees
363sub ToDegrees($;$)
364{
365 my ($val, $doSign) = @_;
366 # extract decimal values out of any other garbage
367 my ($d, $m, $s) = ($val =~ /((?:[+-]?)(?=\d|\.\d)\d*(?:\.\d*)?)/g);
368 my $deg = ($d || 0) + (($m || 0) + ($s || 0)/60) / 60;
369 # make negative if S or W coordinate
370 $deg = -$deg if $doSign ? $val =~ /[^A-Z](S|W)$/i : $deg < 0;
371 return $deg;
372}
373
374
3751; #end
376
377__END__
378
379=head1 NAME
380
381Image::ExifTool::GPS - EXIF GPS meta information tags
382
383=head1 SYNOPSIS
384
385This module is loaded automatically by Image::ExifTool when required.
386
387=head1 DESCRIPTION
388
389This module contains definitions required by Image::ExifTool to interpret
390GPS (Global Positioning System) meta information in EXIF data.
391
392=head1 AUTHOR
393
394Copyright 2003-2007, Phil Harvey (phil at owl.phy.queensu.ca)
395
396This library is free software; you can redistribute it and/or modify it
397under the same terms as Perl itself.
398
399=head1 REFERENCES
400
401=over 4
402
403=item L<Image::Info|Image::Info>
404
405=back
406
407=head1 SEE ALSO
408
409L<Image::ExifTool::TagNames/GPS Tags>,
410L<Image::ExifTool(3pm)|Image::ExifTool>,
411L<Image::Info(3pm)|Image::Info>
412
413=cut
Note: See TracBrowser for help on using the repository browser.