Attachment 'Gallery2-1.3.3-5.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - Gallery2 parser
4
5 PURPOSE:
6 This parser is used to visualize a couple of images as a thumbnail gallery.
7 Optional a description of an image could be added including WikiName.
8 On default the image name and it's creation date is shown.
9
10 CALLING SEQUENCE:
11 {{{
12 #!Gallery2 [columns=columns],[filter=filter],[mode=mode],[show_text=show_text],
13 [show_date=show_date], [show_tools=show_tools],
14 [sort_by_name=sort_by_name],[sort_by_date=sort_by_date]
15 [only_items=only_items],[template_itemlist=template_itemlist],
16 [border_thick=border_thick],[renew=renew]
17 * [image1.jpg alias]
18 * [image2.jpg alias]
19 }}}
20
21 KEYWORD PARAMETERS:
22 columns: number of columns for thumbnails
23 filter: regex to select images
24 show_text: default is 1 description is shown
25 any other means no description
26 show_date: default is 1 date info from exif header if available is shown
27 sort_by_name: default is 1, the images are sorted by name, but not if only_items is 1
28 sort_by_date: default is 0, the images are sorted to the modification time
29 reverse_sort: default is 0, if set to 1 the file list is reversed
30 any other means no description
31 show_tools: default is 1 icon toolbar is show any other disables this
32 mode: default is 1 this means description below the image
33 any other number means description right of image
34 only_items: default is 0 if it is set to 1 only images which are described in listitem are shown
35 dependend on the order of the items
36 template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script.
37 border_thick: default is 1 this is the thickness in pixeln of the outer frame
38 renew: default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
39 Afterwards they are new created.
40 help: default is 0 if set a copy of the CALLING SEQUENCE is shown,
41 (there are some new ideas around to show help to an user so this will be later replaced)
42
43 OPTIONAL INPUTS:
44 itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
45 The alias text is used as description of the image instead of the file name
46
47
48 EXAMPLE:
49 = GalleryTest =
50
51 == all images shown, one is decribed ==
52 {{{
53 { { {
54 #!Gallery2
55 * [100_1185.JPG Bremen, SpaceCenter]
56 } } }
57 }}}
58
59 Result: [[BR]]
60 {{{
61 #!Gallery2
62 * [100_1185.JPG Bremen, SpaceCenter]
63 }}}
64
65 == only thumbnails and only_items ==
66 {{{
67 { { {
68 #!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
69 * [100_1185.JPG Bremen, SpaceCenter]
70 * [100_1194.JPG Bremen]
71 } } }
72 }}}
73
74 Result: [[BR]]
75 {{{
76 #!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
77 * [100_1185.JPG Bremen, SpaceCenter]
78 * [100_1194.JPG Bremen]
79 }}}
80
81 == only_items by two columns and text right ==
82
83 {{{
84 { { {
85 #!Gallery2 mode=2,columns=2,only_items=1
86 * [100_1185.JPG Bremen, SpaceCenter]
87 * [100_1194.JPG Bremen]
88 } } }
89 }}}
90
91 Result: [[BR]]
92 {{{
93 #!Gallery2 mode=2,columns=2,only_items=1
94 * [100_1185.JPG Bremen, SpaceCenter]
95 * [100_1194.JPG Bremen, behind SpaceCenter]
96 }}}
97
98 ----
99
100 == only_items by two columns, date supressed ==
101
102 {{{
103 { { {
104 #!Gallery2 columns=2,only_items=1,show_date=0
105 * [100_1185.JPG Bremen, SpaceCenter]
106 * [100_1194.JPG Bremen, behind SpaceCenter]
107 } } }
108 }}}
109
110 Result: [[BR]]
111 {{{
112 #!Gallery2 columns=2,only_items=1,show_date=0
113 * [100_1185.JPG Bremen, SpaceCenter]
114 * [100_1194.JPG Bremen, behind SpaceCenter]
115 }}}
116
117
118 == filter regex used, mode 2, icons and date supressed, one column and border_thick=5 ==
119 {{{
120 { { {
121 #!Gallery2 columns=1,filter=100_118[0-5],mode=2,show_date=0,show_tools=0,border_thick=5
122 } } }
123 }}}
124
125 Result: [[BR]]
126 {{{
127 #!Gallery2 columns=1,filter=100_118[0-7],mode=2,show_date=0,show_tools=0,border_thick=5
128 }}}
129
130 == other macro calls ==
131 {{{
132 { { {
133 #!Gallery2 only_items=1,show_date=0
134 * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
135 } } }
136 }}}
137
138 Result: [[BR]]
139 {{{
140 #!Gallery2 only_items=1,show_date=0
141 * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
142 }}}
143
144 == renew means always new thumbnails and webnails of selection ==
145 {{{
146 { { {
147 #!Gallery2 only_items=1,show_date=0,show_tools=0,renew=1
148 * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
149 } } }
150 }}}
151
152 Result: [[BR]]
153 {{{
154 #!Gallery2 only_items=1,show_date=0,renew=1
155 * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
156 }}}
157
158
159
160 PROCEDURE:
161 Download some images to a page and start with the examples.
162 Aliasing of the filenames are done by adding an itemlist, see example.
163
164 This routine requires the PIL (Python Imaging Library).
165 And the EXIF routine from http://home.cfl.rr.com/genecash/digital_camera.html
166
167
168 At the moment I have added the EXIF routine to the parsers dir.
169 It's not the best place but during developing it is nice to have it there
170 If you put it to another place you have to change the line
171 from MoinMoin.parser import EXIF too.
172
173 This routine requires the Action macro gallery2Image which is used to rotate or delete a selected image.
174 Only users which have the rights to delete are able to execute this action macro.
175 The icons of these are only shown if you have enough rights.
176
177 The gallery2image macro does not take care on the EXIF header. This is lost by rotating.
178 If a file is deleted by this macro it is moved to a bak file.
179
180 Please remove the Version number from the code!
181
182 RESTRICTIONS:
183 The slideshow is not implemented at the moment. The implementation will be done in the acrion macro.
184 This is not a quite big problem normally files with an EXIF header are right rotated.
185
186 Required Images:
187 I have put them to wiki/modern/img/ dir. The icons were created by me. License: GPL
188
189 attachment:to_bak.png
190 attachment:to_left.png
191 attachment:to_right.png
192 attachment:to_slide.png
193 attachment:to_full.png
194
195 HISTORY:
196 While recognizing how to write MiniPage I got the idea to write a Gallery Parser.
197 We have used in our wikis in the past the Gallery macro of SimonRyan.
198 I have tried to modify it a bit to change it for 1.3 but my python skills weren't enough
199 or it was easier to write it completly new.
200 So this one shows now a way how a Gallery could be used by the parser and an action Macro.
201 Probably it is a good example for others who like to know how to do this
202
203 MODIFICATION HISTORY:
204 Version 1.3.3.-1
205 @copyright: 2005 by Reimar Bauer (R.Bauer@fz-juelich.de)
206 @license: GNU GPL, see COPYING for details.
207 2005-03-26: Version 1.3.3-2 keyword renew added
208 creation of thumnails and webnails in two calls splitted
209 Version 1.3.3-3 bug fixed if itemlist is given to describe only some of the images
210 but only_items is not set to 1
211 Example code changed
212 2005-03-27: Version 1.3.3-4 Action macro added and the form to call it. User which have rights to delete
213 could use the functions of gallery2Image.
214 2005-08-03: Version 1.3.3-5 theme path for icons corrected and a platform independent path joining
215 os.unlink removed as suggested by CraigJohnson
216 sort_by_name is default if not only_items is 1
217 optional sort_by_date could be used
218 keyword template_itemlist added
219 keyword help added
220 extra frame by mode=2 removed
221
222
223
224 """
225 Dependencies = []
226 from MoinMoin.action import AttachFile
227 from MoinMoin import wikiutil, config
228 from MoinMoin.Page import Page
229 import os,string,re,Image,StringIO
230 from MoinMoin.parser import EXIF
231
232 from MoinMoin.parser import wiki
233
234 #def ImageProcess(var):
235 # f=open('/tmp/workfile.txt', 'w')
236 # f.write(var)
237 # f.close()
238
239 def get_quotes(self,formatter):
240 quotes = self.raw.split('\n')
241 quotes = [quote.strip() for quote in quotes]
242 quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
243
244 image=[]
245 alias=[]
246 for line in quotes:
247 im,na=line[1:-1].split(' ',1)
248
249 ##taken from MiniPage
250
251 out=StringIO.StringIO()
252 self.request.redirect(out)
253 wikiizer = wiki.Parser(na.strip(),self.request)
254 wikiizer.format(formatter)
255 na=out.getvalue()
256 self.request.redirect()
257 del out
258
259 alias.append(na)
260 image.append(im.strip())
261
262 result={}
263 result['alias']=alias
264 result['image']=image
265
266 return(result)
267
268
269
270 class Parser:
271 def __init__(self, raw, request, **kw):
272 self.raw = raw
273 self.request = request
274 self.form = request.form
275 self._ = request.getText
276 self.kw = {}
277 self.kw['sort_by_date']='0' # nor implemented at the moment
278 self.kw['sort_by_name']='1'
279 self.kw['template_itemlist']='0'
280 self.kw['reverse_sort']='0'
281 self.kw['border_thick']='1'
282 self.kw['columns']='4'
283 self.kw['filter']='.'
284 self.kw['mode']='1'
285 self.kw['help']='0'
286 self.kw['show_text']='1'
287 self.kw['show_date']='1'
288 self.kw['show_tools']='1'
289 self.kw['only_items']='0'
290 self.kw['renew']='0'
291 self.kw['thumbnail_width']='128'
292 self.kw['webnail_width']='640'
293 self.kw['text_width']='140'
294
295
296 for arg in kw.get('format_args','').split(','):
297
298 if (arg.find('=') > -1):
299 key=arg.split('=')
300 self.kw[str(key[0])]=wikiutil.escape(string.join(key[1],''), quote=1)
301
302 self.kw['width']=str((int(self.kw['thumbnail_width'])+int(self.kw['text_width'])))
303
304
305 def format(self, formatter):
306
307 kw=self.kw
308 Dict = {}
309 quotes=get_quotes(self,formatter)
310
311 current_pagename=formatter.page.page_name
312 attachment_path = AttachFile.getAttachDir(self.request,current_pagename,create=1)
313
314 if (kw['help'] == '1'):
315
316 self.request.write('<BR>')
317 self.request.write('{{{<BR>')
318 self.request.write('#!Gallery2 [columns=columns],[filter=filter],[mode=mode],[show_text=show_text],<BR>')
319 self.request.write(' [show_date=show_date], [show_tools=show_tools],<BR>')
320 self.request.write(' [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],<BR>')
321 self.request.write(' [only_items=only_items],[template_itemlist=template_itemlist],<BR>')
322 self.request.write(' [border_thick=border_thick],[renew=renew],[help=help]<BR>')
323 self.request.write(' * [image1.jpg alias]<BR>')
324 self.request.write(' * [image2.jpg alias]<BR>')
325 self.request.write('}}}<BR>')
326 return
327
328 if (kw['only_items'] == '1'):
329 all_files=quotes['image']
330 else:
331 all_files=os.listdir(attachment_path)
332
333 result=[]
334
335 for test in all_files:
336 if re.match(kw['filter'], test):
337 result.append(test)
338
339 all_files=result
340
341 if (len(all_files) == 0):
342 self.request.write("<BR><BR><H1>No matching image file found!</H1>")
343 return
344
345 if ((kw['sort_by_name']=='1') and (kw['only_items'] == '0')):
346 all_files.sort()
347
348 if (kw['sort_by_date']=='1'):
349
350 for attfile in all_files:
351 infile=os.path.join(attachment_path,attfile)
352 ft_file=str(os.path.getmtime(infile))+os.tmpnam()
353 Dict[ft_file]=attfile
354
355 file_mdate=[]
356 keys = Dict.keys()
357 keys.sort()
358 for txt in keys:
359 file_mdate.append(Dict[txt])
360
361 all_files=file_mdate
362
363 if (kw['reverse_sort']=='1'):
364 all_files.reverse()
365
366
367 cells=[]
368 big={}
369 medium={}
370 small={}
371 cell_name=[]
372 exif_date=[]
373
374 big_image_url=[]
375
376 img=[]
377
378 valid_img=0
379 if (kw['template_itemlist'] == '1'):
380 self.request.write('Copy the following listitems into the script. Replace alias with the label you want. Afterwards disable template_itemlist by setting it to 0:<BR>')
381 for attfile in all_files:
382 # only files not thumb or webnails
383 if ((string.find(string.join(attfile,''),'thumbnail_') == -1) and (string.find(string.join(attfile,''),'webnail_') == -1)) :
384 # only images
385 if wikiutil.isPicture(attfile):
386
387 file, ext = os.path.splitext(attfile)
388
389 if (ext == '.gif') or (ext == '.png'):
390 img_type='PNG'
391 thumbfile='thumbnail_'+file+".png"
392 webnail='webnail_'+file+".png"
393 else:
394 img_type="JPEG"
395 thumbfile='thumbnail_'+file+".jpg"
396 webnail='webnail_'+file+".jpg"
397
398
399 infile=os.path.join(attachment_path,attfile)
400 # wikiutil.isPicture checks only the filename if it could be a picture
401 # it does not require to exist
402 if os.path.exists(infile):
403 img.append(attfile)
404
405 f=open(infile, 'rb')
406
407 tags=EXIF.process_file(f)
408
409 if tags.has_key('EXIF DateTimeOriginal'):
410 date=str(tags['EXIF DateTimeOriginal'])
411 date=string.replace(date,':','-',2)
412 exif_date.append(date)
413 else:
414 date='--'
415 exif_date.append(date)
416
417
418 f.close()
419 if (kw['template_itemlist'] == '1'):
420 self.request.write(' * [%(attfile)s %(date)s]<BR>' % {
421 'attfile' : attfile,
422 'date' : 'alias'
423 })
424
425 thumb=os.path.join(attachment_path,thumbfile)
426 webf=os.path.join(attachment_path,webnail)
427
428 if (kw['renew'] == '1'):
429 if os.path.exists(thumb):
430 os.unlink(thumb)
431 if os.path.exists(webf):
432 os.unlink(webf)
433
434 valid_img=valid_img+1
435
436 im = Image.open(infile)
437 if not os.path.exists(webf):
438 im.thumbnail(((int(kw['webnail_width'])),((int(kw['webnail_width'])))), Image.ANTIALIAS)
439 im.save(webf, img_type)
440
441 if not os.path.exists(thumb):
442 im.thumbnail(((int(kw['thumbnail_width'])),((int(kw['thumbnail_width'])))),
443 Image.ANTIALIAS)
444 im.save(thumb, img_type)
445
446
447
448 big_image_url.append(AttachFile.getAttachUrl(current_pagename,
449 attfile,self.request))
450 medium['src']=AttachFile.getAttachUrl(current_pagename,webnail,self.request)
451
452 small['title']=attfile
453 small['alt']=attfile
454 small['src']=AttachFile.getAttachUrl(current_pagename,thumbfile,self.request)
455
456
457 image_link=formatter.image(**small)
458 # collect images
459 cells.append(formatter.url(1,medium['src'] )+image_link+formatter.url(0))
460 cell_name.append(attfile)
461
462
463 ##over all images
464 n=len(cells)
465 cols=int(kw['columns'])
466
467 rows=n/cols
468 first=0
469 result=[]
470 if (valid_img == 0):
471 result.append('Image not found')
472
473 #if (valid_img > 1):
474 result.append('<table border="'+kw['border_thick']+'" valign="bottom">')
475
476 z=1
477 i=0
478
479 ############################################
480 ##TODO: syntax change to formatter - later #
481 ############################################
482
483 # fixed width because of better visualisation on different browsers
484 for line in cells:
485 if (z == 1):
486 if (cols > 1) and (n > 1):
487 if (kw['mode']=='1'):
488 result.append('<td width="'+kw['thumbnail_width']+'" >')
489 #result.append(formatter.table_cell(1))
490 else:
491 result.append('<td width="'+kw['width']+'" >')
492 if n > 1 and cols > 1:
493 result.append('<table border="1" valign="center">')
494
495 result.append('<TR valign="center">')
496 # image align center
497 result.append('<td align="center" valign="center" width="'+kw['thumbnail_width']+'">')
498 result.append(line)
499 result.append(formatter.table_cell(0))
500
501 if (kw['show_text']=='1'):
502 if (kw['mode']=='1'):
503 result.append(formatter.table_row(0))
504 result.append(formatter.table_row(1))
505 # text aligned left in mode 1
506 result.append('<td align="left" width="'+kw['thumbnail_width']+'" >')
507 else:
508 # text aligned on top in mode 2
509 result.append('<td valign="top" width="'+kw['text_width']+'" >')
510
511 i_quote=0
512 found=0
513 for text in quotes['image'] :
514 if (text == cell_name[i]):
515 result.append(quotes['alias'][i_quote])
516 found=1
517 i_quote=i_quote+1
518
519 if (found == 0):
520 result.append(cell_name[i])
521
522 result.append(formatter.table_cell(0))
523 if (kw['mode']=='1'):
524 result.append(formatter.table_row(0))
525
526
527 if (kw['show_date']=='1'):
528 if (kw['mode']=='1'):
529 result.append(formatter.table_row(1))
530 result.append(formatter.table_cell(1))
531 result.append(exif_date[i])
532 result.append(formatter.table_cell(0))
533 result.append(formatter.table_row(0))
534
535 if (kw['show_tools'] == '1'):
536 result.append(formatter.table_row(1))
537 # tool bar centriert
538 result.append('<td align="center">')
539 result.append('<TABLE align="center">')
540 result.append('<TR><td>')
541 result.append('<FORM><TT>')
542
543 result.append('<input type="hidden" name="action" value="AttachFile">')
544 result.append('<input type="hidden" name="do" value=get>')
545 result.append('<input type="hidden" name="target" value='+img[i]+'>')
546 result.append('<input type="image" value="submit" src="/wiki/modern/img/to_full.png" title="load image">')
547 result.append('</TT></FONT></FORM>')
548 result.append('</td><td>')
549 result.append('<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data"><TT>' % {
550 'baseurl': self.request.getScriptname(),
551 'pagename': wikiutil.quoteWikinameURL(current_pagename)})
552
553 result.append('<input type="hidden" name="action" value="gallery2image">')
554 result.append('<input type="hidden" name="do" value=PS>')
555 result.append('<input type="hidden" name="target" value='+string.join(img,',')+'>')
556 result.append('<input type="image" value="submit" src="/wiki/modern/img/to_slide.png" title="slide_show">')
557 result.append('</TT></FONT></FORM>')
558 result.append('</td>')
559
560 if self.request.user.may.delete(current_pagename):
561 result.append('<td>')
562
563 result.append('<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data"><TT>' % {
564 'baseurl': self.request.getScriptname(),
565 'pagename': wikiutil.quoteWikinameURL(current_pagename)})
566
567 result.append('<input type="hidden" name="action" value="gallery2image">')
568 result.append('<input type="hidden" name="do" value=RL>')
569 result.append('<input type="hidden" name="target" value='+img[i]+'>')
570 result.append('<input type="image" value="submit" src="/wiki/modern/img/to_left.png" title="rotate to left">')
571 result.append('</TT></FONT></FORM>')
572 result.append('</td><td>')
573 result.append('<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data"><TT>' % {
574 'baseurl': self.request.getScriptname(),
575 'pagename': wikiutil.quoteWikinameURL(current_pagename)})
576
577 result.append('<input type="hidden" name="action" value="gallery2image">')
578 result.append('<input type="hidden" name="do" value=RR>')
579 result.append('<input type="hidden" name="target" value='+img[i]+'>')
580 result.append('<input type="image" value="submit" src="/wiki/modern/img/to_right.png" title="rotate to right">')
581
582 result.append('</TT></FONT></FORM>')
583 result.append('</td><td>')
584 result.append('<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data"><TT>' % {
585 'baseurl': self.request.getScriptname(),
586 'pagename': wikiutil.quoteWikinameURL(current_pagename)})
587
588 result.append('<input type="hidden" name="action" value="gallery2image">')
589 result.append('<input type="hidden" name="do" value=RM>')
590 result.append('<input type="hidden" name="target" value='+img[i]+'>')
591 result.append('<input type="image" value="submit" src="/wiki/modern/img/to_bak.png" title="move to bak">')
592 result.append('</TT></FONT></FORM>')
593 result.append('</TD>')
594 result.append('</TR>')
595 result.append('</TABLE>')
596
597 result.append(formatter.table_cell(0))
598 if (kw['show_date']=='1'):
599 if not (kw['mode']=='1'):
600 result.append(formatter.table_cell(1))
601 result.append(exif_date[i])
602 result.append(formatter.table_cell(0))
603 if (kw['show_tools'] == '1'):
604 result.append(formatter.table_row(0))
605 if n > 1 and cols > 1:
606 result.append(formatter.table(0))
607 if ((z != cols) and (i < n-1)):
608 result.append(formatter.table_cell(1))
609 if (z == cols):
610 result.append(formatter.table_cell(0))
611 result.append(formatter.table_row(0))
612 z=z+1
613 i=i+1
614 if (z > cols):
615 z=1
616
617 result.append(formatter.table(0))
618 ##Output
619 self.request.write(string.join(result,''))
620
621 return()
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.