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>: '+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,'"','"')
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&do=get&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'],'"','"')
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&do=get&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.You are not allowed to attach a file to this page.