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