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