Attachment 'Gallery2-1.5.4-18.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - Gallery2 parser
   4 
   5     PURPOSE:
   6         This parser is used to visualize a couple of images as a thumbnail gallery.
   7         Optional a description of an image could be added including WikiName.
   8         On default the image name and it's creation date is shown.
   9         If you click on a thumbnail you get the webnails shown. By a menue you are able to toggle between the slides.
  10 
  11     CALLING SEQUENCE:
  12       {{{
  13       #!Gallery2 [columns=columns],[filter=filter],[mode=mode],
  14                  [show_text=show_text],[show_date=show_date], [show_tools=show_tools],
  15                  [sort_by_name=sort_by_name],[sort_by_date=sort_by_date], [sort_by_alias=sort_by_alias],
  16                  [reverse_sort=reverse_sort],
  17                  [only_items=only_items],[template_itemlist=template_itemlist],
  18                  [album=album],[album_name=album_name],[front_image=front_image],
  19                  [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],
  20                  [image_for_webnail=image_for_webnail],
  21                  [sequence_name=sequence_name], [sequence_fps=sequence_fps],
  22                  [border_thick=border_thick],[renew=renew],[help=help]
  23       * [image1.jpg alias]
  24       * [image2.jpg alias]
  25       }}}
  26 
  27     KEYWORD PARAMETERS:
  28         columns:           number of columns for thumbnails
  29         filter:            regex to select images
  30         show_text:         default is 1 description is shown
  31                            any other means no description
  32         show_date:         default is 1 date info from exif header if available is shown
  33         show_tools:        default is 1 icon toolbar is show any other disables this
  34         sort_by_name:      default is 1, the images are sorted by name, but not if only_items is 1
  35         sort_by_date:      default is 0, if set to 1 the images are sorted to the modification time
  36                            if they do have all the same time then the result is random
  37         sort_by_alias      default is 0, if set to 1 and only_items set to 1 it is used to order the images by the alias name
  38         reverse_sort:      default is 0, if set to 1 the file list is reversed
  39                            any other means no description
  40         mode:              default is 1 this means description below the image
  41                            any other number means description right of image
  42         only_items:        default is 0 if it is set to 1 only images which are described in listitem are shown
  43                            dependend on the order of the items
  44         template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script. 
  45         album:             default is 0 if set to 1 only the first image of a series is shown but slideshow over all images 
  46         album_name:        useful for album. default is 'album' use it as short name for the album. 
  47         front_image:       Useful for album.  default is ''. The first image is shown in front of the album and slideshow.
  48                            If set to an existing image name this is shown in front of album and slideshow. 
  49                            The slide show could start by this somewhere.
  50         border_thick:      default is 1 this is the thickness in pixeln of the outer frame
  51         renew:             default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
  52                            Afterwards they are new created.
  53         thumbnail_width:   default is 128
  54         webnail_width:     default is 640
  55         text_width:        default is 140		   
  56         image_for_webnail  default is 0 if set to 1 then the image is shown as preview and not the webnail
  57         sequence_name:     default is ''  if set this name is used for an image
  58                            sequence with an duration of one image per second.
  59         sequence_fps:      (frames per second) default is 1 it is not allowed to set values below 1
  60         help:              default is 0 if set a copy of the CALLING SEQUENCE is shown, 
  61                            (there are some new ideas around to show help to an user so this will be later replaced)
  62                            
  63 
  64     OPTIONAL INPUTS:
  65         itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
  66                    The alias text is used as description of the image instead of the file name
  67 
  68 
  69     EXAMPLE:
  70 = GalleryTest =
  71 
  72 == all images shown, one is decribed ==
  73 {{{
  74 { { {
  75 #!Gallery2
  76 * [100_1185.JPG Bremen, SpaceCenter]
  77 } } }
  78 }}}
  79 
  80 Result: [[BR]]
  81  {{{
  82 #!Gallery2
  83 * [100_1185.JPG Bremen, SpaceCenter]
  84 }}}
  85 
  86 == only thumbnails and only_items ==
  87 {{{
  88 { { {
  89 #!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
  90  * [100_1185.JPG Bremen, SpaceCenter]
  91  * [100_1194.JPG Bremen]
  92 } } }
  93 }}}
  94 
  95 Result: [[BR]]
  96  {{{
  97 #!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
  98  * [100_1185.JPG Bremen, SpaceCenter]
  99  * [100_1194.JPG Bremen]
 100 }}}
 101 
 102 == only_items by two columns and text right ==
 103 
 104 {{{
 105 { { {
 106 #!Gallery2 mode=2,columns=2,only_items=1
 107  * [100_1185.JPG Bremen, SpaceCenter]
 108  * [100_1194.JPG Bremen]
 109 } } }
 110 }}}
 111 
 112 Result: [[BR]]
 113  {{{
 114 #!Gallery2 mode=2,columns=2,only_items=1
 115  * [100_1185.JPG Bremen, SpaceCenter]
 116  * [100_1194.JPG Bremen, behind SpaceCenter]
 117 }}}
 118 
 119 ----
 120 
 121 == only_items by two columns, date supressed ==
 122 
 123 {{{
 124 { { {
 125 #!Gallery2 columns=2,only_items=1,show_date=0
 126  * [100_1185.JPG Bremen, SpaceCenter]
 127  * [100_1194.JPG Bremen, behind SpaceCenter]
 128 } } }
 129 }}}
 130 
 131 Result: [[BR]]
 132  {{{
 133 #!Gallery2 columns=2,only_items=1,show_date=0
 134  * [100_1185.JPG Bremen, SpaceCenter]
 135  * [100_1194.JPG Bremen, behind SpaceCenter]
 136 }}}
 137 
 138 
 139 == filter regex used, mode 2, icons and date supressed, one column and border_thick=5 ==
 140 {{{
 141 { { {
 142 #!Gallery2 columns=1,filter=100_118[0-5],mode=2,show_date=0,show_tools=0,border_thick=5
 143 } } }
 144 }}}
 145 
 146 Result: [[BR]]
 147  {{{
 148 #!Gallery2 columns=1,filter=100_118[0-7],mode=2,show_date=0,show_tools=0,border_thick=5
 149 }}}
 150 
 151 == other macro calls ==
 152 {{{
 153 { { {
 154 #!Gallery2 only_items=1,show_date=0
 155  * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
 156 } } }
 157 }}}
 158 
 159 Result: [[BR]]
 160  {{{
 161 #!Gallery2 only_items=1,show_date=0
 162  * [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
 163 }}}
 164 
 165 == renew means always new thumbnails and webnails of selection ==
 166 {{{
 167 { { {
 168 #!Gallery2 only_items=1,show_date=0,show_tools=0,renew=1
 169  * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
 170 } } }
 171 }}}
 172 
 173 Result: [[BR]]
 174  {{{
 175 #!Gallery2 only_items=1,show_date=0,renew=1
 176  * [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
 177 }}}
 178 
 179 == template_itemlist ==
 180 {{{
 181 { { {
 182 #!Gallery2 template_itemlist=1
 183 * [100_1185.JPG Bremen, SpaceCenter]
 184 } } }
 185 }}}
 186 
 187 Result: [[BR]]
 188  {{{
 189 #!Gallery2 template_itemlist=1
 190 * [100_1185.JPG Bremen, SpaceCenter]
 191 }}}
 192 
 193 == help to show Calling Sequence ==
 194  {{{
 195 { { {
 196 #!Gallery2 help=1
 197 } } }
 198 }}}
 199 
 200 Result: [[BR]]
 201 {{{
 202 #!Gallery2 help=1
 203 }}}
 204 
 205 
 206     PROCEDURE:
 207       ABOUT:
 208       While I have first implemented Gallery2 for something like photos I do use it at work since a while for
 209       output of model calculations too.
 210       Because of the possibility to share a standalone playable file to colleagues I have first decided to use
 211       fli or mpeg as output format for an image sequence. mpeg is not quite good for displaying our data
 212       and fli does sometimes eat a lot of cpu power. Both would make a lot of work getting them working
 213       on a non posix OS. For further development it would be better to have a python only version of Gallery2.
 214       That's the reason why I switch the sequence format to flash now. I do use the library of Matthias Kramm
 215       (http://www.swftools.org).
 216       
 217       HOWTO:
 218       Download some images to a page and start with the examples.
 219       Aliasing of the filenames are done by adding an itemlist, see example.
 220 
 221       NEEDS:
 222       This routine requires the Action macro gallery2image which is used to rotate or delete a
 223       selected image. The actual version is gallery2image-1.5.4-13.py.
 224       Only users which have the rights to delete are able to execute this action macro. 
 225       The icons of these are only shown if you have enough rights. 
 226       Furthermore it requires:
 227        * the PIL (Python Imaging Library).
 228        * the EXIF routine from http://home.cfl.rr.com/genecash/digital_camera.html
 229          (you need a modifed version you'll get it from the Gallery2 documentation page)
 230        * the SWF library from http://www.swftools.org
 231 
 232       Do install them to the usual python library path.
 233       
 234       REQUIRED IMAGES:
 235       You have to put them into wiki/mg/ dir. e.g.: http://moinmoin.wikiwikiweb.de/ParserMarket/Gallery2/ModernImages
 236       
 237       GENERAL:
 238       Please remove the Version number from the code!
 239 
 240       If you want to upload many files at once please look on MoinMoin versions less 1.5.0
 241       at FeatureRequests/UploadMultipleAttachmentFiles/RulesForUnzip
 242       
 243       With many images you can get in trouble by the SurgeProtection for attachment. Then you have to adjust the parameters see HelpOnConfiguration/SurgeProtection. 
 244       
 245       RESTRICTIONS:
 246       If you rotate an image at the moment the exif is destroyed. PIL ignores the exif header.
 247       This is not a quite big problem normally files with an EXIF header are right rotated.
 248       
 249       HISTORY:
 250       While recognizing how to write MiniPage I got the idea to write a Gallery Parser.
 251       We have used in our wikis in the past the Gallery macro of SimonRyan.
 252       I have tried to modify it a bit to change it for 1.3 but my python skills weren't enough
 253       or it was easier to write it completly new.
 254       So this one shows now a way how a Gallery could be used by the parser and an action Macro.
 255       Probably it is a good example for others who like to know how to do this
 256 
 257       OUTLOOK:
 258       Dependent on Matthias Kramm's python interface development the webnails could be exchanged to a
 259       flash animation with action controls. That will ommit the javascript slide show and will give less files.
 260       swftools is able to do this by now but that will need an os.system call. At the moment I like to avoid this.
 261       If you are interested the command is swfcombine -o output.swf movie_control.swf viewport=input.swf.
 262       It is still in the code but commented off. movie_control.swf embbeds the controls 24 pixels above the flash so it's a good idea to resize the flash by the -X and -Y option.
 263 
 264     MODIFICATION HISTORY:
 265         Version 1.3.3.-1
 266         @copyright: 2005 by Reimar Bauer (R.Bauer@fz-juelich.de)
 267         @license: GNU GPL, see COPYING for details.
 268         2005-03-26: Version 1.3.3-2 keyword renew added
 269                     creation of thumbnails and webnails in two calls splitted
 270                     Version 1.3.3-3 bug fixed if itemlist is given to describe only some of the images
 271                                     but only_items is not set to 1
 272                                     Example code changed
 273         2005-03-27: Version 1.3.3-4 Action macro added and the form to call it. User which have rights to delete
 274                                     could use the functions of gallery2Image.
 275         2005-08-03: Version 1.3.3-5 theme path for icons corrected and a platform independent path joining
 276                                     os.unlink removed as suggested by CraigJohnson
 277                                     sort_by_name is default if not only_items is 1
 278                                     optional sort_by_date could be used
 279                                     keyword template_itemlist added 
 280                                     keyword help added
 281                                     extra frame by mode=2 removed 
 282         2005-08-06: Version 1.3.5-6 slideshow mode added
 283                                     keyword image_for_webnail added
 284         2005-08-13: Version 1.3.5-7 syntax changed from GET to POST
 285                                     forms instead of links
 286                                     filenames from images submitted to gallery2image too
 287                                     new keyword sort_by_alias
 288                                     internal code clean up
 289                                     this version needs: gallery2image-1.3.5-5.py
 290         2005-08-14: Version 1.3.5-8 (TW) cleanup                                    
 291         2005-08-14: Version 1.3.5-9 html code for tables changed
 292                                     because of the ugly extra space of form elements
 293                                     div tag removed so now we use the page style
 294                                     slide show action goes to right webnail now
 295                                     this version needs: gallery2image-1.3.5-5.py
 296        2005-08-17: Version 1.3.5-10 html code separated in functions     
 297                                     structure of code changed, now you see the thumbnails after creation
 298                                     bug removed if quote is given but file does not exist
 299        2005-09-02: Version 1.3.5-11 keyword album, album_name and front_image added          
 300                                     image urls changed to complete server url      
 301        2005-11-12: Version 1.3.5-12 bug fixed for image_for_webnail=1            
 302                                     bug fixed at last cell table end tr instead of td
 303                                     bug fixed don't render a filename as WikiName
 304                                     bug fixed " is allowed in alias name
 305                                     bug fixed ' is allowed in alias name
 306                                     bug fixed linebreak by a space in alias  
 307                                     not quite a bug but makes it very difficult to code in 
 308                                     gallery2image so additional id removed in alias name
 309       2005-11-17: Version 1.3.5-13  implementation of sequence video clips at first step for posix only 
 310                                     sequence_type could be used to ommit the autoselection
 311                                     fli/flc files are used for gif and png files,  mpeg files for
 312                                     jpeg files. Duration on both is 1 image/second 
 313                                     feature added of recognising the right url pattern (http opr https)
 314       
 315  
 316                                     
 317      Version 1.5.4-16 2006-08-02 based on 1.3.5-13                    
 318      FlorianFesti: major changes    more flexible but better aligned layout
 319                                     better support for border_width=0              
 320                                     use of cfg.url_prefix insted of hard coding /wiki
 321                                          
 322      ReimarBauer:                   PEP8 style
 323                                     mode2 changed to Florians style too
 324                                     some other changes to get things compatible to previous versions
 325                                     flash (swf) format is used as sequence format
 326                                     keyword sequence_fps added
 327                                     keyword eo_info added
 328                                     EXIF.py moved to python lib 
 329                                        used the version of StigIversen
 330                                        
 331                                     file names of webnails and thumbnails does now have a prefix of tmp.   
 332                                     direct serving of webnails and thumbnails is possible but not default
 333                                        You have to set the var document_root in your wikiconfig.py to the absolute path of
 334                                        the wiki alias. For the default installation it is document_root = '/usr/share/moin/htdocs'
 335                                        Using this method MoinMoin can't use acls for the webnails and thumbnails.
 336     2006-08-22 1.5.4-18 RB for the call of Frame a test if parameters are submitted is added (backport from 1.6.0-18                           
 337                                    
 338 """
 339 Dependencies = ['time'] # do not cache
 340 
 341 from MoinMoin.action import AttachFile
 342 from MoinMoin import wikiutil, config
 343 from MoinMoin.Page import Page
 344 
 345 import os, re, sys, Image, StringIO, codecs
 346 from random import randint
 347 
 348 try:
 349     import EXIF
 350 except ImportError:
 351     EXIF = None
 352 
 353 try:
 354     import SWF
 355 except ImportError:
 356     SWF = None
 357 
 358 
 359 from MoinMoin.parser import wiki
 360 
 361 class Parser:
 362 
 363     def __init__(self, raw, request, **kw):
 364         self.sort_by_date = '0'
 365         self.sort_by_name = '1'
 366         self.sort_by_alias = '0'
 367         self.album = '0'
 368         self.album_name = 'album'
 369         self.front_image = ''
 370         self.template_itemlist = '0'
 371         self.reverse_sort = '0'
 372         self.border_thick = '1'
 373         self.columns = '4'
 374         self.filter = '.'
 375         self.mode = '1'
 376         self.help = '0'
 377         self.show_text = '1'
 378         self.show_date = '1'
 379         self.show_tools = '1'
 380         self.only_items = '0'
 381         self.image_for_webnail = '0'
 382         self.renew = '0'
 383         self.thumbnail_width = '128'
 384         self.webnail_width = '640'
 385         self.text_width = '140'
 386         self.sequence_name = ''
 387         self.sequence_fps = '1'
 388         self.eo_info = '0'
 389 
 390         test = kw.get('format_args', '')
 391         if test:
 392             for arg in kw.get('format_args', '').split(','):
 393                 if arg.find('=') > -1:
 394                     key, value = arg.split('=')
 395                     setattr(self, key, wikiutil.escape(value.strip(), quote=1))
 396 
 397         self.width = str(int(self.thumbnail_width) +
 398                          int(self.text_width))
 399 
 400         self.raw = raw
 401         self.request = request
 402         self.form = request.form
 403         self._ = request.getText
 404 
 405         self.outer_table_style = ' border="%s"' % self.border_thick
 406         self.inner_table_style = ' style="border-style:none; margin:10px;"'
 407         self.td_style = ' align="center" style="padding:0; margin:2px 2px; border-style:none"'
 408 
 409     def images2swf(request, images, swf_filename, swf_fps, description, exif_date):
 410     ## this code is based on
 411     ## http://www.quiss.org/swftools/python/jpeg2swf_exif.py
 412     ## by Matthias Kramm
 413     ##
 414     ## Thanks Matthias
 415 
 416         xmax, ymax = 0, 0
 417         depth = 1
 418         SWF.verbose(0)
 419         # verbose is not used everybody
 420         swf = SWF.create(version=6, bbox=(0, 0, 0, 0), fps=float(swf_fps))
 421 
 422         i = 0
 423         for filename in images:
 424             pic = Image.open(filename)
 425             pic.load()
 426 
 427             width, height = pic.size
 428             if width > xmax: xmax = width
 429             if height > ymax: ymax = height
 430 
 431             pic = pic.convert("RGBA")
 432             image = SWF.Image(pic.im)
 433 
 434             swf.tags += image
 435             shape = SWF.ImageShape(image)
 436             swf.tags += shape
 437             swf.tags += SWF.PlaceObject(shape, depth=depth)
 438             depth += 1
 439             swf.tags += SWF.ShowFrame()
 440 
 441             i += 1
 442 
 443         swf.bbox = (0, 0, xmax, ymax)
 444         swf.save(swf_filename)
 445 
 446         return xmax, ymax
 447 
 448     def show_tools_restricted(self, this_target):
 449         if not self.request.user.may.delete(self.pagename):
 450             return ''
 451 
 452         return '''
 453         <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 454           <td%(style)s>
 455             <input type="hidden" name="action" value="gallery2image">
 456             <input type="hidden" name="do" value="RL">
 457             <input type="hidden" name="target" value="%(this_target)s">
 458             <input type="image" value="submit" src="%(htdocs)s/img/to_right.png" title="rotate to left">
 459           </td>
 460         </form>
 461         <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 462           <td%(style)s>
 463             <input type="hidden" name="action" value="gallery2image">
 464             <input type="hidden" name="do" value="RR">
 465             <input type="hidden" name="target" value="%(this_target)s">
 466             <input type="image"  value="submit" src="%(htdocs)s/img/to_left.png" title="rotate to right" >
 467           </td>
 468         </form>
 469         <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 470           <td%(style)s>
 471             <input type="hidden" name="action" value="gallery2image">
 472             <input type="hidden" name="do" value="RM">
 473             <input type="hidden" name="target" value="%(this_target)s">
 474             <input type="image" value="submit" src="%(htdocs)s/img/to_bak.png" title="move to bak" >
 475            </td>
 476         </form>''' % {
 477             'baseurl': self.request.getBaseURL(),
 478             'style': self.td_style,
 479             'htdocs': self.request.cfg.url_prefix,
 480             "pagename": self.quoted_pagename,
 481             "this_target": this_target}
 482 
 483     def tools_html(self, idx):
 484         this_image = self.full[idx]
 485 
 486         text = '''
 487             <TABLE align="center" width="%(thumbnail_width)s"%(tablestyle)s>
 488                 <TR>
 489                     <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 490                         <td%(style)s>
 491                             <input type="hidden" name="action" value="AttachFile">
 492                             <input type="hidden" name="do" value="get">
 493                             <input type="hidden" name="target" value='%(this_target)s'>
 494                             <input type="image" value="submit" src="%(htdocs)s/img/to_full.png" title="load image">
 495                         </td>
 496                     </form>
 497                     <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 498                         <td%(style)s>
 499                             <input type="hidden" name="action" value="gallery2image">
 500                             <input type="hidden" name="do" value="VS">
 501                             <input type="hidden" name="full" value='%(full)s'>
 502                             <input type="hidden" name="alias" value='%(description)s'>
 503                             <input type="hidden" name="target" value='%(target)s'>
 504                             <input type="hidden" name="exif_date" value='%(exif_date)s'>
 505                             <input type="image" value="submit" src="%(htdocs)s/img/to_slide.png" title="slide_show" >
 506                        </td>
 507                     </form>
 508                     %(show_tools_restricted)s
 509                 </TR>
 510             </TABLE>'''   % {
 511             "baseurl": self.request.getScriptname(),
 512             "pagename": self.quoted_pagename,
 513             "htdocs": self.request.cfg.url_prefix,
 514             "tablestyle": self.inner_table_style,
 515             "style": self.td_style,
 516             "thumbnail_width": self.thumbnail_width,
 517             "full": self.full[idx] + ',' + ','.join(self.full),
 518             "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
 519             "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
 520                                          ','.join(self.exif_date)),
 521             "target": self.webimg[idx] + ',' + ','.join(self.webimg),
 522             "this_target": self.full[idx],
 523             "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
 524             "show_tools_restricted":self.show_tools_restricted(this_image)
 525             }
 526 
 527         return text
 528 
 529     def show_alias_mode2(self, idx):
 530        if self.show_text == '1':
 531            return '''
 532             <td valign="top" width="%(text_width)s" %(style)s>
 533            %(this_alias)s
 534         </td>''' % {
 535         "this_alias":self.description[idx],
 536         "text_width":self.text_width,
 537         "style": ' align="left" style="padding:0px; margin:2px 2px; border-style:none"'}
 538        else:
 539           return ''
 540 
 541     def show_date_mode2(self, idx):
 542        if self.show_date == '1':
 543            return '''
 544                   <td%(style)s><p>%(this_exif_date)s</p></td>''' % {
 545                   "style": self.td_style,
 546                   "this_exif_date": self.to_htmltext(self.exif_date[idx]) }
 547        else:
 548             return ''
 549 
 550     def show_tools_mode2(self, idx):
 551         if self.show_tools == '1':
 552             return "<td align=""center""%(style)s> %(tools)s </td>" % {
 553                 "style":self.td_style,
 554                 "tools":self.tools_html(idx)}
 555         else:
 556             return ''
 557 
 558     def mode2_html(self, idx):
 559         text = '''
 560         <tr valign="center">
 561         <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 562             <td align="center" valign="center" width="%(thumbnail_width)s"
 563             %(tdstyle)s>
 564                 <input type="hidden" name="action" value="gallery2image">
 565                 <input type="hidden" name="do" value="VS">
 566                 <input type="hidden" name="full" value='%(full)s'>
 567                 <input type="hidden" name="alias" value='%(description)s'>
 568                 <input type="hidden" name="exif_date" value='%(exif_date)s'>
 569                 <input type="hidden" name="target" value='%(target)s'>
 570                 <input type="image" value="submit" src="%(thumbnail)s">
 571             </td>
 572         </form>
 573             %(alias_html)s 
 574     </tr>
 575     <tr>%(tools_html)s%(date_html)s</tr>''' % {
 576      "tdstyle": self.td_style,
 577      "baseurl": self.request.getScriptname(),
 578      "pagename": self.quoted_pagename,
 579      "thumbnail_width": self.thumbnail_width,
 580      "full": self.full[idx] + ',' + ','.join(self.full),
 581      "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
 582      "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
 583                                   ','.join(self.exif_date)),
 584      "target": self.webimg[idx] + ',' + ','.join(self.webimg),
 585      "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
 586      "tools_html": self.show_tools_mode2(idx),
 587      "date_html": self.show_date_mode2(idx),
 588      "alias_html": self.show_alias_mode2(idx)
 589      }
 590 
 591         return text
 592 
 593     def show_tools_mode1(self, idx):
 594         if self.show_tools == '1':
 595             text = "<tr><td align=""center""%(style)s>%(tools)s </td></tr>" % {
 596                 "style":self.td_style,
 597                 "tools":self.tools_html(idx)}
 598         else:
 599             text = ''
 600         return text
 601 
 602     def show_date_mode1(self, idx):
 603        if self.show_date == '1':
 604            return '''
 605         <TR>
 606         <td%(style)s>%(this_exif_date)s</td>
 607     </TR>''' % {
 608     "style":self.td_style,
 609     "this_exif_date": self.to_htmltext(self.exif_date[idx])}
 610        else:
 611            return ''
 612 
 613     def show_alias_mode1(self, idx):
 614        if self.show_text == '1':
 615            return '''
 616         <TR>
 617         <td width="%(thumbnail_width)s" %(style)s> %(this_alias)s</td>
 618     </TR>''' % {
 619     "thumbnail_width": self.thumbnail_width,
 620     "style": ' align="left" style="padding:0em; margin:2px 2px; border-style:none"',
 621     "this_alias": self.description[idx]}
 622        else:
 623            return ''
 624 
 625     def mode1_html(self, idx):
 626         text = '''
 627     <table width="%(thumbnail_width)s" align="center" valign="center"%(style)s>
 628     <TR align="center" valign="center">
 629         <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
 630             <td align="center" valign="middle" width="%(thumbnail_width)s"
 631             %(tdstyle)s>
 632                 <input type="hidden" name="action" value="gallery2image">
 633                 <input type="hidden" name="do" value="VS">
 634                 <input type="hidden" name="full" value='%(full)s'>
 635                 <input type="hidden" name="alias" value='%(description)s'>
 636                 <input type="hidden" name="exif_date" value='%(exif_date)s'>
 637                 <input type="hidden" name="target" value='%(target)s'>
 638                 <input type="image" value="submit" src="%(thumbnail)s" >
 639             </td>
 640         </form>
 641     </TR>
 642       %(alias_html)s
 643       %(date_html)s
 644       %(tools_html)s
 645 </table>'''%       {
 646      "tdstyle": self.td_style,
 647      "style": self.inner_table_style,
 648      "baseurl": self.request.getScriptname(),
 649      "pagename": self.quoted_pagename,
 650      "full": self.full[idx] + ',' + ','.join(self.full),
 651      "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
 652      "exif_date": self.to_htmltext(self.exif_date[idx] + ',' +
 653                                   ','.join(self.exif_date)),
 654      "target": self.webimg[idx] + ',' + ','.join(self.webimg),
 655      "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
 656      "thumbnail_width": self.thumbnail_width,
 657      "tools_html": self.show_tools_mode1(idx),
 658      "date_html": self.show_date_mode1(idx),
 659      "alias_html": self.show_alias_mode1(idx)
 660      }
 661 
 662         return text
 663 
 664     def get_files(self, path, files, quotes):
 665         self.web = []
 666         self.full = []
 667         self.thumb = []
 668         self.exif_date = []
 669         self.imgtype = []
 670         self.description = []
 671 
 672         ddict = {}
 673         n = len(quotes['image'])
 674         if n > 0:
 675             i = 0
 676             for txt in quotes['image']:
 677                 ddict[txt] = quotes['alias'][i]
 678                 i += 1
 679 
 680         self.video_type = 'swf'
 681         self.source_type = ''
 682         for attfile in files:
 683             # only files not thumb or webnails
 684             if not attfile.startswith('tmp.') and attfile.find('thumbnail_') == -1 and attfile.find('webnail_') == -1:
 685             #previous naming left for compatibility
 686                 # only images
 687                 if wikiutil.isPicture(attfile):
 688                     self.description.append(ddict.get(attfile, attfile))
 689                     self.full.append(attfile)
 690 
 691                     fname, ext = os.path.splitext(attfile)
 692                     if ext in ('.gif', '.png'):
 693                         self.imgtype.append('PNG')
 694                         webnail = 'tmp.webnail_%s.png' % fname
 695                         thumbfile = 'tmp.thumbnail_%s.png' % fname
 696                         video_type = 'swf'
 697                         source_type = ext[1:]
 698                     else:
 699                         self.imgtype.append("JPEG")
 700                         webnail = 'tmp.webnail_%s.jpg' % fname
 701                         thumbfile = 'tmp.thumbnail_%s.jpg' % fname
 702                         video_type = 'swf'
 703                         source_type = 'jpg'
 704 
 705                     infile = os.path.join(path, attfile)
 706                     if os.path.exists(infile):
 707                          self.web.append(webnail)
 708                          self.thumb.append(thumbfile)
 709 
 710 
 711                     f = open(infile, 'rb')
 712                     tags = EXIF.process_file(f, 'DateTimeOriginal')
 713                     f.close()
 714                     if tags.has_key('EXIF DateTimeOriginal'):
 715                         date = str(tags['EXIF DateTimeOriginal'])
 716                         date = date.replace(':', '-', 2)
 717                     else:
 718                         date = '--'
 719 
 720                     self.exif_date.append(date)
 721 
 722 
 723     def to_htmltext(self, text):
 724         if text.find ("'"):
 725             text = text.split("'")
 726             text = '&#39;'.join(text)
 727         return text
 728 
 729     def to_wikiname(self, formatter, text):
 730         ##taken from MiniPage
 731         out = StringIO.StringIO()
 732         self.request.redirect(out)
 733         wikiizer = wiki.Parser(text.strip(), self.request)
 734         wikiizer.format(formatter)
 735         result = out.getvalue()
 736         self.request.redirect()
 737         del out
 738 
 739         result = result.replace('<a id="line-1"></a>', '')
 740         result = result.replace('<p>', '')
 741         result = result.replace('</p>', '')
 742         result = result.strip()
 743         return result
 744 
 745 
 746     def get_quotes(self, formatter):
 747         quotes = self.raw.split('\n')
 748         quotes = [quote.strip() for quote in quotes]
 749         quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
 750 
 751         image = []
 752         text = []
 753 
 754         for line in quotes:
 755             im, na = line[1:-1].split(' ', 1)
 756             na = na.strip()
 757             na = self.to_htmltext(na)
 758             na = self.to_wikiname(formatter, na)
 759             text.append(na)
 760             image.append(im.strip())
 761 
 762         return {
 763             'alias': text,
 764             'image': image,
 765         }
 766 
 767     def print_help(self):
 768         self.request.write('''
 769 <br>
 770 {{{<br>
 771 #!Gallery2 [columns=columns],[filter=filter],[mode=mode],<br>
 772            [show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
 773            [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
 774            [reverse_sort=reverse_sort],<br>
 775            [only_items=only_items],[template_itemlist=template_itemlist],<br>
 776            [album=album],[album_name=album_name],[front_image=front_image],<br>
 777            [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
 778            [image_for_webnail=image_for_webnail],<br>
 779            [sequence_name=sequence_name],[sequence_fps=sequence_fps]<br>
 780            [border_thick=border_thick],[renew=renew],[help=help]<br>
 781  * [image1.jpg alias]<br>
 782  * [image2.jpg alias]<br>
 783 }}}<br>''')
 784 
 785     def format(self, formatter):
 786         if self.help == '1':
 787             self.print_help()
 788             return
 789         Dict = {}
 790         quotes = self.get_quotes(formatter)
 791         current_pagename = formatter.page.page_name
 792         self.pagename = current_pagename
 793         self.quoted_pagename = wikiutil.quoteWikinameURL(self.pagename)
 794         attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
 795 
 796         if hasattr(self.request.cfg, 'document_root'):
 797 
 798             self.static_path = "%(dir)s/tmp/Gallery2%(wiki_name)s/%(pagename)s" % {
 799                  "wiki_name": self.request.getScriptname(),
 800                  "pagename": self.pagename,
 801                  "dir": self.request.cfg.document_root,
 802                  }
 803             if os.path.exists(self.static_path) == 0:
 804                  os.makedirs(self.static_path)
 805 
 806             self.static_url = "%(prefix)s/tmp/Gallery2%(wiki_name)s/%(pagename)s/" % {
 807                  "prefix": self.request.cfg.url_prefix,
 808                  "wiki_name": self.request.getScriptname(),
 809                  "pagename": self.pagename,
 810                  }
 811         else:
 812             self.static_path = attachment_path
 813             self.static_url = AttachFile.getAttachUrl(self.pagename, '', self.request)
 814 
 815 
 816         if self.only_items == '1':
 817             all_files = quotes['image']
 818             result = []
 819             for attfile in all_files:
 820                 infile = os.path.join(attachment_path, attfile)
 821                 if os.path.exists(infile):
 822                    result.append(attfile)
 823             all_files = result
 824 
 825             if self.sort_by_alias == '1':
 826                 new_ordered_files = []
 827                 alias_text = quotes['alias']
 828 
 829                 i = 0
 830                 for attfile in all_files:
 831                     infile = os.path.join(attachment_path, attfile)
 832                     Dict[alias_text[i]] = attfile
 833                     i += 1
 834 
 835                 keys = Dict.keys()
 836                 keys.sort()
 837                 for txt in keys:
 838                     new_ordered_files.append(Dict[txt])
 839 
 840                 all_files = new_ordered_files
 841                 Dict.clear()
 842 
 843         else:
 844             all_files = os.listdir(attachment_path)
 845 
 846 
 847         if self.filter != '.':
 848             result = []
 849             for test in all_files:
 850                 if re.match(self.filter, test):
 851                   result.append(test)
 852 
 853             all_files = result
 854 
 855         if not all_files:
 856             self.request.write("<br><br><h1>No matching image file found!</h1>")
 857             return
 858 
 859         if self.sort_by_name == '1' and self.only_items == '0':
 860             all_files.sort()
 861 
 862         if self.sort_by_date == '1':
 863            for attfile in all_files:
 864                infile = os.path.join(attachment_path, attfile)
 865                ft_file = "%s%s" % (str(os.path.getmtime(infile)), str(randint(0, 65535)))
 866                Dict[ft_file] = attfile
 867 
 868            keys = Dict.keys()
 869            keys.sort()
 870            file_mdate = []
 871            for txt in keys:
 872                file_mdate.append(Dict[txt])
 873            all_files = file_mdate
 874            Dict.clear()
 875 
 876         if self.reverse_sort == '1':
 877              all_files.reverse()
 878 
 879         cells = []
 880         cell_name = []
 881         img = []
 882 
 883         self.get_files(attachment_path, all_files, quotes)
 884 
 885         if self.template_itemlist == '1':
 886             self.request.write('Copy the following listitems into the script. Replace alias with the label you want. Afterwards disable template_itemlist by setting it to 0:<BR>')
 887             for attfile in self.full:
 888                 self.request.write(' * [%(attfile)s %(date)s]<br>\n' % {
 889                                    'attfile': attfile,
 890                                    'date': 'alias'
 891                                     })
 892 
 893         i = 0
 894         z = 1
 895         cols = int(self.columns)
 896 
 897         n = len(self.full)
 898         if  self.album == '0':
 899             self.request.write("<table%s>" % self.outer_table_style)
 900             if self.mode == '1' or cols > 1:
 901                 self.request.write('<TR valign="top">')
 902                 self.request.write('<TD%s>' % self.td_style)
 903 
 904 
 905         if self.album == '1':
 906             if self.front_image == '':
 907                 front_image = self.full[0]
 908             else:
 909                 front_image = self.front_image
 910             ii = 0
 911             for tst in self.full:
 912                 if tst == front_image:
 913                     break
 914                 ii += 1
 915 
 916         for attfile in self.full:
 917             if  self.album == '1':
 918                 if tst == front_image:
 919                    i = ii
 920 
 921             this_description = self.description[i]
 922             this_exif_date = self.exif_date[i]
 923             this_webnail = self.web[i]
 924             this_imgtype = self.imgtype[i]
 925             this_thumbfile = self.thumb[i]
 926 
 927             thumbf = os.path.join(self.static_path, this_thumbfile)
 928             webf = os.path.join(self.static_path, this_webnail)
 929 
 930             if self.renew == '1':
 931                 if os.path.exists(thumbf):
 932                    os.unlink(thumbf)
 933                 if os.path.exists(webf):
 934                    os.unlink(webf)
 935 
 936             if not os.path.exists(webf) or not os.path.exists(thumbf):
 937                 infile = os.path.join(attachment_path, attfile)
 938                 im = Image.open(infile)
 939 
 940                 if not os.path.exists(webf):
 941                     im.thumbnail((int(self.webnail_width), int(self.webnail_width)), Image.ANTIALIAS)
 942                     if self.image_for_webnail == '1':
 943                        os.link(os.path.join(attachment_path, attfile), webf)
 944                     else:
 945                        im.save(webf, this_imgtype)
 946                 if not os.path.exists(thumbf):
 947                     im.thumbnail(((int(self.thumbnail_width)), ((int(self.thumbnail_width)))),
 948                                    Image.ANTIALIAS)
 949                     im.save(thumbf, this_imgtype)
 950 
 951             if self.image_for_webnail == '1':
 952                  this_webnailimg = attfile
 953                  self.webimg = self.full
 954             else:
 955                  this_webnailimg = this_webnail
 956                  self.webimg = self.web
 957 
 958             if self.mode == '1':
 959                 text = self.mode1_html(i)
 960                 self.request.write(''.join(text))
 961 
 962             if self.mode == '2':
 963                 text = self.mode2_html(i)
 964                 if cols > 1: self.request.write('<table valign="bottom">')
 965                 self.request.write(''.join(text))
 966                 if cols > 1: self.request.write('</table>')
 967 
 968             if self.mode == '1' or cols > 1:
 969                 if self.album == '0':
 970                     if  z < cols:
 971                         self.request.write('</TD>')
 972                         if z < n and  i < n - 1:
 973                             self.request.write('<TD%s>' % self.td_style)
 974                         if i == n - 1:
 975                             self.request.write('</TR>')
 976                     else:
 977                         self.request.write('</TD>')
 978                         self.request.write('</TR>')
 979                         if i < n - 1:
 980                             self.request.write('<TR valign="top">')
 981                             self.request.write('<TD%s>' % self.td_style)
 982 
 983             i += 1
 984             z += 1
 985             if z > cols:
 986                 z = 1
 987 
 988             if self.album == '1':
 989                 self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name": self.album_name})
 990                 break
 991 
 992         if self.album == '0':
 993             if i < n:
 994                 self.request.write('</TD>')
 995                 self.request.write('</TR>')
 996             self.request.write('</table>')
 997 
 998 
 999         if self.sequence_name != '':
1000             video_file = "%(file)s.%(ext)s" % {
1001                  "file": os.path.join(attachment_path, self.sequence_name),
1002                  "ext": 'swf'}
1003             if self.renew == '1':
1004                if os.path.exists(video_file):
1005                   os.unlink(video_file)
1006 
1007             cmd = ''
1008             if float(self.sequence_fps) < 1:
1009                 fps = 1
1010             else:
1011                 fps = round(float(self.sequence_fps))
1012 
1013             f_list = []
1014             for attfile in self.web:
1015                 file = os.path.join(self.static_path, attfile)
1016                 if os.path.exists(file):
1017                    f_list.append(file)
1018 
1019             if not os.path.exists(video_file):
1020                 width, height = self.images2swf(f_list, video_file, fps, self.description, self.exif_date)
1021             else:
1022                 swf = SWF.load(video_file)
1023                 for tag in swf.tags:
1024                     if tag.isImage():
1025                        width, height = tag.image.size
1026                        break
1027 
1028             if os.path.exists(video_file):
1029                   dict = {}
1030                   dict['src'] = AttachFile.getAttachUrl(current_pagename, '%(file)s.%(videotype)s'  % {
1031                      'file': self.sequence_name,
1032                      'videotype': 'swf',
1033                      }, self.request)
1034 
1035                   image_link = '%(file)s.%(videotype)s' % {'file':self.sequence_name, 'videotype': 'swf'}
1036                   if  self.eo_info == '1':
1037                       eo = "Or embed it into your wiki page by [[EmbedObject(%(file)s,width=%(width)s,height=%(height)s)]]." % {
1038                            'file': image_link,
1039                            'width': str(width),
1040                            'height': str(height)}
1041                   else:
1042                       eo = ''
1043 
1044                   self.request.write('<P>')
1045                   text = formatter.url(1, dict['src'] ) + image_link + formatter.url(0)
1046                   self.request.write('Download this image sequence %(text)s for your archive. %(EO)s' % {
1047                        'text': text,
1048                        'EO': eo
1049                        })
1050                   self.request.write('</P>')

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2006-08-06 08:57:54, 41.8 KB) [[attachment:EXIF.py]]
  • [get | view] (2005-03-24 20:14:37, 10.6 KB) [[attachment:Gallery2-1.3.3-1.py]]
  • [get | view] (2005-03-26 08:39:13, 11.6 KB) [[attachment:Gallery2-1.3.3-2.py]]
  • [get | view] (2005-03-26 12:41:49, 13.1 KB) [[attachment:Gallery2-1.3.3-3.py]]
  • [get | view] (2005-03-27 20:23:01, 19.0 KB) [[attachment:Gallery2-1.3.3-4.py]]
  • [get | view] (2005-08-03 19:30:10, 23.2 KB) [[attachment:Gallery2-1.3.3-5.py]]
  • [get | view] (2005-08-18 07:58:38, 31.9 KB) [[attachment:Gallery2-1.3.5-10.py]]
  • [get | view] (2005-09-02 19:55:13, 34.1 KB) [[attachment:Gallery2-1.3.5-11.py]]
  • [get | view] (2005-11-13 18:09:11, 35.4 KB) [[attachment:Gallery2-1.3.5-12.py]]
  • [get | view] (2005-11-18 20:13:04, 46.2 KB) [[attachment:Gallery2-1.3.5-13.py]]
  • [get | view] (2005-12-03 15:33:06, 46.6 KB) [[attachment:Gallery2-1.3.5-14.py]]
  • [get | view] (2006-01-01 09:20:19, 43.3 KB) [[attachment:Gallery2-1.3.5-15.py]]
  • [get | view] (2005-08-07 15:46:28, 26.9 KB) [[attachment:Gallery2-1.3.5-6.py]]
  • [get | view] (2005-08-13 15:13:59, 28.7 KB) [[attachment:Gallery2-1.3.5-7.py]]
  • [get | view] (2005-08-14 13:02:00, 27.5 KB) [[attachment:Gallery2-1.3.5-8.py]]
  • [get | view] (2005-08-14 14:38:32, 28.7 KB) [[attachment:Gallery2-1.3.5-9.py]]
  • [get | view] (2006-08-06 08:45:47, 41.8 KB) [[attachment:Gallery2-1.5.4-16.py]]
  • [get | view] (2006-08-22 20:29:39, 42.0 KB) [[attachment:Gallery2-1.5.4-18.py]]
  • [get | view] (2006-08-06 08:57:36, 514.8 KB) [[attachment:example.swf]]
  • [get | view] (2005-08-17 18:10:27, 11.3 KB) [[attachment:gallery2image_test.py]]
  • [get | view] (2005-08-10 16:49:16, 1.3 KB) [[attachment:patchpullfromdir.diff]]
  • [get | view] (2006-08-17 16:32:50, 41.9 KB) [[attachment:text_x_gallery2-1.6.0-17.py]]
  • [get | view] (2006-08-22 20:23:06, 42.1 KB) [[attachment:text_x_gallery2-1.6.0-18.py]]
  • [get | view] (2008-02-06 10:08:05, 42.2 KB) [[attachment:text_x_gallery2-1.6.0-19.py]]
 All files | Selected Files: delete move to page copy to page

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