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