ImageField.py 7.72 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
4
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

from Products.Formulator import Widget, Validator
from Products.Formulator.Field import ZMIField
from Products.Formulator.DummyField import fields
32 33 34
from lxml.etree import Element
from Acquisition import aq_base
from lxml import etree
35

36 37 38 39 40 41 42
DRAW_URI = 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'
TEXT_URI = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'

NSMAP = {
          'draw': DRAW_URI,
          'text': TEXT_URI,
        }
Jean-Paul Smets's avatar
Jean-Paul Smets committed
43 44

class ImageFieldWidget(Widget.TextWidget):
45
    """ImageField widget.
Fabien Morin's avatar
Fabien Morin committed
46

47 48 49
    Renders an HTML <img> element where the src is the 'default' field value.
    The 'description' field value is used as 'alt' attribute.
    The image size is calculated using 'image_display'.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
50 51 52 53 54 55 56
    """
    property_names = Widget.TextWidget.property_names + \
      ['image_display', 'image_format','image_resolution']

    image_display = fields.StringField('image_display',
                               title='Image Display',
                               description=(
57 58
        "The display size. See ERP5.Document.Image.default_displays_id_list "
        "for possible values. This is only used with ERP5 Images."),
Jean-Paul Smets's avatar
Jean-Paul Smets committed
59 60 61 62 63 64
                               default='thumbnail',
                               required=1)

    image_format = fields.StringField('image_format',
                               title='Image Format',
                               description=(
65 66
        "The format in which the image should be converted to. "
        "This is only used with ERP5 Images."),
Jean-Paul Smets's avatar
Jean-Paul Smets committed
67 68 69 70 71 72
                               default='',
                               required=0)

    image_resolution = fields.IntegerField('image_resolution',
                               title='Image Resolution',
                               description=(
73 74
        "The resolution used when converting the image. "
        "This is only used with ERP5 Images."),
Jean-Paul Smets's avatar
Jean-Paul Smets committed
75 76 77
                               default=75,
                               required=0)

78
    def render(self, field, key, value, REQUEST, render_prefix=None):
79 80
        """Render image field as a link to the image
        """
81
        return self.render_view(field, value, REQUEST=REQUEST)
82

83
    def render_view(self, field, value, REQUEST=None, render_prefix=None):
84
        """Render image field as a link to the image
Jean-Paul Smets's avatar
Jean-Paul Smets committed
85
        """
86
        # Url is already defined in value
87 88
        if value is None:
          return ''
89
        image = value
90 91
        alt = field.get_value('description') or \
              field.get_value('title')
92 93
        css_class = field.get_value('css_class')
        extra = field.get_value('extra')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
94 95 96
        display = field.get_value('image_display')
        format = field.get_value('image_format')
        resolution = field.get_value('image_resolution')
97 98 99 100 101 102 103
        return Widget.render_element(
            "img",
            alt=alt,
            src="%s?display=%s&format=%s&" % (image, display, format),
            css_class=css_class,
            extra=extra,
        )
Jean-Paul Smets's avatar
Jean-Paul Smets committed
104

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    def _replaceImage(self, image_frame_node, ooo_builder, image_field,
        printout, REQUEST, attr_dict):
      """
      Replace the image in an odg file using an ERP5Form image field.
      return True if the image have been found, else return False
      """
      image_node = image_frame_node.getchildren()[0]
      path = '/'.join(REQUEST.physicalPathFromURL(image_field.get_value('default')))
      if path in (None, ''):
        # not possible to add image, remove the existing one
        image_frame_node = image_node.getparent()
        image_frame_node.remove(image_node)
        return False
      path = path.encode()
      image_object = image_field.getPortalObject().restrictedTraverse(path)
      image_parameter_dict = {
                    'display': image_field.get_value('image_display'),
                    'format': image_field.get_value('image_format')
                   }
      picture_type, image_data = image_object.convert(**image_parameter_dict)
      if image_data is None:
        # not possible to add image, remove the existing one
        image_frame_node = image_node.getparent()
        image_frame_node.remove(image_node)
        return False
      picture_path = printout._createOdfUniqueFileName(path=path,
          picture_type=picture_type)
      ooo_builder.addFileEntry(picture_path, media_type=picture_type, content=image_data)
      width, height = printout._getPictureSize(image_object, image_node)
      image_node.set('{%s}href' % image_node.nsmap['xlink'], picture_path)
      image_frame_node.set('{%s}width' % image_node.nsmap['svg'], width)
      image_frame_node.set('{%s}height' % image_node.nsmap['svg'], height)
      attr_dict.setdefault(image_node.tag, {}).update(image_node.attrib)
      attr_dict.setdefault(image_frame_node.tag, {}).update(image_frame_node.attrib)
      return True

    def render_odg(self, field, as_string, local_name, target_node, printout,
        REQUEST, ooo_builder, attr_dict=None):
      """
        return an image xml node rendered in odg format
        if as_string is True (default) the returned value is a string (xml
        reprensation of the node), if it's False, the value returned is the node
        object.
        attr_dict can be used for additional parameters (like style).
      """
      # replace the image in the odg document
      if not self._replaceImage(target_node, ooo_builder, field, printout,
          REQUEST, attr_dict):
        # if image is not found, return None
        return None

      if attr_dict is None:
        attr_dict = {}

      draw_frame_tag_name = '{%s}%s' % (DRAW_URI, 'frame')
      draw_frame_node = Element(draw_frame_tag_name, nsmap=NSMAP)
      draw_frame_node.attrib.update(attr_dict.get(draw_frame_tag_name, {}))

      draw_image_tag_name = '{%s}%s' % (DRAW_URI, 'image')
      draw_image_node = Element(draw_image_tag_name, nsmap=NSMAP)
      draw_image_node.attrib.update(attr_dict.get(draw_image_tag_name, {}))

      text_p_tag_name = '{%s}%s' % (TEXT_URI, local_name)
      text_p_node = Element(text_p_tag_name, nsmap=NSMAP)
      text_p_node.attrib.update(attr_dict.get(text_p_tag_name, {}))

      draw_image_node.append(text_p_node)
      draw_frame_node.append(draw_image_node)

      if as_string:
        return etree.tostring(draw_frame_node)
      return draw_frame_node

Jean-Paul Smets's avatar
Jean-Paul Smets committed
178 179 180 181 182 183 184 185 186 187
ImageFieldWidgetInstance = ImageFieldWidget()
ImageFieldValidatorInstance = Validator.StringValidator()

class ImageField(ZMIField):
    meta_type = "ImageField"

    widget = ImageFieldWidgetInstance
    validator = ImageFieldValidatorInstance