kopia lustrzana https://github.com/wagtail/wagtail
				
				
				
			Handle preserve-svg within AbstractImage.get_renditions
							rodzic
							
								
									12b77ac51d
								
							
						
					
					
						commit
						94dbe5f02b
					
				|  | @ -54,6 +54,8 @@ The return value is a dictionary of renditions keyed by the specifications that | |||
| } | ||||
| ``` | ||||
| 
 | ||||
| If any specification contains the `preserve-svg` directive, the resulting dictionary key will be the final filter specification used for the rendition (omitting the `preserve-svg` directive, and any non-SVG-safe operations in the case that the image is an SVG) rather than the one originally passed. This may result in multiple specifications in the list resolving to the same final value - for example, if the list contains `width-400|format-jpeg|preserve-svg` and `width-400|format-webp|preserve-svg`, these will both reduce to `width-400` when applied to an SVG image. In this case, the return value will have fewer items than the original list. | ||||
| 
 | ||||
| (caching_image_renditions)= | ||||
| 
 | ||||
| ## Caching image renditions | ||||
|  |  | |||
|  | @ -501,6 +501,31 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode | |||
|         except AttributeError: | ||||
|             pass | ||||
| 
 | ||||
|     def clean_filter_for_svg(self, filter: Filter) -> Filter: | ||||
|         """ | ||||
|         Given a Filter object, check if its spec contains a 'preserve-svg' directive. If so, | ||||
|         remove it from the spec (along with any rasterising operations, in the case that this | ||||
|         image is an SVG) and return a new Filter object with the cleaned spec. | ||||
|         """ | ||||
|         spec_elements = filter.spec.split("|") | ||||
|         if "preserve-svg" in spec_elements: | ||||
|             # remove 'preserve-svg' from filter specs for all image types | ||||
|             clean_spec = "|".join( | ||||
|                 item for item in spec_elements if item != "preserve-svg" | ||||
|             ) | ||||
|             if not clean_spec: | ||||
|                 # no formatting directives were included in filter | ||||
|                 raise InvalidFilterSpecError( | ||||
|                     "Filter should include at least one formatting directive other than 'preserve-svg'" | ||||
|                 ) | ||||
|             if self.is_svg(): | ||||
|                 # remove rasterizing directives | ||||
|                 clean_spec = to_svg_safe_spec(clean_spec) | ||||
| 
 | ||||
|             return Filter(spec=clean_spec) | ||||
| 
 | ||||
|         return filter | ||||
| 
 | ||||
|     def get_rendition(self, filter: Filter | str) -> AbstractRendition: | ||||
|         """ | ||||
|         Returns a ``Rendition`` instance with a ``file`` field value (an | ||||
|  | @ -519,22 +544,7 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode | |||
|                 "Unrecognised filter format - string or Filter instance expected" | ||||
|             ) | ||||
| 
 | ||||
|         spec_elements = filter.spec.split("|") | ||||
|         if "preserve-svg" in spec_elements: | ||||
|             # remove 'preserve-svg' from filter specs for all image types | ||||
|             clean_spec = "|".join( | ||||
|                 item for item in spec_elements if item != "preserve-svg" | ||||
|             ) | ||||
|             if not clean_spec: | ||||
|                 # no formatting directives were included in filter | ||||
|                 raise InvalidFilterSpecError( | ||||
|                     "Filter should include at least one formatting directive other than 'preserve-svg'" | ||||
|                 ) | ||||
|             if self.is_svg(): | ||||
|                 # remove rasterizing directives | ||||
|                 clean_spec = to_svg_safe_spec(clean_spec) | ||||
| 
 | ||||
|             filter = Filter(spec=clean_spec) | ||||
|         filter = self.clean_filter_for_svg(filter) | ||||
| 
 | ||||
|         try: | ||||
|             rendition = self.find_existing_rendition(filter) | ||||
|  | @ -599,12 +609,17 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode | |||
|         model will be returned. | ||||
|         """ | ||||
|         Rendition = self.get_rendition_model() | ||||
|         # We don’t support providing mixed Filter and string arguments in the same call. | ||||
|         if isinstance(filters[0], str): | ||||
|             filters = [Filter(spec) for spec in dict.fromkeys(filters).keys()] | ||||
| 
 | ||||
|         clean_filters = [] | ||||
|         for filter in filters: | ||||
|             if isinstance(filter, str): | ||||
|                 filter = Filter(spec=filter) | ||||
| 
 | ||||
|             filter = self.clean_filter_for_svg(filter) | ||||
|             clean_filters.append(filter) | ||||
| 
 | ||||
|         # Remove duplicate filters from the list while preserving order | ||||
|         filters = list(dict.fromkeys(filters)) | ||||
|         filters = list(dict.fromkeys(clean_filters)) | ||||
| 
 | ||||
|         # Find existing renditions where possible | ||||
|         renditions = self.find_existing_renditions(*filters) | ||||
|  |  | |||
|  | @ -1013,6 +1013,47 @@ class TestRenditions(TestCase): | |||
|         with self.assertRaises(AttributeError): | ||||
|             self.svg_image.get_rendition(Filter("width-400|bgcolor-000|format-jpeg")) | ||||
| 
 | ||||
|     def test_image_get_renditions_preserve_svg(self): | ||||
|         renditions = self.image.get_renditions( | ||||
|             "width-400|bgcolor-000|format-jpeg|preserve-svg", | ||||
|             "width-200|bgcolor-000|format-jpeg|preserve-svg", | ||||
|         ) | ||||
|         filename1 = get_test_image_filename( | ||||
|             self.image, "width-400.bgcolor-000.format-jpeg" | ||||
|         ) | ||||
|         filename2 = get_test_image_filename( | ||||
|             self.image, "width-200.bgcolor-000.format-jpeg" | ||||
|         ) | ||||
| 
 | ||||
|         # no directives stripped except 'preserve-svg' | ||||
|         # (which is stripped from both the dictionary key and the resulting rendition) | ||||
|         self.assertEqual( | ||||
|             renditions["width-400|bgcolor-000|format-jpeg"].filter_spec, | ||||
|             "width-400|bgcolor-000|format-jpeg", | ||||
|         ) | ||||
|         self.assertEqual(renditions["width-400|bgcolor-000|format-jpeg"].url, filename1) | ||||
| 
 | ||||
|         self.assertEqual( | ||||
|             renditions["width-200|bgcolor-000|format-jpeg"].filter_spec, | ||||
|             "width-200|bgcolor-000|format-jpeg", | ||||
|         ) | ||||
|         self.assertEqual(renditions["width-200|bgcolor-000|format-jpeg"].url, filename2) | ||||
| 
 | ||||
|     def test_svg_get_renditions_preserve_svg(self): | ||||
|         renditions = self.svg_image.get_renditions( | ||||
|             "width-400|bgcolor-000|format-jpeg|preserve-svg", | ||||
|             "width-200|bgcolor-000|format-jpeg|preserve-svg", | ||||
|         ) | ||||
|         filename1 = get_test_image_filename(self.svg_image, "width-400") | ||||
|         filename2 = get_test_image_filename(self.svg_image, "width-200") | ||||
| 
 | ||||
|         # all non-SVG-safe directives stripped (from both the dictionary key and the resulting rendition) | ||||
|         self.assertEqual(renditions["width-400"].filter_spec, "width-400") | ||||
|         self.assertEqual(renditions["width-400"].url, filename1) | ||||
| 
 | ||||
|         self.assertEqual(renditions["width-200"].filter_spec, "width-200") | ||||
|         self.assertEqual(renditions["width-200"].url, filename2) | ||||
| 
 | ||||
| 
 | ||||
| @override_settings( | ||||
|     CACHES={"default": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"}} | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Matt Westcott
						Matt Westcott