view data/plugin/parser/text_x_arnica.py @ 43:623ddf996af2

text_x_arnica: album after creating of all thumbnails and webnails
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Tue, 03 Jun 2008 08:44:51 +0200
parents 7bf792c8364b
children 769a97fcdcbe
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 caching, wikiutil
from MoinMoin.action import AttachFile
from MoinMoin.packages import packLine
from MoinMoin.Page import Page
from MoinMoin.filter import EXIF
from MoinMoin.util.dataset import TupleDataset, Column
from MoinMoin.widget.browser import DataBrowserWidget

try:
    import Image
except ImportError:
    Image = None

parser_name = __name__.split('.')[-1]

# ToDo may be move to wikiutil
def get_exif_info(file_name):
    """ gets exif info from image file
    @param: image file name
    """
    date = "--"
    if wikiutil.isPicture(file_name):
        id_file = open(file_name, 'rb')
        tags = EXIF.process_file(id_file, 'DateTimeOriginal')
        id_file.close()
        if tags.has_key('EXIF DateTimeOriginal'):
            date = str(tags['EXIF DateTimeOriginal'])
            date = date.replace(':', '-', 2)

    return date

class Parser:
    """ arnica parser """
    extensions = '*.jpg'
    def __init__(self, raw, request, **kw):
        # list of optional arguments for the parser starts here
        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'
        # list of optional arguments for the parser ends here

        # get the paraemters
        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))
        # calc
        self.width = str(int(self.thumbnail_width) + int(self.text_width))

        self.pagename = request.page.page_name
        self.raw = raw
        self.request = request
        self.form = None
        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"'

        self.web = [] # array for webnails
        self.full = [] # array for  images
        self.thumb = [] # array for thumbnails
        self.exif_date = [] # array of exif date description
        self.imgtype = [] # array of imagetype of full image
        self.description = [] # array of description
        self.webimg = [] # array of images for forms

    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": wikiutil.quoteWikinameURL(self.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="images" value='%(images)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": wikiutil.quoteWikinameURL(self.pagename),
            "htdocs": self.request.cfg.url_prefix_static,
            "tablestyle": self.inner_table_style,
            "style": self.td_style,
            "thumbnail_width": self.thumbnail_width,
            "description": packLine([self.description[idx]] + self.description),
            "exif_date": packLine([self.exif_date[idx]] + self.exif_date),
            "target": self.webimg[idx],
            "images": packLine([self.webimg[idx]] + self.webimg),
            "this_target": self.full[idx],
            "thumbnail": "%s%s" % (AttachFile.getAttachUrl(self.pagename, '', self.request), 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 = '''
        <form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
                <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="hidden" name="images" value='%(images)s'>
                <input type="hidden" name="image_for_webnail" value='%(image_for_webnail)s'>
                <input type="image" value="submit" src="?action=arnica_slides&do=view&target=%(thumbnail)s">
        </form>
            %(alias_html)s
    <tr>%(tools_html)s%(date_html)s</tr>''' % {
     "tdstyle": self.td_style,
     "baseurl": self.request.getScriptname(),
     "pagename": wikiutil.quoteWikinameURL(self.pagename),
     "thumbnail_width": self.thumbnail_width,
     "description": packLine([self.description[idx]] + self.description),
     "exif_date": packLine([self.exif_date[idx]] + self.exif_date),
     "image_for_webnail": self.image_for_webnail,
     "target": self.webimg[idx],
     "images": packLine([self.webimg[idx]] + self.webimg),
     "thumbnail": 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="hidden" name="images" value='%(images)s'>
                <input type="hidden" name="image_for_webnail" value='%(image_for_webnail)s'>
                <input type="image" value="submit" type="button" src="?action=arnica_slides&do=view&target=%(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": wikiutil.quoteWikinameURL(self.pagename),
     "description": packLine([self.description[idx]] + self.description),
     "exif_date": packLine([self.exif_date[idx]] + self.exif_date),
     "image_for_webnail": self.image_for_webnail,
     "target": self.webimg[idx],
     "images": packLine([self.webimg[idx]] + self.webimg),
     "thumbnail": 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)
     }
        #self.request.write(data)

        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
        """
        ddict = {}
        if len(quotes['image']) > 0:
            i = 0
            for txt in quotes['image']:
                ddict[txt] = quotes['alias'][i]
                i += 1

        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

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

                        date = get_exif_info(att_file)
                        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)

    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 """

        # we need to take the page_name from the formatter.page otherwise
        # include does not work
        self.pagename = formatter.page.page_name
        if self.target_page:
            self.pagename = self.target_page
        path = AttachFile.getAttachDir(self.request, self.pagename, create=1)

        image_dict = {}
        quotes = self.get_quotes()

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

            if self.sort_by_alias == '1':
                alias_text = quotes['alias']
                i = 0
                for attfile in all_files:
                    image_dict[alias_text[i]] = attfile
                    i += 1
                keys = image_dict.keys()
                keys.sort()
                all_files = [image_dict[txt] for txt in keys]

        else:
            all_files = os.listdir(path)

        if self.filter != '.':
            all_files = [attfile for attfile in all_files if re.match(self.filter, attfile)]

        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(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()
            all_files = [image_dict[txt] for txt in keys]

        image_dict.clear()

        if self.reverse_sort == '1':
            all_files.reverse()

        if all_files:
            self.get_files(path, all_files, quotes)

        return all_files

    def create_thumbnail_and_webnail(self, image, webnail, thumbnail, image_type):
        """creates thumbnails and webnails cache files for given image type
        @param image: filename of image
        @param webnail: name of webnail file
        @param thumbnail: name of thumbnail file
        @param image_type: filetype of image
        """
        _ = self.request.getText
        if not Image:
            msg = _('The parser %(parser)s needs python imaging library (PIL) installed' % {'parser': parser_name})
            self.request.write(msg)
            return

        path = AttachFile.getAttachDir(self.request, self.pagename, create=1)
        imagef = os.path.join(path, image)


        page = Page(self.request, self.pagename)
        cache_web = caching.CacheEntry(self.request, page, webnail, scope='item', use_pickle=True)
        cache_thumb = caching.CacheEntry(self.request, page, thumbnail, scope='item', use_pickle=True)

        arena_dir = caching.get_arena_dir(self.request, page, 'item')
        webf = os.path.join(arena_dir, webnail)
        thumbf = os.path.join(arena_dir, thumbnail)

        if self.renew == '1':
            cache_web.remove()
            cache_thumb.remove()

        if not cache_web.exists() or not cache_thumb.exists():
            im_obj = Image.open(imagef)
            if not cache_web.exists():
                if not self.image_for_webnail == '1':
                    im_obj.thumbnail((int(self.webnail_width), int(self.webnail_width)), Image.ANTIALIAS)
                    im_obj.save(webf, image_type)

            if not cache_thumb.exists():
                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'
                                    })

        COLUMNS = int(self.columns)
        if self.album == '1':
            COLUMNS = 1

        data = TupleDataset()
        data.columns = []

        for dummy in range(COLUMNS):
            data.columns.extend([Column('', label=(''))])

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

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

                if self.mode == '2':
                    text = self.mode2_html(i)

                if col_count <= COLUMNS:
                    result.append(''.join(text))

                if col_count == COLUMNS and self.album == '0':
                    col_count = 0
                    data.addRow(tuple(result))
                    result = []

                col_count += 1

        if self.album == '1':
            front_image = self.front_image or self.full[0]
            i = self.full.index(front_image)
            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

            text = self.mode1_html(i)
            result.append(''.join(text))

        if result:
            data.addRow(tuple(result))

        browser = DataBrowserWidget(self.request, show_header=False)
        browser.setData(data)
        self.request.write(browser.format())