From aec500f87ebbf0da29dbc87cd1e77415cd4426e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Le=20Ninivin?= <cedric.leninivin@tiolive.com>
Date: Tue, 29 Jan 2013 13:49:48 +0100
Subject: [PATCH] Add crop option to image parameters

Conflicts:
	product/ERP5OOo/tests/testDms.py
---
 product/ERP5/Document/Image.py   | 35 ++++++++++++++++++++++----------
 product/ERP5OOo/tests/testDms.py |  9 +++++++-
 2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/product/ERP5/Document/Image.py b/product/ERP5/Document/Image.py
index 8a66451435..73d4b024a2 100644
--- a/product/ERP5/Document/Image.py
+++ b/product/ERP5/Document/Image.py
@@ -294,20 +294,23 @@ class Image(TextConvertableMixin, File, OFSImage):
       # pixel (number of it = 128x128)
       kw['image_size'] = image_size
       display = kw.pop('display', None)
-      mime, image = self._makeDisplayPhoto(**kw)
+      crop = kw.pop('crop', None)
+      mime, image = self._makeDisplayPhoto(crop=crop, **kw)
       image_data = image.data
       # as image will always be requested through a display not by passing exact
       # pixels we need to restore this way in cache
       if display is not None:
         # only set if we have a real value
         kw['display'] = display
+      if crop:
+        kw['crop'] = crop
       image_size = kw.pop('image_size', None)
       self.setConversion(image_data, mime, **kw)
     return mime, image_data
 
   # Display
   security.declareProtected(Permissions.View, 'index_html')
-  @fill_args_from_request('display', 'quality', 'resolution', 'frame')
+  @fill_args_from_request('display', 'quality', 'resolution', 'frame', 'crop')
   def index_html(self, REQUEST, *args, **kw):
     """Return the image data."""
     self._upgradeImage()
@@ -317,11 +320,16 @@ class Image(TextConvertableMixin, File, OFSImage):
   # Photo processing
   #
 
-  def _resize(self, quality, width, height, format, resolution, frame):
+  def _resize(self, quality, width, height, format, resolution, frame, crop=False):
     """Resize and resample photo."""
-    parameter_list = ['convert', '-colorspace', 'sRGB', '-depth', '8',
-                                 '-quality', str(quality),
-                                 '-geometry', '%sx%s' % (width, height)]
+    parameter_list = ['convert', '-colorspace', 'sRGB', '-depth', '8']
+    if crop :
+      parameter_list += '-thumbnail', '%sx%s^' % (width, height),\
+                        '-gravity', 'center',\
+                        '-extent','%sx%s' % (width, height)
+    else:
+      parameter_list += '-geometry', '%sx%s' % (width, height)
+    parameter_list += '-quality', str(quality)
     if format not in VALID_TRANSPARENT_IMAGE_FORMAT_LIST:
       # ImageMagick way to remove transparent that works with multiple
       # images. http://www.imagemagick.org/Usage/masking/#remove
@@ -357,18 +365,22 @@ class Image(TextConvertableMixin, File, OFSImage):
       return StringIO(image)
     raise ConversionError('Image conversion failed (%s).' % err)
 
-  def _getDisplayData(self, format, quality, resolution, frame, image_size):
+  def _getDisplayData(self, format, quality, resolution, frame, image_size, crop):
     """Return raw photo data for given display."""
-    width, height = self._getAspectRatioSize(*image_size)
+    if crop:
+      width, height = image_size
+    else:
+      width, height = self._getAspectRatioSize(*image_size)
     if ((width, height) == image_size or (width, height) == (0, 0))\
        and quality == self.getDefaultImageQuality(format) and resolution is None and frame is None\
        and not format:
       # No resizing, no conversion, return raw image
       return self.getData()
-    return self._resize(quality, width, height, format, resolution, frame)
+    return self._resize(quality, width, height, format, resolution, frame, crop)
 
   def _makeDisplayPhoto(self, format=None, quality=_MARKER,
-                                 resolution=None, frame=None, image_size=None):
+                                 resolution=None, frame=None, image_size=None,
+                                 crop=False):
     """Create given display."""
     if quality is _MARKER:
       quality = self.getDefaultImageQuality(format)
@@ -377,7 +389,8 @@ class Image(TextConvertableMixin, File, OFSImage):
     id = '%s_%s_%s.%s'% (base, width, height, ext,)
     image = OFSImage(id, self.getTitle(),
                      self._getDisplayData(format, quality, resolution,
-                                                            frame, image_size))
+                                                            frame, image_size,
+                                                            crop))
     return image.content_type, aq_base(image)
 
   def _getAspectRatioSize(self, width, height):
diff --git a/product/ERP5OOo/tests/testDms.py b/product/ERP5OOo/tests/testDms.py
index ae7c16d3ba..51e17c038c 100644
--- a/product/ERP5OOo/tests/testDms.py
+++ b/product/ERP5OOo/tests/testDms.py
@@ -76,6 +76,7 @@ import re
 from AccessControl import Unauthorized
 from Products.ERP5Type import Permissions
 from DateTime import DateTime
+from ZTUtils import make_query
 
 QUIET = 0
 
@@ -243,7 +244,7 @@ class TestDocument(TestDocumentMixin):
 
   def getURLSizeList(self, uri, **kw):
     # __ac=RVJQNVR5cGVUZXN0Q2FzZTo%3D is encoded ERP5TypeTestCase with empty password
-    url = '%s?%s&__ac=%s' %(uri, urllib.urlencode(kw), 'RVJQNVR5cGVUZXN0Q2FzZTo%3D')
+    url = '%s?%s&__ac=%s' %(uri, make_query(kw), 'RVJQNVR5cGVUZXN0Q2FzZTo%3D')
     format=kw.get('format', 'jpeg')
     infile = urllib.urlopen(url)
     # save as file with proper incl. format filename (for some reasons PIL uses this info)
@@ -2252,6 +2253,12 @@ return 1
         # Image
         image_document_image_size, image_document_file_size = self.getURLSizeList(image_document_url, **convert_kw)
         self.assertTrue(max(preffered_size_for_display) - max(image_document_image_size) <= max_tollerance_px)
+        self.assertTrue(abs(min(preffered_size_for_display) - min(image_document_image_size)) >= max_tollerance_px)
+
+        cropped_image_document_image_size, cropped_image_document_file_size = \
+            self.getURLSizeList(image_document_url, crop = 1, **convert_kw)
+        self.assertEqual(max(preffered_size_for_display), max(cropped_image_document_image_size))
+        self.assertEqual(min(preffered_size_for_display), min(cropped_image_document_image_size))
 
         # Web Page
         web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw)
-- 
2.30.9