Thibault Delavallée (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-server/trunk-image-standardize-tde into 
lp:openobject-server.

Requested reviews:
  OpenERP Core Team (openerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-image-standardize-tde/+merge/112376

Standardize avatars/images

See specifications in 
http://pad.openerp.com/internalv61-project-task-3626-YDAVGI2M.
-- 
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-image-standardize-tde/+merge/112376
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-server/trunk-image-standardize-tde.
=== modified file 'openerp/addons/base/res/res_users.py'
--- openerp/addons/base/res/res_users.py	2012-06-19 08:10:05 +0000
+++ openerp/addons/base/res/res_users.py	2012-06-27 15:06:35 +0000
@@ -25,7 +25,6 @@
 
 import pytz
 
-import io, StringIO
 from lxml import etree
 from lxml.builder import E
 import netsvc
@@ -33,7 +32,6 @@
 import openerp.exceptions
 from osv import fields,osv
 from osv.orm import browse_record
-from PIL import Image
 import pooler
 import random
 from service import security
@@ -152,33 +150,6 @@
                                          body=(self.get_welcome_mail_body(cr, uid, context=context) % user))
         return ir_mail_server.send_email(cr, uid, msg, context=context)
 
-    def onchange_avatar(self, cr, uid, ids, value, context=None):
-        if not value:
-            return {'value': {'avatar_big': value, 'avatar': value} }
-        return {'value': {'avatar_big': self._avatar_resize(cr, uid, value, 540, 450, context=context), 'avatar': self._avatar_resize(cr, uid, value, context=context)} }
-    
-    def _set_avatar(self, cr, uid, id, name, value, args, context=None):
-        if not value:
-            vals = {'avatar_big': value}
-        else:
-            vals = {'avatar_big': self._avatar_resize(cr, uid, value, 540, 450, context=context)}
-        return self.write(cr, uid, [id], vals, context=context)
-    
-    def _avatar_resize(self, cr, uid, avatar, height=180, width=150, context=None):
-        image_stream = io.BytesIO(avatar.decode('base64'))
-        img = Image.open(image_stream)
-        img.thumbnail((height, width), Image.ANTIALIAS)
-        img_stream = StringIO.StringIO()
-        img.save(img_stream, "PNG")
-        return img_stream.getvalue().encode('base64')
-
-    def _get_avatar(self, cr, uid, ids, name, args, context=None):
-        result = dict.fromkeys(ids, False)
-        for user in self.browse(cr, uid, ids, context=context):
-            if user.avatar_big:
-                result[user.id] = self._avatar_resize(cr, uid, user.avatar_big, context=context)
-        return result
-
     def _set_new_password(self, cr, uid, id, name, value, args, context=None):
         if value is False:
             # Do not update the password if no value is provided, ignore silently.
@@ -194,6 +165,35 @@
     def _get_password(self, cr, uid, ids, arg, karg, context=None):
         return dict.fromkeys(ids, '')
 
+    def _get_image_resized(self, cr, uid, ids, name, args, context=None):
+        result = dict.fromkeys(ids, False)
+        for user in self.browse(cr, uid, ids, context=context):
+            result[user.id] = {'image_medium': False, 'image_small': False}
+            if user.image:
+                result[user.id]['image_medium'] = tools.resize_image_medium(user.image)
+                result[user.id]['image_small'] = tools.resize_image_small(user.image)
+        return result
+    
+    def _set_image_resized(self, cr, uid, id, name, value, args, context=None):
+        if not value:
+            vals = {'image': value}
+        else:
+            vals = {'image': tools.resize_image_big(value)}
+        return self.write(cr, uid, [id], vals, context=context)
+    
+    def onchange_image(self, cr, uid, ids, value, context=None):
+        if not value:
+            return {'value': {
+                    'image': value,
+                    'image_medium': value,
+                    'image_small': value,
+                    }}
+        return {'value': {
+                    'image': tools.resize_image_big(value),
+                    'image_medium': tools.resize_image_medium(value),
+                    'image_small': tools.resize_image_small(value),
+                    }}
+    
     _columns = {
         'id': fields.integer('ID'),
         'name': fields.char('User Name', size=64, required=True, select=True,
@@ -208,11 +208,28 @@
                                                             "otherwise leave empty. After a change of password, the user has to login again."),
         'user_email': fields.char('Email', size=64),
         'signature': fields.text('Signature', size=64),
-        'avatar_big': fields.binary('Big-sized avatar', help="This field holds the image used as avatar for the user. The avatar field is used as an interface to access this field. The image is base64 encoded, and PIL-supported. It is stored as a 540x450 px image, in case a bigger image must be used."),
-        'avatar': fields.function(_get_avatar, fnct_inv=_set_avatar, string='Avatar', type="binary",
-            store = {
-                'res.users': (lambda self, cr, uid, ids, c={}: ids, ['avatar_big'], 10),
-            }, help="Image used as avatar for the user. It is automatically resized as a 180x150 px image. This field serves as an interface to the avatar_big field."),
+        'image': fields.binary("Avatar",
+            help="This field holds the image used as avatar for the "\
+                 "user. The avatar field is used as an interface to "\
+                 "access this field. The image is base64 encoded, "\
+                 "and PIL-supported. It is stored as a 540x450 px "\
+                 "image, in case a bigger image must be used."),
+        'image_medium': fields.function(_get_image_resized, fnct_inv=_set_image_resized,
+            string="Medium-sized avatar", type="binary", multi="_get_image_resized",
+            store = {
+                'res.users': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+            },
+            help="Medium-sized image of the user. It is automatically "\
+                 "resized as a 180x180px image, with aspect ratio keps. "\
+                 "Use this field in form views or some kanban views."),
+        'image_small': fields.function(_get_image_resized, fnct_inv=_set_image_resized,
+            string="Smal-sized avatar", type="binary", multi="_get_image_resized",
+            store = {
+                'res.users': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
+            },
+            help="Small-sized image of the user. It is automatically "\
+                 "resized as a 50x50px image, with aspect ratio keps. "\
+                 "Use this field in form views or some kanban views."),
         'active': fields.boolean('Active'),
         'action_id': fields.many2one('ir.actions.actions', 'Home Action', help="If specified, this action will be opened at logon for this user, in addition to the standard menu."),
         'menu_id': fields.many2one('ir.actions.actions', 'Menu Action', help="If specified, the action will replace the standard menu for this user."),
@@ -321,16 +338,16 @@
             pass
         return result
 
-    def _get_avatar(self, cr, uid, context=None):
-        # default avatar file name: avatar0 -> avatar6.png, choose randomly
-        avatar_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar%d.png' % random.randint(0, 6))
-        return self._avatar_resize(cr, uid, open(avatar_path, 'rb').read().encode('base64'), context=context)
+    def _get_image(self, cr, uid, context=None):
+        # default image file name: avatar0 -> avatar6.png, choose randomly
+        image_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar%d.png' % random.randint(0, 6))
+        return tools.resize_image_big(open(image_path, 'rb').read().encode('base64'))
 
     _defaults = {
         'password' : '',
         'context_lang': lambda self, cr, uid, context: context.get('lang', 'en_US'),
         'context_tz': lambda self, cr, uid, context: context.get('tz', False),
-        'avatar': _get_avatar,
+        'image_medium': _get_image,
         'active' : True,
         'menu_id': _get_menu,
         'company_id': _get_company,
@@ -340,7 +357,7 @@
     }
 
     # User can write to a few of her own fields (but not her groups for example)
-    SELF_WRITEABLE_FIELDS = ['menu_tips','password', 'signature', 'action_id', 'company_id', 'user_email', 'name', 'avatar', 'avatar_big']
+    SELF_WRITEABLE_FIELDS = ['menu_tips','password', 'signature', 'action_id', 'company_id', 'user_email', 'name', 'image', 'image_medium', 'image_small']
 
     def write(self, cr, uid, ids, values, context=None):
         if not hasattr(ids, '__iter__'):

=== modified file 'openerp/addons/base/res/res_users_view.xml'
--- openerp/addons/base/res/res_users_view.xml	2012-06-22 06:12:32 +0000
+++ openerp/addons/base/res/res_users_view.xml	2012-06-27 15:06:35 +0000
@@ -82,7 +82,7 @@
                     <field name="id" invisible="1"/>
                     <sheet>
                         <div class="oe_right">
-                            <field name="avatar" widget='image' nolabel="1" on_change="onchange_avatar(avatar)" class="oe_avatar"/>
+                            <field name="image_medium" widget='image' nolabel="1" on_change="onchange_image(image_medium)" class="oe_avatar"/>
                         </div>
                         <div class="oe_title">
                             <label for="name" class="oe_edit_only"/>
@@ -196,7 +196,7 @@
                 <form string="Users" version="7.0">
                    <sheet>
                     <div class="oe_right oe_avatar">
-                        <field name="avatar" widget='image' on_change="onchange_avatar(avatar)"/>
+                        <field name="image_small" widget='image' on_change="onchange_image(image_small)"/>
                     </div>
                     <div class="oe_title">
                         <h1>

=== modified file 'openerp/tools/__init__.py'
--- openerp/tools/__init__.py	2011-12-16 16:04:26 +0000
+++ openerp/tools/__init__.py	2012-06-27 15:06:35 +0000
@@ -19,19 +19,20 @@
 #
 ##############################################################################
 
-import copy
-import win32
+from amount_to_text import *
+from amount_to_text_en import *
 from config import config
-from misc import *
 from convert import *
-from translate import *
+import copy
+from float_utils import *
 from graph import graph
-from amount_to_text import *
-from amount_to_text_en import *
+from image import *
+from misc import *
 from pdf_utils import *
+from sql import *
+from translate import *
 from yaml_import import *
-from sql import *
-from float_utils import *
+import win32
 
 #.apidoc title: Tools
 

=== added file 'openerp/tools/image.py'
--- openerp/tools/image.py	1970-01-01 00:00:00 +0000
+++ openerp/tools/image.py	2012-06-27 15:06:35 +0000
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2012-today OpenERP s.a. (<http://openerp.com>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import io
+from PIL import Image
+import StringIO
+
+def resize_image(base64_source, size=(1024, 1024), encoding='base64', filetype='PNG', avoid_if_small=False):
+    image_stream = io.BytesIO(base64_source.decode(encoding))
+    image = Image.open(image_stream)
+    # check image size: do not create a thumbnail if avoiding smaller images
+    if avoid_if_small and image.size[0] <= size[0] and image.size[1] <= size[1]:
+        return base64_source
+    # create a thumbnail: will resize and keep ratios
+    image.thumbnail(size, Image.ANTIALIAS)
+    # create a transparent image for background
+    background = Image.new('RGBA', size, (255, 255, 255, 0))
+    # past the resized image on the background
+    background.paste(image, ((size[0] - image.size[0]) / 2, (size[1] - image.size[1]) / 2))
+    # return an encoded image
+    background_stream = StringIO.StringIO()
+    background.save(background_stream, filetype)
+    return background_stream.getvalue().encode(encoding)
+
+def resize_image_big(base64_source, size=(1204, 1204), encoding='base64', filetype='PNG'):
+    return resize_image(base64_source, size, encoding, filetype, True)
+
+def resize_image_medium(base64_source, size=(180, 180), encoding='base64', filetype='PNG'):
+    return resize_image(base64_source, size, encoding, filetype)
+    
+def resize_image_small(base64_source, size=(50, 50), encoding='base64', filetype='PNG'):
+    return resize_image(base64_source, size, encoding, filetype)

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to