Updated 2011-01-24 23:46:55 by AK

started by Theo Verelst

(higher res: http://www.theover.org/Bwise/screenwwwdb1.png , this one only saves on my netscape, its about .5 MB, explorer buys it a image in the browser window)

In Webserver combined with bwise (see also for related links), I've started describing a setup which allows live interaction with bwise over a webserver, using an ordinary browser, or, if you like, automating parts of a webserver using the net-editing blockwise programming environment bwise, which allows blockwise execution trace composition, visual function composition or de-composition (not so much automatically yet, though that is prepared), and treewise and more complicated pushing and pulling of data over a network.

Having combined bwise and the tclhttpd server, with repeated warning that it is wise to strip the file system it has under it's document root directory, and which libraries are provided, because on the world wide web tclhttpd by itself, especially on an 'open' system like any windows system except NT and 2000 (but then most files are quite unprotected, too), out-of-the box is a major possible security hazard. It doesn't hide it, though.

The in core database of bwise is used here, in updated (but not much) form to store information about images, in my examples a number of thousand high quality digital photographs. Those are stored under c:/Memorystick on an XP managed disc, to begin with on a machine which can run the bwise/tclhttpd combination. To make previews, I used the djpeg/cjpeg tools which are also part of cygwin (though they are seperately available and I don't use much of cygwin here), which for each image is stored in a automatically generated subdirectory called Medium. When a file has no counterpart with the same filename a directory level higher, it is assumed to be a target.

I used the latest ilist procedure:
 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}}

To make the 'Medium' preview directories automatically:
 foreach i [ilist c:/Memorystick/ files] {
    if [file isdir $i] {
       if ![file exists [file join $i Medium]] {
          file mkdir [file join $i Medium]
       } {
          puts "Error: file exists $i/Medium"
       }
    }
 }

Making a database of image files

This sets up the dbase using bwise routines
 set dbvar {}                 ;# initialize the database list to empty
 dbaccess                     ;# opens a picture and data window
 dbcontrol mydatabase.tcl     ;# opens a db load/save/new entry window

Some named functions would make this clearer (bwise should automatically decompose this...), but this lists the right image files in the database variable dbvar, using the format function image_todb:
 proc image_todb { {im} } {
   global ic dbvar
   incr ic

   set medium [file join [file dirname $im] Medium [file tail $im]]
   exec djpeg -scale 2/8 $im | cjpeg -q 80 -outfile $medium

   lappend dbvar   [list  [list File $im]  [list Image $medium]  [list Id [file rootname [file tail $im]] ]  Name Description Date  [list Size [lrange  [exec djpeg $im | head -3] 1 2]]  ]
 }
 set dbvar {};
 set ic 0 ;
 foreach i [ilist c:/Memorystick files 100 0 isleaf] {
    if {[string equal [string tolower [file extension $i]] .jpg] && \
       ![file exists [eval file join [lrange [file split [file dirname $i]] 0 end-1] [list [file tail $i]]] ]
    } {
       image_todb $i
    }
 }

Sorting the database based on picture ID in another variable:
 set dbvarunsorted $dbvar ; puts fin    ; print something to prevent very large return value in console
 proc sp {a b} {
    return [string compare [lindex [lindex $a 2] 1] [lindex [lindex $b 2] 1]]
 }
 set dbvar [lsort -command sp $dbvarunsorted] ; puts fin
 dbform [lindex $dbvar 0]    ; # update or show the viewer
                             ; # without updating dbvar with the previous window data !

No doubt there are dbase systems which can do stuff like this elegantly (I know dbase, and have worked with ms and msql), but for me this is not bad insightwise, and certainly not efficiencywise, and freedomwise.

We can now edit the data fields in out database fairly comfortably however, and 'stepping through' the dbase with image can be done at high speed on a recent machine.

Simply edit the text fields, and use Next/Prev and the index in between (followed by Return) to navigate. The selection and cursor will be in the field with the same name (when it exists) during navigating, so typing data for images on a row can be efficient. Possibly bind a function key to the prev and next buttons.

The database can easily be compressed by some zipper very efficiency, but is small compared to image size, and of course these fields are just examples, and for each entry a completely different, and dynamically changeable number and type of fields can be used and searched through the dbsearch procedure. Basically [lindex $dbvar $index] returns a list of all fields of an entry, organized mainly as pairs (list with 2 elements) of name/value.

Now we can make a link with the server. I set the docroot directory to the top of the image tree in the tclhttp resource file (or in the main tcl script), so that in principle we can server the images by relative path, and because we've got all the data we want about them in the dbvar global variable, it is easy enough to make a
 Direct_Url /test test

which uses a procedure test which must return a webpage when it is called when a browser acccesses the page /test on the (probably for this test local) webserver.

This non-production proc prints the raw contents of the next database entry in text form, and show the accompanying image in a webpage. It uses the dbform window, and pushes it's next button every time the page is reloaded:
 proc test { {args} } {
    global dbcurrent dbvar;

# send $args; for debugging use when setup is also fitted with pcom for remote management
    .dbf.wb.ne invoke ;
    return "<html>$dbcurrent<p><img src=\"[eval file join [lrange [file split [lindex [lindex $dbcurrent 1] 1]] 2 end]]\"></html>"
 }

Updating the fields in the .bdf window can be done this way, and will be recorded automatically in dbvar, which can be saved by pressing 'Save' in the Database Control window, without asking for overwrite confirm.

...

To start the whole setup automatically, I use the following startup script:
 console show
 source e:/Theo/bwiseprocs0343.tcl

 bwise
 update

 wm geom . 636x350+9+4
 #update

 # comment out when no more need..
 welcome

 package require Img
 dbcontrol e:/Theo/dbimages2sort.tcl
 set defaultprocs {}
 unset defaultprocs
 get_procvanilla c:/Theo/tcl/tclhttpd3.4.1/bin/defaultprocs.tcl
 procs_window
 update
 wm geom .f 355x351+658+4
 .f.fu.l conf -font {{MS Sans Serif} 10}
 .f.ft.t conf -font {{MS Sans Serif} 12}
 source c:/Theo/tcl/tclhttpd3.4.1/bin/tryserv.tcl

Press the Database Control 'load' button to get the previously saved version back. And make a index.html file to point to the /test semi-cgi.