From the Exiftool website[
1]:
ExifTool is a platform-independent Perl library plus a command-line application for reading, writing and editing meta information in a wide variety of files.The command-line has a large variety of options to do various things to one file or many.
I (
EMJ) use ExifTool a lot with my photo collection, adding metadata as well retrieving it for a variety of purposes. Doing the same thing with lots of files is easy and efficient, but doing the same sort of updates but with different values to a lot of files can be very slow, needing many invocations of the program. Howver, ExifTool provides for this (again from the website):
... the -execute option may be used to perform multiple independent operations with a single invocation of exiftool, and together with the -stay_open option provides a method for calling applications to avoid (the) startup overheadAdd this to
- -@ ARGFILE
- Read command-line arguments from the specified file. The file contains one argument per line (NOT one option per line -- some options require additional arguments, and all arguments must be placed on separate lines). Blank lines and lines beginning with # and are ignored. Normal shell processing of arguments is not performed, which among other things means that arguments should not be quoted and spaces are treated as any other character. ARGFILE may exist relative to either the current directory or the exiftool directory unless an absolute pathname is given.
(which doesn't mention
-@ - for
stdin) and you have something that can easily be driven from Tcl using
open (as
open |) and
fileevent. After a fair bit of messing about, I have ended up with the following:
namespace eval ::run_exiftool {
variable et_vars
set et_vars [dict create]
}
proc ::run_exiftool::start { func } {
variable et_vars
dict set et_vars func $func
set et [open "|exiftool -stay_open true -@ -" r+]
fconfigure $et -blocking false
fileevent $et readable [list [namespace current]::isReadable]
dict set et_vars chan $et
$func [namespace current]::et_vars INIT
vwait ::DONE
close [dict get $et_vars chan]
}
proc ::run_exiftool::stop {} {
variable et_vars
set et [dict get $et_vars chan]
puts $et "-stay_open"
puts $et "false"
flush $et
}
proc ::run_exiftool::isReadable {} {
variable et_vars
set et [dict get $et_vars chan]
set status [catch { gets $et line } result]
if { $status != 0 } {
puts "error reading $et: $result"
set ::DONE 2
} elseif { $result >= 0 } {
set usr_status [catch { [dict get $et_vars func] [namespace current]::et_vars $line } usr_result]
if { $usr_status != 0 } {
puts "error in user function: $usr_result"
close $et
set ::DONE 99
}
} elseif { [eof $et] } {
set ::DONE 1
} elseif { [fblocked $et] } {
} else {
puts "can't happen"
set ::DONE 3
}
}
Not actually a package yet, of course.
When everthing is ready, we will want to do
so here is a suitable proc:
proc do_one_line { et_dict line } {
upvar 1 $et_dict et_vars
set et [dict get $et_vars chan]
switch -regexp -- $line {
{^INIT$} {
dict set et_vars fp [open captionlist]
dict set et_vars dates -
sendnext et_vars
}
{^date} {
dict set et_vars dates [lindex [split $line] 1]
}
{^{ready1}$} {
updnext et_vars
}
{^{ready2}$} {
sendnext et_vars
}
default {
puts $line
}
}
}
To be continued ...