From ab47688609a808090e339a5707325ed1c8c7998e Mon Sep 17 00:00:00 2001 From: Tom Gross Date: Wed, 26 Feb 2014 22:32:05 +0100 Subject: [PATCH] override scaling view to keep crops on metadata change --- buildout.cfg | 3 +++ .../app/imagecropping/browser/configure.zcml | 9 ++++++++ src/plone/app/imagecropping/browser/crop.py | 3 +-- src/plone/app/imagecropping/browser/editor.py | 4 ---- .../app/imagecropping/browser/scaling.py | 17 +++++++++++++++ src/plone/app/imagecropping/interfaces.py | 2 +- .../app/imagecropping/tests/test_cropping.py | 21 +++++++++++++++++++ .../app/imagecropping/tests/test_editor.py | 3 ++- src/plone/app/imagecropping/utils.py | 10 +++++++-- 9 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 src/plone/app/imagecropping/browser/scaling.py diff --git a/buildout.cfg b/buildout.cfg index bc71374c..2cb1449b 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -24,6 +24,9 @@ test-eggs += versions = versions +[versions] +Pillow = 2.3.0 + [omelette] recipe = collective.recipe.omelette eggs = ${instance:eggs} ${buildout:test-eggs} diff --git a/src/plone/app/imagecropping/browser/configure.zcml b/src/plone/app/imagecropping/browser/configure.zcml index e910f9d7..80418eb3 100644 --- a/src/plone/app/imagecropping/browser/configure.zcml +++ b/src/plone/app/imagecropping/browser/configure.zcml @@ -2,6 +2,7 @@ xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser" xmlns:i18n="http://xml.zope.org/namespaces/i18n" + xmlns:zcml="http://namespaces.zope.org/zcml" i18n_domain="plone"> @@ -43,4 +44,12 @@ permission="cmf.ModifyPortalContent" /> + + diff --git a/src/plone/app/imagecropping/browser/crop.py b/src/plone/app/imagecropping/browser/crop.py index b18e61ac..ec77c013 100644 --- a/src/plone/app/imagecropping/browser/crop.py +++ b/src/plone/app/imagecropping/browser/crop.py @@ -25,7 +25,6 @@ def _crop(self, fieldname, scale, box, interface=None): """switch between dexterity and Archetypes """ croputils = IImageCroppingUtils(self.context) - field = croputils.get_image_field(fieldname) data = croputils.get_image_data(fieldname) original_file = StringIO(data) @@ -38,7 +37,7 @@ def _crop(self, fieldname, scale, box, interface=None): cropped_image_file.seek(0) croputils.save_cropped( - fieldname, field, scale, cropped_image_file, interface) + fieldname, scale, cropped_image_file, interface) # store crop information in annotations self._store(fieldname, scale, box) diff --git a/src/plone/app/imagecropping/browser/editor.py b/src/plone/app/imagecropping/browser/editor.py index 83cd4b9a..31406097 100644 --- a/src/plone/app/imagecropping/browser/editor.py +++ b/src/plone/app/imagecropping/browser/editor.py @@ -154,10 +154,6 @@ def _crop(self): scale=scale_name, box=(x1, y1, x2, y2), interface=self.interface) - # Avoid browser cache - # an empty call of setModificationDate uses current timestamp - self.context.setModificationDate() - self.context.reindexObject() def __call__(self): form = self.request.form diff --git a/src/plone/app/imagecropping/browser/scaling.py b/src/plone/app/imagecropping/browser/scaling.py new file mode 100644 index 00000000..46132f98 --- /dev/null +++ b/src/plone/app/imagecropping/browser/scaling.py @@ -0,0 +1,17 @@ +from zope.annotation.interfaces import IAnnotations + +from plone.app.imagecropping import PAI_STORAGE_KEY +from plone.app.imaging.scaling import ImageScaling as BaseImageScaling + + +class ImageScaling(BaseImageScaling): + + def modified(self): + cropped = IAnnotations(self.context).get(PAI_STORAGE_KEY) + if not cropped: + return super(ImageScaling, self).modified() + else: + return 1 + + +# XXX need this for plone.namedfile and NEWSItem too diff --git a/src/plone/app/imagecropping/interfaces.py b/src/plone/app/imagecropping/interfaces.py index 9b22f993..8882a0d7 100644 --- a/src/plone/app/imagecropping/interfaces.py +++ b/src/plone/app/imagecropping/interfaces.py @@ -30,7 +30,7 @@ def get_image_size(fieldname, interface): (100, 200) """ - def save_cropped(fieldname, field, scale, image_file, interface=None): + def save_cropped(fieldname, scale, image_file, interface=None): """ Save the cropped iamge under the name of the selected scale in plone.scale.storage.AnnotationStorage, so that it is available in plone.app.imaging @@images view diff --git a/src/plone/app/imagecropping/tests/test_cropping.py b/src/plone/app/imagecropping/tests/test_cropping.py index 36dfc731..bd019ae8 100644 --- a/src/plone/app/imagecropping/tests/test_cropping.py +++ b/src/plone/app/imagecropping/tests/test_cropping.py @@ -117,3 +117,24 @@ def test_image_formats(self): # XXX: fixme # self.assertEqual(open(croppedData).format, 'JPEG', # "cropped scale does not have same format as the original") + + def test_modify_context(self): + """ See https://github.com/collective/plone.app.imagecropping/issues/21 + """ + + view = self.img.restrictedTraverse('@@crop-image') + traverse = self.portal.REQUEST.traverseName + scales = traverse(self.img, '@@images') + unscaled_thumb = scales.scale('image', 'thumb') + + # store cropped version for thumb and check if the result + # is a square now + view._crop(fieldname='image', scale='thumb', box=(14, 14, 218, 218)) + thumb = scales.scale('image', 'thumb') + self.failIfEqual(thumb.data, unscaled_thumb.data) + + self.img.setTitle('A new title') + self.img.reindexObject() + + thumb2 = scales.scale('image', 'thumb') + self.assertEqual(thumb.data, thumb2.data) diff --git a/src/plone/app/imagecropping/tests/test_editor.py b/src/plone/app/imagecropping/tests/test_editor.py index 4917e819..4c439014 100644 --- a/src/plone/app/imagecropping/tests/test_editor.py +++ b/src/plone/app/imagecropping/tests/test_editor.py @@ -58,7 +58,8 @@ def test_singleimage_editorview(self): def test_editview_crop(self): request = self.layer['request'] - request.form.update({'x1': 1.0, 'y1': 2.7, 'x2': 10.6, 'y2': 8.4}) + request.form.update({'x1': 1.0, 'y1': 2.7, 'x2': 10.6, 'y2': 8.4, + 'scalename': 'mini'}) cropview = self.img.restrictedTraverse('@@croppingeditor') cropview._crop() diff --git a/src/plone/app/imagecropping/utils.py b/src/plone/app/imagecropping/utils.py index bd812913..203acbd2 100644 --- a/src/plone/app/imagecropping/utils.py +++ b/src/plone/app/imagecropping/utils.py @@ -82,9 +82,10 @@ def get_image_size(self, fieldname, interface=None): return image_size def save_cropped( - self, fieldname, field, scale, image_file, interface=None): + self, fieldname, scale, image_file, interface=None): """ see interface """ + field = self.get_image_field(fieldname) handler = IImageScaleHandler(field) sizes = field.getAvailableSizes(self.context) w, h = sizes[scale] @@ -104,6 +105,10 @@ def crop_factory(fieldname, direction='keep', **parameters): result.close() return blob, image_format, dimensions + # Avoid browser cache + # calling reindexObject updates the modified metadate too + self.context.reindexObject() + # call storage with actual time in milliseconds # this always invalidates old scales storage = AnnotationStorage(self.context, self.now_millis) @@ -162,7 +167,7 @@ def get_image_size(self, fieldname, interface=None): return image_size def save_cropped( - self, fieldname, field, scale, image_file, interface=None): + self, fieldname, scale, image_file, interface=None): """ see interface """ sizes = getAllowedSizes() @@ -173,6 +178,7 @@ def crop_factory(fieldname, **parameters): if result is not None: data, format, dimensions = result mimetype = 'image/%s' % format.lower() + field = self.get_image_field(fieldname) value = field.__class__( data, contentType=mimetype,