Attachment 'text_x_gallery2-1.6.0-18.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 2006-08-11 1.6.0-17 RB ported to 1.6.0 dev alpha version
338 2006-08-22 1.6.0-18 RB for the call of Frame a test if parameters are submitted is added
339
340
341 """
342 Dependencies = ['time'] # do not cache
343
344 from MoinMoin.action import AttachFile
345 from MoinMoin import wikiutil, config
346 from MoinMoin.Page import Page
347
348 import os, re, sys, Image, StringIO, codecs
349 from random import randint
350
351 try:
352 import EXIF
353 except ImportError:
354 EXIF = None
355
356 try:
357 import SWF
358 except ImportError:
359 SWF = None
360
361
362 from MoinMoin.parser import text_moin_wiki
363
364 class Parser:
365 extensions = '*'
366 def __init__(self, raw, request, **kw):
367 self.sort_by_date = '0'
368 self.sort_by_name = '1'
369 self.sort_by_alias = '0'
370 self.album = '0'
371 self.album_name = 'album'
372 self.front_image = ''
373 self.template_itemlist = '0'
374 self.reverse_sort = '0'
375 self.border_thick = '1'
376 self.columns = '4'
377 self.filter = '.'
378 self.mode = '1'
379 self.help = '0'
380 self.show_text = '1'
381 self.show_date = '1'
382 self.show_tools = '1'
383 self.only_items = '0'
384 self.image_for_webnail = '0'
385 self.renew = '0'
386 self.thumbnail_width = '128'
387 self.webnail_width = '640'
388 self.text_width = '140'
389 self.sequence_name = ''
390 self.sequence_fps = '1'
391 self.eo_info = '0'
392
393
394 test = kw.get('format_args', '')
395 if test:
396 for arg in kw.get('format_args', '').split(','):
397 if arg.find('=') > -1:
398 key, value = arg.split('=')
399 setattr(self, key, wikiutil.escape(value.strip(), quote=1))
400
401 self.width = str(int(self.thumbnail_width) +
402 int(self.text_width))
403
404 self.raw = raw
405 self.request = request
406 self.form = request.form
407 self._ = request.getText
408
409 self.outer_table_style = ' border="%s"' % self.border_thick
410 self.inner_table_style = ' style="border-style:none; margin:10px;"'
411 self.td_style = ' align="center" style="padding:0; margin:2px 2px; border-style:none"'
412
413 def images2swf(request, images, swf_filename, swf_fps, description, exif_date):
414 ## this code is based on
415 ## http://www.quiss.org/swftools/python/jpeg2swf_exif.py
416 ## by Matthias Kramm
417 ##
418 ## Thanks Matthias
419
420 xmax, ymax = 0, 0
421 depth = 1
422 SWF.verbose(0)
423 # verbose is not used everybody
424 swf = SWF.create(version=6, bbox=(0, 0, 0, 0), fps=float(swf_fps))
425
426 i = 0
427 for filename in images:
428 pic = Image.open(filename)
429 pic.load()
430
431 width, height = pic.size
432 if width > xmax: xmax = width
433 if height > ymax: ymax = height
434
435 pic = pic.convert("RGBA")
436 image = SWF.Image(pic.im)
437
438 swf.tags += image
439 shape = SWF.ImageShape(image)
440 swf.tags += shape
441 swf.tags += SWF.PlaceObject(shape, depth=depth)
442 depth += 1
443 swf.tags += SWF.ShowFrame()
444
445 i += 1
446
447 swf.bbox = (0, 0, xmax, ymax)
448 swf.save(swf_filename)
449
450 return xmax, ymax
451
452 def show_tools_restricted(self, this_target):
453 if not self.request.user.may.delete(self.pagename):
454 return ''
455
456 return '''
457 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
458 <td%(style)s>
459 <input type="hidden" name="action" value="gallery2image">
460 <input type="hidden" name="do" value="RL">
461 <input type="hidden" name="target" value="%(this_target)s">
462 <input type="image" value="submit" src="%(htdocs)s/img/to_right.png" title="rotate to left">
463 </td>
464 </form>
465 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
466 <td%(style)s>
467 <input type="hidden" name="action" value="gallery2image">
468 <input type="hidden" name="do" value="RR">
469 <input type="hidden" name="target" value="%(this_target)s">
470 <input type="image" value="submit" src="%(htdocs)s/img/to_left.png" title="rotate to right" >
471 </td>
472 </form>
473 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
474 <td%(style)s>
475 <input type="hidden" name="action" value="gallery2image">
476 <input type="hidden" name="do" value="RM">
477 <input type="hidden" name="target" value="%(this_target)s">
478 <input type="image" value="submit" src="%(htdocs)s/img/to_bak.png" title="move to bak" >
479 </td>
480 </form>''' % {
481 'baseurl': self.request.getBaseURL(),
482 'style': self.td_style,
483 'htdocs': self.request.cfg.url_prefix,
484 "pagename": self.quoted_pagename,
485 "this_target": this_target}
486
487 def tools_html(self, idx):
488 this_image = self.full[idx]
489
490 text = '''
491 <TABLE align="center" width="%(thumbnail_width)s"%(tablestyle)s>
492 <TR>
493 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
494 <td%(style)s>
495 <input type="hidden" name="action" value="AttachFile">
496 <input type="hidden" name="do" value="get">
497 <input type="hidden" name="target" value='%(this_target)s'>
498 <input type="image" value="submit" src="%(htdocs)s/img/to_full.png" title="load image">
499 </td>
500 </form>
501 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
502 <td%(style)s>
503 <input type="hidden" name="action" value="gallery2image">
504 <input type="hidden" name="do" value="VS">
505 <input type="hidden" name="full" value='%(full)s'>
506 <input type="hidden" name="alias" value='%(description)s'>
507 <input type="hidden" name="target" value='%(target)s'>
508 <input type="hidden" name="exif_date" value='%(exif_date)s'>
509 <input type="image" value="submit" src="%(htdocs)s/img/to_slide.png" title="slide_show" >
510 </td>
511 </form>
512 %(show_tools_restricted)s
513 </TR>
514 </TABLE>''' % {
515 "baseurl": self.request.getScriptname(),
516 "pagename": self.quoted_pagename,
517 "htdocs": self.request.cfg.url_prefix,
518 "tablestyle": self.inner_table_style,
519 "style": self.td_style,
520 "thumbnail_width": self.thumbnail_width,
521 "full": self.full[idx] + ',' + ','.join(self.full),
522 "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
523 "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
524 ','.join(self.exif_date)),
525 "target": self.webimg[idx] + ',' + ','.join(self.webimg),
526 "this_target": self.full[idx],
527 "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
528 "show_tools_restricted":self.show_tools_restricted(this_image)
529 }
530
531 return text
532
533 def show_alias_mode2(self, idx):
534 if self.show_text == '1':
535 return '''
536 <td valign="top" width="%(text_width)s" %(style)s>
537 %(this_alias)s
538 </td>''' % {
539 "this_alias":self.description[idx],
540 "text_width":self.text_width,
541 "style": ' align="left" style="padding:0px; margin:2px 2px; border-style:none"'}
542 else:
543 return ''
544
545 def show_date_mode2(self, idx):
546 if self.show_date == '1':
547 return '''
548 <td%(style)s><p>%(this_exif_date)s</p></td>''' % {
549 "style": self.td_style,
550 "this_exif_date": self.to_htmltext(self.exif_date[idx]) }
551 else:
552 return ''
553
554 def show_tools_mode2(self, idx):
555 if self.show_tools == '1':
556 return "<td align=""center""%(style)s> %(tools)s </td>" % {
557 "style":self.td_style,
558 "tools":self.tools_html(idx)}
559 else:
560 return ''
561
562 def mode2_html(self, idx):
563 text = '''
564 <tr valign="center">
565 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
566 <td align="center" valign="center" width="%(thumbnail_width)s"
567 %(tdstyle)s>
568 <input type="hidden" name="action" value="gallery2image">
569 <input type="hidden" name="do" value="VS">
570 <input type="hidden" name="full" value='%(full)s'>
571 <input type="hidden" name="alias" value='%(description)s'>
572 <input type="hidden" name="exif_date" value='%(exif_date)s'>
573 <input type="hidden" name="target" value='%(target)s'>
574 <input type="image" value="submit" src="%(thumbnail)s">
575 </td>
576 </form>
577 %(alias_html)s
578 </tr>
579 <tr>%(tools_html)s%(date_html)s</tr>''' % {
580 "tdstyle": self.td_style,
581 "baseurl": self.request.getScriptname(),
582 "pagename": self.quoted_pagename,
583 "thumbnail_width": self.thumbnail_width,
584 "full": self.full[idx] + ',' + ','.join(self.full),
585 "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
586 "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
587 ','.join(self.exif_date)),
588 "target": self.webimg[idx] + ',' + ','.join(self.webimg),
589 "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
590 "tools_html": self.show_tools_mode2(idx),
591 "date_html": self.show_date_mode2(idx),
592 "alias_html": self.show_alias_mode2(idx)
593 }
594
595 return text
596
597 def show_tools_mode1(self, idx):
598 if self.show_tools == '1':
599 text = "<tr><td align=""center""%(style)s>%(tools)s </td></tr>" % {
600 "style":self.td_style,
601 "tools":self.tools_html(idx)}
602 else:
603 text = ''
604 return text
605
606 def show_date_mode1(self, idx):
607 if self.show_date == '1':
608 return '''
609 <TR>
610 <td%(style)s>%(this_exif_date)s</td>
611 </TR>''' % {
612 "style":self.td_style,
613 "this_exif_date": self.to_htmltext(self.exif_date[idx])}
614 else:
615 return ''
616
617 def show_alias_mode1(self, idx):
618 if self.show_text == '1':
619 return '''
620 <TR>
621 <td width="%(thumbnail_width)s" %(style)s> %(this_alias)s</td>
622 </TR>''' % {
623 "thumbnail_width": self.thumbnail_width,
624 "style": ' align="left" style="padding:0em; margin:2px 2px; border-style:none"',
625 "this_alias": self.description[idx]}
626 else:
627 return ''
628
629 def mode1_html(self, idx):
630 text = '''
631 <table width="%(thumbnail_width)s" align="center" valign="center"%(style)s>
632 <TR align="center" valign="center">
633 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
634 <td align="center" valign="middle" width="%(thumbnail_width)s"
635 %(tdstyle)s>
636 <input type="hidden" name="action" value="gallery2image">
637 <input type="hidden" name="do" value="VS">
638 <input type="hidden" name="full" value='%(full)s'>
639 <input type="hidden" name="alias" value='%(description)s'>
640 <input type="hidden" name="exif_date" value='%(exif_date)s'>
641 <input type="hidden" name="target" value='%(target)s'>
642 <input type="image" value="submit" src="%(thumbnail)s" >
643 </td>
644 </form>
645 </TR>
646 %(alias_html)s
647 %(date_html)s
648 %(tools_html)s
649 </table>'''% {
650 "tdstyle": self.td_style,
651 "style": self.inner_table_style,
652 "baseurl": self.request.getScriptname(),
653 "pagename": self.quoted_pagename,
654 "full": self.full[idx] + ',' + ','.join(self.full),
655 "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
656 "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
657 ','.join(self.exif_date)),
658 "target": self.webimg[idx] + ',' + ','.join(self.webimg),
659 "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
660 "thumbnail_width": self.thumbnail_width,
661 "tools_html": self.show_tools_mode1(idx),
662 "date_html": self.show_date_mode1(idx),
663 "alias_html": self.show_alias_mode1(idx)
664 }
665
666 return text
667
668 def get_files(self, path, files, quotes):
669 self.web = []
670 self.full = []
671 self.thumb = []
672 self.exif_date = []
673 self.imgtype = []
674 self.description = []
675
676 ddict = {}
677 n = len(quotes['image'])
678 if n > 0:
679 i = 0
680 for txt in quotes['image']:
681 ddict[txt] = quotes['alias'][i]
682 i += 1
683
684 self.video_type = 'swf'
685 self.source_type = ''
686 for attfile in files:
687 # only files not thumb or webnails
688 if not attfile.startswith('tmp.') and attfile.find('thumbnail_') == -1 and attfile.find('webnail_') == -1:
689 #previous naming left for compatibility
690 # only images
691 if wikiutil.isPicture(attfile):
692 self.description.append(ddict.get(attfile, attfile))
693 self.full.append(attfile)
694
695 fname, ext = os.path.splitext(attfile)
696 if ext in ('.gif', '.png'):
697 self.imgtype.append('PNG')
698 webnail = 'tmp.webnail_%s.png' % fname
699 thumbfile = 'tmp.thumbnail_%s.png' % fname
700 video_type = 'swf'
701 source_type = ext[1:]
702 else:
703 self.imgtype.append("JPEG")
704 webnail = 'tmp.webnail_%s.jpg' % fname
705 thumbfile = 'tmp.thumbnail_%s.jpg' % fname
706 video_type = 'swf'
707 source_type = 'jpg'
708
709 infile = os.path.join(path, attfile)
710 if os.path.exists(infile):
711 self.web.append(webnail)
712 self.thumb.append(thumbfile)
713
714
715 f = open(infile, 'rb')
716 tags = EXIF.process_file(f, 'DateTimeOriginal')
717 f.close()
718 if tags.has_key('EXIF DateTimeOriginal'):
719 date = str(tags['EXIF DateTimeOriginal'])
720 date = date.replace(':', '-', 2)
721 else:
722 date = '--'
723
724 self.exif_date.append(date)
725
726
727 def to_htmltext(self, text):
728 if text.find ("'"):
729 text = text.split("'")
730 text = '''.join(text)
731 return text
732
733 def to_wikiname(self, formatter, text):
734 ##taken from MiniPage
735 out = StringIO.StringIO()
736 self.request.redirect(out)
737 wikiizer = text_moin_wiki.Parser(text.strip(), self.request)
738 wikiizer.format(formatter)
739 result = out.getvalue()
740 self.request.redirect()
741 del out
742
743 result = result.replace('<a id="line-1"></a>', '')
744 result = result.replace('<p>', '')
745 result = result.replace('</p>', '')
746 result = result.strip()
747 return result
748
749
750 def get_quotes(self, formatter):
751 quotes = self.raw.split('\n')
752 quotes = [quote.strip() for quote in quotes]
753 quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
754
755 image = []
756 text = []
757
758 for line in quotes:
759 im, na = line[1:-1].split(' ', 1)
760 na = na.strip()
761 na = self.to_htmltext(na)
762 na = self.to_wikiname(formatter, na)
763 text.append(na)
764 image.append(im.strip())
765
766 return {
767 'alias': text,
768 'image': image,
769 }
770
771 def print_help(self):
772 self.request.write('''
773 <br>
774 {{{<br>
775 #!Gallery2 [columns=columns],[filter=filter],[mode=mode],<br>
776 [show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
777 [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
778 [reverse_sort=reverse_sort],<br>
779 [only_items=only_items],[template_itemlist=template_itemlist],<br>
780 [album=album],[album_name=album_name],[front_image=front_image],<br>
781 [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
782 [image_for_webnail=image_for_webnail],<br>
783 [sequence_name=sequence_name],[sequence_fps=sequence_fps]<br>
784 [border_thick=border_thick],[renew=renew],[help=help]<br>
785 * [image1.jpg alias]<br>
786 * [image2.jpg alias]<br>
787 }}}<br>''')
788
789 def format(self, formatter):
790 if self.help == '1':
791 self.print_help()
792 return
793 Dict = {}
794 quotes = self.get_quotes(formatter)
795 current_pagename = formatter.page.page_name
796 self.pagename = current_pagename
797 self.quoted_pagename = wikiutil.quoteWikinameURL(self.pagename)
798 attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
799
800 if hasattr(self.request.cfg, 'document_root'):
801
802 self.static_path = "%(dir)s/tmp/Gallery2%(wiki_name)s/%(pagename)s" % {
803 "wiki_name": self.request.getScriptname(),
804 "pagename": self.pagename,
805 "dir": self.request.cfg.document_root,
806 }
807 if os.path.exists(self.static_path) == 0:
808 os.makedirs(self.static_path)
809
810 self.static_url = "%(prefix)s/tmp/Gallery2%(wiki_name)s/%(pagename)s/" % {
811 "prefix": self.request.cfg.url_prefix,
812 "wiki_name": self.request.getScriptname(),
813 "pagename": self.pagename,
814 }
815 else:
816 self.static_path = attachment_path
817 self.static_url = AttachFile.getAttachUrl(self.pagename, '', self.request)
818
819
820 if self.only_items == '1':
821 all_files = quotes['image']
822 result = []
823 for attfile in all_files:
824 infile = os.path.join(attachment_path, attfile)
825 if os.path.exists(infile):
826 result.append(attfile)
827 all_files = result
828
829 if self.sort_by_alias == '1':
830 new_ordered_files = []
831 alias_text = quotes['alias']
832
833 i = 0
834 for attfile in all_files:
835 infile = os.path.join(attachment_path, attfile)
836 Dict[alias_text[i]] = attfile
837 i += 1
838
839 keys = Dict.keys()
840 keys.sort()
841 for txt in keys:
842 new_ordered_files.append(Dict[txt])
843
844 all_files = new_ordered_files
845 Dict.clear()
846
847 else:
848 all_files = os.listdir(attachment_path)
849
850
851 if self.filter != '.':
852 result = []
853 for test in all_files:
854 if re.match(self.filter, test):
855 result.append(test)
856
857 all_files = result
858
859 if not all_files:
860 self.request.write("<br><br><h1>No matching image file found!</h1>")
861 return
862
863 if self.sort_by_name == '1' and self.only_items == '0':
864 all_files.sort()
865
866 if self.sort_by_date == '1':
867 for attfile in all_files:
868 infile = os.path.join(attachment_path, attfile)
869 ft_file = "%s%s" % (str(os.path.getmtime(infile)), str(randint(0, 65535)))
870 Dict[ft_file] = attfile
871
872 keys = Dict.keys()
873 keys.sort()
874 file_mdate = []
875 for txt in keys:
876 file_mdate.append(Dict[txt])
877 all_files = file_mdate
878 Dict.clear()
879
880 if self.reverse_sort == '1':
881 all_files.reverse()
882
883 cells = []
884 cell_name = []
885 img = []
886
887 self.get_files(attachment_path, all_files, quotes)
888
889 if self.template_itemlist == '1':
890 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>')
891 for attfile in self.full:
892 self.request.write(' * [%(attfile)s %(date)s]<br>\n' % {
893 'attfile': attfile,
894 'date': 'alias'
895 })
896
897 i = 0
898 z = 1
899 cols = int(self.columns)
900
901 n = len(self.full)
902 if self.album == '0':
903 self.request.write("<table%s>" % self.outer_table_style)
904 if self.mode == '1' or cols > 1:
905 self.request.write('<TR valign="top">')
906 self.request.write('<TD%s>' % self.td_style)
907
908
909 if self.album == '1':
910 if self.front_image == '':
911 front_image = self.full[0]
912 else:
913 front_image = self.front_image
914 ii = 0
915 for tst in self.full:
916 if tst == front_image:
917 break
918 ii += 1
919
920 for attfile in self.full:
921 if self.album == '1':
922 if tst == front_image:
923 i = ii
924
925 this_description = self.description[i]
926 this_exif_date = self.exif_date[i]
927 this_webnail = self.web[i]
928 this_imgtype = self.imgtype[i]
929 this_thumbfile = self.thumb[i]
930
931 thumbf = os.path.join(self.static_path, this_thumbfile)
932 webf = os.path.join(self.static_path, this_webnail)
933
934 if self.renew == '1':
935 if os.path.exists(thumbf):
936 os.unlink(thumbf)
937 if os.path.exists(webf):
938 os.unlink(webf)
939
940 if not os.path.exists(webf) or not os.path.exists(thumbf):
941 infile = os.path.join(attachment_path, attfile)
942 im = Image.open(infile)
943
944 if not os.path.exists(webf):
945 im.thumbnail((int(self.webnail_width), int(self.webnail_width)), Image.ANTIALIAS)
946 if self.image_for_webnail == '1':
947 os.link(os.path.join(attachment_path, attfile), webf)
948 else:
949 im.save(webf, this_imgtype)
950 if not os.path.exists(thumbf):
951 im.thumbnail(((int(self.thumbnail_width)), ((int(self.thumbnail_width)))),
952 Image.ANTIALIAS)
953 im.save(thumbf, this_imgtype)
954
955 if self.image_for_webnail == '1':
956 this_webnailimg = attfile
957 self.webimg = self.full
958 else:
959 this_webnailimg = this_webnail
960 self.webimg = self.web
961
962 if self.mode == '1':
963 text = self.mode1_html(i)
964 self.request.write(''.join(text))
965
966 if self.mode == '2':
967 text = self.mode2_html(i)
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 self.mode == '1' or cols > 1:
973 if self.album == '0':
974 if z < cols:
975 self.request.write('</TD>')
976 if z < n and i < n - 1:
977 self.request.write('<TD%s>' % self.td_style)
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="top">')
985 self.request.write('<TD%s>' % self.td_style)
986
987 i += 1
988 z += 1
989 if z > cols:
990 z = 1
991
992 if self.album == '1':
993 self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name": self.album_name})
994 break
995
996 if self.album == '0':
997 if i < n:
998 self.request.write('</TD>')
999 self.request.write('</TR>')
1000 self.request.write('</table>')
1001
1002
1003 if self.sequence_name != '':
1004 video_file = "%(file)s.%(ext)s" % {
1005 "file": os.path.join(attachment_path, self.sequence_name),
1006 "ext": 'swf'}
1007 if self.renew == '1':
1008 if os.path.exists(video_file):
1009 os.unlink(video_file)
1010
1011 cmd = ''
1012 if float(self.sequence_fps) < 1:
1013 fps = 1
1014 else:
1015 fps = round(float(self.sequence_fps))
1016
1017 f_list = []
1018 for attfile in self.web:
1019 file = os.path.join(self.static_path, attfile)
1020 if os.path.exists(file):
1021 f_list.append(file)
1022
1023 if not os.path.exists(video_file):
1024 width, height = self.images2swf(f_list, video_file, fps, self.description, self.exif_date)
1025 else:
1026 swf = SWF.load(video_file)
1027 for tag in swf.tags:
1028 if tag.isImage():
1029 width, height = tag.image.size
1030 break
1031
1032 if os.path.exists(video_file):
1033 dict = {}
1034 dict['src'] = AttachFile.getAttachUrl(current_pagename, '%(file)s.%(videotype)s' % {
1035 'file': self.sequence_name,
1036 'videotype': 'swf',
1037 }, self.request)
1038
1039 image_link = '%(file)s.%(videotype)s' % {'file':self.sequence_name, 'videotype': 'swf'}
1040 if self.eo_info == '1':
1041 eo = "Or embed it into your wiki page by [[EmbedObject(%(file)s,width=%(width)s,height=%(height)s)]]." % {
1042 'file': image_link,
1043 'width': str(width),
1044 'height': str(height)}
1045 else:
1046 eo = ''
1047
1048 self.request.write('<P>')
1049 text = formatter.url(1, dict['src'] ) + image_link + formatter.url(0)
1050 self.request.write('Download this image sequence %(text)s for your archive. %(EO)s' % {
1051 'text': text,
1052 'EO': eo
1053 })
1054 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.