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

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.
  • [get | view] (2006-06-18 19:05:16, 45.0 KB) [[attachment:Gallery2.py]]
  • [get | view] (2006-06-18 19:06:04, 20.3 KB) [[attachment:gallery2image.py]]
  • [get | view] (2006-08-01 12:22:34, 7.5 KB) [[attachment:moinmoin-forms.tar.gz]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.