Reputation: 39
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
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:
Example 2: This scales the portrait image to 200 x 200 pixel avatar:
http://plone/portal_memberdata/portraits/maethu?size=200
This results in:
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
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