Version 0 of Image Server starter code for tclhttpd

Updated 2002-10-22 04:12:59

This code implements a quick and dirty image server for tclhttpd. It is was intented to allow hassle free deployment of your digital photos. It runs in 2 modes. Mode 1 shows a table of thumb nails of which you can click on an download the full image. Mode 2 performs a slide show using a JavaScript(cough cough) template. Other features include traversal through catalogs, auto thumbnail generation, and a not completed album file which will include presentation info for the current catalog being viewed. This code is only tested on an Windows XP machine. Place this code in your Document Root/Custom directory. Some modifications will be needed. I'll fix it up later. Good luck !

Art [email protected]

# $Id: 4371,v 1.1 2002-10-22 08:01:12 jcw Exp $# # This is my Tcl http image server.

if { ! info exists IserverInit } {

        Url_PrefixInstall /images [list ImageServerDomain /images]
        set IserverInit 1

}

package require Img

proc ImageServerDomain {prefix sock suffix} {

 upvar #0 Httpd$sock data

# fix this kludge

 regsub -all {%20} $prefix { } prefix
 regsub -all {%20} $suffix { } suffix


 global Config

#make prefix relative

 regsub {^/} $suffix {} suffix
 set fullRelativePath [file join $prefix $suffix] ; # (eg. /image/dirA/dirB/DirC )

 regsub {^/} $fullRelativePath {} pfx
 set realdir [file join $Config(docRoot) $pfx]
 if { ! [file isdirectory $realdir] } {

# it appears that all the images needed to populate a html page all call this routine enter this spot here to return image data

  Httpd_ReturnFile $sock image/JPEG $realdir 
  return 
 }

 set title [file tail $realdir]
 set usePresentation 0
 set srcImages,names {}
 set {srcImages,thumbs} {}
 set srcImages,titles {}
 set sub,dirs {}

# Generate page header

 set html "<html><title>Album $title </title>\n"

#--- This is a control file in a album directory # it has things like a list of files not to display , titles for image, to be defined later...

 global album
 array set album {skipImages {}}
 set albumFile [file join $realdir album]
 if { [file exists $albumFile] } {
  set f [open $albumFile r]
  set Data [read $f]
  close $f
  foreach line [split $Data \n] {
   array set album $line
  }
 }

 set thumbdir [file join $realdir thumbs]
 if { ! [file exists $thumbdir] } {  file mkdir $thumbdir } 

## -- This populates: srcImages,names ; srcImages,titles ; lappend sub,dirs ## -- and created thumbnails if they do not exist

 foreach x [glob $realdir/*] {
 if { [lsearch $album(skipImages) [file tail $x]] >= 0 } {  continue }
  if { [string compare [string tolower [file extension $x]] ".jpg"] == 0 } { 
   lappend srcImages,names $x
   lappend srcImages,titles [file tail $x]
   set thumbfile [file join $thumbdir [file tail $x] ]
   lappend srcImages,thumbs $thumbfile
   if { ! [file exists $thumbfile ] || ( [file mtime $x] > [file mtime $thumbfile] ) } {
    set src [image create photo -file $x -format jpeg]
    set wi [image width $src]
    set he [image height $src]
    set dest [image create photo -width 128 -height 128]
    $dest copy $src -subsample [expr $wi/128] [expr $he/128]
    image del $src
    $dest write $thumbfile -format jpeg
    image del $dest
   }
  } elseif { [file isdirectory $x] &&   [string compare [file tail $x] "thumbs"] != 0 } {
   lappend sub,dirs $x
  }
 }

 append html "<dl>"
 if { [string compare [file dirname $fullRelativePath] "/"] != 0 } {
         append html "<dt><A href=\"[file dirname $fullRelativePath]\"> Back to Last Catalog</A></li>"
 }
 if { [llength ${srcImages,titles}] >=2 } { 
         append html "<dt><A href=\"/slide/go?url=$fullRelativePath&files=${srcImages,titles}\" target = 1> Slide show</A></li>"
 }

 foreach x ${sub,dirs} {
  append html "<dt><dd><img src=\"/folder.gif\"> <A href=\"[file join $fullRelativePath [file tail $x]]\"> [file tail $x]</A>"
 }
 append html "</dl>"

 if { [llength ${srcImages,thumbs} ] > 0 } {
  append html "<Table border=\"0\" align=\"center\" width=\"100%\"><tbody><tr>"
 }
 set row 0
 set col 1
 foreach thumbFile ${srcImages,thumbs} localSrcFileName ${srcImages,names} {
  set hrefImg [file join $fullRelativePath [file tail $localSrcFileName] ]
  set srcImg [file join $fullRelativePath thumbs [file tail $thumbFile] ]
  if { [expr int( fmod( $col,4)) ] == 0 } { append html "</tr><tr>"  } 
  append html "<td><A href=\"$hrefImg\"> <img src=\"$srcImg\"></A></td>"
  incr col
 }
 if { [llength ${srcImages,thumbs} ] > 0 } {
  append html "</tr></tbody></Table>"
 }

 Httpd_ReturnData $sock text/html $html

}

proc isJpeg {afile } {

 if { [string compare [string tolower [file extension $afile]] ".jpg"] == 0 } {
  if { [file exists $afile] } { 
   return 1 
  }
 }
 return 0

}

# $Id: 4371,v 1.1 2002-10-22 08:01:12 jcw Exp $#

if { ! info exists SlideInit } {

 Direct_Url /slide        ::slide::
        set SlideInit 1

}

namespace eval ::slide {

    variable x [clock format [clock seconds]]

}

# ::hello::/ -- # # This implements /hello/

proc ::slide::/ {args} {

    return "Hello, World!"

}

# ::hello::/ -- # # This implements /hello/

# Need to pass in the directory name and not the files # or do a %s encoding of spaces in names when passing in mike vonplinksis files # put mini pictures in the catalog # title each picture as it is drawn # when slide show hits end. the back button needs to be pressed twice # table for control buttons seperate from table from other controls # somehow put in a toolbarless window # raise the window if exists already # verify the javascript # consider how to obfuscate the code # fix aspect ratio change of the image

proc ::slide::/go {args} {

    variable x
 set url [lindex $args 1]
 set files [lindex $args 3]
 set files [join $files ,]

# regsub -all {,} $files "\",\"http://68.6.44.242:8085$url/ " files # set files \"http://68.6.44.242:8085$url/$files\ "

 regsub -all {,} $files "\",\"$url/" files
 set files \"$url/$files\"
 set tmp $::data                        
 regsub -all {theLen} $tmp $files tmp
 return $tmp

}

set data {<html> <head> <script language="JavaScript"> //# XXX$Id: 4371,v 1.1 2002-10-22 08:01:12 jcw Exp $#

// replace ---- // theLen= // url= // baja //var url="http://68.6.44.242:8085/images/Trips/Baja/ "; // PUT THE URL'S OF YOUR IMAGES INTO THIS ARRAY... //var x=25; var t1=100; var t2=4000; var cur=0; var drawCnt=0; var start =1;

var CamDim = new Array('1152', '864'); var CamAspectRatio = CamDim0/CamDim1; var dispX=450; var dispY=dispX/CamAspectRatio; var ImAspectRatio = 1.0;

Slides=new Array(theLen); //for (var i = 0; i < Slides.length ; i++) //{ // Slidesi=url+'baja.'+i+'.jpg'; //}

function SetAspect( im ) { var x,y,ix,iy;

x = dispX; y = dispY; ix=im.width iy=im.height ImAspectRatio=ix/iy; var res = ""

if( CamAspectRatio > ImAspectRatio ) { x=y*ImAspectRatio

res = "cam>im" } else if ( CamAspectRatio < ImAspectRatio ) { y = x/ImAspectRatio;

//res="cam<im" } document.images'Screen'.width=x; document.images'Screen'.height=y; //window.status="res="+res+x+'/'+y + CamAspectRatio + ImAspectRatio; }

// Only called by buttons when auto play is not going function Step( val ) {

 var on=0
 var off=1
 var startB=on
 var stopB=on
 var endB=on
 var nextB=on
 var prevB=on
 var BeginB=on

 drawCnt=drawCnt+val;
 if( drawCnt < 0 ) {
                drawCnt=0;
                startB=on
                stopB=off
                endB=on
                nextB=on
                prevB=off
                BeginB=off
        } else {
                if(drawCnt >= Slides.length) {
                 drawCnt=Slides.length-1;
                startB=off
                stopB=off
                endB=off
                nextB=off
                prevB=on
                BeginB=on
         } else {
                startB=on
                stopB=off
                endB=on
                nextB=on
                prevB=on
                BeginB=on        
         }
        }

 if ( (typeof Slides[drawCnt] != 'string') ) {

SetAspect(SlidesdrawCnt);

  document.images['Screen'].src = Slides[drawCnt].src;
  document.SlideShow.text1.value=(1+drawCnt) + '/' + Slides.length ;
 }

// Handle Button states

                document.SlideShow.stop.disabled=stopB;
                document.SlideShow.start.disabled=startB;
                document.SlideShow.Next.disabled=nextB; 
                document.SlideShow.Previous.disabled=prevB; 
                document.SlideShow.End.disabled=endB; 
                document.SlideShow.Beginning.disabled=BeginB; 

}

function go ( val ) {

        if ( val == 1 ) { 
                if ( start == 1 ) { return true; }
                start = 1; drawit() ;
                document.SlideShow.stop.disabled=!val;
                document.SlideShow.start.disabled=val;
                document.SlideShow.Next.disabled=!val; 
                document.SlideShow.Previous.disabled=!val; 
                document.SlideShow.End.disabled=!val; 
                document.SlideShow.Beginning.disabled=!val;                 
        } else { 
                start = 0 
                document.SlideShow.stop.disabled=!val;
                document.SlideShow.start.disabled=val;
                document.SlideShow.Next.disabled=val; 
                document.SlideShow.End.disabled=val; 
                document.SlideShow.Previous.disabled=val;
                document.SlideShow.Beginning.disabled=val;                                                 
        }
        return true;

}

// Keep scheduling a cache of image indexed by cur variable // schedule a Draw only if cur == 0 function dl() {

 var ImageObject = new Image();
 ImageObject.src = Slides[cur];
 Slides[cur]=ImageObject;
 if(cur == 0 ) {

window.resizeTo(700,650) window.forward=1 window.toolbar=0 SetAspect(Slidescur);

  document.images['Screen'].src = Slides[cur].src;
         setTimeout("drawit()", t1);
 }
 cur++;
 if( cur < Slides.length ) {
                setTimeout("dl()", 100);
        }
        return true;

}

function drawit() {

 if ( (typeof Slides[drawCnt] != 'string') ) {

SetAspect(SlidesdrawCnt);

  document.images['Screen'].src = Slides[drawCnt].src;
  document.SlideShow.text1.value=(1+drawCnt) + '/' + Slides.length ;
  t2 = 1000*document.SlideShow.t2.value;

  drawCnt++;
  if( drawCnt < Slides.length ) { 
                  if (start )
                          setTimeout("drawit()", t2);
  } else { 
  go(0)
                document.SlideShow.Next.disabled=1; 
                document.SlideShow.End.disabled=1; 
                document.SlideShow.start.disabled=1;

  }
 } else {
          if (start )
                 setTimeout("drawit()", t1);
 }
 return true;

}

</script>

</head>

<body onLoad="dl()";> <body> <form name="SlideShow"> <img name="Screen" > <table align=left> <tr> <td><input type="button" disabled= 1 name="Beginning" value="<<" onClick="Step(-100)"></td> <td><input type="button" disabled= 1 name="Previous" value="<" onClick="Step(-1)"></td> <td> <input type="button" disabled= 1 name="start" value="Start" onClick="go(1)"></td> <td> <input type="button" name="stop" value="Stop" onClick="go(0)"></td> <td> <input type="button" disabled= 1 name="Next" value=">" onClick="Step(1)"></td> <td> <input type="button" disabled= 1 name="End" value=">>" onClick="Step(100000)"></td>

</tr> <tr><td><input type=text name="text1" size="7" disabled=1></td> <td>Show Time (seconds)<select size=1 name=t2><Option value=1>1<option selected value=2>2<option value=3>3<option value=4>4<option value=5>5<option value=6>6 </select></td></tr>

</table> </form>

</body> </html> }