Attachment 'Gallery-086.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     Gallery.py  Version 0.86
   4                                                                                                            
   5     This macro creates dynamic tabulated displays based on attachment contents
   6                                                                                                            
   7     @copyright: 2004,2005 by Simon Ryan <simon<at>smartblackbox.com>  http://smartblackbox.com/simon
   8     @license: GPL
   9 
  10     Special thanks go to: 
  11 	My beautiful wife Jenny: For keeping the kids at bay long enough for me to code it :-)
  12         Adam Shand: For his GallerySoftware feature wish list, support, ideas and suggestions.
  13 
  14     Usage: [[Gallery(key1=value1,key2=value2....)]]
  15 
  16       where the following keys are valid:
  17 	  thumbnailwidth     = no of pixels wide to make the thumbnails
  18 	  webnailwidth       = width in pixels of the web sized images
  19 	  numberofcolumns    = no of columns used in the thumbnail table
  20 
  21     Bugs:
  22 
  23       Continued rotation will degrade the tmp images (but they can be forced to regen)
  24 
  25     Features:
  26 
  27       Simple usage, just put [[Gallery]] on any page and upload some pictures as attachments
  28       Rotate buttons
  29       Annotation
  30       Should work with MoinMoin versions 1.2.x and 1.3.x
  31       Support for Python Imaging Library
  32       Works with FastCGI mode
  33 
  34 
  35     Not yet implemented:
  36       Handling of video formats 
  37 
  38     Speed up:
  39 	# When you get really sick of how slow the moinmoin image system is, 
  40 	# you can either reconfigure your setup for FastCGI (highly recommended)
  41 	# or: set the following variables in your wikiconfig.py
  42 	gallerytempdir (the path to a writable directory)
  43 	gallerytempurl (the path in your webservers url space where this directory can be read from)
  44         eg:
  45 	    gallerytempdir='/var/www/html/nails'
  46 	    gallerytempurl='/nails'
  47 	  or maybe:
  48 	    gallerytempurl=url_prefix+'/nails'
  49 	# There are other ways of getting speedups for attachments, but these methods are the safest (IMHO)
  50 
  51 """
  52 
  53 __author__ = "Simon D. Ryan"
  54 __version__ = "0.86"
  55 
  56 from MoinMoin import config, wikiutil
  57 import string, cStringIO, os
  58 import commands, shutil
  59 from random import randint
  60 try:
  61     import Image
  62 except:
  63     pass
  64 
  65 class Globs:
  66     # A quick place to plonk those shared variables
  67     thumbnailwidth='200'
  68     webnailwidth='600'
  69     numberofcolumns=4
  70     adminmsg=''
  71     debuglevel=0
  72     originals={}
  73     convertbin=''
  74     annotated={}
  75     attachmentdir=''
  76     gallerytempdirroot=''
  77     gallerytempdir=''
  78     gallerytempurl=''
  79     galleryrotchar=''
  80     pagename=''
  81     admin=''
  82     bcomp=''
  83     baseurl=''
  84     timeout=40
  85     allowedextensions=['jpg','jpeg','png','bmp','tiff','gif']
  86 
  87 def message(astring,level=1):
  88     if level<=Globs.debuglevel:
  89         Globs.adminmsg=Globs.adminmsg+'<font color="#FF0000"><strong>Gallery</strong></font>:&nbsp;&nbsp;'+astring+'<br>\n'
  90 
  91 def version():
  92         return(' version <b>'+Globs.version+'</b> by Simon D. Ryan.'+\
  93 	'<br>Copyright 2004,2005 Simon D. Ryan<br>Gallery is a MoinMoin macro and is released under the '+\
  94 	'<a href="http://www.gnu.org/licenses/gpl.txt">GPL</a>\n'+\
  95 	'<p>Upload some images as attachments to <a href="'+Globs.baseurl+Globs.pagename+'?action=AttachFile"><b>'+Globs.pagename+'</b></a> and I will generate a gallery for you.')
  96 
  97 # Thanks to denny<at>ece.arizona.edu
  98 # This can be replaced with a static translation table to speed things up (later)
  99 def mktrans():
 100         # Allow only letters and digits and a few other valid file characters
 101 	alphanumeric=string.letters+string.digits+'.,-_\'!"'
 102 	source_string=""
 103 	destination_string=""
 104 	for i in range(256):
 105 		source_string=source_string+chr(i)
 106 		if chr(i) in alphanumeric:
 107 			destination_string=destination_string+chr(i)
 108 		else:
 109 			destination_string=destination_string+' '
 110 	return string.maketrans(source_string,destination_string)
 111 
 112 def qlink(pagename, querystring, query, description=''):
 113     # Returns a hyperlink constructed as a form query on pagename
 114     if not description:
 115         description=query
 116     return '<a href="'+Globs.baseurl+pagename+'?'+querystring+'='+query+Globs.bcomp+'">'+description+'</a>'
 117 
 118 def navibar(target,querystring):
 119     # Returns a navigational bar with PREV,THUMBS,NEXT
 120     positions=Globs.originals.keys()
 121     positions.sort()
 122     thumbs='<a href="'+Globs.subname+'">THUMBS</a>'
 123     index=positions.index(target)
 124     back,forward='',''
 125     if not index==0:
 126         # We are not the first so we can provide a back link
 127 	back=qlink(Globs.pagename, querystring, positions[index-1], 'PREV')
 128     if not index==len(positions)-1:
 129         # We are not the last so we can provide a forward link
 130 	forward=qlink(Globs.pagename, querystring, positions[index+1], 'NEXT')
 131     return '<table><tr><td>'+back+'</td><td>'+thumbs+'</td><td>'+forward+'</td></tr></table>'
 132 
 133 def toolbar(target,naillevel):
 134     if Globs.admin:
 135 	rotateleft='<input type="submit" name="rotate" value="rotate left">'
 136 	rotateright='<input type="submit" name="rotate" value="rotate right">'
 137 	htarget='<input type=hidden value="'+target+'" name="'+naillevel+'">'
 138 	compat='<input type=hidden value="show" name="action">'
 139 	return '<form METHOD=POST><table><tr><td>'+rotateleft+'</td><td>'+rotateright+'</td></tr></table>\n'+htarget+compat+'</form>'
 140     else:
 141         return ''
 142 
 143 def buildnails(items):
 144     # For now we use commands.getoutput to do our dirty work
 145     # Later we can build a batch job and fork it off.
 146 
 147     # Make sure our temp directory is writable and generate a message if it isn't
 148     try:
 149 	if not os.path.isfile(Globs.gallerytempdir+'/tmp.writetest'):
 150 	    # There is probably a less ugly was to do this using stat (later)
 151 	    open(Globs.gallerytempdir+'/tmp.writetest','w').close()
 152     except IOError:
 153         message('I had some trouble writing to the temp directory. Is it owned by me and writable?',0)
 154 
 155     # Don't go further if there is a lock in place
 156     if os.path.isfile(Globs.attachmentdir+'/tmp.lock'):
 157         message("I'm currently busy generating thumbnails and webnails, please try again later.",0)
 158 	return ''
 159 
 160     # Find the convert binary in standard locations
 161     if not globals().has_key('Image'):
 162 	if not os.path.isfile('/usr/bin/convert'):
 163 	    if not os.path.isfile('/usr/X11R6/bin/convert'):
 164 		message('<b>Please install ImageMagick or PIL so I can build thumbnails and webnails</b><p>',0)
 165 		return
 166 	    else:
 167 		Globs.convertbin='/usr/X11R6/bin/convert'
 168 	else:
 169 	    Globs.convertbin='/usr/bin/convert'
 170     else:
 171         # Use Python Imaging Library
 172         Globs.convertbin='Image'
 173 
 174     # Create a lock file in the attachments dir so we can always remotely remove it if there is a problem
 175     open(Globs.attachmentdir+'/tmp.lock','w').close()
 176     
 177     import time
 178     tstart=time.time()
 179     pid,pid2='',''
 180 
 181     # For each original file, check for the existance of a nail
 182     for item in items:
 183         basename,prefix,width=item
 184 
 185 	# Check to see if we tarry too long on the road
 186 	if tstart and (time.time()-tstart) > Globs.timeout:
 187 	    # This is taking waaay too long let us fork and detach else the browser will time out or worse, the webserver may kill us
 188 	    pid = os.fork()
 189 	    if pid != 0:
 190 	        # We are in the parent so we break out
 191 		message('The thumbnail generation process was taking too long so it has been backgrounded. Please try again later to see the full set of thumbnails',0)
 192 		break
 193 	    else:
 194 		# Once we are forked we want to ignore the time
 195 		tstart=''
 196 	        # Break away from the controlling terminal, so that the web server cannot kill us by killing our parent
 197 	        os.setsid()
 198 		# Fork again so we can get away without a controlling terminal
 199 		pid2 = os.fork()
 200 		if (pid2 != 0):
 201 		    os._exit(0)
 202 		else:
 203 		    # Close all open file descriptors
 204 		    try:
 205 		        max_fd = os.sysconf("SC_OPEN_MAX")
 206 		    except (AttributeError, ValueError):
 207 		        max_fd = 256
 208 		    for fd in range(0, max_fd):
 209                         try:
 210 			    os.close(fd)
 211 			except OSError:
 212 			    pass
 213 		    # Redirect the standard file descriptors to /dev/null
 214 		    os.open("/dev/null", os.O_RDONLY)    # stdin
 215 		    os.open("/dev/null", os.O_RDWR)      # stdout
 216 		    os.open("/dev/null", os.O_RDWR)      # stderr
 217 
 218 		    # Now we are finally free to continue the conversions as a daemon
 219 		    # If you would like to know more about the above, see:
 220 		    #   Advanced Programming in the Unix Environment: W. Richard Stevens
 221 		    # It is also explained in:
 222 		    #   Unix Network Programming (Volume 1): W. Richard Stevens
 223 
 224 	#pathtooriginal='"'+Globs.attachmentdir+'/'+Globs.originals[basename]+'"'
 225 	pathtooriginal='"'+os.path.join(Globs.attachmentdir,Globs.originals[basename])+'"'
 226 	# Warning:
 227 	# Take care if modifying the following line, 
 228 	# you may inadvertantly overwrite your original images!
 229 	if not Globs.convertbin == 'Image':
 230 	    #print 'building nail for '+pathtooriginal
 231 	    #convout=commands.getoutput('%s -geometry %s \"%s\" "\"%s/%s.%s.jpg\""' % (Globs.convertbin,width+'x'+width,pathtooriginal,Globs.gallerytempdir,prefix,basename))
 232 	    convout=commands.getoutput('%s -geometry %s %s "%s/%s.%s.jpg"' % (Globs.convertbin,width+'x'+width,pathtooriginal,Globs.gallerytempdir,prefix,basename))
 233 	    convout=''
 234 	    convout=string.strip(convout)
 235 	    if convout:
 236 		message(convout)
 237 	else:
 238 	    # Use PIL  (strip off the "")
 239 	    im = Image.open(pathtooriginal[1:-1])
 240 	    # Use the integer version for PIL
 241 	    width=string.atoi(width)
 242 	    im.thumbnail((width,width), Image.ANTIALIAS)
 243 	    im.save(os.path.join(Globs.gallerytempdir,prefix)+'.'+basename+'.jpg','JPEG')
 244 
 245     if (not pid) and (not pid2):
 246 	# Release the lock file when finished
 247 	os.unlink(Globs.attachmentdir+'/tmp.lock')
 248 
 249     # We have built thumbnails so we can deposit an indicator file to prevent rebuilding next time
 250     if not os.path.isfile(Globs.attachmentdir+'/delete.me.to.regenerate.thumbnails.and.webnails'):
 251         open(Globs.attachmentdir+'/delete.me.to.regenerate.thumbnails.and.webnails','w').close()
 252 
 253 
 254 def rotate(target,direction):
 255     # Rotate the images
 256     # Don't go further if there is a lock in place
 257     if os.path.isfile(Globs.attachmentdir+'/tmp.lock'):
 258         message("I'm currently busy generating thumbnails and webnails. Please try your rotate request again later.",0)
 259 	return ''
 260 
 261     # Find the correct binary
 262     if not globals().has_key('Image'):
 263 	if not os.path.isfile('/usr/bin/mogrify'):
 264 	    if not os.path.isfile('/usr/X11R6/bin/mogrify'):
 265 		message('<b>Please install ImageMagick so I can build thumbnails and webnails</b><p>',0)
 266 		return
 267 	    else:
 268 		Globs.convertbin='/usr/X11R6/bin/mogrify'
 269 	else:
 270 	    Globs.convertbin='/usr/bin/mogrify'
 271     else:
 272         Globs.convertbin = 'Image'
 273 
 274     # Do the actual rotations
 275     if direction=='rotate right':
 276 	degs='90'
 277     else:
 278 	degs='270'
 279     if not Globs.convertbin == 'Image':
 280 	convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.webnail.'+target+'.jpg"')
 281 	convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.thumbnail.'+target+'.jpg"')
 282 	if not os.path.isfile(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg'):
 283 	    # Generate from original
 284 	    pathtooriginal=Globs.attachmentdir+'/'+Globs.originals[target]
 285 	    shutil.copy(pathtooriginal,Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg')
 286 	convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg"')
 287     else:
 288 	# Use PIL  (strip off the "")
 289 	if direction=='rotate right':
 290 	    degs=270.0
 291 	else:
 292 	    degs=90.0
 293 	im = os.path.join(Globs.gallerytempdir,'tmp.webnail.')+target+'.jpg'
 294 	imw = Image.open(im)
 295 	imw.rotate(degs).save(im,'JPEG')
 296 	im = os.path.join(Globs.gallerytempdir,'tmp.thumbnail.')+target+'.jpg'
 297 	imw = Image.open(im)
 298 	imw.rotate(degs).save(im,'JPEG')
 299 	imo = os.path.join(Globs.gallerytempdir,'tmp.rotated.')+target+'.jpg'
 300 	if not os.path.isfile(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg'):
 301 	    # Generate from original
 302 	    im=Globs.attachmentdir+'/'+Globs.originals[target]
 303 	else:
 304 	    im = imo
 305 	imw = Image.open(im)
 306 	imw.rotate(degs).save(imo,'JPEG')
 307 
 308 def getannotation(target):
 309     # Annotations are stored as a file for now (later to be stored in images)
 310     atext=''
 311     if Globs.annotated.has_key(target):
 312 	atext=open(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt').readline()
 313 	message('was annotated')
 314     else:
 315 	message('was not annotated')
 316     # replace double quotes with the html escape so quoted annotations appear
 317     return string.replace(atext,'"','&quot;')
 318 
 319 def execute(macro, args):
 320 
 321     Globs.version=__version__
 322 
 323     # Containers
 324     formvals={}
 325     thumbnails={}
 326     webnails={}
 327     rotated={}
 328     try:
 329         import wikiconfig
 330     except:
 331         wikiconfig=''
 332 
 333     # Class variables need to be specifically set 
 334     # (except for the case where a value is to be shared with another Gallery macro on the same wiki page)
 335     Globs.originals={}
 336     Globs.annotated={}
 337     Globs.attachmentdir=''
 338     Globs.admin=''
 339     Globs.adminmsg=''
 340     Globs.pagename=''
 341 
 342     # process arguments
 343     if args:
 344 	# Arguments are comma delimited key=value pairs
 345 	sargs=string.split(args,',')
 346 	for item in sargs:
 347 	    sitem=string.split(item,'=')
 348 	    if len(sitem)==2:
 349 		key,value=sitem[0],sitem[1]
 350 		if key=='thumbnailwidth':
 351 		    Globs.thumbnailwidth=value
 352 		elif key=='webnailwidth':
 353 		    Globs.webnailwidth=value
 354 		elif key=='numberofcolumns':
 355 		    try:
 356 			Globs.numberofcolumns=string.atoi(value)
 357 		    except TypeError:
 358 		        pass
 359 		# Experimental, uncomment at own risk
 360 		#elif key=='pagename':
 361 		#    Globs.pagename=value
 362 
 363     transtable=mktrans()
 364 
 365     # Useful variables
 366     dontregen=''
 367     annotationmessage=''
 368     Globs.baseurl=macro.request.getBaseURL()+'/'
 369     if not Globs.pagename:
 370 	#Globs.pagename = string.replace(macro.formatter.page.page_name,'/','_2f')
 371 	Globs.pagename = macro.formatter.page.page_name
 372 	# This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
 373 	Globs.subname = string.split(Globs.pagename,'/')[-1]
 374     # Hmmm. A bug in moinmoin? underscores are getting escaped. These doubly escaped pagenames are even appearing in data/pages
 375     try:
 376         # Try the old MoinMoin-1.2.x way first
 377         textdir=config.text_dir
 378         pagepath = string.replace(wikiutil.getPagePath(Globs.pagename),'_5f','_')
 379     except:
 380         pagepath = macro.formatter.page.getPagePath()
 381     Globs.attachmentdir = pagepath+'/attachments'
 382     Globs.galleryrotchar='?'
 383     if hasattr(macro,'cfg') and hasattr(macro.cfg,'gallerytempdir') and hasattr(macro.cfg,'gallerytempurl'):
 384 	Globs.gallerytempdirroot=macro.cfg.gallerytempdir
 385 	Globs.gallerytempdir=macro.cfg.gallerytempdir+'/'+Globs.pagename+'/'
 386 	Globs.gallerytempurl=macro.cfg.gallerytempurl+'/'+Globs.pagename+'/'
 387     elif hasattr(wikiconfig,'gallerytempdir') and hasattr(wikiconfig,'gallerytempurl'):
 388         message('gallerytempdir and gallerytempurl found')
 389 	Globs.gallerytempdirroot=wikiconfig.gallerytempdir
 390 	Globs.gallerytempdir=wikiconfig.gallerytempdir+'/'+Globs.pagename+'/'
 391 	Globs.gallerytempurl=wikiconfig.gallerytempurl+'/'+Globs.pagename+'/'
 392     elif hasattr(wikiconfig,'attachments'):
 393 	Globs.gallerytempdirroot=wikiconfig.attachments['dir']
 394 	Globs.gallerytempdir=wikiconfig.attachments['dir']+'/'+Globs.pagename+'/attachments/'
 395 	Globs.gallerytempurl=wikiconfig.attachments['url']+'/'+Globs.pagename+'/attachments/'
 396 	Globs.attachmentdir = Globs.gallerytempdir
 397     else:
 398 	Globs.gallerytempdir=Globs.attachmentdir
 399 	Globs.gallerytempurl=Globs.subname+'?action=AttachFile&amp;do=get&amp;target='
 400 	# MoinMoin no longer allows us to use a ? to trigger a refetch, so we pass it a &
 401 	Globs.galleryrotchar='&'
 402     if args:
 403         args=macro.request.getText(args)
 404 
 405     # HTML Constants
 406     tleft='<table><tr><td><center>'
 407     tmidd='</center></td><td><center>'
 408     trigh='</center></td></tr></table>\n'
 409     # Add this to the end of each URL to keep some versions of moinmoin happy 
 410     Globs.bcomp='&action=show'
 411 
 412     # Process any form items into a dictionary (values become unique)
 413     for item in macro.form.items():
 414         if not formvals.has_key(item[0]):
 415             # Here is where we clean the untrusted web input
 416 	    # (sometimes we get foreign keys from moinmoin when the page is edited)
 417 	    try:
 418 		formvals[item[0]]=string.translate(item[1][0],transtable)
 419 	    except AttributeError:
 420 	        pass
 421 
 422     # Figure out if we have delete privs
 423     try:
 424         # If a user can delete the page containing the Gallery, then they are considered a Gallery administrator
 425 	# This probably should be configurable via a wikiconfig variable eg: galleryadminreq = <admin|delete|any>
 426         if macro.request.user.may.delete(macro.formatter.page.page_name):
 427             Globs.admin='true'
 428     except AttributeError:
 429         pass
 430     
 431     out=cStringIO.StringIO()
 432 
 433     # Grab a list of the files in the attachment directory
 434     if os.path.isdir(Globs.attachmentdir):
 435         if Globs.gallerytempdir==Globs.attachmentdir:
 436 	    afiles=os.listdir(Globs.attachmentdir)
 437 	else:
 438 	    if not os.path.isdir(Globs.gallerytempdirroot):
 439 	        message('You need to create the temp dir first:'+Globs.gallerytempdirroot,0)
 440 		return macro.formatter.rawHTML(
 441 		    Globs.adminmsg+'<p>')
 442 	    if not os.path.isdir(Globs.gallerytempdir):
 443 	        # Try to create it if it is absent
 444 		spagename=string.split(Globs.pagename,'/')
 445 		compbit=''
 446 		for component in spagename:
 447 		    compbit=compbit+'/'+component
 448                     try:
 449 		        os.mkdir(Globs.gallerytempdirroot+compbit)
 450                     except:
 451 			message('Please check permissions on temp dir:'+Globs.gallerytempdirroot,0)
 452 			return macro.formatter.rawHTML(
 453 			    Globs.adminmsg+'<p>')
 454                         
 455 	    if os.path.isdir(Globs.gallerytempdir):
 456 		afiles=os.listdir(Globs.attachmentdir)+os.listdir(Globs.gallerytempdir)
 457 	    else:
 458 	        message('You need to create the temp dir first:'+Globs.gallerytempdir,0)
 459 		return macro.formatter.rawHTML(
 460 		    Globs.adminmsg+'<p>')
 461 
 462 	# Split out the thumbnails and webnails
 463 	for item in afiles:
 464 	    if item.startswith('tmp.thumbnail.'):
 465 	        origname=item[14:-4]
 466 		thumbnails[origname]=''
 467 	    elif item.startswith('tmp.webnail.'):
 468 	        origname=item[12:-4]
 469 		webnails[origname]=''
 470 	    elif item.startswith('tmp.rotated.'):
 471 	        origname=item[12:-4]
 472 		rotated[origname]=''
 473 	    elif item.startswith('tmp.annotation.'):
 474 	        origname=item[15:-4]
 475 		Globs.annotated[origname]=''
 476 	    elif item == 'delete.me.to.regenerate.thumbnails.and.webnails':
 477 	        dontregen='true'
 478 	    elif item == 'tmp.writetest' or item == 'tmp.lock':
 479 	        pass
 480 	    else:
 481 	        # This must be one of the original images
 482 		lastdot=string.rfind(item,'.')
 483 		origname=item[:lastdot]
 484                 ext = item[lastdot+1:]
 485                 if string.lower(ext) not in Globs.allowedextensions:
 486                     continue
 487 		Globs.originals[origname]=item
 488     else:
 489         message(version(),0)
 490 	return macro.formatter.rawHTML( Globs.adminmsg )
 491 
 492     if not Globs.gallerytempdir==Globs.attachmentdir and os.path.isfile(Globs.attachmentdir+'/tmp.writetest'):
 493 	    # If we are using the new gallerytempdir and we were using the old system then make sure there are no 
 494 	    # remnant files from the old system in the attachment dir to confuse us
 495 	    message('You have changed to using a gallerytempdir so I am cleaning old tmp files from your attachment dir.',0)
 496 	    for item in webnails.keys():
 497 	        try:
 498 		    os.unlink(Globs.attachmentdir+'/tmp.webnail.'+item+'.jpg')
 499 		except:
 500 		    pass
 501 	    # Try deleting any old thumbnails which may be in the attachment directory
 502             for item in thumbnails.keys():	
 503 	        try:
 504 		    os.unlink(Globs.attachmentdir+'/tmp.thumbnail.'+item+'.jpg')
 505 		except:
 506 		    pass
 507 	    # Try deleting any old rotated originals which may be in the attachment directory
 508             for item in rotated.keys():	
 509 	        try:
 510 		    os.unlink(Globs.attachmentdir+'/tmp.rotated.'+item+'.jpg')
 511 		except:
 512 		    pass
 513 	    os.unlink(Globs.attachmentdir+'/tmp.writetest')
 514 
 515     newnails=[]
 516     # Any thumbnails need to be built?
 517     for key in Globs.originals.keys():
 518         if (not thumbnails.has_key(key)) or (not dontregen):
 519 	    # Create a thumbnail for this original
 520 	    newnails.append((key,'tmp.thumbnail',Globs.thumbnailwidth))
 521     # Any webnails need to be built?
 522     for key in Globs.originals.keys():
 523         if (not webnails.has_key(key)) or (not dontregen):
 524 	    # Create a webnail for this original
 525 	    newnails.append((key,'tmp.webnail',Globs.webnailwidth))
 526     # Ok, lets build them all at once
 527     if not len(newnails)==0:
 528 	buildnails(newnails)
 529 
 530     # If a regen of thumbnails and webnails has occurred, then we should also delete any tmp.rotated files.
 531     if not dontregen:
 532         for key in rotated.keys():
 533 	    # Wrapped in a try except since child processes may try to unlink a second time
 534 	    try:
 535 		os.unlink(Globs.gallerytempdir+'/tmp.rotated.'+key+'.jpg')
 536 	    except:
 537 		pass
 538 
 539     if formvals.has_key('annotate'):
 540         if Globs.admin and formvals.has_key('target'):
 541 	    target=formvals['target']
 542 	    # Write an annotation file
 543 	    atext=string.replace(formvals['annotate'],'"','&quot;')
 544 	    target=formvals['target']
 545 	    ouf=open(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt','w')
 546 	    ouf.write(atext)
 547 	    ouf.close()
 548 	    message('Annotation updated to <i>'+atext+'</i>',0)
 549 	    # Now update the annotated dictionary
 550             if not Globs.annotated.has_key(target):
 551 	        Globs.annotated[target]=''
 552 
 553     if formvals.has_key('webnail'):
 554 	# Does the webnail exist?
 555         message('webnail requested')
 556 	target=formvals['webnail']
 557 	rotend=''
 558 	if Globs.originals.has_key(target):
 559 	    out.write(navibar(target,'webnail'))
 560 	    if formvals.has_key('rotate'):
 561 		direction=formvals['rotate']
 562 		message(direction)
 563 		rotate(target,direction)
 564 		rotend=Globs.galleryrotchar+'rot='+repr(randint(1,10000))
 565 	    # Put things in a table
 566 	    out.write(tleft)
 567 	    # Lets build up an image tag
 568 	    out.write('<a href="'+Globs.baseurl+Globs.pagename+'?original='+target+'&action=content"><img src="'+Globs.gallerytempurl+'tmp.webnail.'+target+'.jpg'+rotend+'"></a>\n')
 569 	    out.write(trigh)
 570 	    out.write(tleft)
 571 
 572 	    atext=getannotation(target)
 573 
 574 	    # Are we an administrator?
 575 	    if Globs.admin:
 576 	        # We always provide an annotation text field
 577 		out.write('<form action='+Globs.subname+' name=annotate METHOD=POST>')
 578 		out.write('<input maxLength=256 size=55 name=annotate value="'+atext+'">')
 579 		out.write('<input type=hidden value="'+target+'" name="target">')
 580 		out.write('<input type=hidden value="show" name="action">')
 581 		out.write('<input type=hidden value="'+target+'" name="webnail">')
 582 		out.write('</form>')
 583 	    else:
 584 		out.write(atext)
 585 	    out.write(trigh)
 586 	    out.write(toolbar(target,'webnail'))
 587 
 588 	else:
 589 	    message('I do not have file: '+target,0)
 590     elif formvals.has_key('original'):
 591 	# Now we just construct a single item rather than a table
 592 	# Does the webnail exist?
 593         message('original requested')
 594 	target=formvals['original']
 595 	rotend=''
 596 	if not Globs.originals.has_key(target):
 597 	    message('I do not have file: '+target,0)
 598 	else:
 599 	    if formvals.has_key('rotate'):
 600 		direction=formvals['rotate']
 601 		message(direction)
 602 		rotate(target,direction)
 603 		rotend=Globs.galleryrotchar+'rot='+repr(randint(1,10000))
 604 		rotated[target]=''
 605 	    # Lets build up an image tag
 606 	    out.write(navibar(target,'original'))
 607 	    out.write(tleft)
 608 	    originalfilename=Globs.originals[target]
 609 	    # If there is a rotated version, show that instead
 610 	    if rotated.has_key(target):
 611 		out.write('<a href="'+Globs.baseurl+Globs.pagename+'?webnail='+target+Globs.bcomp+'"><img src="'+Globs.gallerytempurl+'tmp.rotated.'+target+'.jpg'+rotend+'"></a>\n')
 612 	    else:
 613 		out.write('<a href="'+Globs.baseurl+Globs.pagename+'?webnail='+target+Globs.bcomp+'"><img src="'+Globs.subname+'?action=AttachFile&amp;do=get&amp;target='+originalfilename+'"></a>\n')
 614 	    out.write(trigh)
 615 	    out.write(tleft)
 616 
 617 	    atext=getannotation(target)
 618 
 619 	    # Are we an administrator?
 620 	    if Globs.admin:
 621 	        # We always provide an annotation text field
 622 		out.write('<form action='+Globs.subname+' name=annotate METHOD=POST>')
 623 		out.write('<input maxLength=256 size=55 name=annotate value="'+atext+'">')
 624 		out.write('<input type=hidden value="'+target+'" name="target">')
 625 		out.write('<input type=hidden value="show" name="action">')
 626 		out.write('<input type=hidden value="'+target+'" name="original">')
 627 		out.write('</form>')
 628 	    else:
 629 		out.write(atext)
 630 	    out.write(trigh)
 631 	    out.write(toolbar(target,'original'))
 632 
 633     elif formvals.has_key('rotate'):
 634         # We rotate all sizes of this image to the left or right
 635 	message('rotate requested')
 636 	target=formvals['target']
 637 	direction=formvals['rotate']
 638 	if not Globs.originals.has_key(target):
 639 	    message('I do not have file: '+target,0)
 640 	else:
 641 	    # Do the rotation
 642 	    rotate(target,direction)
 643             # Display the new image in webnail mode 
 644 	    # We may need a way of forcing the browser to reload the newly rotated image here (later)
 645 	    out.write(tleft)
 646 	    out.write('<a href="'+Globs.baseurl+Globs.pagename+'?webnail='+target+Globs.bcomp+'"><img src="'+Globs.gallerytempurl+'tmp.webnail.'+target+'.jpg"></a>\n')
 647 	    out.write(trigh)
 648 
 649     else:
 650 	# Finally lets build a table of thumbnails
 651 	thumbs=Globs.originals.keys()
 652 	thumbs.sort()
 653 	thumbs.reverse()
 654 	# If version number is requested (append a ?version=tellme&action=show to the page request)
 655 	# or if there are no original images, just give help message and return
 656 	if formvals.has_key('version') or len(thumbs)==0:
 657 	    message(version(),0)
 658 	    return macro.formatter.rawHTML( Globs.adminmsg )
 659 	out.write('\n<table>')
 660 	cease=''
 661 	rollover=''
 662 	while 1:
 663 	    out.write('<tr>')
 664 	    for i in range(Globs.numberofcolumns):
 665 		try:
 666 		    item=thumbs.pop()
 667 		except IndexError:
 668 		    cease='true'
 669 		    break
 670 
 671 		# Alt text
 672 		atext=getannotation(item)
 673 		rollover='alt="'+atext+'" title="'+atext+'"'
 674 
 675 		# Table entry for thumbnail image
 676 		out.write('<td><a href="'+Globs.baseurl+Globs.pagename+'?webnail='+item+Globs.bcomp+'"><center><img src="'+Globs.gallerytempurl+'tmp.thumbnail.'+item+'.jpg" '+rollover+'></a></center></td>')
 677 	    out.write('</tr>\n')
 678 	    if cease:
 679 		out.write('</table>')
 680 		break
 681 	
 682     out.seek(0)
 683     # Finally output any administrative messages at the top followed by any generated content
 684     return macro.formatter.rawHTML(
 685         Globs.adminmsg+'<p>'
 686         +out.read()	
 687     )

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2004-07-12 23:54:14, 22.8 KB) [[attachment:Gallery-082.py]]
  • [get | view] (2005-08-19 07:17:36, 26.0 KB) [[attachment:Gallery-086.py]]
  • [get | view] (2006-07-21 22:15:07, 28.0 KB) [[attachment:Gallery-087.py]]
  • [get | view] (2008-04-07 11:37:15, 9.0 KB) [[attachment:UmlautError_Gallery.txt]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.