Commit e86d6f1f authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

Add crop option to image parameters

parent ec010da7
...@@ -294,20 +294,23 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -294,20 +294,23 @@ class Image(TextConvertableMixin, File, OFSImage):
# pixel (number of it = 128x128) # pixel (number of it = 128x128)
kw['image_size'] = image_size kw['image_size'] = image_size
display = kw.pop('display', None) 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 image_data = image.data
# as image will always be requested through a display not by passing exact # as image will always be requested through a display not by passing exact
# pixels we need to restore this way in cache # pixels we need to restore this way in cache
if display is not None: if display is not None:
# only set if we have a real value # only set if we have a real value
kw['display'] = display kw['display'] = display
if crop:
kw['crop'] = crop
image_size = kw.pop('image_size', None) image_size = kw.pop('image_size', None)
self.setConversion(image_data, mime, **kw) self.setConversion(image_data, mime, **kw)
return mime, image_data return mime, image_data
# Display # Display
security.declareProtected(Permissions.View, 'index_html') 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): def index_html(self, REQUEST, *args, **kw):
"""Return the image data.""" """Return the image data."""
self._upgradeImage() self._upgradeImage()
...@@ -317,11 +320,16 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -317,11 +320,16 @@ class Image(TextConvertableMixin, File, OFSImage):
# Photo processing # 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.""" """Resize and resample photo."""
parameter_list = ['convert', '-colorspace', 'sRGB', '-depth', '8', parameter_list = ['convert', '-colorspace', 'sRGB', '-depth', '8']
'-quality', str(quality), if crop :
'-geometry', '%sx%s' % (width, height)] 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: if format not in VALID_TRANSPARENT_IMAGE_FORMAT_LIST:
# ImageMagick way to remove transparent that works with multiple # ImageMagick way to remove transparent that works with multiple
# images. http://www.imagemagick.org/Usage/masking/#remove # images. http://www.imagemagick.org/Usage/masking/#remove
...@@ -357,18 +365,22 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -357,18 +365,22 @@ class Image(TextConvertableMixin, File, OFSImage):
return StringIO(image) return StringIO(image)
raise ConversionError('Image conversion failed (%s).' % err) 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.""" """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))\ if ((width, height) == image_size or (width, height) == (0, 0))\
and quality == self.getDefaultImageQuality(format) and resolution is None and frame is None\ and quality == self.getDefaultImageQuality(format) and resolution is None and frame is None\
and not format: and not format:
# No resizing, no conversion, return raw image # No resizing, no conversion, return raw image
return self.getData() 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, 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.""" """Create given display."""
if quality is _MARKER: if quality is _MARKER:
quality = self.getDefaultImageQuality(format) quality = self.getDefaultImageQuality(format)
...@@ -377,7 +389,8 @@ class Image(TextConvertableMixin, File, OFSImage): ...@@ -377,7 +389,8 @@ class Image(TextConvertableMixin, File, OFSImage):
id = '%s_%s_%s.%s'% (base, width, height, ext,) id = '%s_%s_%s.%s'% (base, width, height, ext,)
image = OFSImage(id, self.getTitle(), image = OFSImage(id, self.getTitle(),
self._getDisplayData(format, quality, resolution, self._getDisplayData(format, quality, resolution,
frame, image_size)) frame, image_size,
crop))
return image.content_type, aq_base(image) return image.content_type, aq_base(image)
def _getAspectRatioSize(self, width, height): def _getAspectRatioSize(self, width, height):
......
...@@ -76,6 +76,7 @@ from AccessControl import Unauthorized ...@@ -76,6 +76,7 @@ from AccessControl import Unauthorized
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.tests.backportUnittest import expectedFailure from Products.ERP5Type.tests.backportUnittest import expectedFailure
from DateTime import DateTime from DateTime import DateTime
from ZTUtils import make_query
QUIET = 0 QUIET = 0
...@@ -248,7 +249,7 @@ class TestDocument(TestDocumentMixin): ...@@ -248,7 +249,7 @@ class TestDocument(TestDocumentMixin):
def getURLSizeList(self, uri, **kw): def getURLSizeList(self, uri, **kw):
# __ac=RVJQNVR5cGVUZXN0Q2FzZTo%3D is encoded ERP5TypeTestCase with empty password # __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') format=kw.get('format', 'jpeg')
infile = urllib.urlopen(url) infile = urllib.urlopen(url)
# save as file with proper incl. format filename (for some reasons PIL uses this info) # save as file with proper incl. format filename (for some reasons PIL uses this info)
...@@ -2250,11 +2251,16 @@ return 1 ...@@ -2250,11 +2251,16 @@ return 1
# Image # Image
image_document_image_size, image_document_file_size = self.getURLSizeList(image_document_url, **convert_kw) 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(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
web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw) web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw)
self.assertTrue(max(preffered_size_for_display) - max(web_page_image_size) <= max_tollerance_px) self.assertTrue(max(preffered_size_for_display) - max(web_page_image_size) <= max_tollerance_px)
# test changing image quality will decrease its file size # test changing image quality will decrease its file size
for url in (image_document_url, pdf_document_url, ooo_document_url, web_page_document_url): for url in (image_document_url, pdf_document_url, ooo_document_url, web_page_document_url):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment