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