[Products.Silva][Sylvain Viollon] Fix various image issues.

[email protected] Tue, 17 Sep 2013 11:48:03 +0200
Newsgroups gmane.comp.web.zope.silva.cvs
Message-ID <[email protected]>
author:    Sylvain Viollon
date:      Tue Sep 17 11:48:00 2013 +0200
revision:  11859:d88cd4ce0728 in Products.Silva
branch:    2.4
details:   https://hg.infrae.com/Products.Silva?cmd=changeset;node=d88cd4ce0728
modified:  Products/Silva/Image/content.py Products/Silva/Image/smi.py Products/Silva/Image/smi_templates/infoportlet.cpt Products/Silva/tests/test_image.py Products/Silva/tests/test_image_utils.py
added:     
removed:   
log:       Fix various image issues.


diffstat:

 Products/Silva/Image/content.py                    |  83 ++++++++++-----------
 Products/Silva/Image/smi.py                        |  31 +++----
 Products/Silva/Image/smi_templates/infoportlet.cpt |  37 +++++---
 Products/Silva/tests/test_image.py                 |  20 +++-
 Products/Silva/tests/test_image_utils.py           |   7 +
 5 files changed, 97 insertions(+), 81 deletions(-)

diffs (335 lines):

diff -r 25cf922b3707 -r d88cd4ce0728 Products/Silva/Image/content.py
--- a/Products/Silva/Image/content.py	Mon Sep 02 14:52:31 2013 +0200
+++ b/Products/Silva/Image/content.py	Tue Sep 17 11:48:00 2013 +0200
@@ -96,8 +96,6 @@
 class ImageFile(object):
 
     def __init__(self, image):
-        if image is None:
-            raise ValueError("Missing image.")
         self._fd = image.get_file_fd()
         self._changed = False
         try:
@@ -274,28 +272,31 @@
 
         Automaticaly updates cached web presentation image.
         """
-        update_cache = False
+        update = False
         if self.hires_image is None:
-            update_cache = True
+            update = True
             self.hires_image = self.image
             self.image = None
-        if web_format != 'unknown':
-            if self.web_format != web_format and \
-                    web_format in self.web_formats:
+
+        # Set web format.
+        if web_format not in ('unknown', '') and self.web_format != web_format:
+            if web_format in self.web_formats:
                 self.web_format = web_format
-                update_cache = True
+                update = True
+            else:
+                raise ValueError('Unknown image format %s' % web_format)
         # check if web_scale can be parsed:
         self.get_canonical_web_scale(web_scale)
         if self.web_scale != web_scale:
-            update_cache = True
             self.web_scale = web_scale
+            update = True
         # check if web_crop can be parsed:
         self.get_crop_box(web_crop)
         if self.web_crop != web_crop:
-            update_cache = True
             # if web_crop is None it should be replaced by an empty string
             self.web_crop = web_crop and web_crop or ''
-        if self.hires_image is not None and update_cache:
+            update = True
+        if update and self.hires_image is not None:
             self._create_derived_images()
 
     security.declareProtected(
@@ -320,26 +321,25 @@
     def get_image(self, hires=True, webformat=False):
         """Return image data.
         """
-        image = None
         if hires:
-            # You want hires
-            image = self.hires_image
-            if webformat and image is not None:
-                # Hires in webformat
-                with ImageFile(image) as working:
-                    data = working.save(self.web_format)
-                if data is not None:
-                    return data.getvalue()
-        else:
-            # Resized version
+            if self.hires_image is not None:
+                if webformat:
+                    # Create web format of original image.
+                    with ImageFile(self.hires_image) as working:
+                        data = working.save(self.web_format)
+                    if data is not None:
+                        return data.getvalue()
+                # Original format of the original image is the orginal.
+                return self.hires_image.get_file()
+            return None
+        if self.image is not None:
             if webformat:
-                image = self.image
-            else:
-                raise ValueError(
-                    _(u"Low resolution image in original format is "
-                      u"not supported"))
-        if image is not None:
-            return image.get_file()
+                # Webformat of the cropped/resized image is already computed.
+                return self.image.get_file()
+            # Original format of the cropped/resize image is not possible.
+            raise ValueError(
+                _(u"Low resolution image in original format is "
+                  u"not supported"))
         return None
 
     security.declareProtected(SilvaPermissions.View, 'get_canonical_web_scale')
@@ -584,11 +584,6 @@
                 self._image_factory('image', image_io, content_type)
             else:
                 self.image = self.hires_image
-        except ValueError as error:
-            logger.error("Web presentation creation failed for %s with %s" %
-                        ('/'.join(self.getPhysicalPath()), str(error)))
-            self.image = self.hires_image
-            return
         except IOError as error:
             logger.error("Web presentation creation failed for %s with %s" %
                         ('/'.join(self.getPhysicalPath()), str(error)))
@@ -596,6 +591,11 @@
                 self.image = self.hires_image
                 return
             raise ValueError(str(error))
+        except ValueError as error:
+            logger.error("Web presentation creation failed for %s with %s" %
+                        ('/'.join(self.getPhysicalPath()), str(error)))
+            self.image = self.hires_image
+            return
 
     def _create_thumbnail(self):
         try:
@@ -605,14 +605,14 @@
             if thumb:
                 content_type = self._web2ct[self.web_format]
                 self._image_factory('thumbnail_image', thumb, content_type)
-        except IOError, e:
+        except IOError as error:
             logger.info("Thumbnail creation failed for %s with %s" %
-                        ('/'.join(self.getPhysicalPath()), str(e)))
-            if str(e.args[0]) == "cannot read interlaced PNG files":
+                        ('/'.join(self.getPhysicalPath()), str(error)))
+            if str(error.args[0]) == "cannot read interlaced PNG files":
                 self.thumbnail_image = None
                 return
             else:
-                raise ValueError(str(e))
+                raise ValueError(str(error))
         except ValueError, e:
             logger.info("Thumbnail creation failed for %s with %s" %
                         ('/'.join(self.getPhysicalPath()), str(e)))
@@ -621,18 +621,13 @@
             return
 
     def _image_factory(self, identifier, stream, content_type=None):
-        service_files = getUtility(IFilesService)
-        new_image = service_files.new_file(identifier)
+        new_image = getUtility(IFilesService).new_file(identifier)
         setattr(self, identifier, new_image)
         new_image = getattr(self, identifier)
         new_image.set_file(stream, content_type)
         getUtility(IMimeTypeClassifier).guess_filename(new_image, self.getId())
         return new_image
 
-    def _image_is_hires(self):
-        return (self.image is not None and
-                self.image.aq_base is self.hires_image.aq_base)
-
 
 InitializeClass(Image)
 
diff -r 25cf922b3707 -r d88cd4ce0728 Products/Silva/Image/smi.py
--- a/Products/Silva/Image/smi.py	Mon Sep 02 14:52:31 2013 +0200
+++ b/Products/Silva/Image/smi.py	Tue Sep 17 11:48:00 2013 +0200
@@ -133,30 +133,27 @@
     grok.order(10)
 
     def update(self):
-        self.format = self.context.web_format.lower()
+        self.thumbnail = None
         self.dimensions = None
-        try:
-            dimensions = self.context.get_dimensions()
+        self.original_available = False
+        self.original_dimensions = None
+        self.web_format = self.context.web_format.lower()
+        dimensions = self.context.get_dimensions(hires=False)
+        if dimensions != (0, 0):
             self.dimensions = dict(zip(['width', 'height'], dimensions))
-        except ValueError:
-            dimensions = None
-        self.scaling = None
+
         if self.context.hires_image is not None:
-            try:
-                scaled_dimensions = self.context.get_canonical_web_scale()
-                if scaled_dimensions != dimensions:
-                    self.scaling = dict(
-                        zip(['width', 'height'], scaled_dimensions))
-            except ValueError:
-                scaled_dimensions = None
-        self.thumbnail = None
+            self.original_available = True
+            original_dimensions = self.context.get_dimensions(hires=True)
+            if original_dimensions not in (dimensions, (0, 0)):
+                self.original_dimensions = dict(
+                    zip(['width', 'height'], original_dimensions))
+
         if self.context.thumbnail_image:
             self.thumbnail = self.context.tag(request=self.request,
                                               preview=True,
                                               thumbnail=True)
-        self.original = self.context.url(request=self.request,
-                                         preview=True,
-                                         hires=True)
+
         self.orientation = self.context.get_orientation()
         self.orientation_cls = unicode(self.orientation)
 
diff -r 25cf922b3707 -r d88cd4ce0728 Products/Silva/Image/smi_templates/infoportlet.cpt
--- a/Products/Silva/Image/smi_templates/infoportlet.cpt	Mon Sep 02 14:52:31 2013 +0200
+++ b/Products/Silva/Image/smi_templates/infoportlet.cpt	Tue Sep 17 11:48:00 2013 +0200
@@ -2,7 +2,7 @@
      i18n:domain="silva">
   <h4 i18n:translate="">Format</h4>
   <p i18n:translate="">
-    <span i18n:name="format" tal:replace="viewlet.format" /> image
+    <span i18n:name="format" tal:replace="viewlet.web_format" /> image
   </p>
 
   <h4 i18n:translate="">Dimensions</h4>
@@ -10,11 +10,9 @@
      i18n:translate="">
     unknown
   </p>
-  <p tal:condition="viewlet.dimensions">
-    <!-- Template is not properly indented to prevent a spaces before 'x' and '.' -->
-    <tal:original i18n:translate="">
-      <span tal:replace="viewlet.dimensions.width" i18n:name="width"/>x<span tal:replace="viewlet.dimensions.height" i18n="height" /> pixels</tal:original><tal:scaled tal:condition="viewlet.scaling" i18n:translate="">
-      scaled to <span tal:replace="viewlet.scaling.width" i18n:name="width"/>x<span tal:replace="viewlet.scaling.height" i18n="height" /> pixels</tal:scaled>
+  <!-- Template is not properly indented to prevent a spaces before 'x'-->
+  <p tal:condition="viewlet.dimensions" i18n:translate="">
+    <span tal:replace="viewlet.dimensions.width" i18n:name="width"/>x<span tal:replace="viewlet.dimensions.height" i18n="height" /> pixels
   </p>
 
   <tal:thumbnail tal:condition="viewlet.thumbnail">
@@ -24,15 +22,24 @@
     </p>
   </tal:thumbnail>
 
-  <h4 i18n:translate="">Original</h4>
-  <div class="external-controls">
-    <a title="View the original image"
-       class="open-screen form-button ui-state-default" rel="preview/hires"
-       i18n:attributes="title">
-      <ins class="ui-icon ui-icon-search"></ins>
-      <tal:msg i18n:translate="">View unscaled image</tal:msg>
-    </a>
-  </div>
+  <tal:original tal:condition="viewlet.original_available">
+    <h4 i18n:translate="">Original</h4>
+    <!-- Template is not properly indented to prevent a spaces before 'x'-->
+    <p tal:condition="viewlet.original_dimensions" i18n:translate="">
+      Original dimensions are <span tal:replace="viewlet.original_dimensions.width" i18n:name="width"/>x<span tal:replace="viewlet.original_dimensions.height" i18n="height" /> pixels.
+    </p>
+    <p tal:condition="not: viewlet.original_dimensions" i18n:translate="">
+      Original image is not resized or cropped.
+    </p>
+    <div class="external-controls">
+      <a title="View the original image"
+         class="open-screen form-button ui-state-default" rel="preview/hires"
+         i18n:attributes="title">
+        <ins class="ui-icon ui-icon-search"></ins>
+        <tal:msg i18n:translate="">View unscaled image</tal:msg>
+      </a>
+    </div>
+  </tal:original>
 
   <h4 i18n:translate="">Orientation</h4>
   <p>
diff -r 25cf922b3707 -r d88cd4ce0728 Products/Silva/tests/test_image.py
--- a/Products/Silva/tests/test_image.py	Mon Sep 02 14:52:31 2013 +0200
+++ b/Products/Silva/tests/test_image.py	Tue Sep 17 11:48:00 2013 +0200
@@ -58,7 +58,7 @@
     def test_image(self):
         """Test image content.
         """
-        image = self.root.test_image
+        image = self.root._getOb('test_image')
         self.assertTrue(verifyObject(interfaces.IAsset, image))
         self.assertTrue(verifyObject(interfaces.IImage, image))
         self.assertNotEqual(image.get_modification_datetime(), None)
@@ -71,14 +71,13 @@
         self.assertEquals(image.get_mime_type(), 'image/tiff')
 
         # Image methods
+        self.assertTrue(image.tag() is not None)
         self.assertEquals(image.get_format(), 'TIFF')
         self.assertEquals(image.get_web_format(), 'JPEG')
         self.assertEquals(image.get_dimensions(), (960, 1280))
         self.assertEquals(str(image.get_orientation()), "portrait")
+
         image.set_web_presentation_properties('JPEG', '100x100', '')
-        with self.assertRaises(ValueError):
-            image.get_image(hires=False, webformat=False)
-        self.assertTrue(image.tag() is not None)
         self.assertEquals(image.get_web_format(), 'JPEG')
 
         data = io.BytesIO(image.get_image(hires=False, webformat=True))
@@ -94,7 +93,18 @@
         self.assertEquals((960, 1280), pil_image.size)
         self.assertEquals('JPEG', pil_image.format)
 
-    def test_upload_image_with_existing_id(self):
+        with self.assertRaises(ValueError) as error:
+            image.get_image(hires=False, webformat=False)
+        self.assertEquals(
+            str(error.exception),
+            'Low resolution image in original format is not supported')
+
+    def test_set_web_presentation_properties(self):
+        """Test set web presentation.
+        """
+        image = self.root._getOb('test_image')
+
+    def test_add_image_with_existing_id(self):
         with Transaction():
             with self.layer.open_fixture('photo.tif') as image:
                 factory = self.root.manage_addProduct['Silva']
diff -r 25cf922b3707 -r d88cd4ce0728 Products/Silva/tests/test_image_utils.py
--- a/Products/Silva/tests/test_image_utils.py	Mon Sep 02 14:52:31 2013 +0200
+++ b/Products/Silva/tests/test_image_utils.py	Tue Sep 17 11:48:00 2013 +0200
@@ -15,6 +15,13 @@
 
 class ImageUtilsTestCase(unittest.TestCase):
 
+    def test_size(self):
+        """Test Size.
+        """
+        size = Size(10, 10)
+        self.assertEqual(size, (10, 10)) # You can compare it to a tuple.
+        self.assertNotEqual(size, (15, 10))
+
     def test_percentresizespec(self):
         """Test PercentResizeSpec used to express a resize specification.
         """