Attachment 'Gallery2-1.3.5-15.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 If you click on a thumbnail you get the webnails shown. By a menue you are able to toggle between the slides.
10 Optional you could get a flash animation of the selected images.
11
12 CALLING SEQUENCE:
13 {{{
14 #!Gallery2 [columns=columns] [,filter=filter] [,mode=mode]
15 [,show_text=show_text] [,show_date=show_date] [,show_tools=show_tools]
16 [,sort_by_name=sort_by_name] [,sort_by_date=sort_by_date] [,sort_by_alias=sort_by_alias]
17 [,reverse_sort=reverse_sort]
18 [,only_items=only_items] [,template_itemlist=template_itemlist]
19 [,album=album] [,album_name=album_name] [,front_image=front_image]
20 [,thumbnail_width=thumbnail_width] [,webnail_width=webnail_width] [,text_width=text_width]
21 [,image_for_webnail=image_for_webnail]
22 [,sequence_name=sequence_name] [,sequence_fps=sequence_fps]
23 [,border_thick=border_thick] [,eo_info=eo_info] [,renew=renew] [,help=help]
24 * [image1.jpg alias]
25 * [image2.jpg alias]
26 }}}
27
28 KEYWORD PARAMETERS:
29 columns: number of columns for thumbnails
30 filter: regex to select images
31 show_text: default is 1 description is shown
32 any other means no description
33 show_date: default is 1 date info from exif header if available is shown
34 show_tools: default is 1 icon toolbar is show any other disables this
35 sort_by_name: default is 1, the images are sorted by name, but not if only_items is 1
36 sort_by_date: default is 0, if set to 1 the images are sorted to the modification time
37 sort_by_alias default is 0, if set to 1 and only_items set to 1 it is used to order the images by the alias name
38 reverse_sort: default is 0, if set to 1 the file list is reversed
39 any other means no description
40 mode: default is 1 this means description below the image
41 any other number means description right of image
42 only_items: default is 0 if it is set to 1 only images which are described in listitem are shown
43 dependend on the order of the items
44 template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script.
45 album: default is 0 if set to 1 only the first image of a series is shown but slideshow over all images
46 album_name: useful for album. default is 'album' use it as short name for the album.
47 front_image: Useful for album. default is ''. The first image is shown in front of the album and slideshow.
48 If set to an existing image name this is shown in front of album and slideshow.
49 The slide show could start by this somewhere.
50 border_thick: default is 1 this is the thickness in pixeln of the outer frame
51 renew: default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
52 Afterwards they are new created.
53 thumbnail_width: default is 128
54 webnail_width: default is 640
55 text_width: default is 140
56 image_for_webnail default is 0 if set to 1 then the image is shown as preview and not the webnail
57 help: default is 0 if set a copy of the CALLING SEQUENCE is shown,
58 (there are some new ideas around to show help to an user so this will be later replaced)
59 sequence_name: default is '' if set this name is used for an image
60 sequence with an duration of one image per second.
61 sequence_fps: (frames per second) default is 1 it is not allowed to set values below 1
62 eo_info: default is 0 if set to 1 an info line about how to embed the flash is shown
63 help: default is 0 if set to 1 a copy of the CALLING SEQUENCE is shown,
64 (there are some new ideas around to show help to an user so this will be later replaced)
65
66
67 OPTIONAL INPUTS:
68 itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
69 The alias text is used as description of the image instead of the file name
70
71
72 EXAMPLE:
73 = GalleryTest =
74
75 == all images shown, one is decribed ==
76 {{{
77 { { {
78 #!Gallery2
79 * [100_1185.JPG Bremen, SpaceCenter]
80 } } }
81 }}}
82
83 Result: [[BR]]
84 {{{
85 #!Gallery2
86 * [100_1185.JPG Bremen, SpaceCenter]
87 }}}
88
89 == only thumbnails and only_items ==
90 {{{
91 { { {
92 #!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
93 * [100_1185.JPG Bremen, SpaceCenter]
94 * [100_1194.JPG Bremen]
95 } } }
96 }}}
97
98 Result: [[BR]]
99 {{{
100 #!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
101 * [100_1185.JPG Bremen, SpaceCenter]
102 * [100_1194.JPG Bremen]
103 }}}
104
105 == only_items by two columns and text right ==
106
107 {{{
108 { { {
109 #!Gallery2 mode=2,columns=2,only_items=1
110 * [100_1185.JPG Bremen, SpaceCenter]
111 * [100_1194.JPG Bremen]
112 } } }
113 }}}
114
115 Result: [[BR]]
116 {{{
117 #!Gallery2 mode=2,columns=2,only_items=1
118 * [100_1185.JPG Bremen, SpaceCenter]
119 * [100_1194.JPG Bremen, behind SpaceCenter]
120 }}}
121
122 ----
123
124 == only_items by two columns, date supressed ==
125
126 {{{
127 { { {
128 #!Gallery2 columns=2,only_items=1,show_date=0
129 * [100_1185.JPG Bremen, SpaceCenter]
130 * [100_1194.JPG Bremen, behind SpaceCenter]
131 } } }
132 }}}
133
134 Result: [[BR]]
135 {{{
136 #!Gallery2 columns=2,only_items=1,show_date=0
137 * [100_1185.JPG Bremen, SpaceCenter]
138 * [100_1194.JPG Bremen, behind SpaceCenter]
139 }}}
140
141
142 == filter regex used, mode 2, icons and date supressed, one column and border_thick=5 ==
143 {{{
144 { { {
145 #!Gallery2 columns=1,filter=100_118[0-5],mode=2,show_date=0,show_tools=0,border_thick=5
146 } } }
147 }}}
148
149 Result: [[BR]]
150 {{{
151 #!Gallery2 columns=1,filter=100_118[0-7],mode=2,show_date=0,show_tools=0,border_thick=5
152 }}}
153
154 == other macro calls ==
155 {{{
156 { { {
157 #!Gallery2 only_items=1,show_date=0
158 * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
159 } } }
160 }}}
161
162 Result: [[BR]]
163 {{{
164 #!Gallery2 only_items=1,show_date=0
165 * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
166 }}}
167
168 == renew means always new thumbnails and webnails of selection ==
169 {{{
170 { { {
171 #!Gallery2 only_items=1,show_date=0,show_tools=0,renew=1
172 * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
173 } } }
174 }}}
175
176 Result: [[BR]]
177 {{{
178 #!Gallery2 only_items=1,show_date=0,renew=1
179 * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
180 }}}
181
182 == template_itemlist ==
183 {{{
184 { { {
185 #!Gallery2 template_itemlist=1
186 * [100_1185.JPG Bremen, SpaceCenter]
187 } } }
188 }}}
189
190 Result: [[BR]]
191 {{{
192 #!Gallery2 template_itemlist=1
193 * [100_1185.JPG Bremen, SpaceCenter]
194 }}}
195
196 == help to show Calling Sequence ==
197 {{{
198 { { {
199 #!Gallery2 help=1
200 } } }
201 }}}
202
203 Result: [[BR]]
204 {{{
205 #!Gallery2 help=1
206 }}}
207
208
209 PROCEDURE:
210 ABOUT:
211 While I have first implemented Gallery2 for something like photos I do use it at work since a while for
212 output of model calculations too.
213 Because of the possibility to share a standalone playable file to colleagues I have first decided to use
214 fli or mpeg as output format for an image sequence. mpeg is not quite good for displaying our data
215 and fli does sometimes eat a lot of cpu power. Both would make a lot of work getting them working
216 on a non posix OS. For further development it would be better to have a python only version of Gallery2.
217 That's the reason why I switch the sequence format to flash now. I do use the library of Matthias Kramm
218 (http://www.swftools.org).
219
220 HOWTO:
221 Download some images to a page and start with the examples.
222 Aliasing/Description of the filenames are done by adding an itemlist, see example.
223
224 NEEDS:
225 This routine requires the action macro gallery2image which is used to rotate or delete a
226 selected image. The actual version is gallery2image-1.3.5-11.py.
227 Only users which have the rights to delete are able to execute this action macro.
228 The icons of these are only shown if you have enough rights.
229 Furthermore it requires these python libraries:
230 * the PIL (Python Imaging Library).
231 * the EXIF routine from http://home.cfl.rr.com/genecash/digital_camera.html
232 * the SWF library from http://www.swftools.org
233
234 Do install them to the usual python library path.
235
236 GENERAL:
237 Please remove the Version number from the code!
238
239 If you want to upload many files at once please look on MoinMoin versions less 1.5.0
240 at FeatureRequests/UploadMultipleAttachmentFiles/RulesForUnzip
241
242 RESTRICTIONS:
243 If you rotate an image at the moment the exif is destroyed. PIL ignores the exif header.
244 This is not a quite big problem normally files with an EXIF header are right rotated.
245
246 REQUIRED IMAGES:
247 I have put them to wiki/modern/img/ dir. The icons were created by me. License: GPL
248
249 attachment:to_bak.png
250 attachment:to_left.png
251 attachment:to_right.png
252 attachment:to_slide.png
253 attachment:to_full.png
254
255 gallery2image needs from version 1.3.5-6 these images saved to /wiki/modern/img/
256
257 attachment:back.png attachment:first_disabled.png attachment:first.png attachment:last_disabled.png attachment:last.png attachment:next_disabled.png attachment:next.png attachment:previous_disabled.png attachment:previous.png
258
259 One of my colleagues searched for some more /ModernImages
260
261 HISTORY:
262 While recognizing how to write MiniPage I got the idea to write a Gallery Parser.
263 We have used in our wikis in the past the Gallery macro of SimonRyan.
264 I have tried to modify it a bit to change it for 1.3 but my python skills weren't enough
265 or it was easier to write it completly new.
266 So this one shows now a way how a Gallery could be used by the parser and an action Macro.
267 Probably it is a good example for others who like to know how to do this
268
269 OUTLOOK:
270 Dependent on Matthias Kramm's python interface development the webnails could be exchanged to a
271 flash animation with action controls. That will ommit the javascript slide show and will give less files.
272 swftools is able to do this by now but that will need an os.system call. At the moment I like to avoid this.
273 If you are interested the command is swfcombine -o output.swf movie_control.swf viewport=input.swf.
274 It is still in the code but commented off. movie_control.swf embbeds the controls 24 pixels above the flash so it's a good idea to
275 resize the flash by the -X and -Y option.
276
277
278 MODIFICATION HISTORY:
279 Version 1.3.3.-1
280 @copyright: 2005 by Reimar Bauer (R.Bauer@fz-juelich.de)
281 @license: GNU GPL, see COPYING for details.
282 2005-03-26: Version 1.3.3-2 keyword renew added
283 creation of thumbnails and webnails in two calls splitted
284 Version 1.3.3-3 bug fixed if itemlist is given to describe only some of the images
285 but only_items is not set to 1
286 Example code changed
287 2005-03-27: Version 1.3.3-4 Action macro added and the form to call it. User which have rights to delete
288 could use the functions of gallery2Image.
289 2005-08-03: Version 1.3.3-5 theme path for icons corrected and a platform independent path joining
290 os.unlink removed as suggested by CraigJohnson
291 sort_by_name is default if not only_items is 1
292 optional sort_by_date could be used
293 keyword template_itemlist added
294 keyword help added
295 extra frame by mode=2 removed
296 2005-08-06: Version 1.3.5-6 slideshow mode added
297 keyword image_for_webnail added
298 2005-08-13: Version 1.3.5-7 syntax changed from GET to POST
299 forms instead of links
300 filenames from images submitted to gallery2image too
301 new keyword sort_by_alias
302 internal code clean up
303 this version needs: gallery2image-1.3.5-5.py
304 2005-08-14: Version 1.3.5-8 (TW) cleanup
305 2005-08-14: Version 1.3.5-9 html code for tables changed
306 because of the ugly extra space of form elements
307 div tag removed so now we use the page style
308 slide show action goes to right webnail now
309 this version needs: gallery2image-1.3.5-5.py
310 2005-08-17: Version 1.3.5-10 html code separated in functions
311 structure of code changed, now you see the thumbnails after creation
312 bug removed if quote is given but file does not exist
313 2005-09-02: Version 1.3.5-11 keyword album, album_name and front_image added
314 image urls changed to complete server url
315 2005-11-12: Version 1.3.5-12 bug fixed for image_for_webnail=1
316 bug fixed at last cell table end tr instead of td
317 bug fixed don't render a filename as WikiName
318 bug fixed " is allowed in alias name
319 bug fixed ' is allowed in alias name
320 bug fixed linebreak by a space in alias
321 not quite a bug but makes it very difficult to code in
322 gallery2image so additional id removed in alias name
323 2005-11-17: Version 1.3.5-13 implementation of sequence video clips at first step for posix only
324 sequence_type could be used to ommit the autoselection
325 fli/flc files are used for gif and png files, mpeg files for
326 jpeg files. Duration on both is 1 image/second
327 feature added of recognising the right url pattern (http opr https)
328 2005-12-03: Version 1.3.5-14 bug fixed of to_slide tools function a wrong mark was used
329 all output of convert or ppm2fli redirected to /dev/null
330 it is not necessary to keep output in the webservers log file
331 2006-01-01: Version 1.3.5-15 only python libs are used in this version
332 flash (swf) format is used as sequence format
333 keyword sequence_fps added, keyword sequence_type removed
334 keyword eo_info added
335 EXIF.py moved to python lib
336 var wiki added as supposed
337
338 """
339 Dependencies = []
340 import os, sys, string, re, Image, StringIO, codecs, SWF, EXIF
341 from MoinMoin.action import AttachFile
342 from MoinMoin import wikiutil, config
343 from MoinMoin.Page import Page
344 from MoinMoin.parser import wiki
345
346
347 def images2swf(request,images,swf_filename,swf_fps,description,exif_date):
348 ## this code is based on
349 ## http://www.quiss.org/swftools/python/jpeg2swf_exif.py
350 ## by Matthias Kramm
351 ##
352 ## Thanks Matthias
353
354 xmax,ymax = 0,0
355 depth = 1
356 SWF.verbose(0)
357 # verbose is not used everybody
358 swf = SWF.create(version = 6, bbox = (0,0,0,0), fps = float(swf_fps))
359
360 i = 0
361 for filename in images:
362 pic = Image.open(filename)
363 pic.load()
364
365 width, height = pic.size
366 if width > xmax: xmax = width
367 if height > ymax: ymax = height
368
369 pic = pic.convert("RGBA")
370 image = SWF.Image(pic.im)
371
372 swf.tags += image
373 shape = SWF.ImageShape(image)
374 swf.tags += shape
375 swf.tags += SWF.PlaceObject(shape, depth=depth)
376 depth += 1
377 swf.tags += SWF.ShowFrame()
378
379 i += 1
380
381 swf.bbox = (0,0,xmax,ymax)
382 swf.save(swf_filename)
383
384 return xmax,ymax
385
386 # After Matthias has finished action for swf in python this call could be replaced by the new code ...
387
388
389 # movie_control = "%(path)s/%(type)s/%(name)s" % {
390 # "type": 'support',
391 # "path" : request.cfg.moinmoin_dir,
392 # "name" : 'movie_control.swf'}
393 #
394 # cmd = "swfcombine -r %(fps)s -X %(xmax)s -Y %(ymax)s -o %(filename)s %(movie_control)s viewport=%(filename)s" % {
395 # "fps": int(swf_fps),
396 # "xmax": xmax,
397 # "ymax": ymax+24,
398 # "movie_control":movie_control,
399 # "filename":swf_filename,
400 # }
401
402 # os.system(cmd)
403
404 def server(request):
405 if request.is_ssl:
406 url_pattern = 'https'
407 else:
408 url_pattern = 'http'
409
410 return "%(url_pattern)s://%(server_name)s:%(server_port)s" % {
411 "url_pattern":url_pattern,
412 "server_name":request.server_name,
413 "server_port":str(request.server_port)}
414
415 def show_tools_restricted(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
416 if request.user.may.delete(pagename):
417 return tools_restricted_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request)
418 else:
419 return ''
420
421 def tools_restricted_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
422 text = '''
423 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
424 <td>
425 <input type="hidden" name="action" value="gallery2image">
426 <input type="hidden" name="do" value="RL">
427 <input type="hidden" name="target" value="%(this_target)s">
428 <input type="image" value="submit" src="%(server)s%(wiki)s/modern/img/to_left.png" title="rotate to left">
429 </td>
430 </form>
431 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
432 <td>
433 <input type="hidden" name="action" value="gallery2image">
434 <input type="hidden" name="do" value="RR">
435 <input type="hidden" name="target" value="%(this_target)s">
436 <input type="image" value="submit" src="%(server)s%(wiki)s/modern/img/to_right.png" title="rotate to right" >
437 </td>
438 </form>
439 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
440 <td>
441 <input type="hidden" name="action" value="gallery2image">
442 <input type="hidden" name="do" value="RM">
443 <input type="hidden" name="target" value="%(this_target)s">
444 <input type="image" value="submit" src="%(server)s%(wiki)s/modern/img/to_bak.png" title="move to bak" >
445 </td>
446 </form>''' % {
447 "server" : server(request),
448 "wiki": request.cfg.url_prefix,
449 'baseurl': request.getScriptname(),
450 "pagename": pagename,
451 "this_target": this_target}
452 return text
453
454 def tools_html(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request):
455 text = '''
456 <TABLE align="center" width="%(thumbnail_width)s">
457 <TR>
458 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
459 <td>
460 <input type="hidden" name="action" value="AttachFile">
461 <input type="hidden" name="do" value="get">
462 <input type="hidden" name="target" value='%(this_target)s'>
463 <input type="image" value="submit" src="%(server)s%(wiki)s/modern/img/to_full.png" title="load image">
464 </td>
465 </form>
466 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
467 <td>
468 <input type="hidden" name="action" value="gallery2image">
469 <input type="hidden" name="do" value="VS">
470 <input type="hidden" name="full" value='%(full)s'>
471 <input type="hidden" name="alias" value='%(alias)s'>
472 <input type="hidden" name="target" value='%(target)s'>
473 <input type="hidden" name="exif_date" value='%(exif_date)s'>
474 <input type="image" value="submit" src="%(server)s%(wiki)s/modern/img/to_slide.png" title="slide_show" >
475 </td>
476 </form>
477 %(show_tools_restricted)s
478 </TR>
479 </TABLE>''' % {
480 "server": server(request),
481 "wiki": request.cfg.url_prefix,
482 'baseurl': request.getScriptname(),
483 "pagename": pagename,
484 "thumbnail_width": thumbnail_width,
485 "full": full,
486 "alias": alias,
487 "exif_date": exif_date,
488 "target": target,
489 "this_target": this_image,
490 "show_tools_restricted": show_tools_restricted(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request)
491 }
492
493 return text
494
495 def show_alias_mode2(show_alias,thumbnail_width,this_alias,text_width):
496 if show_alias == '1':
497 return '''
498 <td valign="top" width="%(text_width)s">
499 %(this_alias)s
500 </td>''' % {
501 "this_alias": this_alias,
502 "text_width": text_width}
503 else:
504 return ''
505
506 def show_date_mode2(show_date,this_exif_date):
507 if show_date == '1':
508 return '''
509 <td>
510 <p>%(this_exif_date)s</p>
511 </td>''' % {
512 "this_exif_date": this_exif_date }
513 else:
514 return ''
515
516 def show_tools_mode2(show_tools,pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
517 if show_tools == '1' :
518 return "<td align=""center""> %s </td>" % tools_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request)
519 else:
520 return ''
521
522 def mode2_html(pagename,border_thick,width,thumbnail_width,text_width,full,this_image,alias,this_alias,exif_date,this_exif_date,target,this_target,submit,show_tools,show_date,show_alias,request):
523 text = '''
524 <tr valign="center">
525 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
526 <td align="center" valign="center" width="%(thumbnail_width)s">
527 <input type="hidden" name="action" value="gallery2image">
528 <input type="hidden" name="do" value="VS">
529 <input type="hidden" name="full" value='%(full)s'>
530 <input type="hidden" name="alias" value='%(alias)s'>
531 <input type="hidden" name="exif_date" value='%(exif_date)s'>
532 <input type="hidden" name="target" value='%(target)s'>
533 <input type="image" value="submit" src="%(server)s%(submit)s">
534 </td>
535 </form>
536 %(alias_html)s
537 </tr>
538 <tr>%(tools_html)s%(date_html)s</tr>'''% {
539 "server" : server(request),
540 "baseurl": request.getScriptname(),
541 "pagename": pagename,
542 "thumbnail_width": thumbnail_width,
543 "full": full,
544 "alias": alias,
545 "exif_date": exif_date,
546 "target": target,
547 "submit": submit,
548 "tools_html": show_tools_mode2(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request),
549 "date_html": show_date_mode2(show_date,this_exif_date),
550 "alias_html": show_alias_mode2(show_alias,thumbnail_width,this_alias,text_width)
551 }
552
553 return text
554
555 def show_tools_mode1(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request):
556 if show_tools == '1' :
557 text="<tr><td align=""center"">%s </td></tr>" % tools_html(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request)
558 else:
559 text = ''
560 return text
561
562 def show_date_mode1(show_date,this_exif_date):
563 if show_date == '1':
564 return '''
565 <TR>
566 <td>%(this_exif_date)s</td>
567 </TR>''' % {
568 "this_exif_date":this_exif_date}
569 else:
570 return ''
571
572 def show_alias_mode1(show_alias,thumbnail_width,this_alias,text_width):
573 if show_alias == '1':
574 return '''
575 <TR>
576 <td align="left" width="%(thumbnail_width)s"> %(this_alias)s</td>
577 </TR>''' % {
578 "thumbnail_width": thumbnail_width,
579 "this_alias": this_alias}
580 else:
581 return ''
582
583 def mode1_html(pagename,border_thick,width,thumbnail_width,text_width,full,this_image,alias,this_alias,exif_date,this_exif_date,target,this_target,submit,
584 show_tools,show_date,show_alias,request):
585 text = '''
586 <table width="%(thumbnail_width)s" align="center" valign="center">
587 <TR align="center" valign="center">
588 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
589 <td align="center" valign="middle" width="%(thumbnail_width)s">
590 <input type="hidden" name="action" value="gallery2image">
591 <input type="hidden" name="do" value="VS">
592 <input type="hidden" name="full" value='%(full)s'>
593 <input type="hidden" name="alias" value='%(alias)s'>
594 <input type="hidden" name="exif_date" value='%(exif_date)s'>
595 <input type="hidden" name="target" value='%(target)s'>
596 <input type="image" value="submit" src="%(server)s%(submit)s" >
597 </td>
598 </form>
599 </TR>
600 %(alias_html)s
601 %(date_html)s
602 %(tools_html)s
603 </table>'''% {
604 "server" : server(request),
605 "baseurl": request.getScriptname() ,
606 "pagename":pagename,
607 "full":full,
608 "alias":alias,
609 "exif_date":exif_date,
610 "target":target,
611 "submit":submit,
612 "thumbnail_width":thumbnail_width,
613 "tools_html": show_tools_mode1(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request),
614 "date_html":show_date_mode1(show_date,this_exif_date),
615 "alias_html": show_alias_mode1(show_alias,thumbnail_width,this_alias,text_width)
616 }
617
618 return text
619
620 def get_files(kw,path,files,quotes,request):
621 web = []
622 full = []
623 thumb = []
624 exif_date = []
625 img_type = []
626 description = []
627 ddict = {}
628 n = len(quotes['image'])
629 if n > 0 :
630 i = 0
631 for txt in quotes['image']:
632 ddict[txt] = quotes['alias'][i]
633 i += 1
634
635 video_type = 'swf'
636 source_type = ''
637 for attfile in files:
638 # only files not thumb or webnails
639 if attfile.find('thumbnail_') == -1 and attfile.find('webnail_') == -1:
640 # only images
641 if wikiutil.isPicture(attfile):
642 description.append(ddict.get(attfile, attfile))
643 full.append(attfile)
644
645 fname, ext = os.path.splitext(attfile)
646 if ext in ('.gif', '.png'):
647 img_type.append('PNG')
648 webnail = 'webnail_%s.png' % fname
649 thumbfile = 'thumbnail_%s.png' % fname
650 source_type = ext[1:]
651 else:
652 img_type.append("JPEG")
653 webnail = 'webnail_%s.jpg' % fname
654 thumbfile = 'thumbnail_%s.jpg' % fname
655 source_type = 'jpg'
656
657
658 infile = os.path.join(path, attfile)
659 if os.path.exists(infile):
660 web.append(webnail)
661 thumb.append(thumbfile)
662
663 f = open(infile, 'rb')
664 tags = EXIF.process_file(f)
665 if tags.has_key('EXIF DateTimeOriginal'):
666 date = str(tags['EXIF DateTimeOriginal'])
667 date = date.replace(':', '-', 2)
668 else:
669 date = '--'
670 exif_date.append(date)
671 f.close()
672
673 return thumb,web,full,video_type, exif_date,img_type,source_type,description
674
675 def to_htmltext(text):
676 if text.find ("'"):
677 text = text.split("'")
678 text = '''.join(text)
679 return text
680
681 def to_wikiname(request,formatter,text):
682 ##taken from MiniPage
683 out=StringIO.StringIO()
684 request.redirect(out)
685 wikiizer = wiki.Parser(text.strip(),request)
686 wikiizer.format(formatter)
687 result = out.getvalue()
688 request.redirect()
689 del out
690
691 result = result.replace('<a id="line-1"></a>','')
692 result = result.replace('<p>','')
693 result = result.replace('</p>','')
694 result = result.strip()
695 return result
696
697
698 def get_quotes(self,formatter):
699 quotes = self.raw.split('\n')
700 quotes = [quote.strip() for quote in quotes]
701 quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
702
703
704 image = []
705 text = []
706
707 for line in quotes:
708 im, na=line[1:-1].split(' ',1)
709 na = na.strip()
710 na = to_htmltext(na)
711 na = to_wikiname(self.request,formatter,na)
712 text.append(na)
713 image.append(im.strip())
714
715 return {
716 'alias': text,
717 'image': image,
718 }
719
720 class Parser:
721
722 def __init__(self, raw, request, **kw):
723 self.raw = raw
724 self.request = request
725 self.form = request.form
726 self._ = request.getText
727 self.kw = {
728 'sort_by_date': '0',
729 'sort_by_name': '1',
730 'sort_by_alias': '0',
731 'album': '0',
732 'album_name': 'album',
733 'front_image':'',
734 'template_itemlist': '0',
735 'reverse_sort': '0',
736 'border_thick': '1',
737 'columns': '4',
738 'filter': '.',
739 'mode': '1',
740 'help': '0',
741 'show_text': '1',
742 'show_date': '1',
743 'show_tools': '1',
744 'only_items': '0',
745 'image_for_webnail': '0',
746 'renew': '0',
747 'thumbnail_width': '128',
748 'webnail_width': '640',
749 'text_width': '140',
750 'sequence_name' : '',
751 'sequence_fps' : '1',
752 'eo_info' : '0',
753 }
754
755
756 for arg in kw.get('format_args','').split(','):
757
758 if arg.find('=') > -1:
759 key, value=arg.split('=')
760 self.kw[key]=wikiutil.escape(value, quote=1)
761
762
763 self.kw['width']=str((int(self.kw['thumbnail_width'])+int(self.kw['text_width'])))
764
765
766 def format(self, formatter):
767 kw=self.kw
768 Dict = {}
769 quotes=get_quotes(self,formatter)
770 current_pagename=formatter.page.page_name
771 attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
772
773 if kw['help'] == '1':
774 self.request.write('''
775 <br>
776 {{{<br>
777 #!Gallery2 [columns=columns] [,filter=filter] [,mode=mode] <br>
778 [,show_text=show_text] [,show_date=show_date] [,show_tools=show_tools]<br>
779 [,sort_by_name=sort_by_name] [,sort_by_date=sort_by_date] [,sort_by_alias=sort_by_alias]<br>
780 [,reverse_sort=reverse_sort]<br>
781 [,only_items=only_items] [,template_itemlist=template_itemlist]<br>
782 [,album=album] [album_name=album_name] [,front_image=front_image]<br>
783 [,thumbnail_width=thumbnail_width] [,webnail_width=webnail_width] [,text_width=text_width]<br>
784 [,image_for_webnail=image_for_webnail]<br>
785 [,sequence_name=sequence_name] [,sequence_fps=sequence_fps]<br>
786 [,border_thick=border_thick] [,eo_info=eo_info] [,renew=renew] [,help=help]<br>
787 * [image1.jpg alias]<br>
788 * [image2.jpg alias]<br>
789 }}}<br>''')
790 return
791
792 if kw['only_items'] == '1':
793 all_files=quotes['image']
794 result=[]
795 for attfile in all_files:
796 infile=os.path.join(attachment_path,attfile)
797 if os.path.exists(infile):
798 result.append(attfile)
799 all_files = result
800
801 if kw['sort_by_alias'] == '1':
802 new_ordered_files=[]
803 alias_text=quotes['alias']
804
805 i=0
806 for attfile in all_files:
807 infile=os.path.join(attachment_path,attfile)
808 ft_file=str(os.path.getmtime(infile))+os.tmpnam()
809 Dict[alias_text[i]]=attfile
810 i += 1
811
812 keys = Dict.keys()
813 keys.sort()
814 for txt in keys:
815 new_ordered_files.append(Dict[txt])
816
817 all_files=new_ordered_files
818 Dict.clear()
819
820 else:
821 all_files=os.listdir(attachment_path)
822
823 result = []
824
825 for test in all_files:
826 if re.match(kw['filter'], test):
827 result.append(test)
828 all_files=result
829
830 if not all_files:
831 self.request.write("<br><br><h1>No matching image file found!</h1>")
832 return
833
834 if kw['sort_by_name'] == '1' and kw['only_items'] == '0':
835 all_files.sort()
836
837 if kw['sort_by_date']=='1':
838 for attfile in all_files:
839 infile=os.path.join(attachment_path,attfile)
840 ft_file=str(os.path.getmtime(infile))+os.tmpnam()
841 Dict[ft_file]=attfile
842
843 keys = Dict.keys()
844 keys.sort()
845 file_mdate=[]
846 for txt in keys:
847 file_mdate.append(Dict[txt])
848 all_files=file_mdate
849 Dict.clear()
850
851 if kw['reverse_sort'] == '1':
852 all_files.reverse()
853
854 thumb, web, full, video_type, exif_date, imgtype, source_type, description = get_files(kw, attachment_path, all_files, quotes, self.request)
855
856 if kw['template_itemlist'] == '1':
857 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>')
858 for attfile in full :
859 self.request.write(' * [%(attfile)s %(date)s]<br>' % {
860 'attfile' : attfile,
861 'date' : 'alias'
862 })
863
864 i = 0
865 z = 1
866 cols = int(kw['columns'])
867 n = len(full)
868 if kw['album'] == '0' :
869 self.request.write("<table align='center' border='%s' >" % self.kw['border_thick'])
870 if kw['mode'] == '1' or cols > 1 :
871 self.request.write('<TR valign="bottom">')
872 self.request.write('<TD>')
873
874 if kw['album'] == '1' :
875 if kw['front_image'] == '' :
876 front_image = full[0]
877 else:
878 front_image = kw['front_image']
879 ii = 0
880 for tst in full :
881 if tst == front_image :
882 break
883 ii += 1
884
885 for attfile in full :
886 if kw['album'] == '1' :
887 if tst == front_image :
888 i = ii
889 this_description = description[i]
890 this_exif_date = exif_date[i]
891 this_webnail = web[i]
892 this_imgtype = imgtype[i]
893 this_thumbfile = thumb[i]
894 thumbf = os.path.join(attachment_path,this_thumbfile)
895 webf = os.path.join(attachment_path,this_webnail)
896
897 if kw['renew'] == '1':
898 if os.path.exists(thumbf):
899 os.unlink(thumbf)
900 if os.path.exists(webf):
901 os.unlink(webf)
902
903 if not os.path.exists(webf) or not os.path.exists(thumbf):
904 infile = os.path.join(attachment_path,attfile)
905 im = Image.open(infile)
906
907 if not os.path.exists(webf):
908 im.thumbnail(((int(kw['webnail_width'])),((int(kw['webnail_width'])))), Image.ANTIALIAS)
909 if kw['image_for_webnail'] == '1' :
910 os.link(os.path.join(attachment_path,attfile),webf)
911 else:
912 im.save(webf, this_imgtype)
913 if not os.path.exists(thumbf):
914 im.thumbnail(((int(kw['thumbnail_width'])),((int(kw['thumbnail_width'])))),
915 Image.ANTIALIAS)
916 im.save(thumbf, this_imgtype)
917
918 if kw['image_for_webnail'] == '1' :
919 this_webnailimg = attfile
920 webimg = full
921 else:
922 this_webnailimg = this_webnail
923 webimg = web
924
925 if kw['mode'] == '1':
926 text = mode1_html(current_pagename,
927 kw['border_thick'],
928 kw['width'],
929 kw['thumbnail_width'],
930 kw['text_width'],
931 attfile + "," + ','.join(full),
932 attfile,
933 this_description + '!,!' + '!,!'.join(description),
934 this_description,
935 to_htmltext(this_exif_date + ',' + ','.join(exif_date)),
936 to_htmltext(this_exif_date),
937 this_webnailimg + ',' + ','.join(webimg),
938 this_webnailimg,
939 AttachFile.getAttachUrl(current_pagename, this_thumbfile, self.request),
940 kw['show_tools'],
941 kw['show_date'],
942 kw['show_text'],
943 self.request
944 )
945 self.request.write(''.join(text))
946
947 if kw['mode'] == '2':
948 text = mode2_html(current_pagename,
949 kw['border_thick'],
950 kw['width'],
951 kw['thumbnail_width'],
952 kw['text_width'],
953 attfile + "," + ','.join(full),
954 attfile,
955 this_description + '!,!' + '!,!'.join(description),
956 this_description,
957 to_htmltext(this_exif_date + ',' + ','.join(exif_date)),
958 to_htmltext(this_exif_date),
959 this_webnailimg + ',' + ','.join(webimg),
960 this_webnailimg,
961 AttachFile.getAttachUrl(current_pagename, this_thumbfile, self.request),
962 kw['show_tools'],
963 kw['show_date'],
964 kw['show_text'],
965 self.request
966 )
967
968 if cols > 1 : self.request.write('<table valign="bottom">')
969 self.request.write(''.join(text))
970 if cols > 1 : self.request.write('</table>')
971
972 if kw['mode'] == '1' or cols > 1:
973 if kw['album'] == '0' :
974 if z < cols :
975 self.request.write('</TD>')
976 if z < n and i < n - 1 :
977 self.request.write('<TD>')
978 if i == n - 1 :
979 self.request.write('</TR>')
980 else:
981 self.request.write('</TD>')
982 self.request.write('</TR>')
983 if i < n - 1 :
984 self.request.write('<TR valign="bottom">')
985 self.request.write('<TD>')
986
987 i += 1
988 z += 1
989 if z > cols :
990 z = 1
991
992 if kw['album'] == '1' :
993 self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name":kw['album_name']})
994 break
995 if kw['album'] == '0' :
996 if i < n :
997 self.request.write('</TD>')
998 self.request.write('</TR>')
999 self.request.write('</table>')
1000
1001 ############################################
1002 ##TODO: syntax change to formatter - later #
1003 ############################################
1004
1005
1006 if kw['sequence_name'] != '' :
1007 video_file = "%(file)s.%(ext)s" % {
1008 "file":os.path.join(attachment_path,kw['sequence_name']),
1009 "ext":video_type}
1010 if kw['renew'] == '1':
1011 if os.path.exists(video_file):
1012 os.unlink(video_file)
1013
1014 cmd = ''
1015 if float(kw['sequence_fps']) < 1 :
1016 fps = 1
1017 else:
1018 fps = round(float(kw['sequence_fps']))
1019
1020 f_list=[]
1021 for attfile in web :
1022 file = os.path.join(attachment_path,attfile)
1023 f_list.append(file)
1024
1025 if not os.path.exists(video_file):
1026 width,height = images2swf(self.request,f_list,video_file,fps,description,exif_date)
1027 else:
1028 swf = SWF.load(video_file)
1029 for tag in swf.tags:
1030 if tag.isImage():
1031 width,height = tag.image.size
1032 break
1033
1034 if os.path.exists(video_file):
1035 dict = {}
1036 dict['src'] = AttachFile.getAttachUrl(current_pagename,'%(file)s.%(videotype)s' % {
1037 'file': kw['sequence_name'],
1038 'videotype':video_type,
1039 },self.request)
1040
1041 image_link = '%(file)s.%(videotype)s' % { 'file':kw['sequence_name'],'videotype':video_type}
1042 if kw['eo_info'] == '1' :
1043 eo = "Or embed it into your wiki page by [[EO(%(file)s,width=%(width)s,height=%(height)s)]]." % {
1044 'file': image_link,
1045 'width': str(width),
1046 'height': str(height)}
1047 else:
1048 eo = ''
1049
1050 self.request.write('<P>')
1051 text = formatter.url(1,dict['src'] ) + image_link + formatter.url(0)
1052 self.request.write('Download this image sequence %(text)s for your archive. %(EO)s' % {
1053 'text': text,
1054 'EO': eo
1055 })
1056 self.request.write('</P>')
1057
1058
1059
1060
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.