T. H.
T. H.

Reputation: 39

Plone: get Portrait from getPersonalPortrait() scales with @@images or else

I'd like to modify the imagesize of the user's portrait from Plone-Membertool in a custom-view. I thought that schould be possible over plone.app.imaging with the following page-template snippet:

<img tal:define="scales user/img/@@images;
                 image python: scales.scale('image', width=75, height=100);"
     tal:condition="image"
     tal:attributes="src image/url;
         width image/width;
         height image/height"/>

The user/img is defined in a helper-class as follow (and passed in the view-class as 'user'):

mtool = api.portal.get_tool(name='portal_membership')
uid = user.id
fullname = user.getProperty('fullname')
...
dct = {
          'id': uid,
          'img': mtool.getPersonalPortrait(id=uid),
          'fullname': fullname,
          ...
}
return dct

If I apply now the @@images on this user/img I get the following AttributeError:

  ...
  Module zope.tales.tales, line 696, in evaluate
  URL: /opt/workspace/my-plone-buildout/src/myproduct.content/myproduct/content/browser/templates/user_list.pt
  Line 42, Column 4
  Expression: <PathExpr standard:u'user/img/@@images'>
  Names:
    ...
  Module Products.PageTemplates.Expressions, line 94, in trustedBoboAwareZopeTraverse
  Module OFS.Traversable, line 300, in unrestrictedTraverse
  __traceback_info__: ([], '@@images')
AttributeError: @@images

It seems, that mtool.getPersonalPortrait(id) dosn't return a Image-Element where plone.app.image could be applied on it. But if I use this construct in the template just for showing the unchanged image it works fine:

<img src="#" tal:replace="structure user/img" />

As next I tried to use the absolut-url to the user's portrait for getting @@images work. First in the helper-class:

...
dct = {
...
          'img': mtool.getPersonalPortrait(id=uid),
          'imgurl': mtool.getPersonalPortrait(id=uid).absolute_url(),
...

And then in the page-template:

<img tal:define="scales user/imgurl/@@images;
                 image python: scales.scale('image', width=75, height=100);"
                 ...

Then I get a LocationError:

...
Expression: <PathExpr standard:u'user/imgurl/@@images'>
...

  Module Products.CMFPlone.patches.security, line 12, in traverse
  Module zope.traversing.namespace, line 329, in traverse

LocationError: ('http://localhost:8080/Plone/defaultUser.png', 'images')

Even if the URL http://localhost:8080/Plone/defaultUser.png shows the right picture (there are others then the default one, that dosn't change).

I didn't find any documentation, what type of object getPersonalPortrait() gets back and which methods could be apllied on it. And how I can resize this user portraits to some specific needs in the custom view (compare width and height in python according to some rules to calculate the right resize).

It would be great to get some pointers for manipulating the user-portrait in the view-class in python.

Upvotes: 3

Views: 582

Answers (2)

Mathias
Mathias

Reputation: 6839

There's Plone AddOn called ftw.avatar, which extends the default portrait functionality of Plone by two main Features.

First, it replaces the default Plone avatar, by a Google like avatar. It generates an image using the first letter of the firstname and lastname.

Second, it adds an size parameter to the portrait url

Example 1: This scales the portrait image to 26 x 26 pixel avatar: http://plone/portal_memberdata/portraits/maethu?size=26 This results in: enter image description here

Example 2: This scales the portrait image to 200 x 200 pixel avatar: http://plone/portal_memberdata/portraits/maethu?size=200 This results in: enter image description here

Implementation: It overrides the default portrait by the following view: https://github.com/4teamwork/ftw.avatar/blob/750fbc52f8c2fd6cca538525f72141982008b719/ftw/avatar/browser/portrait.py

from Products.Five.browser import BrowserView
from plone.scale.scale import scaleImage
from plone.scale.storage import AnnotationStorage
from webdav.common import rfc1123_date
from zope.annotation import IAttributeAnnotatable
from zope.interface import alsoProvides


class PortraitScalingView(BrowserView):

    def __call__(self):
        form = self.request.form
        size = form.get('size', form.get('s', None))
        if size is None:
            # return original - no scaling required
            return self.context.index_html(self.request, self.request.RESPONSE)
        else:
            size = int(size)

        if not IAttributeAnnotatable.providedBy(self.context):
            alsoProvides(self.context, IAttributeAnnotatable)

        storage = AnnotationStorage(self.context, self.context.modified)
        scale = storage.scale(self.scale_factory,
                              width=size,
                              height=size)

        response = self.request.RESPONSE
        response.setHeader('Last-Modified', rfc1123_date(scale['modified']))
        response.setHeader('Content-Type', scale['mimetype'])
        response.setHeader('Content-Length', len(scale['data']))
        response.setHeader('Accept-Ranges', 'bytes')
        return scale['data']

    def scale_factory(self, **parameters):
        return scaleImage(self.context.data, **parameters)

Corresponding zcml:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:browser="http://namespaces.zope.org/browser"
    i18n_domain="ftw.avatar">

    <browser:page
        for="plone.app.linkintegrity.interfaces.IOFSImage"
        name="index_html"
        class=".portrait.PortraitScalingView"
        permission="zope2.View"
        />

    <browser:defaultView
        for="plone.app.linkintegrity.interfaces.IOFSImage"
        name="index_html"
        />

</configure>

Upvotes: 2

keul
keul

Reputation: 7819

No, the @@images view is for contents, the portrait is managed in a very (and low level) different way.

Just take a look at the scale_image function from Products.PlonePAS module. You can use that function or learn how to use PIL library directly.

Upvotes: 0

Related Questions