Index: ow/templates/dashboard.pt
===================================================================
--- ow/templates/dashboard.pt	(revision eb20dc818a798cb30bba9c9f57b4e372ab06e03c)
+++ ow/templates/dashboard.pt	(revision f0e64eb4891e151368a45b26fb6e56b04b832136)
@@ -101,5 +101,5 @@
           <tal:c tal:condition="getattr(context, 'picture', None)">
             <a href="" tal:attributes="href request.resource_url(context, 'profile')">
-              <img tal:attributes="src request.resource_path(context, 'picture')"
+              <img tal:attributes="src request.resource_path(context, 'picture', query={'size': 200})"
                    width="450" />
             </a>
Index: ow/templates/edit_profile.pt
===================================================================
--- ow/templates/edit_profile.pt	(revision eb20dc818a798cb30bba9c9f57b4e372ab06e03c)
+++ ow/templates/edit_profile.pt	(revision f0e64eb4891e151368a45b26fb6e56b04b832136)
@@ -49,5 +49,7 @@
                       <label for="current_picture" i18n:translate="">
                           Current picture:</label>
-                      <img id="current_picture" tal:attributes="src request.resource_path(context, 'picture')" width="150">
+                      <img id="current_picture"
+                           tal:attributes="src request.resource_path(context, 'picture', query={'size': 200})"
+                           width="150">
                   </tal:c>
                 </div>
Index: ow/templates/profile.pt
===================================================================
--- ow/templates/profile.pt	(revision eb20dc818a798cb30bba9c9f57b4e372ab06e03c)
+++ ow/templates/profile.pt	(revision f0e64eb4891e151368a45b26fb6e56b04b832136)
@@ -18,5 +18,5 @@
         <div>
           <tal:c tal:condition="getattr(user, 'picture', None)">
-            <img tal:attributes="src request.resource_path(user, 'picture')"
+            <img tal:attributes="src request.resource_path(user, 'picture', query={'size': 200})"
                  width="450" />
           </tal:c>
Index: ow/tests/views/test_user.py
===================================================================
--- ow/tests/views/test_user.py	(revision eb20dc818a798cb30bba9c9f57b4e372ab06e03c)
+++ ow/tests/views/test_user.py	(revision f0e64eb4891e151368a45b26fb6e56b04b832136)
@@ -5,4 +5,5 @@
 from shutil import copyfileobj
 from unittest.mock import Mock, patch
+from io import BytesIO
 
 import pytest
@@ -15,4 +16,6 @@
 
 from webob.multidict import MultiDict
+
+from PIL import Image
 
 from ow.models.root import OpenWorkouts
@@ -417,4 +420,31 @@
         assert response.status_int == 200
         assert response.content_type == 'image'
+        # as we did not pass a specific size as a get parameter, the size is
+        # the same as the original image
+        original_image = Image.open(image_path)
+        returned_image = Image.open(BytesIO(response.body))
+        assert original_image.size == returned_image.size
+
+        # now, ask for a smaller image
+        request.GET['size'] = original_image.size[0] - 20
+        response = user_views.profile_picture(user, request)
+        assert isinstance(response, Response)
+        assert response.status_int == 200
+        assert response.content_type == 'image'
+        # now the size of the original image is bigger
+        returned_image = Image.open(BytesIO(response.body))
+        assert original_image.size > returned_image.size
+
+        # now, ask for a size that is bigger than the original image,
+        # image will be the same size, as we do not "grow" its size
+        request.GET['size'] = original_image.size[0] + 1000
+        response = user_views.profile_picture(user, request)
+        assert isinstance(response, Response)
+        assert response.status_int == 200
+        assert response.content_type == 'image'
+        # now the size of the original image is bigger
+        returned_image = Image.open(BytesIO(response.body))
+        assert original_image.size == returned_image.size
+
 
     def test_edit_profile_get(self, dummy_request, john):
Index: ow/views/user.py
===================================================================
--- ow/views/user.py	(revision eb20dc818a798cb30bba9c9f57b4e372ab06e03c)
+++ ow/views/user.py	(revision f0e64eb4891e151368a45b26fb6e56b04b832136)
@@ -3,4 +3,5 @@
 from datetime import datetime, timezone, timedelta
 from decimal import Decimal
+from io import BytesIO
 
 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
@@ -11,4 +12,5 @@
 from pyramid_simpleform import Form, State
 from pytz import common_timezones
+from PIL import Image
 
 from ..models.user import User
@@ -212,7 +214,22 @@
     permission='view')
 def profile_picture(context, request):
-    return Response(
-        content_type='image',
-        body_file=context.picture.open())
+    if context.picture is None:
+        return HTTPNotFound()
+
+    size = request.GET.get('size', 0)
+    # we will need a tuple, it does not matter if both values are the same,
+    # Pillow will keep aspect ratio
+    size = (int(size), int(size))
+
+    image = Image.open(context.picture.open())
+
+    if size > (0, 0) and size < image.size:
+        # resize only if they are asking for smaller size, prevent
+        # someone asking for a "too big" image
+        image.thumbnail(size)
+
+    body_file = BytesIO()
+    image.save(body_file, format=image.format)
+    return Response(content_type='image', body=body_file.getvalue())
 
 
