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