Plone: get portrait from getPersonalPortrait () scales with images @@ or otherwise
I would like to change the custom portrait image from Plone-Membertool in custom view. I thought it was possible over plone.app.imaging
with the following snippet of the page template:
<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"/>
user/img
is defined in the helper class as follows (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 applied now @@images
in 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 mtool.getPersonalPortrait(id)
doesn't seem to return Image-Element where plone.app.image
can be applied to it. But if I use this construct in the template just to display the unmodified image, it works fine:
<img src="#" tal:replace="structure user/img" />
As the next, I tried to use the absolut-url for the custom portrait to get it @@images
working. 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 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 correct image (there are others, by default, which do not change).
I haven't found any documentation of what type of object is getPersonalPortrait()
returned and what methods can be used on it. And how can I resize the custom portraits to some specific needs of the custom view (compare the width and height in python according to some rules to calculate the correct resizing).
It would be great to get some pointers to manipulate the custom portrait in the view class in python.
source to share
Here is Plone AddOn called ftw.avatar
, which extends the default portrait functionality for Plone with two main features.
First, it replaces the default Plone avatar with a Google-like one. It generates an image using the first letter of the name and name.
Second, it adds a size parameter to the portrait of the portrait
Example 1: This reduces the portrait image to 26 x 26 pixels:
http://plone/portal_memberdata/portraits/maethu?size=26
This results in:
Example 2: This reduces the portrait image to 200 x 200 pixels:
http://plone/portal_memberdata/portraits/maethu?size=200
This results in:
Implementation: It overrides the default portrait with the following look: 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>
source to share
No, viewing @@ images for content, portrait is handled very (and low-level) differently.
Just take a look at the scale_image function from the module Products.PlonePAS
. You can use this feature or learn to use the PIL library directly.
source to share