gpsfold: Remove $Id$ at EOF.
[gpstools.git] / branches / gpst.gpxfix / gpst-pic
blobbfad36943cdd8eb691e75ff688cf0394d0fd39e0
1 #!/usr/bin/perl -w
3 #=======================================================================
4 # $Id$
5 # File ID: 18245170-f924-11dd-93fc-0001805bf4b1
6 # Extract EXIF data from pictures for use with COPY in Postgres
8 # Character set: UTF-8
9 # ©opyleft 2008– Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later, see end of
11 # file for legal stuff.
12 #=======================================================================
14 BEGIN {
15 our @version_array;
18 use strict;
19 use Getopt::Long;
21 BEGIN {
22 push(@INC, "$ENV{'HOME'}/bin/src/gpstools");
23 our @version_array;
26 use GPST;
27 use GPSTxml;
29 $| = 1;
31 our $Debug = 0;
32 our $NA = '\N';
33 our %Std = (
35 'output-format' => 'pgtab',
36 'timezone' => '',
39 our %Opt = (
41 'author' => '',
42 'debug' => 0,
43 'description' => '',
44 'help' => 0,
45 'output-format' => $Std{'output-format'},
46 'strip-whitespace' => 0,
47 'timezone' => $Std{'timezone'},
48 'verbose' => 0,
49 'version' => 0,
53 our $progname = $0;
54 $progname =~ s/^.*\/(.*?)$/$1/;
56 my $rcs_id = '$Id$';
57 my $id_date = $rcs_id;
58 $id_date =~ s/^.*?\d+ (\d\d\d\d-.*?\d\d:\d\d:\d\d\S+).*/$1/;
60 push(@main::version_array, $rcs_id);
62 Getopt::Long::Configure("bundling");
63 GetOptions(
65 "author|a=s" => \$Opt{'author'},
66 "debug" => \$Opt{'debug'},
67 "description|d=s" => \$Opt{'description'},
68 "help|h" => \$Opt{'help'},
69 "output-format|o=s" => \$Opt{'output-format'},
70 "strip-whitespace|w" => \$Opt{'strip-whitespace'},
71 "timezone|T=s" => \$Opt{'timezone'},
72 "verbose|v+" => \$Opt{'verbose'},
73 "version" => \$Opt{'version'},
75 ) || die("$progname: Option error. Use -h for help.\n");
77 $Opt{'debug'} && ($Debug = 1);
78 $Opt{'help'} && usage(0);
79 if ($Opt{'version'}) {
80 print_version();
81 exit(0);
84 $GPST::Spc = $Opt{'strip-whitespace'} ? "" : " ";
85 my $Spc = $GPST::Spc; # FIXME
86 my $tz_str = "";
87 if (length($Opt{'timezone'})) {
88 if ($Opt{'timezone'} =~ /^[\+\-][0-2][0-9]{3}$/) {
89 $tz_str = $Opt{'timezone'};
90 } elsif ($Opt{'timezone'} =~ /^z$/i) {
91 $tz_str = $Opt{'timezone'};
92 } elsif ($Opt{'timezone'} =~ /^[a-z]+$/i) {
93 $tz_str = " $Opt{'timezone'}";
94 } else {
95 die("$progname: $Opt{'timezone'}: Invalid time zone\n");
99 if ($Opt{'output-format'} eq "xml") {
100 print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpstpic>\n");
103 if ($#ARGV < 0) {
104 while (<>) {
105 chomp();
106 print_entry($_);
108 } else {
109 for my $fname (@ARGV) {
110 print_entry($fname);
114 if ($Opt{'output-format'} eq "xml") {
115 print("</gpstpic>\n");
118 sub print_entry {
119 # {{{
120 my $filename = shift;
121 my $Retval = 0;
122 my ($date, $coor) =
123 ( '', '');
124 my @Dates = ();
125 local *PicFP;
126 D("filename = '$filename'");
127 if (open(PicFP, "exifprobe -L \"$filename\" |")) { # FIXME: Quick & Dirty™
128 while (<PicFP>) {
129 if (/DateTime/) {
130 s/^.*'(.*?)'.*$/$1/;
131 chomp($date = $_);
132 $date =~ s/^(\d\d\d\d)(.)(\d\d)(.)(\d\d)(.)(\d\d:\d\d:\d\d)(.*)/$1-$3-${5}T$7$8/;
133 D("date = '$date'");
134 push(@Dates, $date);
137 close(PicFP);
138 @Dates = reverse sort @Dates;
139 $date = $Dates[0];
140 defined($date) || ($date = '');
141 D("final date = '$date'");
142 if ($date =~ /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d$/) {
143 $filename =~ s/^.*\/(.*?)$/$1/;
144 my $Output = "";
145 if ($Opt{'output-format'} eq "xml") {
146 if (length("$filename$date")) {
147 $Output = join("",
148 "$Spc$Spc<img>\n",
149 length($filename)
150 ? sprintf("$Spc$Spc$Spc$Spc<filename>%s</filename>\n",
151 txt_to_xml($filename))
152 : "",
153 length($date)
154 ? sprintf("$Spc$Spc$Spc$Spc<date>%s</date>\n",
155 txt_to_xml($date))
156 : "",
157 "$Spc$Spc</img>\n",
160 } elsif ($Opt{'output-format'} eq "pgtab") {
161 # Version information {{{
162 # Without version field (same as version 1):
163 # date \t
164 # "(lat,lon)"-coordinates \t
165 # description \t
166 # filename \t
167 # author \t
168 # Version 1:
169 # "1" \t
170 # date \t
171 # "(lat,lon)"-coordinates \t
172 # description \t
173 # filename \t
174 # author \n
175 # }}}
176 $Output = pgtab_entry(
177 1, # Version number
178 $date,
179 $coor,
180 $Opt{'description'},
181 $filename,
182 $Opt{'author'}
184 } else {
185 die("$progname: $Opt{'output-format'}: Unknown output format\n");
187 print($Output);
188 $Opt{'verbose'} && print(STDERR $Output);
189 } else {
190 if (length($date)) {
191 warn("$filename: $date: Invalid date format");
192 $Retval = 2;
195 } else {
196 warn("$filename: Cannot open exifprobe(1) pipe: $!");
197 $Retval = 1;
199 return($Retval);
200 # }}}
201 } # print_entry()
203 sub pgtab_entry {
204 # {{{
205 my ($Version, $Date, $Coor, $Descr, $Filename, $Author) = @_;
206 defined($Date) || ($Date = $NA);
207 defined($Coor) || ($Coor = $NA);
208 defined($Descr) || ($Descr = $NA);
209 defined($Filename) || ($Filename = $NA);
210 defined($Author) || ($Author = $NA);
211 my $Retval = "";
212 if ($Version == 1) {
213 $Retval = join("\t",
214 1, # Version number
215 postgresql_copy_safe($Date) . $tz_str,
216 length($Coor)
217 ? postgresql_copy_safe($Coor)
218 : $NA,
219 length($Opt{'description'})
220 ? postgresql_copy_safe($Opt{'description'})
221 : $NA,
222 length($Filename)
223 ? postgresql_copy_safe($Filename)
224 : $NA,
225 length($Opt{'author'})
226 ? postgresql_copy_safe($Opt{'author'})
227 : $NA
228 ) . "\n";
230 return($Retval);
231 # }}}
232 } # pgtab_entry()
234 sub print_version {
235 # Print program version {{{
236 for (@main::version_array) {
237 print("$_\n");
239 # }}}
240 } # print_version()
242 sub usage {
243 # Send the help message to stdout {{{
244 my $Retval = shift;
246 if ($Opt{'verbose'}) {
247 print("\n");
248 print_version();
250 print(<<END);
252 Usage: $progname [options] [file [files [...]]]
254 Extract EXIF info from pictures for use with PostgreSQL's COPY command.
255 If no filenames are specified on the command line, file names are read
256 from stdin.
258 Options:
260 -a, --author x
261 Specify author of picture.
262 -d, --description x
263 Specify description for picture.
264 -h, --help
265 Show this help.
266 -v, --verbose
267 Increase level of verbosity. Can be repeated.
268 -o x, --output-format x
269 Create output of type x:
271 pgtab
272 Default: "$Std{'output-format'}".
273 -T X, --timezone X
274 Prepend X as timezone to the date. Valid formats:
275 UTC offset
276 A '+' or '-' followed by a four-digit number (HHMM) which
277 indicates the offset relative to UTC. Examples:
278 +0000
279 -1600
280 +0630
281 Time zone abbreviation. Examples:
285 -w, --strip-whitespace
286 Strip all unnecessary whitespace.
287 --version
288 Print version information.
289 --debug
290 Print debugging messages.
293 exit($Retval);
294 # }}}
295 } # usage()
297 sub msg {
298 # Print a status message to stderr based on verbosity level {{{
299 my ($verbose_level, $Txt) = @_;
301 if ($Opt{'verbose'} >= $verbose_level) {
302 print(STDERR "$progname: $Txt\n");
304 # }}}
305 } # msg()
307 sub D {
308 # Print a debugging message {{{
309 $Debug || return;
310 my @call_info = caller;
311 chomp(my $Txt = shift);
312 my $File = $call_info[1];
313 $File =~ s#\\#/#g;
314 $File =~ s#^.*/(.*?)$#$1#;
315 print(STDERR "$File:$call_info[2] $$ $Txt\n");
316 return("");
317 # }}}
318 } # D()
320 __END__
322 # Plain Old Documentation (POD) {{{
324 =pod
326 =head1 NAME
330 =head1 REVISION
332 $Id$
334 =head1 SYNOPSIS
336 [options] [file [files [...]]]
338 =head1 DESCRIPTION
342 =head1 OPTIONS
344 =over 4
346 =item B<-h>, B<--help>
348 Print a brief help summary.
350 =item B<-v>, B<--verbose>
352 Increase level of verbosity. Can be repeated.
354 =item B<--version>
356 Print version information.
358 =item B<--debug>
360 Print debugging messages.
362 =back
364 =head1 BUGS
368 =head1 AUTHOR
370 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
372 =head1 COPYRIGHT
374 Copyleft © Øyvind A. Holm E<lt>sunny@sunbase.orgE<gt>
375 This is free software; see the file F<COPYING> for legalese stuff.
377 =head1 LICENCE
379 This program is free software; you can redistribute it and/or modify it
380 under the terms of the GNU General Public License as published by the
381 Free Software Foundation; either version 2 of the License, or (at your
382 option) any later version.
384 This program is distributed in the hope that it will be useful, but
385 WITHOUT ANY WARRANTY; without even the implied warranty of
386 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
387 See the GNU General Public License for more details.
389 You should have received a copy of the GNU General Public License along
390 with this program; if not, write to the Free Software Foundation, Inc.,
391 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
393 =head1 SEE ALSO
395 =cut
397 # }}}
399 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :
400 # End of file $Id$