Updated 2016-02-13 17:00:24 by escargo

by Theo Verelst

When taking pictures with a digital camera on a removable storage medium like a memory stick, flash card, or other, or, by hooking it up via an usb connection, when you're taking pictures, you want to take the latest pictures you took, and store them on your harddisc.

Either to make place on the memory thing, or to make sure you don't erase important pictures, that you maybe can never take again, or simply because you want to see the pictures you tool on the pc, and don't want to do that by pointing your viewer directly into the mapped device.

Probably pictures are arranged hierarchically, and it is quite possible we want to update the disc set of pictures from the stick without erasing it, and without copying the whole thing again. If we'd blindly copy all files, which on every decent os should be easy enough, we possibly take a lot longer time than needed, and more importantly, we might overwrite files on harddisc we don't want overwritten, for instance because we edited pictures.

So the first script takes all files on the memory devices, by finding all .jpg and .JPG files down from a certain directory (the top of the stick or card device file hierarchy), determines if the filename (minus the path) exists in the target directory, and copies the file if that is not the case:
 # set variables MEMORY_DEVICE_TOPDIR and DESTINATION_DIR first
 foreach i [ilist $MEMORY_DEVICE_TOPDIR files 100 0 isleaf ] {
    if [string equal [string tolower [file extension $i ]] .jpg ] {
       set itail [file tail $i] ; 
       set inew [file join $DESTINATION_DIR [file tail $i]] ;
       if ![file exists $inew] {
          file copy  $i $inew
       } {
          puts "file existed: $itail"
       }
    }
 }

# This script makes use of the function ilist, which returns a list of filenames including path:
 proc ilist { {begin {.}} {listf {winfo children}} {maxdepth {100}} {ident {0}} {isleaf {}} } {
 # isleaf function defined means not-leafs themselves are filtered out
 # and that puts of the results is turned off
   if {$maxdepth <1} return
   set de {}; set o {}
   for {set i 0} {$i < $ident} {incr i} {append de "   "}
   foreach i [eval "$listf $begin"] {
      if {$isleaf == {}} {
         lappend o $i
         puts "$de $i"
         eval lappend o [ilist [list $i] $listf [expr $maxdepth-1] [expr $ident +1] $isleaf]
      } {
         if {[isleaf $i]} {
            lappend o $i
         } {
            eval lappend o [ilist [list $i] $listf [expr $maxdepth-1] [expr $ident +1] $isleaf]
         }
      }
   }
   return $o
 }

 # for which we need the functions:

 proc files  {d} {if [catch {glob $d/*} r] {return {}} {return $r} }
 proc isleaf {f} {if [file isdir $f] {return 0} {return 1}}

if 0 {
To make the idea work as a block on a [bwise] canvas, 
I made a procedure which outputs to two global, 
block-related variables, and which takes the directories 
(and a name related variable) as arguments:
}

 proc copymemstick { {stickdir} {destdir} {blockname {copymemstick}} } {
   set copycount 0
   set faillist {}
 foreach i [ilist $stickdir files 100 0 isleaf ] {
    if [string equal [string tolower [file extension $i ]] .jpg ] {
       set itail [file tail $i] ;
       set inew [file join $destdir [file tail $i]] ;
       if ![file exists $inew] {
          file copy  $i $inew
          incr copycount
       } {
          lappend faillist $itail
       }
    }
 }

   uplevel #0 "
      set $blockname.copycount $copycount
      set $blockname.faillist [list $faillist]
   "
 } 

which we can use inside a bwise block (after having loaded bwise), which can be generated by:
 newproc {set copymemstick.out [copymemstick ${copymemstick.stickdir} ${copymemstick.destdir} ${copymemstick.blockname}] } copymemstick {stickdir destdir blockname} out 40 {} {} 300 200

which makes a new block with pins corresponding to variables which correspond to the formal arguments, and two global return variables of the memstickcopy procedure.

I tried this approach a bit, and found that it seems to work satisfactory, though it happens when previews are made for instance by a drawing program, that the source directory tree can contain he same name twice, which generates a 'file exists' situation, and it is not clear whether in such case the preview or the intended file has been copied.

A possible way out of there is to use a limited tree search recursion level:
 foreach i [ilist $MEMORY_DEVICE_TOPDIR files 1 0 isleaf ] {
 ...

here recursion level is 1, when the images normally are in a subdir, make it 2 or higher.

Other ways of dealing with double file names (different dirs, which can easily happen when the camera doesn't continue numbering but starts over again for a new roll, or when the numbers wrap around) require more elaborate changes.