Attachment 'Gallery2-1.3.5-13.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 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:
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
278 at FeatureRequests/UploadMultipleAttachmentFiles/RulesForUnzip
279
280 RESTRICTIONS:
281 The mnovie 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 """
354 Dependencies = []
355 from MoinMoin.action import AttachFile
356 from MoinMoin import wikiutil, config
357 from MoinMoin.Page import Page
358
359 import os, string, re, Image, StringIO, codecs
360
361 from MoinMoin.parser import EXIF
362
363 from MoinMoin.parser import wiki
364
365 def server(request):
366
367 if request.is_ssl:
368 url_pattern = 'https'
369 else:
370 url_pattern = 'http'
371
372 return "%(url_pattern)s://%(server_name)s:%(server_port)s" % {
373 "url_pattern":url_pattern,
374 "server_name":request.server_name,
375 "server_port":str(request.server_port)}
376
377 def show_tools_restricted(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
378 if request.user.may.delete(pagename):
379 return tools_restricted_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request)
380 else:
381 return ''
382
383 def tools_restricted_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
384 text='''
385 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
386 <td>
387 <input type="hidden" name="action" value="gallery2image">
388 <input type="hidden" name="do" value="RL">
389 <input type="hidden" name="target" value="%(this_target)s">
390 <input type="image" value="submit" src="%(server)s/wiki/modern/img/to_left.png" title="rotate to left">
391 </td>
392 </form>
393 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
394 <td>
395 <input type="hidden" name="action" value="gallery2image">
396 <input type="hidden" name="do" value="RR">
397 <input type="hidden" name="target" value="%(this_target)s">
398 <input type="image" value="submit" src="%(server)s/wiki/modern/img/to_right.png" title="rotate to right" >
399 </td>
400 </form>
401 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
402 <td>
403 <input type="hidden" name="action" value="gallery2image">
404 <input type="hidden" name="do" value="RM">
405 <input type="hidden" name="target" value="%(this_target)s">
406 <input type="image" value="submit" src="%(server)s/wiki/modern/img/to_bak.png" title="move to bak" >
407 </td>
408 </form>''' % {
409 "server" : server(request),
410 'baseurl': request.getScriptname(),
411 "pagename":pagename,
412 "this_target":this_target}
413 return text
414
415 def tools_html(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request):
416 text='''
417 <TABLE align="center" width="%(thumbnail_width)s">
418 <TR>
419 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
420 <td>
421 <input type="hidden" name="action" value="AttachFile">
422 <input type="hidden" name="do" value="get">
423 <input type="hidden" name="target" value='%(this_target)s'>
424 <input type="image" value="submit" src="%(server)s/wiki/modern/img/to_full.png" title="load image">
425 </td>
426 </form>
427 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
428 <td>
429 <input type="hidden" name="action" value="gallery2image">
430 <input type="hidden" name="do" value="VS">
431 <input type="hidden" name="full" value='%(full)s'>
432 <input type="hidden" name="alias" value='%(alias)s'>
433 <input type="hidden" name="target" value='%(target)s`>
434 <input type="hidden" name="exif_date" value='%(exif_date)s'>
435 <input type="image" value="submit" src="%(server)s/wiki/modern/img/to_slide.png" title="slide_show" >
436 </td>
437 </form>
438 %(show_tools_restricted)s
439 </TR>
440 </TABLE>''' % {
441 "server" : server(request),
442 'baseurl': request.getScriptname(),
443 "pagename":pagename,
444 "thumbnail_width":thumbnail_width,
445 "full":full,
446 "alias":alias,
447 "exif_date":exif_date,
448 "target":target,
449 "this_target":this_image,
450 "show_tools_restricted":show_tools_restricted(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request)
451 }
452
453 return text
454
455 def show_alias_mode2(show_alias,thumbnail_width,this_alias,text_width):
456 if show_alias == '1':
457 return '''
458 <td valign="top" width="%(text_width)s">
459 %(this_alias)s
460 </td>''' % {
461 "this_alias":this_alias,
462 "text_width":text_width}
463 else:
464 return ''
465
466 def show_date_mode2(show_date,this_exif_date):
467 if show_date == '1':
468 return '''
469 <td>
470 <p>%(this_exif_date)s</p>
471 </td>''' % {
472 "this_exif_date":this_exif_date }
473 else:
474 return '';
475
476 def show_tools_mode2(show_tools,pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
477 if show_tools == '1' :
478 return "<td align=""center""> %s </td>" % tools_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request)
479 else:
480 return ''
481
482
483
484 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):
485 text='''
486 <tr valign="center">
487 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
488 <td align="center" valign="center" width="%(thumbnail_width)s">
489 <input type="hidden" name="action" value="gallery2image">
490 <input type="hidden" name="do" value="VS">
491 <input type="hidden" name="full" value='%(full)s'>
492 <input type="hidden" name="alias" value='%(alias)s'>
493 <input type="hidden" name="exif_date" value='%(exif_date)s'>
494 <input type="hidden" name="target" value='%(target)s'>
495 <input type="image" value="submit" src="%(server)s%(submit)s">
496 </td>
497 </form>
498 %(alias_html)s
499 </tr>
500 <tr>%(tools_html)s%(date_html)s</tr>'''% {
501 "server" : server(request),
502 "baseurl": request.getScriptname(),
503 "pagename":pagename,
504 "thumbnail_width":thumbnail_width,
505 "full":full,
506 "alias":alias,
507 "exif_date":exif_date,
508 "target":target,
509 "submit":submit,
510 "tools_html":show_tools_mode2(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request),
511 "date_html": show_date_mode2(show_date,this_exif_date),
512 "alias_html": show_alias_mode2(show_alias,thumbnail_width,this_alias,text_width)
513 }
514
515 return text
516
517 def show_tools_mode1(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request):
518 if show_tools == '1' :
519 text="<tr><td align=""center"">%s </td></tr>" % tools_html(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request)
520 else:
521 text=''
522 return text
523
524 def show_date_mode1(show_date,this_exif_date):
525 if show_date == '1':
526 return '''
527 <TR>
528 <td>%(this_exif_date)s</td>
529 </TR>''' % {
530 "this_exif_date":this_exif_date}
531 else:
532 return ''
533
534 def show_alias_mode1(show_alias,thumbnail_width,this_alias,text_width):
535 if show_alias == '1':
536 return '''
537 <TR>
538 <td align="left" width="%(thumbnail_width)s"> %(this_alias)s</td>
539 </TR>''' % {
540 "thumbnail_width": thumbnail_width,
541 "this_alias":this_alias}
542 else:
543 return ''
544
545 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,
546 show_tools,show_date,show_alias,request):
547 text='''
548 <table width="%(thumbnail_width)s" align="center" valign="center">
549 <TR align="center" valign="center">
550 <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
551 <td align="center" valign="middle" width="%(thumbnail_width)s">
552 <input type="hidden" name="action" value="gallery2image">
553 <input type="hidden" name="do" value="VS">
554 <input type="hidden" name="full" value='%(full)s'>
555 <input type="hidden" name="alias" value='%(alias)s'>
556 <input type="hidden" name="exif_date" value='%(exif_date)s'>
557 <input type="hidden" name="target" value='%(target)s'>
558 <input type="image" value="submit" src="%(server)s%(submit)s" >
559 </td>
560 </form>
561 </TR>
562 %(alias_html)s
563 %(date_html)s
564 %(tools_html)s
565 </table>'''% {
566 "server" : server(request),
567 "baseurl": request.getScriptname() ,
568 "pagename":pagename,
569 "full":full,
570 "alias":alias,
571 "exif_date":exif_date,
572 "target":target,
573 "submit":submit,
574 "thumbnail_width":thumbnail_width,
575 "tools_html": show_tools_mode1(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request),
576 "date_html":show_date_mode1(show_date,this_exif_date),
577 "alias_html": show_alias_mode1(show_alias,thumbnail_width,this_alias,text_width)
578 }
579
580 return text
581
582 def get_files(kw,path,files,quotes,request):
583 web=[]
584 full=[]
585 thumb=[]
586 exif_date=[]
587 img_type=[]
588 description=[]
589
590
591 ddict={}
592 n=len(quotes['image'])
593 if n > 0 :
594 i = 0
595 for txt in quotes['image']:
596 ddict[txt]=quotes['alias'][i]
597 i += 1
598
599 video_type = ''
600 source_type = ''
601 for attfile in files:
602 # only files not thumb or webnails
603 if attfile.find('thumbnail_') == -1 and attfile.find('webnail_') == -1:
604 # only images
605 if wikiutil.isPicture(attfile):
606 description.append(ddict.get(attfile, attfile))
607 full.append(attfile)
608
609 fname, ext = os.path.splitext(attfile)
610 if ext in ('.gif', '.png'):
611 img_type.append('PNG')
612 webnail = 'webnail_%s.png' % fname
613 thumbfile = 'thumbnail_%s.png' % fname
614 video_type = 'fli'
615 source_type = ext[1:]
616 else:
617 img_type.append("JPEG")
618 webnail = 'webnail_%s.jpg' % fname
619 thumbfile = 'thumbnail_%s.jpg' % fname
620 video_type = 'mpg'
621 source_type = 'jpg'
622
623
624 infile = os.path.join(path, attfile)
625 if os.path.exists(infile):
626 web.append(webnail)
627 thumb.append(thumbfile)
628
629 f = open(infile, 'rb')
630 tags = EXIF.process_file(f)
631 if tags.has_key('EXIF DateTimeOriginal'):
632 date = str(tags['EXIF DateTimeOriginal'])
633 date = date.replace(':', '-', 2)
634 else:
635 date = '--'
636 exif_date.append(date)
637 f.close()
638 if kw['sequence_type'] != '':
639 video_type = kw['sequence_type']
640
641 return thumb,web,full,video_type, exif_date,img_type,source_type,description
642
643 def to_htmltext(text):
644
645 if text.find ("'"):
646 text = text.split("'")
647 text = '''.join(text)
648
649 return text
650
651 def to_wikiname(request,formatter,text):
652 ##taken from MiniPage
653 out=StringIO.StringIO()
654 request.redirect(out)
655 wikiizer = wiki.Parser(text.strip(),request)
656 wikiizer.format(formatter)
657 result=out.getvalue()
658 request.redirect()
659 del out
660
661
662
663 result = result.replace('<a id="line-1"></a>','')
664 result = result.replace('<p>','')
665 result = result.replace('</p>','')
666 result = result.strip()
667 return result
668
669
670 def get_quotes(self,formatter):
671 quotes = self.raw.split('\n')
672 quotes = [quote.strip() for quote in quotes]
673 quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
674
675
676 image=[]
677 text=[]
678
679 for line in quotes:
680 im, na=line[1:-1].split(' ',1)
681 na = na.strip()
682 na = to_htmltext(na)
683 na = to_wikiname(self.request,formatter,na)
684 text.append(na)
685 image.append(im.strip())
686
687 return {
688 'alias': text,
689 'image': image,
690 }
691
692
693
694 class Parser:
695
696 def __init__(self, raw, request, **kw):
697 self.raw = raw
698 self.request = request
699 self.form = request.form
700 self._ = request.getText
701 self.kw = {
702 'sort_by_date': '0',
703 'sort_by_name': '1',
704 'sort_by_alias': '0',
705 'album': '0',
706 'album_name': 'album',
707 'front_image':'',
708 'template_itemlist': '0',
709 'reverse_sort': '0',
710 'border_thick': '1',
711 'columns': '4',
712 'filter': '.',
713 'mode': '1',
714 'help': '0',
715 'show_text': '1',
716 'show_date': '1',
717 'show_tools': '1',
718 'only_items': '0',
719 'image_for_webnail': '0',
720 'renew': '0',
721 'thumbnail_width': '128',
722 'webnail_width': '640',
723 'text_width': '140',
724 'sequence_name' : '',
725 'sequence_type' : '',
726 }
727
728
729 for arg in kw.get('format_args','').split(','):
730
731 if arg.find('=') > -1:
732 key, value=arg.split('=')
733 self.kw[key]=wikiutil.escape(value, quote=1)
734
735
736 self.kw['width']=str((int(self.kw['thumbnail_width'])+int(self.kw['text_width'])))
737
738
739 def format(self, formatter):
740 kw=self.kw
741 Dict = {}
742 quotes=get_quotes(self,formatter)
743 current_pagename=formatter.page.page_name
744 attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
745
746 if kw['help'] == '1':
747 self.request.write('''
748 <br>
749 {{{<br>
750 #!Gallery2 [columns=columns],[filter=filter],[mode=mode],<br>
751 [show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
752 [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
753 [reverse_sort=reverse_sort],<br>
754 [only_items=only_items],[template_itemlist=template_itemlist],<br>
755 [album=album],[album_name=album_name],[front_image=front_image],<br>
756 [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
757 [image_for_webnail=image_for_webnail],<br>
758 [sequence_name=sequence_name],[sequence_type=sequence_type]<br>
759 [border_thick=border_thick],[renew=renew],[help=help]<br>
760 * [image1.jpg alias]<br>
761 * [image2.jpg alias]<br>
762 }}}<br>''')
763 return
764
765
766 if kw['only_items'] == '1':
767 all_files=quotes['image']
768 result=[]
769 for attfile in all_files:
770 infile=os.path.join(attachment_path,attfile)
771 if os.path.exists(infile):
772 result.append(attfile)
773 all_files = result
774
775 if kw['sort_by_alias'] == '1':
776 new_ordered_files=[]
777 alias_text=quotes['alias']
778
779 i=0
780 for attfile in all_files:
781 infile=os.path.join(attachment_path,attfile)
782 ft_file=str(os.path.getmtime(infile))+os.tmpnam()
783 Dict[alias_text[i]]=attfile
784 i += 1
785
786 keys = Dict.keys()
787 keys.sort()
788 for txt in keys:
789 new_ordered_files.append(Dict[txt])
790
791
792 all_files=new_ordered_files
793 Dict.clear()
794
795 else:
796 all_files=os.listdir(attachment_path)
797
798 result = []
799
800 for test in all_files:
801 if re.match(kw['filter'], test):
802 result.append(test)
803 all_files=result
804
805 if not all_files:
806 self.request.write("<br><br><h1>No matching image file found!</h1>")
807 return
808
809
810
811 if kw['sort_by_name'] == '1' and kw['only_items'] == '0':
812 all_files.sort()
813
814 if kw['sort_by_date']=='1':
815 for attfile in all_files:
816 infile=os.path.join(attachment_path,attfile)
817 ft_file=str(os.path.getmtime(infile))+os.tmpnam()
818 Dict[ft_file]=attfile
819
820 keys = Dict.keys()
821 keys.sort()
822 file_mdate=[]
823 for txt in keys:
824 file_mdate.append(Dict[txt])
825 all_files=file_mdate
826 Dict.clear()
827
828 if kw['reverse_sort']=='1':
829 all_files.reverse()
830
831
832 cells=[]
833 cell_name=[]
834 img=[]
835
836 thumb, web, full, video_type, exif_date, imgtype, source_type, description = get_files(kw, attachment_path, all_files, quotes, self.request)
837
838 if kw['template_itemlist'] == '1':
839 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>')
840 for attfile in full :
841 self.request.write(' * [%(attfile)s %(date)s]<br>' % {
842 'attfile' : attfile,
843 'date' : 'alias'
844 })
845
846
847 i = 0
848 z = 1
849 cols = int(kw['columns'])
850
851
852 n = len(full)
853 if kw['album'] == '0' :
854 self.request.write("<table align='center' border='%s' >" % self.kw['border_thick'])
855 if kw['mode'] == '1' or cols > 1 :
856 self.request.write('<TR valign="bottom">')
857 self.request.write('<TD>')
858
859
860 if kw['album'] == '1' :
861 if kw['front_image'] == '' :
862 front_image = full[0]
863 else:
864 front_image = kw['front_image']
865 ii = 0
866 for tst in full :
867 if tst == front_image :
868 break
869 ii += 1
870
871
872 for attfile in full :
873 if kw['album'] == '1' :
874 if tst == front_image :
875 i = ii
876
877
878 this_description=description[i]
879 this_exif_date=exif_date[i]
880 this_webnail=web[i]
881 this_imgtype=imgtype[i]
882 this_thumbfile=thumb[i]
883
884
885 thumbf=os.path.join(attachment_path,this_thumbfile)
886 webf=os.path.join(attachment_path,this_webnail)
887
888
889 if kw['renew'] == '1':
890 if os.path.exists(thumbf):
891 os.unlink(thumbf)
892 if os.path.exists(webf):
893 os.unlink(webf)
894
895 if not os.path.exists(webf) or not os.path.exists(thumbf):
896 infile = os.path.join(attachment_path,attfile)
897 im = Image.open(infile)
898
899 if not os.path.exists(webf):
900 im.thumbnail(((int(kw['webnail_width'])),((int(kw['webnail_width'])))), Image.ANTIALIAS)
901 if kw['image_for_webnail'] == '1' :
902 os.link(os.path.join(attachment_path,attfile),webf)
903 else:
904 im.save(webf, this_imgtype)
905 if not os.path.exists(thumbf):
906 im.thumbnail(((int(kw['thumbnail_width'])),((int(kw['thumbnail_width'])))),
907 Image.ANTIALIAS)
908 im.save(thumbf, this_imgtype)
909
910
911 if kw['image_for_webnail'] == '1' :
912 this_webnailimg = attfile
913 webimg = full
914 else:
915 this_webnailimg = this_webnail
916 webimg = web
917
918
919 if kw['mode'] == '1':
920 text = mode1_html(current_pagename,
921 kw['border_thick'],
922 kw['width'],
923 kw['thumbnail_width'],
924 kw['text_width'],
925 attfile + "," + ','.join(full),
926 attfile,
927 this_description + '!,!' + '!,!'.join(description),
928 this_description,
929 to_htmltext(this_exif_date + ',' + ','.join(exif_date)),
930 to_htmltext(this_exif_date),
931 this_webnailimg + ',' + ','.join(webimg),
932 this_webnailimg,
933 AttachFile.getAttachUrl(current_pagename, this_thumbfile, self.request),
934 kw['show_tools'],
935 kw['show_date'],
936 kw['show_text'],
937 self.request
938 )
939 self.request.write(''.join(text))
940
941 if kw['mode'] == '2':
942 text = mode2_html(current_pagename,
943 kw['border_thick'],
944 kw['width'],
945 kw['thumbnail_width'],
946 kw['text_width'],
947 attfile + "," + ','.join(full),
948 attfile,
949 this_description + '!,!' + '!,!'.join(description),
950 this_description,
951 to_htmltext(this_exif_date + ',' + ','.join(exif_date)),
952 to_htmltext(this_exif_date),
953 this_webnailimg + ',' + ','.join(webimg),
954 this_webnailimg,
955 AttachFile.getAttachUrl(current_pagename, this_thumbfile, self.request),
956 kw['show_tools'],
957 kw['show_date'],
958 kw['show_text'],
959 self.request
960 )
961
962 if cols > 1 : self.request.write('<table valign="bottom">')
963 self.request.write(''.join(text))
964 if cols > 1 : self.request.write('</table>')
965
966 if kw['mode'] == '1' or cols > 1:
967 if kw['album'] == '0' :
968 if z < cols :
969 self.request.write('</TD>')
970 if z < n and i < n - 1 :
971 self.request.write('<TD>')
972 if i == n - 1 :
973 self.request.write('</TR>')
974 else:
975 self.request.write('</TD>')
976 self.request.write('</TR>')
977 if i < n - 1 :
978 self.request.write('<TR valign="bottom">')
979 self.request.write('<TD>')
980
981 i += 1
982 z += 1
983 if z > cols :
984 z = 1
985
986 if kw['album'] == '1' :
987 self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name":kw['album_name']})
988 break
989 if kw['album'] == '0' :
990 if i < n :
991 self.request.write('</TD>')
992 self.request.write('</TR>')
993 self.request.write('</table>')
994
995 ############################################
996 ##TODO: syntax change to formatter - later #
997 ############################################
998
999 if os.name != 'posix':
1000 text = '<p><FONT color="Red" >sequence_name feature not defined for this platform: %(platform)s </FONT><p>' % {"platform":os.name}
1001 self.request.write(text)
1002 return
1003
1004 if kw['sequence_name'] != '' :
1005
1006 ppm2fli = '/usr/local/bin/ppm2fli'
1007 video_file = os.path.join(attachment_path,kw['sequence_name'])
1008
1009 if video_type == 'fli' :
1010
1011 if kw['renew'] == '1':
1012 if os.path.exists(video_file + '.fli'):
1013 os.unlink(video_file + '.fli')
1014 liste_file = '%(flcfile)s.txt' % { 'flcfile': video_file}
1015 if not os.path.exists(video_file+'.fli'):
1016
1017 data = open(liste_file,'w')
1018 x=[]
1019 y=[]
1020 for attfile in full :
1021 file = os.path.join(attachment_path,attfile)
1022 im = Image.open(file)
1023 size = im.size
1024 x.append(size[0])
1025 y.append(size[1])
1026 data.write("%(file)s\n" % {'file':attfile})
1027 data.close()
1028
1029
1030 if max(x) > 1280.0:
1031 this_x = 1280.0
1032 f = this_x / max(x)
1033 this_y = max(y) * f
1034 else:
1035 this_x = max(x)
1036 this_y = max(y)
1037
1038 if this_y > 1024.0:
1039 new_y = 1024.0
1040 f = new_y /this_y
1041 this_y = new_y
1042 this_x = this_x * f
1043
1044 sz = '%(szx)sx%(szy)s' % { 'szx': long(this_x),
1045 'szy': long(this_y) }
1046 #wir mueesen in den pfad wechseln
1047 #wenn Zeit ist ppm12fli überarbeiten
1048 cmd = ''
1049 if source_type == 'png':
1050 cmd = 'cd "%(attachment_path)s" && %(ppm2fli)s -g %(sz)s -fpngtopnm -s 1000 %(flcfile)s.txt %(flcfile)s.fli > /dev/null ' % {
1051 'ppm2fli': ppm2fli,
1052 'flcfile': kw['sequence_name'] ,
1053 'attachment_path': attachment_path,
1054 'sz': sz }
1055
1056 if source_type == 'gif':
1057 cmd = 'cd "%(attachment_path)s" && %(ppm2fli)s -g %(sz)s -fgiftopnm -s 1000 %(flcfile)s.txt %(flcfile)s.fli > /dev/null ' % {
1058 'ppm2fli': ppm2fli,
1059 'flcfile': kw['sequence_name'] ,
1060 'attachment_path': attachment_path,
1061 'sz': sz }
1062
1063 if source_type == 'jpg':
1064
1065 cmd = 'cd "%(attachment_path)s" && %(ppm2fli)s -g %(sz)s -fjpegtopnm -s 1000 %(flcfile)s.txt %(flcfile)s.fli > /dev/null' % {
1066 'ppm2fli': ppm2fli,
1067 'flcfile': kw['sequence_name'] ,
1068 'attachment_path': attachment_path,
1069 'sz': sz }
1070
1071
1072 if cmd != '':
1073 os.system(cmd)
1074
1075 if os.path.exists(video_file+'.fli'):
1076 if os.path.exists(liste_file):
1077 os.unlink(liste_file) # liste entfernen wenn file da ist
1078 dict = {}
1079 dict['src'] = AttachFile.getAttachUrl(current_pagename,'%(flcfile)s.fli' % {
1080 'flcfile': kw['sequence_name']},self.request)
1081 image_link = '%(flcfile)s.fli' % { 'flcfile':kw['sequence_name']}
1082
1083 self.request.write('<BR>')
1084 text = formatter.url(1,dict['src'] ) + image_link + formatter.url(0)
1085 self.request.write('Download this image sequence %(text)s for your archive' % { 'text': text})
1086
1087
1088 if video_type == 'mpg':
1089 # http://www.stillhq.com/jpeg2mpeg
1090 if kw['renew'] == '1':
1091 if os.path.exists(video_file + '.mpg'):
1092 os.unlink(video_file + '.mpg')
1093 if not os.path.exists(os.path.join(attachment_path,'%(file)s.mpg' % {'file':kw['sequence_name']})):
1094 if kw['sequence_type'] == 'mpg':
1095 liste = string.join(full,' ')
1096 else:
1097 liste = string.join(web,' ')
1098
1099 cmd = 'cd "%(attachment_path)s" && convert -delay 100 %(liste)s %(file)s.mpg > /dev/null &' % {
1100 'liste':liste,
1101 'file':kw['sequence_name'] ,
1102 'attachment_path':attachment_path}
1103 os.system(cmd)
1104 self.request.write('<P><FONT color="Red" > MPEG creation as background process started </FONT></P>')
1105 if os.path.exists(os.path.join(attachment_path,'%(file)s.mpg' % {'file':kw['sequence_name']})):
1106 dict = {}
1107 dict['src'] = AttachFile.getAttachUrl(current_pagename,'%(file)s.mpg' % {
1108 'file': kw['sequence_name']},self.request)
1109
1110 image_link = '%(file)s.mpg' % { 'file':kw['sequence_name']}
1111
1112 self.request.write('<BR>')
1113 text = formatter.url(1,dict['src'] ) + image_link + formatter.url(0)
1114 self.request.write('Download this image sequence %(text)s for your archive' % { 'text': text})
1115
1116
1117 ## the sequence block needs to be refactored by better names
1118
1119
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.