[Zope3-checkins] CVS: Zope3/src/zope/products/image - __init__.py:1.1.2.1 browser.py:1.1.2.1 configure.zcml:1.1.2.1 edit.pt:1.1.2.1 image.py:1.1.2.1 image_icon.gif:1.1.2.1 interfaces.py:1.1.2.1

Philipp von Weitershausen philikon at philikon.de
Wed Feb 11 11:29:25 EST 2004


Update of /cvs-repository/Zope3/src/zope/products/image
In directory cvs.zope.org:/tmp/cvs-serv21715/image

Added Files:
      Tag: philikon-movecontent-branch
	__init__.py browser.py configure.zcml edit.pt image.py 
	image_icon.gif interfaces.py 
Log Message:
Get rid of zope.products.content and zope.products.codecontent and move
content components in their own packages at zope.products.

See the package geddon proposal: http://dev.zope.org/Zope3/PackageGeddon


=== Added File Zope3/src/zope/products/image/__init__.py ===
#
# This file is necessary to make this directory a package.


=== Added File Zope3/src/zope/products/image/browser.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Define view component for naive file editing.

$Id: browser.py,v 1.1.2.1 2004/02/11 16:29:23 philikon Exp $
"""
from zope.app.size import byteDisplay
from zope.app.event.objectevent import ObjectModifiedEvent
from zope.app.event import publish
from zope.app.publisher.browser import BrowserView

class ImageData(BrowserView):

    def __call__(self):
        image = self.context
        if self.request is not None:
            self.request.response.setHeader('content-type',
                                            image.getContentType())
        return image.getData()

    def tag(self, height=None, width=None, alt=None,
            scale=0, xscale=0, yscale=0, css_class=None, **args):
        """
        Generate an HTML IMG tag for this image, with customization.
        Arguments to self.tag() can be any valid attributes of an IMG tag.
        'src' will always be an absolute pathname, to prevent redundant
        downloading of images. Defaults are applied intelligently for
        'height', 'width', and 'alt'. If specified, the 'scale', 'xscale',
        and 'yscale' keyword arguments will be used to automatically adjust
        the output height and width values of the image tag.

        Since 'class' is a Python reserved word, it cannot be passed in
        directly in keyword arguments which is a problem if you are
        trying to use 'tag()' to include a CSS class. The tag() method
        will accept a 'css_class' argument that will be converted to
        'class' in the output tag to work around this.
        """
        if width is None:
            width = self.context.getImageSize()[0]
        if height is None:
            height = self.context.getImageSize()[1]

        # Auto-scaling support
        xdelta = xscale or scale
        ydelta = yscale or scale

        if xdelta and width:
            width = str(int(round(int(width) * xdelta)))
        if ydelta and height:
            height = str(int(round(int(height) * ydelta)))

        result = '<img src="%s"' % (self.absolute_url())

        if alt is None:
            alt = getattr(self, 'title', '')
        result = '%s alt="%s"' % (result, alt)

        if height is not None:
            result = '%s height="%s"' % (result, height)

        if width is not None:
            result = '%s width="%s"' % (result, width)

        if not 'border' in [a.lower() for a in args.keys()]:
            result = '%s border="0"' % result

        if css_class is not None:
            result = '%s class="%s"' % (result, css_class)

        for key in args.keys():
            value = args.get(key)
            result = '%s %s="%s"' % (result, key, value)

        return '%s />' % result


class ImageUpload:
    """Image edit view mix-in that provides access to image size info"""

    def size(self):
        sx, sy = self.context.getImageSize()
        if sx < 0:
            sx = '?'
        if sy < 0:
            sy = '?'
        return "%s x %s pixels, %s" % (
                sx, sy, byteDisplay(self.context.getSize())
                )

    def apply_update(self, data):
        """Apply user inputs

        These inputs have already been validated.

        Return a boolean indicating whether we changed anything,
        """

        unchanged = True

        # if we can compute the content type from the raw data, then
        # that overrides what the user provided, so set the content
        # type first.

        contentType = data.get('contentType')
        if contentType and contentType != self.context.contentType:
            self.context.contentType = contentType
            unchanged = False

        if 'data' in data:
            self.context.data = data['data']
            unchanged = False

        if not unchanged:
            publish(self.context, ObjectModifiedEvent(self.context))

        return unchanged


=== Added File Zope3/src/zope/products/image/configure.zcml ===
<configure
    xmlns='http://namespaces.zope.org/zope'
    xmlns:browser='http://namespaces.zope.org/browser'
    xmlns:fssync='http://namespaces.zope.org/fssync'
    i18n_domain='zope'
    >

  <!-- Module alias for backward compat -->

  <modulealias
      module=".image"
      alias="zope.app.content.image"
      />

  <permission
      id="zope.AddImages"
      title="[add-images-permission] Add Images"
      />

  <interface 
      interface=".interfaces.IImage" 
      type="zope.app.interfaces.content.IContentType"
      /> 

  <content class=".image.Image">
    <factory
        id="Image"
        permission="zope.ManageContent"
        title="Image"
        description="An Image"
        />

    <require
        permission="zope.View"
        interface="zope.products.file.interfaces.IReadFile"
        attributes="getImageSize"
        />

    <require
        permission="zope.ManageContent"
        interface="zope.products.file.interfaces.IWriteFile"
        set_schema="zope.products.file.interfaces.IReadFile"
        />

    <implements
        interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
        />
  </content>

  <adapter
      factory=".image.ImageSized"
      provides="zope.app.interfaces.size.ISized"
      for=".interfaces.IImage"
      />

  <adapter
      for="zope.app.interfaces.folder.IFolder"
      provides="zope.app.interfaces.file.IFileFactory"
      factory=".image.FileFactory"
      permission="zope.ManageContent"
      />


  <fssync:adapter
      class=".image.Image"
      factory="zope.products.file.fssync.FileAdapter"
      />


  <!-- Browser stuff -->

  <browser:editform
      schema=".interfaces.IImage"
      name="upload.html"
      menu="zmi_views" title="Upload"
      label="Upload an image"
      permission="zope.ManageContent"
      class=".browser.ImageUpload"
      template="edit.pt"
      />

  <browser:page
      name="index.html"
      for=".interfaces.IImage"
      permission="zope.View"
      allowed_attributes="__call__ tag"
      class=".browser.ImageData"
      />

  <!--browser:page
      for=".interfaces.IImage"
      name="preview.html"
      menu="zmi_views" title="Preview"
      template="preview.pt"
      permission="zope.ManageContent"
      /-->

  <browser:icon
      name="zmi_icon"
      for=".interfaces.IImage"
      file="image_icon.gif"
      />

  <browser:addMenuItem
      class=".image.Image"
      title="Image"
      permission="zope.ManageContent"
      view="zope.products.image.Image"
      />

  <browser:addform
      schema=".interfaces.IImage"
      label="Add a Image"
      content_factory=".image.Image"
      name="zope.products.image.Image"
      permission="zope.ManageContent"
      />

</configure>


=== Added File Zope3/src/zope/products/image/edit.pt ===
<html metal:use-macro="views/standard_macros/page">
<body>
<div metal:fill-slot="body">

  <div metal:use-macro="view/generated_form/macros/body">

  <form action=".">   

    <table metal:fill-slot="extra_top">
      <tr>
        <td i18n:translate="">Size</td>
        <td tal:content="view/size" i18n:translate=""
           >103 x 45 pixels, 43KB</td>            
      </tr>
    </table>

    <input type="submit" name="save" value="Save Changes" 
        i18n:attributes="value save-changes-button"/>

  </form>

  </div>
</div>
</body>

</html>


=== Added File Zope3/src/zope/products/image/image.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: image.py,v 1.1.2.1 2004/02/11 16:29:23 philikon Exp $
"""
import struct
from cStringIO import StringIO

from zope.interface import implements

from zope.app.interfaces.size import ISized
from zope.app.size import byteDisplay
from zope.app.content_types import guess_content_type
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.products.file.file import File

from interfaces import IImage

__metaclass__ = type

class Image(File):
    implements(IImage)

    def __init__(self, data=''):
        '''See interface IFile'''
        self.contentType, self._width, self._height = getImageInfo(data)
        self.data = data

    def setData(self, data):
        super(Image, self).setData(data)

        contentType, self._width, self._height = getImageInfo(self.data)
        if contentType:
            self.contentType = contentType

    def getImageSize(self):
        '''See interface IImage'''
        return (self._width, self._height)

    data = property(File.getData, setData, None,
                    """Contains the data of the file.""")


class ImageSized:

    implements(ISized)

    def __init__(self, image):
        self._image = image

    def sizeForSorting(self):
        'See ISized'
        return ('byte', self._image.getSize())

    def sizeForDisplay(self):
        'See ISized'
        w, h = self._image.getImageSize()
        if w < 0:
            w = '?'
        if h < 0:
            h = '?'
        bytes = self._image.getSize()
        byte_size = byteDisplay(bytes)
        mapping = byte_size.mapping
        size = _(byte_size + ' ${width}x${height}')
        mapping.update({'width': str(w), 'height': str(h)})
        size.mapping = mapping 
        return size


def getImageInfo(data):
    data = str(data)
    size = len(data)
    height = -1
    width = -1
    content_type = ''

    # handle GIFs
    if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
        # Check to see if content_type is correct
        content_type = 'image/gif'
        w, h = struct.unpack("<HH", data[6:10])
        width = int(w)
        height = int(h)

    # See PNG v1.2 spec (http://www.cdrom.com/pub/png/spec/)
    # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
    # and finally the 4-byte width, height
    elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
          and (data[12:16] == 'IHDR')):
        content_type = 'image/png'
        w, h = struct.unpack(">LL", data[16:24])
        width = int(w)
        height = int(h)

    # Maybe this is for an older PNG version.
    elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
        # Check to see if we have the right content type
        content_type = 'image/png'
        w, h = struct.unpack(">LL", data[8:16])
        width = int(w)
        height = int(h)

    # handle JPEGs
    elif (size >= 2) and data.startswith('\377\330'):
        content_type = 'image/jpeg'
        jpeg = StringIO(data)
        jpeg.read(2)
        b = jpeg.read(1)
        try:
            while (b and ord(b) != 0xDA):
                while (ord(b) != 0xFF): b = jpeg.read(1)
                while (ord(b) == 0xFF): b = jpeg.read(1)
                if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                    jpeg.read(3)
                    h, w = struct.unpack(">HH", jpeg.read(4))
                    break
                else:
                    jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
                b = jpeg.read(1)
            width = int(w)
            height = int(h)
        except struct.error:
            pass
        except ValueError:
            pass

    return content_type, width, height


class FileFactory:

    def __init__(self, context):
        self.context = context

    def __call__(self, name, content_type, data):
        if not content_type and data:
            content_type, width, height = getImageInfo(data)
        if not content_type:
            content_type, encoding = guess_content_type(name, data, '')

        if content_type.startswith('image/'):
            return Image(data)

        return File(data, content_type)


=== Added File Zope3/src/zope/products/image/image_icon.gif ===
  <Binary-ish file>

=== Added File Zope3/src/zope/products/image/interfaces.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: interfaces.py,v 1.1.2.1 2004/02/11 16:29:23 philikon Exp $
"""

from zope.products.file.interfaces import IFile

class IImage(IFile):
    """This interface defines an Image that can be displayed.
    """

    def getImageSize():
        """Return a tuple (x, y) that describes the dimensions of
        the object.
        """




More information about the Zope3-Checkins mailing list