Browse Source

Add support for ico files

Jake Howard 1 year ago
parent
commit
a204baddc0

+ 1 - 0
CHANGELOG.txt

@@ -7,6 +7,7 @@ Changelog
  * Refine wording of page & collection privacy using password is a shared password and should not be used for secure content (Rohit Sharma, Jake Howard)
  * Add RelatedObjectsColumn to the table UI framework (Matt Westcott)
  * Reduce memory usage when rebuilding search indexes (Jake Howard)
+ * Support creating images in .ico format (Jake Howard)
  * Fix: Fix typo in `__str__` for MySQL search index (Jake Howard)
  * Fix: Ensure that unit tests correctly check for migrations in all core Wagtail apps (Matt Westcott)
  * Docs: Add contributing development documentation on how to work with a fork of Wagtail (Nix Asteri, Dan Braghis)

+ 1 - 0
docs/releases/6.1.md

@@ -16,6 +16,7 @@ depth: 1
  * Refine wording of page & collection privacy using password is a shared password and should not be used for secure content (Rohit Sharma, Jake Howard)
  * Add RelatedObjectsColumn to the table UI framework (Matt Westcott)
  * Reduce memory usage when rebuilding search indexes (Jake Howard)
+ * Support creating images in .ico format (Jake Howard)
 
 
 ### Bug fixes

+ 9 - 1
docs/topics/images.md

@@ -431,7 +431,7 @@ For example, to make the tag always convert the image to a JPEG, use `format-jpe
 {% image page.photo width-400 format-jpeg %}
 ```
 
-You may also use `format-png` or `format-gif`.
+You may also use `format-png`, `format-gif` or `format-ico`.
 
 ### Lossless AVIF and WebP
 
@@ -442,6 +442,14 @@ You can encode the image into lossless AVIF or WebP format by using `format-avif
 {% image page.photo width-400 format-webp-lossless %}
 ```
 
+### Favicon generation
+
+You can save images as a `.ico` file using `format-ico`, which is especially useful when managing a site's favicon through the Admin.
+
+```html+django
+<link rel="icon" href="{% image favicon_image format-ico %}" />
+```
+
 (image_background_colour)=
 
 ## Background color

+ 1 - 1
setup.py

@@ -29,7 +29,7 @@ install_requires = [
     "draftjs_exporter>=2.1.5,<6.0",
     "Pillow>=9.1.0,<11.0.0",
     "beautifulsoup4>=4.8,<4.13",
-    "Willow[heif]>=1.6.2,<2",
+    "Willow[heif]>=1.8.0,<2",
     "requests>=2.11.1,<3.0",
     "l18n>=2018.5",
     "openpyxl>=3.0.10,<4.0",

+ 2 - 0
wagtail/images/fields.py

@@ -205,5 +205,7 @@ def image_format_name_to_content_type(image_format_name):
         return "image/webp"
     elif image_format_name == "avif":
         return "image/avif"
+    elif image_format_name == "ico":
+        return "image/x-icon"
     else:
         raise ValueError("Unknown image format name")

+ 1 - 1
wagtail/images/image_operations.py

@@ -409,7 +409,7 @@ class WebPQualityOperation(FilterOperation):
 
 
 class FormatOperation(FilterOperation):
-    supported_formats = ["jpeg", "png", "gif", "webp", "avif"]
+    supported_formats = ["jpeg", "png", "gif", "webp", "avif", "ico"]
 
     def construct(self, format, *options):
         self.format = format

+ 2 - 0
wagtail/images/models.py

@@ -1033,6 +1033,8 @@ class Filter:
                 return willow.save_as_avif(output, quality=quality)
             elif output_format == "svg":
                 return willow.save_as_svg(output)
+            elif output_format == "ico":
+                return willow.save_as_ico(output)
             raise UnknownOutputImageFormatError(
                 f"Unknown output image format '{output_format}'"
             )

+ 10 - 0
wagtail/images/tests/test_image_operations.py

@@ -683,6 +683,16 @@ class TestFormatFilter(TestCase):
 
         self.assertEqual(out.format_name, "webp")
 
+    def test_ico(self):
+        fil = Filter(spec="width-400|format-ico")
+        image = Image.objects.create(
+            title="Test image",
+            file=get_test_image_file(),
+        )
+        out = fil.run(image, BytesIO())
+
+        self.assertEqual(out.format_name, "ico")
+
     def test_webp_lossless(self):
         fil = Filter(spec="width-400|format-webp-lossless")
         image = Image.objects.create(