view data/plugin/parser/text_x_arnica.py @ 5:413a64b78621

text_x_arnica: factored out create_thumbnail_and_webnail from format
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Sat, 08 Mar 2008 21:18:36 +0100
parents ccc40ffe14fc
children 756cb845ddad
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - arnica parser 
       
    This parser is used to visualize a couple of images as a thumbnail gallery.
    Optional a description of an image could be added including WikiName.
    On default the image name and it's creation date is shown.
    If you click on a thumbnail you get the webnails shown. By a menue you are able to toggle between the slides.

    Syntax:
      {{{
      #!arnica [target_page=target_page]
               [columns=columns],[filter=filter],[mode=mode],
               [show_text=show_text],[show_date=show_date], [show_tools=show_tools],
               [sort_by_name=sort_by_name],[sort_by_date=sort_by_date], [sort_by_alias=sort_by_alias],
               [reverse_sort=reverse_sort],
               [only_items=only_items],[template_itemlist=template_itemlist],
               [album=album],[album_name=album_name],[front_image=front_image],
               [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],
               [image_for_webnail=image_for_webnail],
               [sequence_name=sequence_name], [sequence_fps=sequence_fps],
               [border_thick=border_thick],[renew=renew],[help=help]
      * [[image1.jpg|alias]]
      * [[image2.jpg|alias]]
      }}}

    KEYWORD PARAMETERS:
        target_page:       page to read attachments
        columns:           number of columns for thumbnails
        filter:            regex to select images
        show_text:         default is 1 description is shown
                           any other means no description
        show_date:         default is 1 date info from exif header if available is shown
        show_tools:        default is 1 icon toolbar is show any other disables this
        sort_by_name:      default is 1, the images are sorted by name, but not if only_items is 1
        sort_by_date:      default is 0, if set to 1 the images are sorted to the modification time
                           if they do have all the same time then the result is random
        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
        reverse_sort:      default is 0, if set to 1 the file list is reversed
                           any other means no description
        mode:              default is 1 this means description below the image
                           any other number means description right of image
        only_items:        default is 0 if it is set to 1 only images which are described in listitem are shown
                           dependend on the order of the items
        template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script. 
        album:             default is 0 if set to 1 only the first image of a series is shown but slideshow over all images 
        album_name:        useful for album. default is 'album' use it as short name for the album. 
        front_image:       Useful for album.  default is ''. The first image is shown in front of the album and slideshow.
                           If set to an existing image name this is shown in front of album and slideshow. 
                           The slide show could start by this somewhere.
        border_thick:      default is 1 this is the thickness in pixeln of the outer frame
        renew:             default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
                           Afterwards they are new created.
        thumbnail_width:   default is 128
        webnail_width:     default is 640
        text_width:        default is 140		   
        image_for_webnail  default is 0 if set to 1 then the image is shown as preview and not the webnail
        help:              default is 0 if set a copy of the CALLING SEQUENCE is shown, 
                           (there are some new ideas around to show help to an user so this will be later replaced)
                           

    OPTIONAL INPUTS:
        itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
                   The alias text is used as description of the image instead of the file name


    
    MODIFICATION HISTORY:
    based on Gallery2 by ReimarBauer 2005-2008, ThomasWaldmann 2005, FlorianFesti 2006
       
    @copyright: 2008 by MoinMoin:ReimarBauer
    @license: GNU GPL, see COPYING for details.
"""
Dependencies = ['time'] # do not cache

import os, re
from random import randint
from MoinMoin import wikiutil
from MoinMoin.action import AttachFile
from MoinMoin.Page import Page
from MoinMoin.filter import EXIF

try:
    import Image
except ImportError:
    Image = None

class Parser:
    """ arnica parser """
    extensions = '*.jpg'
    def __init__(self, raw, request, **kw):
        self.target_page = ''
        self.sort_by_date = '0'
        self.sort_by_name = '1'
        self.sort_by_alias = '0'
        self.album = '0'
        self.album_name = 'album'
        self.front_image = ''
        self.template_itemlist = '0'
        self.reverse_sort = '0'
        self.border_thick = '1'
        self.columns = '4'
        self.filter = '.'
        self.mode = '1'
        self.help = '0'
        self.show_text = '1'
        self.show_date = '1'
        self.show_tools = '1'
        self.only_items = '0'
        self.image_for_webnail = '0'
        self.renew = '0'
        self.thumbnail_width = '128'
        self.webnail_width = '640'
        self.text_width = '140'
        self.form = None

        test = kw.get('format_args', '')
        if test:
            for arg in kw.get('format_args', '').split(','):
                if arg.find('=') > -1:
                    key, value = arg.split('=')
                    setattr(self, key, wikiutil.escape(value.strip(), quote=1))

        self.width = str(int(self.thumbnail_width) + int(self.text_width))

        self.raw = raw
        self.request = request
        self.form = request.form
        self._ = request.getText

        self.outer_table_style = ' border="%s"' % self.border_thick
        self.inner_table_style = ' style="border-style:none; margin:10px;"'
        self.td_style = ' align="center" style="padding:0; margin:2px 2px; border-style:none"'

    def show_tools_restricted(self, this_target):
        """ show only tools to users with enough rights 
        @param this_target: image
        """
        if not self.request.user.may.delete(self.pagename):
            return ''

        return '''
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
          <td%(style)s>
            <input type="hidden" name="action" value="arnica_slides">
            <input type="hidden" name="do" value="RL">
            <input type="hidden" name="target" value="%(this_target)s">
            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_right.png" title="rotate to left">
          </td>
        </form>
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
          <td%(style)s>
            <input type="hidden" name="action" value="arnica_slides">
            <input type="hidden" name="do" value="RR">
            <input type="hidden" name="target" value="%(this_target)s">
            <input type="image"  value="submit" src="%(htdocs)s/common/arnica/arnica_to_left.png" title="rotate to right" >
          </td>
        </form>
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
          <td%(style)s>
            <input type="hidden" name="action" value="arnica_slides">
            <input type="hidden" name="do" value="RM">
            <input type="hidden" name="target" value="%(this_target)s">
            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_bak.png" title="move to bak" >
           </td>
        </form>''' % {
            'baseurl': self.request.getBaseURL(),
            'style': self.td_style,
            'htdocs': self.request.cfg.url_prefix_static,
            "pagename": self.quoted_pagename,
            "this_target": this_target}

    def tools_html(self, idx):
        """ html code of thumbnails view with contol
        @param idx: index postion of corresponding data
        """
        this_image = self.full[idx]

        text = '''
            <table align="center" width="%(thumbnail_width)s"%(tablestyle)s>
                <tr>
                    <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
                        <td%(style)s>
                            <input type="hidden" name="action" value="AttachFile">
                            <input type="hidden" name="do" value="get">
                            <input type="hidden" name="target" value='%(this_target)s'>
                            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_full.png" title="load image">
                        </td>
                    </form>
                    <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
                        <td%(style)s>
                            <input type="hidden" name="action" value="arnica_slides">
                            <input type="hidden" name="do" value="VS">
                            <input type="hidden" name="alias" value='%(description)s'>
                            <input type="hidden" name="target" value='%(target)s'>
                            <input type="hidden" name="exif_date" value='%(exif_date)s'>
                            <input type="image" value="submit" src="%(htdocs)s/common/arnica/arnica_to_slide.png" title="slide_show" >
                       </td>
                    </form>
                    %(show_tools_restricted)s
                </tr>
            </table>'''   % {
            "baseurl": self.request.getScriptname(),
            "pagename": self.quoted_pagename,
            "htdocs": self.request.cfg.url_prefix_static,
            "tablestyle": self.inner_table_style,
            "style": self.td_style,
            "thumbnail_width": self.thumbnail_width,
            "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
            "exif_date": self.exif_date[idx] + ',' + ','.join(self.exif_date),
            "target": self.webimg[idx] + ',' + ','.join(self.webimg),
            "this_target": self.full[idx],
            "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
            "show_tools_restricted":self.show_tools_restricted(this_image)
            }

        return text

    def show_alias_mode2(self, idx):
        """ view mode 2 alias text is on righthand of image """
        if self.show_text == '1':
            return '''
<td valign="top" width="%(text_width)s" %(style)s>
 %(this_alias)s
</td>''' % {
        "this_alias": self.description[idx],
        "text_width": self.text_width,
        "style": ' align="left" style="padding:0px; margin:2px 2px; border-style:none"'}
        else:
            return ''

    def show_date_mode2(self, idx):
        """ view mode 2 selection for date """
        if self.show_date == '1':
            return '''<td%(style)s><p>%(this_exif_date)s</p></td>''' % {
                      "style": self.td_style,
                      "this_exif_date": self.exif_date[idx]}
        else:
            return ''

    def show_tools_mode2(self, idx):
        """ view mode 2 selection for tools """
        if self.show_tools == '1':
            return "<td align=""center""%(style)s> %(tools)s </td>" % {
                "style": self.td_style,
                "tools": self.tools_html(idx)}
        else:
            return ''

    def mode2_html(self, idx):
        """ html code of mode 2 """
        text = '''
        <tr valign="center">
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
            <td align="center" valign="center" width="%(thumbnail_width)s"
            %(tdstyle)s>
                <input type="hidden" name="action" value="arnica_slides">
                <input type="hidden" name="do" value="VS">
                <input type="hidden" name="alias" value='%(description)s'>
                <input type="hidden" name="exif_date" value='%(exif_date)s'>
                <input type="hidden" name="target" value='%(target)s'>
                <input type="image" value="submit" src="%(thumbnail)s">
            </td>
        </form>
            %(alias_html)s 
    </tr>
    <tr>%(tools_html)s%(date_html)s</tr>''' % {
     "tdstyle": self.td_style,
     "baseurl": self.request.getScriptname(),
     "pagename": self.quoted_pagename,
     "thumbnail_width": self.thumbnail_width,
     "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
     "exif_date": self.exif_date[idx] + ',' + ','.join(self.exif_date),
     "target": self.webimg[idx] + ',' + ','.join(self.webimg),
     "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
     "tools_html": self.show_tools_mode2(idx),
     "date_html": self.show_date_mode2(idx),
     "alias_html": self.show_alias_mode2(idx)
     }

        return text

    def show_tools_mode1(self, idx):
        """ view mode 1 selection of tools """
        if self.show_tools == '1':
            text = "<tr><td align=""center""%(style)s>%(tools)s </td></tr>" % {
                "style":self.td_style,
                "tools":self.tools_html(idx)}
        else:
            text = ''
        return text

    def show_date_mode1(self, idx):
        """ view mode 1 selection of date """
        if self.show_date == '1':
            return '''
<tr>
<td%(style)s>%(this_exif_date)s</td>
</tr>''' % {
        "style":self.td_style,
        "this_exif_date": self.exif_date[idx]}
        else:
            return ''

    def show_alias_mode1(self, idx):
        """ view mode 1 alias text below image """
        if self.show_text == '1':
            return '''
<tr>
<td width="%(thumbnail_width)s" %(style)s> %(this_alias)s</td>
</tr>''' % {
        "thumbnail_width": self.thumbnail_width,
        "style": ' align="left" style="padding:0em; margin:2px 2px; border-style:none"',
        "this_alias": self.to_wikitext(self.description[idx])}
        else:
            return ''

    def mode1_html(self, idx):
        """ html code of mode 1 (default)"""
        text = '''
    <table width="%(thumbnail_width)s" align="center" valign="center"%(style)s>
    <TR align="center" valign="center">
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
            <td align="center" valign="middle" width="%(thumbnail_width)s"
            %(tdstyle)s>
                <input type="hidden" name="action" value="arnica_slides">
                <input type="hidden" name="do" value="VS">
                <input type="hidden" name="alias" value='%(description)s'>
                <input type="hidden" name="exif_date" value='%(exif_date)s'>
                <input type="hidden" name="target" value='%(target)s'>
                <input type="image" value="submit" src="%(thumbnail)s" >
            </td>
        </form>
    </TR>
      %(alias_html)s
      %(date_html)s
      %(tools_html)s
</table>'''% {
     "tdstyle": self.td_style,
     "style": self.inner_table_style,
     "baseurl": self.request.getScriptname(),
     "pagename": self.quoted_pagename,
     "description": self.description[idx] + '!,!' + '!,!'.join(self.description),
     "exif_date": self.exif_date[idx] + ',' + ','.join(self.exif_date),
     "target": self.webimg[idx] + ',' + ','.join(self.webimg),
     "thumbnail": "%s%s" % (self.static_url, self.thumb[idx]),
     "thumbnail_width": self.thumbnail_width,
     "tools_html": self.show_tools_mode1(idx),
     "date_html": self.show_date_mode1(idx),
     "alias_html": self.show_alias_mode1(idx)
     }

        return text

    def get_files(self, path, files, quotes):
        """ get files creates lists for thumbnails and webnails 
        @param path: path to attachment
        @param files: file names of images
        @param quotes: text alias for image file
        """
        self.web = []
        self.full = []
        self.thumb = []
        self.exif_date = []
        self.imgtype = []
        self.description = []

        ddict = {}
        n = len(quotes['image'])
        if n > 0:
            i = 0
            for txt in quotes['image']:
                ddict[txt] = quotes['alias'][i]
                i += 1

        self.source_type = ''
        for attfile in files:
            # only files not thumb or webnails
            if not attfile.startswith('tmp.'):
                # only images
                if wikiutil.isPicture(attfile):
                    self.description.append(ddict.get(attfile, attfile))
                    self.full.append(attfile)

                    fname, ext = os.path.splitext(attfile)
                    if ext in ('.gif', '.png'):
                        self.imgtype.append('PNG')
                        webnail = 'tmp.webnail_%s.png' % fname
                        thumbfile = 'tmp.thumbnail_%s.png' % fname
                    else:
                        self.imgtype.append("JPEG")
                        webnail = 'tmp.webnail_%s.jpg' % fname
                        thumbfile = 'tmp.thumbnail_%s.jpg' % fname

                    infile = os.path.join(path, attfile)
                    if os.path.exists(infile):
                        self.web.append(webnail)
                        self.thumb.append(thumbfile)

                    f = open(infile, 'rb')
                    tags = EXIF.process_file(f, 'DateTimeOriginal')
                    f.close()
                    if tags.has_key('EXIF DateTimeOriginal'):
                        date = str(tags['EXIF DateTimeOriginal'])
                        date = date.replace(':', '-', 2)
                    else:
                        date = '--'

                    self.exif_date.append(wikiutil.escape(date, quote=1))

    def to_wikitext(self, text):
        """
        converts text to wiki name if it is written as WikiName or [[wikiname]]
        @param text: text to parse and render
        """
        text = ''.join(text)
        from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
        return wikiutil.renderText(self.request, WikiParser, text, line_anchors=False)

    def get_quotes(self):
        """  get's the qoutes from the itemlist  """
        quotes = self.raw.split('\n')
        quotes = [quote.strip() for quote in quotes]
        quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]

        image = []
        text = []

        for line in quotes:
            img, alias = line[2:-2].split('|', 1)
            alias = alias.strip()
            alias = wikiutil.escape(alias, quote=1)
            text.append(alias)
            image.append(img.strip())

        return {
            'alias': text,
            'image': image,
        }

    def print_help(self):
        """ print help """
        self.request.write('''
<br>
{{{<br>
#!arnica   [target_page=target_page], <br>
           [columns=columns],[filter=filter],[mode=mode],<br>
           [show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
           [sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
           [reverse_sort=reverse_sort],<br>
           [only_items=only_items],[template_itemlist=template_itemlist],<br>
           [album=album],[album_name=album_name],[front_image=front_image],<br>
           [thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
           [image_for_webnail=image_for_webnail],<br>
           [border_thick=border_thick],[renew=renew],[help=help]<br>
 * [[image1.jpg|alias]] <br>
 * [[image2.jpg|alias]] <br>
}}}''')
        
    def select_files(self, formatter):
        """ select files """
        self.pagename = formatter.page.page_name
        if self.target_page:
            self.pagename = self.target_page
        
        self.quoted_pagename = wikiutil.quoteWikinameURL(self.pagename)
        self.static_path = AttachFile.getAttachDir(self.request, self.pagename, create=1)

        self.static_url = AttachFile.getAttachUrl(self.pagename, '', self.request)
        Image_Dict = {}
        quotes = self.get_quotes()

        if self.only_items == '1':
            all_files = quotes['image']
            result = []
            for attfile in all_files:
                if os.path.exists(os.path.join(self.static_path, attfile)):
                    result.append(attfile)
            all_files = result

            if self.sort_by_alias == '1':
                result = []
                alias_text = quotes['alias']

                i = 0
                for attfile in all_files:
                    infile = os.path.join(self.static_path, attfile)
                    Image_Dict[alias_text[i]] = attfile
                    i += 1

                keys = Image_Dict.keys()
                keys.sort()
                for txt in keys:
                    result.append(Image_Dict[txt])
                all_files = result
        else:
            all_files = os.listdir(self.static_path)
        
        if self.filter != '.':
            result = []
            for test in all_files:
                if re.match(self.filter, test):
                    result.append(test)
            all_files = result
            
        if self.sort_by_name == '1' and self.only_items == '0':
            all_files.sort()

        if self.sort_by_date == '1':
            for attfile in all_files:
                infile = os.path.join(self.static_path, attfile)
                ft_file = "%s%s" % (str(os.path.getmtime(infile)), str(randint(0, 65535)))
                Image_Dict[ft_file] = attfile   
            keys = Image_Dict.keys()
            keys.sort()
            result = []
            for txt in keys:
                result.append(Image_Dict[txt])
            all_files = result
            
        Image_Dict.clear()
        
        if self.reverse_sort == '1':
            all_files.reverse()

        if all_files:
            self.get_files(self.static_path, all_files, quotes)        
        
        return all_files
    
    def create_thumbnail_and_webnail(self, image, webnail, thumbnail, image_type):
        """creates thumbnails and webnails for given image type
        @param image: filename of image
        @param webnail: filename of webnail file
        @param thumbnail: filename of thumbnail file
        @param image_type: filetype of image
        """
        imagef = os.path.join(self.static_path, image)
        webf = os.path.join(self.static_path, webnail)
        thumbf = os.path.join(self.static_path, thumbnail) 
        
        if self.renew == '1':
            if os.path.exists(thumbf):
                os.unlink(thumbf)
            if os.path.exists(webf):
                os.unlink(webf)
                    
        if not os.path.exists(webf) or not os.path.exists(thumbf):
            im_obj = Image.open(imagef)
            if not os.path.exists(webf):
                im_obj.thumbnail((int(self.webnail_width), int(self.webnail_width)), Image.ANTIALIAS)
                if self.image_for_webnail == '1':
                    os.link(imagef, webf)
                else:
                    im_obj.save(webf, image_type)
            if not os.path.exists(thumbf):
                im_obj.thumbnail(((int(self.thumbnail_width)), ((int(self.thumbnail_width)))),
                               Image.ANTIALIAS)
                im_obj.save(thumbf, image_type)

                
    def format(self, formatter):
        """ does the format """
        _ = self._

        if self.help == '1':
            self.print_help()
            return

        if self.target_page and (not self.request.user.may.read(self.target_page) or not Page(self.request, self.target_page).exists()):
            self.request.write(_("Page %(pagename)s does not exists or you don't have enough rights." % {"pagename": self.target_page}))
            return

        if not self.select_files(formatter):
            self.request.write(_("No matching image file found!"))
            return
        
        if self.template_itemlist == '1':
            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:"))
            self.request.write('<br>')
            for image in self.full:
                self.request.write(' * [[%(image)s|%(alias)s]]<br>\n' % {
                                   'image': image,
                                   'alias': 'alias'
                                    })

        i = 0
        z = 1
        cols = int(self.columns)

        n = len(self.full)
        if  self.album == '0':
            self.request.write("<table%s>" % self.outer_table_style)
            if self.mode == '1' or cols > 1:
                self.request.write('<tr valign="top">')
                self.request.write('<td%s>' % self.td_style)

        if self.album == '1':
            front_image = self.front_image or self.full[0]
            i = self.full.index(front_image)

        for image in self.full:
            self.create_thumbnail_and_webnail(image, self.web[i], self.thumb[i], self.imgtype[i])
            
            if self.image_for_webnail == '1':
                self.webimg = self.full
            else:
                self.webimg = self.web

            if self.mode == '1':
                text = self.mode1_html(i)
                self.request.write(''.join(text))

            if self.mode == '2':
                text = self.mode2_html(i)
                if cols > 1: self.request.write('<table valign="bottom">')
                self.request.write(''.join(text))
                if cols > 1: self.request.write('</table>')

            if self.mode == '1' or cols > 1:
                if self.album == '0':
                    if  z < cols:
                        self.request.write('</td>')
                        if z < n and  i < n - 1:
                            self.request.write('<td%s>' % self.td_style)
                        if i == n - 1:
                            self.request.write('</tr>')
                    else:
                        self.request.write('</td>')
                        self.request.write('</tr>')
                        if i < n - 1:
                            self.request.write('<tr valign="top">')
                            self.request.write('<td%s>' % self.td_style)
            i += 1
            z += 1
            if z > cols:
                z = 1

            if self.album == '1':
                self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name": self.album_name})
                break

        if self.album == '0':
            if i < n:
                self.request.write('</td>')
                self.request.write('</tr>')
            self.request.write('</table>')