We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Nightly] Image upload broken for some images
### Issue Summary

In the current Nightly version, it is no longer possible for me to upload an image. Maybe it is already known or fixed, but I preferred to report it.

```text
Internal Server Error: /admin/images/multiple/add/
Traceback (most recent call last):
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/views/decorators/cache.py", line 62, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/urls/__init__.py", line 170, in wrapper
    return view_func(request, *args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/auth.py", line 205, in decorated_view
    return view_func(request, *args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/utils/decorators.py", line 46, in _wrapper
    return bound_method(*args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/views/decorators/vary.py", line 21, in inner_func
    response = func(*args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/views/generic/multiple_upload.py", line 44, in dispatch
    return super().dispatch(request)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/views/generic/permissions.py", line 36, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/views/generic/base.py", line 142, in dispatch
    return handler(request, *args, **kwargs)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/views/generic/multiple_upload.py", line 144, in post
    if form.is_valid():
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py", line 205, in is_valid
    return self.is_bound and not self.errors
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py", line 200, in errors
    self.full_clean()
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py", line 437, in full_clean
    self._clean_fields()
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py", line 447, in _clean_fields
    value = field.clean(value, bf.initial)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/fields.py", line 678, in clean
    return super().clean(data)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/fields.py", line 198, in clean
    value = self.to_python(value)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/images/fields.py", line 156, in to_python
    self.check_image_pixel_size(f)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/images/fields.py", line 107, in check_image_pixel_size
    width, height = f.image.get_size()
  File "/wagtailNightly/.env/lib/python3.10/site-packages/willow/image.py", line 78, in wrapper
    image = converter(image)
  File "/wagtailNightly/.env/lib/python3.10/site-packages/willow/plugins/pillow.py", line 248, in open
    image_file.f.seek(0)
AttributeError: 'str' object has no attribute 'seek'
[01/Nov/2022 10:28:08] "POST /admin/images/multiple/add/ HTTP/1.1" 500 150299
```

### Steps to Reproduce

1. Start a new project with `wagtail start myproject`
2. Install the nightly version `pip install https://releases.wagtail.org/nightly/dist/wagtail-4.2.dev20221101-py3-none-any.whl`
3. Start the server and open the wagtail admin interface
4. Click on `Images` in the left sidebar
5. Upload an image

Any other relevant information. For example, why do you consider this a bug and what did you expect to happen instead?

-   I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: yes

### Technical details

-   Python version: 3.10.8
-   Django version: 4.1.1
-   Wagtail version: 4.2.dev20221101
-   Browser version: Firefox 106 and Chrome 107


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wagtail/images/fields.py`
Content:
```
1 import os
2 from io import BytesIO
3 
4 import willow
5 from django.conf import settings
6 from django.core.exceptions import ValidationError
7 from django.core.validators import FileExtensionValidator
8 from django.forms.fields import FileField, ImageField
9 from django.template.defaultfilters import filesizeformat
10 from django.utils.translation import gettext_lazy as _
11 
12 ALLOWED_EXTENSIONS = ["gif", "jpg", "jpeg", "png", "webp"]
13 SUPPORTED_FORMATS_TEXT = _("GIF, JPEG, PNG, WEBP")
14 
15 
16 class WagtailImageField(ImageField):
17     default_validators = [FileExtensionValidator(ALLOWED_EXTENSIONS)]
18 
19     def __init__(self, *args, **kwargs):
20         super().__init__(*args, **kwargs)
21 
22         # Get max upload size from settings
23         self.max_upload_size = getattr(
24             settings, "WAGTAILIMAGES_MAX_UPLOAD_SIZE", 10 * 1024 * 1024
25         )
26         self.max_image_pixels = getattr(
27             settings, "WAGTAILIMAGES_MAX_IMAGE_PIXELS", 128 * 1000000
28         )
29         max_upload_size_text = filesizeformat(self.max_upload_size)
30 
31         # Help text
32         if self.max_upload_size is not None:
33             self.help_text = _(
34                 "Supported formats: %(supported_formats)s. Maximum filesize: %(max_upload_size)s."
35             ) % {
36                 "supported_formats": SUPPORTED_FORMATS_TEXT,
37                 "max_upload_size": max_upload_size_text,
38             }
39         else:
40             self.help_text = _("Supported formats: %(supported_formats)s.") % {
41                 "supported_formats": SUPPORTED_FORMATS_TEXT,
42             }
43 
44         # Error messages
45         self.error_messages["invalid_image_extension"] = (
46             _("Not a supported image format. Supported formats: %s.")
47             % SUPPORTED_FORMATS_TEXT
48         )
49 
50         self.error_messages["invalid_image_known_format"] = _(
51             "Not a valid .%s image. The extension does not match the file format (%s)"
52         )
53 
54         self.error_messages["file_too_large"] = (
55             _("This file is too big (%%s). Maximum filesize %s.") % max_upload_size_text
56         )
57 
58         self.error_messages["file_too_many_pixels"] = (
59             _("This file has too many pixels (%%s). Maximum pixels %s.")
60             % self.max_image_pixels
61         )
62 
63         self.error_messages["file_too_large_unknown_size"] = (
64             _("This file is too big. Maximum filesize %s.") % max_upload_size_text
65         )
66 
67     def check_image_file_format(self, f):
68         # Check file extension
69         extension = os.path.splitext(f.name)[1].lower()[1:]
70 
71         if extension not in ALLOWED_EXTENSIONS:
72             raise ValidationError(
73                 self.error_messages["invalid_image_extension"],
74                 code="invalid_image_extension",
75             )
76 
77         if extension == "jpg":
78             extension = "jpeg"
79 
80         # Check that the internal format matches the extension
81         # It is possible to upload PSD files if their extension is set to jpg, png or gif. This should catch them out
82         if extension != f.image.format_name:
83             raise ValidationError(
84                 self.error_messages["invalid_image_known_format"]
85                 % (extension, f.image.format_name),
86                 code="invalid_image_known_format",
87             )
88 
89     def check_image_file_size(self, f):
90         # Upload size checking can be disabled by setting max upload size to None
91         if self.max_upload_size is None:
92             return
93 
94         # Check the filesize
95         if f.size > self.max_upload_size:
96             raise ValidationError(
97                 self.error_messages["file_too_large"] % (filesizeformat(f.size),),
98                 code="file_too_large",
99             )
100 
101     def check_image_pixel_size(self, f):
102         # Upload pixel size checking can be disabled by setting max upload pixel to None
103         if self.max_image_pixels is None:
104             return
105 
106         # Check the pixel size
107         width, height = f.image.get_size()
108         frames = f.image.get_frame_count()
109         num_pixels = width * height * frames
110 
111         if num_pixels > self.max_image_pixels:
112             raise ValidationError(
113                 self.error_messages["file_too_many_pixels"] % (num_pixels),
114                 code="file_too_many_pixels",
115             )
116 
117     def to_python(self, data):
118         """
119         Check that the file-upload field data contains a valid image (GIF, JPG,
120         PNG, etc. -- whatever Willow supports). Overridden from ImageField to use
121         Willow instead of Pillow as the image library in order to enable SVG support.
122         """
123         f = FileField.to_python(self, data)
124         if f is None:
125             return None
126 
127         # We need to get a file object for Pillow. We might have a path or we might
128         # have to read the data into memory.
129         if hasattr(data, "temporary_file_path"):
130             file = data.temporary_file_path()
131         else:
132             if hasattr(data, "read"):
133                 file = BytesIO(data.read())
134             else:
135                 file = BytesIO(data["content"])
136 
137         try:
138             # Annotate the python representation of the FileField with the image
139             # property so subclasses can reuse it for their own validation
140             f.image = willow.Image.open(file)
141             f.content_type = image_format_name_to_content_type(f.image.format_name)
142 
143         except Exception as exc:
144             # Willow doesn't recognize it as an image.
145             raise ValidationError(
146                 self.error_messages["invalid_image"],
147                 code="invalid_image",
148             ) from exc
149 
150         if hasattr(f, "seek") and callable(f.seek):
151             f.seek(0)
152 
153         if f is not None:
154             self.check_image_file_size(f)
155             self.check_image_file_format(f)
156             self.check_image_pixel_size(f)
157 
158         return f
159 
160 
161 def image_format_name_to_content_type(image_format_name):
162     """
163     Convert a Willow image format name to a content type.
164     TODO: Replace once https://github.com/wagtail/Willow/pull/102 and
165           a new Willow release is out
166     """
167     if image_format_name == "svg":
168         return "image/svg+xml"
169     elif image_format_name == "jpeg":
170         return "image/jpeg"
171     elif image_format_name == "png":
172         return "image/png"
173     elif image_format_name == "gif":
174         return "image/gif"
175     elif image_format_name == "bmp":
176         return "image/bmp"
177     elif image_format_name == "tiff":
178         return "image/tiff"
179     elif image_format_name == "webp":
180         return "image/webp"
181     else:
182         raise ValueError("Unknown image format name")
183
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/wagtail/images/fields.py b/wagtail/images/fields.py
--- a/wagtail/images/fields.py
+++ b/wagtail/images/fields.py
@@ -124,10 +124,11 @@
         if f is None:
             return None
 
-        # We need to get a file object for Pillow. We might have a path or we might
-        # have to read the data into memory.
+        # We need to get a file object for Pillow. When we get a path, we need to open
+        # the file first. And we have to read the data into memory to pass to Willow.
         if hasattr(data, "temporary_file_path"):
-            file = data.temporary_file_path()
+            with open(data.temporary_file_path(), "rb") as fh:
+                file = BytesIO(fh.read())
         else:
             if hasattr(data, "read"):
                 file = BytesIO(data.read())

{"golden_diff": "diff --git a/wagtail/images/fields.py b/wagtail/images/fields.py\n--- a/wagtail/images/fields.py\n+++ b/wagtail/images/fields.py\n@@ -124,10 +124,11 @@\n         if f is None:\n             return None\n \n-        # We need to get a file object for Pillow. We might have a path or we might\n-        # have to read the data into memory.\n+        # We need to get a file object for Pillow. When we get a path, we need to open\n+        # the file first. And we have to read the data into memory to pass to Willow.\n         if hasattr(data, \"temporary_file_path\"):\n-            file = data.temporary_file_path()\n+            with open(data.temporary_file_path(), \"rb\") as fh:\n+                file = BytesIO(fh.read())\n         else:\n             if hasattr(data, \"read\"):\n                 file = BytesIO(data.read())\n", "issue": "[Nightly] Image upload broken for some images\n### Issue Summary\r\n\r\nIn the current Nightly version, it is no longer possible for me to upload an image. Maybe it is already known or fixed, but I preferred to report it.\r\n\r\n```text\r\nInternal Server Error: /admin/images/multiple/add/\r\nTraceback (most recent call last):\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/core/handlers/exception.py\", line 55, in inner\r\n    response = get_response(request)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/core/handlers/base.py\", line 197, in _get_response\r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/views/decorators/cache.py\", line 62, in _wrapped_view_func\r\n    response = view_func(request, *args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/urls/__init__.py\", line 170, in wrapper\r\n    return view_func(request, *args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/auth.py\", line 205, in decorated_view\r\n    return view_func(request, *args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/views/generic/base.py\", line 103, in view\r\n    return self.dispatch(request, *args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/utils/decorators.py\", line 46, in _wrapper\r\n    return bound_method(*args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/views/decorators/vary.py\", line 21, in inner_func\r\n    response = func(*args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/views/generic/multiple_upload.py\", line 44, in dispatch\r\n    return super().dispatch(request)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/views/generic/permissions.py\", line 36, in dispatch\r\n    return super().dispatch(request, *args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/views/generic/base.py\", line 142, in dispatch\r\n    return handler(request, *args, **kwargs)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/admin/views/generic/multiple_upload.py\", line 144, in post\r\n    if form.is_valid():\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py\", line 205, in is_valid\r\n    return self.is_bound and not self.errors\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py\", line 200, in errors\r\n    self.full_clean()\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py\", line 437, in full_clean\r\n    self._clean_fields()\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/forms.py\", line 447, in _clean_fields\r\n    value = field.clean(value, bf.initial)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/fields.py\", line 678, in clean\r\n    return super().clean(data)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/django/forms/fields.py\", line 198, in clean\r\n    value = self.to_python(value)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/images/fields.py\", line 156, in to_python\r\n    self.check_image_pixel_size(f)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/wagtail/images/fields.py\", line 107, in check_image_pixel_size\r\n    width, height = f.image.get_size()\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/willow/image.py\", line 78, in wrapper\r\n    image = converter(image)\r\n  File \"/wagtailNightly/.env/lib/python3.10/site-packages/willow/plugins/pillow.py\", line 248, in open\r\n    image_file.f.seek(0)\r\nAttributeError: 'str' object has no attribute 'seek'\r\n[01/Nov/2022 10:28:08] \"POST /admin/images/multiple/add/ HTTP/1.1\" 500 150299\r\n```\r\n\r\n### Steps to Reproduce\r\n\r\n1. Start a new project with `wagtail start myproject`\r\n2. Install the nightly version `pip install https://releases.wagtail.org/nightly/dist/wagtail-4.2.dev20221101-py3-none-any.whl`\r\n3. Start the server and open the wagtail admin interface\r\n4. Click on `Images` in the left sidebar\r\n5. Upload an image\r\n\r\nAny other relevant information. For example, why do you consider this a bug and what did you expect to happen instead?\r\n\r\n-   I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: yes\r\n\r\n### Technical details\r\n\r\n-   Python version: 3.10.8\r\n-   Django version: 4.1.1\r\n-   Wagtail version: 4.2.dev20221101\r\n-   Browser version: Firefox 106 and Chrome 107\r\n\n", "before_files": [{"content": "import os\nfrom io import BytesIO\n\nimport willow\nfrom django.conf import settings\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import FileExtensionValidator\nfrom django.forms.fields import FileField, ImageField\nfrom django.template.defaultfilters import filesizeformat\nfrom django.utils.translation import gettext_lazy as _\n\nALLOWED_EXTENSIONS = [\"gif\", \"jpg\", \"jpeg\", \"png\", \"webp\"]\nSUPPORTED_FORMATS_TEXT = _(\"GIF, JPEG, PNG, WEBP\")\n\n\nclass WagtailImageField(ImageField):\n    default_validators = [FileExtensionValidator(ALLOWED_EXTENSIONS)]\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n        # Get max upload size from settings\n        self.max_upload_size = getattr(\n            settings, \"WAGTAILIMAGES_MAX_UPLOAD_SIZE\", 10 * 1024 * 1024\n        )\n        self.max_image_pixels = getattr(\n            settings, \"WAGTAILIMAGES_MAX_IMAGE_PIXELS\", 128 * 1000000\n        )\n        max_upload_size_text = filesizeformat(self.max_upload_size)\n\n        # Help text\n        if self.max_upload_size is not None:\n            self.help_text = _(\n                \"Supported formats: %(supported_formats)s. Maximum filesize: %(max_upload_size)s.\"\n            ) % {\n                \"supported_formats\": SUPPORTED_FORMATS_TEXT,\n                \"max_upload_size\": max_upload_size_text,\n            }\n        else:\n            self.help_text = _(\"Supported formats: %(supported_formats)s.\") % {\n                \"supported_formats\": SUPPORTED_FORMATS_TEXT,\n            }\n\n        # Error messages\n        self.error_messages[\"invalid_image_extension\"] = (\n            _(\"Not a supported image format. Supported formats: %s.\")\n            % SUPPORTED_FORMATS_TEXT\n        )\n\n        self.error_messages[\"invalid_image_known_format\"] = _(\n            \"Not a valid .%s image. The extension does not match the file format (%s)\"\n        )\n\n        self.error_messages[\"file_too_large\"] = (\n            _(\"This file is too big (%%s). Maximum filesize %s.\") % max_upload_size_text\n        )\n\n        self.error_messages[\"file_too_many_pixels\"] = (\n            _(\"This file has too many pixels (%%s). Maximum pixels %s.\")\n            % self.max_image_pixels\n        )\n\n        self.error_messages[\"file_too_large_unknown_size\"] = (\n            _(\"This file is too big. Maximum filesize %s.\") % max_upload_size_text\n        )\n\n    def check_image_file_format(self, f):\n        # Check file extension\n        extension = os.path.splitext(f.name)[1].lower()[1:]\n\n        if extension not in ALLOWED_EXTENSIONS:\n            raise ValidationError(\n                self.error_messages[\"invalid_image_extension\"],\n                code=\"invalid_image_extension\",\n            )\n\n        if extension == \"jpg\":\n            extension = \"jpeg\"\n\n        # Check that the internal format matches the extension\n        # It is possible to upload PSD files if their extension is set to jpg, png or gif. This should catch them out\n        if extension != f.image.format_name:\n            raise ValidationError(\n                self.error_messages[\"invalid_image_known_format\"]\n                % (extension, f.image.format_name),\n                code=\"invalid_image_known_format\",\n            )\n\n    def check_image_file_size(self, f):\n        # Upload size checking can be disabled by setting max upload size to None\n        if self.max_upload_size is None:\n            return\n\n        # Check the filesize\n        if f.size > self.max_upload_size:\n            raise ValidationError(\n                self.error_messages[\"file_too_large\"] % (filesizeformat(f.size),),\n                code=\"file_too_large\",\n            )\n\n    def check_image_pixel_size(self, f):\n        # Upload pixel size checking can be disabled by setting max upload pixel to None\n        if self.max_image_pixels is None:\n            return\n\n        # Check the pixel size\n        width, height = f.image.get_size()\n        frames = f.image.get_frame_count()\n        num_pixels = width * height * frames\n\n        if num_pixels > self.max_image_pixels:\n            raise ValidationError(\n                self.error_messages[\"file_too_many_pixels\"] % (num_pixels),\n                code=\"file_too_many_pixels\",\n            )\n\n    def to_python(self, data):\n        \"\"\"\n        Check that the file-upload field data contains a valid image (GIF, JPG,\n        PNG, etc. -- whatever Willow supports). Overridden from ImageField to use\n        Willow instead of Pillow as the image library in order to enable SVG support.\n        \"\"\"\n        f = FileField.to_python(self, data)\n        if f is None:\n            return None\n\n        # We need to get a file object for Pillow. We might have a path or we might\n        # have to read the data into memory.\n        if hasattr(data, \"temporary_file_path\"):\n            file = data.temporary_file_path()\n        else:\n            if hasattr(data, \"read\"):\n                file = BytesIO(data.read())\n            else:\n                file = BytesIO(data[\"content\"])\n\n        try:\n            # Annotate the python representation of the FileField with the image\n            # property so subclasses can reuse it for their own validation\n            f.image = willow.Image.open(file)\n            f.content_type = image_format_name_to_content_type(f.image.format_name)\n\n        except Exception as exc:\n            # Willow doesn't recognize it as an image.\n            raise ValidationError(\n                self.error_messages[\"invalid_image\"],\n                code=\"invalid_image\",\n            ) from exc\n\n        if hasattr(f, \"seek\") and callable(f.seek):\n            f.seek(0)\n\n        if f is not None:\n            self.check_image_file_size(f)\n            self.check_image_file_format(f)\n            self.check_image_pixel_size(f)\n\n        return f\n\n\ndef image_format_name_to_content_type(image_format_name):\n    \"\"\"\n    Convert a Willow image format name to a content type.\n    TODO: Replace once https://github.com/wagtail/Willow/pull/102 and\n          a new Willow release is out\n    \"\"\"\n    if image_format_name == \"svg\":\n        return \"image/svg+xml\"\n    elif image_format_name == \"jpeg\":\n        return \"image/jpeg\"\n    elif image_format_name == \"png\":\n        return \"image/png\"\n    elif image_format_name == \"gif\":\n        return \"image/gif\"\n    elif image_format_name == \"bmp\":\n        return \"image/bmp\"\n    elif image_format_name == \"tiff\":\n        return \"image/tiff\"\n    elif image_format_name == \"webp\":\n        return \"image/webp\"\n    else:\n        raise ValueError(\"Unknown image format name\")\n", "path": "wagtail/images/fields.py"}], "after_files": [{"content": "import os\nfrom io import BytesIO\n\nimport willow\nfrom django.conf import settings\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import FileExtensionValidator\nfrom django.forms.fields import FileField, ImageField\nfrom django.template.defaultfilters import filesizeformat\nfrom django.utils.translation import gettext_lazy as _\n\nALLOWED_EXTENSIONS = [\"gif\", \"jpg\", \"jpeg\", \"png\", \"webp\"]\nSUPPORTED_FORMATS_TEXT = _(\"GIF, JPEG, PNG, WEBP\")\n\n\nclass WagtailImageField(ImageField):\n    default_validators = [FileExtensionValidator(ALLOWED_EXTENSIONS)]\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n        # Get max upload size from settings\n        self.max_upload_size = getattr(\n            settings, \"WAGTAILIMAGES_MAX_UPLOAD_SIZE\", 10 * 1024 * 1024\n        )\n        self.max_image_pixels = getattr(\n            settings, \"WAGTAILIMAGES_MAX_IMAGE_PIXELS\", 128 * 1000000\n        )\n        max_upload_size_text = filesizeformat(self.max_upload_size)\n\n        # Help text\n        if self.max_upload_size is not None:\n            self.help_text = _(\n                \"Supported formats: %(supported_formats)s. Maximum filesize: %(max_upload_size)s.\"\n            ) % {\n                \"supported_formats\": SUPPORTED_FORMATS_TEXT,\n                \"max_upload_size\": max_upload_size_text,\n            }\n        else:\n            self.help_text = _(\"Supported formats: %(supported_formats)s.\") % {\n                \"supported_formats\": SUPPORTED_FORMATS_TEXT,\n            }\n\n        # Error messages\n        self.error_messages[\"invalid_image_extension\"] = (\n            _(\"Not a supported image format. Supported formats: %s.\")\n            % SUPPORTED_FORMATS_TEXT\n        )\n\n        self.error_messages[\"invalid_image_known_format\"] = _(\n            \"Not a valid .%s image. The extension does not match the file format (%s)\"\n        )\n\n        self.error_messages[\"file_too_large\"] = (\n            _(\"This file is too big (%%s). Maximum filesize %s.\") % max_upload_size_text\n        )\n\n        self.error_messages[\"file_too_many_pixels\"] = (\n            _(\"This file has too many pixels (%%s). Maximum pixels %s.\")\n            % self.max_image_pixels\n        )\n\n        self.error_messages[\"file_too_large_unknown_size\"] = (\n            _(\"This file is too big. Maximum filesize %s.\") % max_upload_size_text\n        )\n\n    def check_image_file_format(self, f):\n        # Check file extension\n        extension = os.path.splitext(f.name)[1].lower()[1:]\n\n        if extension not in ALLOWED_EXTENSIONS:\n            raise ValidationError(\n                self.error_messages[\"invalid_image_extension\"],\n                code=\"invalid_image_extension\",\n            )\n\n        if extension == \"jpg\":\n            extension = \"jpeg\"\n\n        # Check that the internal format matches the extension\n        # It is possible to upload PSD files if their extension is set to jpg, png or gif. This should catch them out\n        if extension != f.image.format_name:\n            raise ValidationError(\n                self.error_messages[\"invalid_image_known_format\"]\n                % (extension, f.image.format_name),\n                code=\"invalid_image_known_format\",\n            )\n\n    def check_image_file_size(self, f):\n        # Upload size checking can be disabled by setting max upload size to None\n        if self.max_upload_size is None:\n            return\n\n        # Check the filesize\n        if f.size > self.max_upload_size:\n            raise ValidationError(\n                self.error_messages[\"file_too_large\"] % (filesizeformat(f.size),),\n                code=\"file_too_large\",\n            )\n\n    def check_image_pixel_size(self, f):\n        # Upload pixel size checking can be disabled by setting max upload pixel to None\n        if self.max_image_pixels is None:\n            return\n\n        # Check the pixel size\n        width, height = f.image.get_size()\n        frames = f.image.get_frame_count()\n        num_pixels = width * height * frames\n\n        if num_pixels > self.max_image_pixels:\n            raise ValidationError(\n                self.error_messages[\"file_too_many_pixels\"] % (num_pixels),\n                code=\"file_too_many_pixels\",\n            )\n\n    def to_python(self, data):\n        \"\"\"\n        Check that the file-upload field data contains a valid image (GIF, JPG,\n        PNG, etc. -- whatever Willow supports). Overridden from ImageField to use\n        Willow instead of Pillow as the image library in order to enable SVG support.\n        \"\"\"\n        f = FileField.to_python(self, data)\n        if f is None:\n            return None\n\n        # We need to get a file object for Pillow. When we get a path, we need to open\n        # the file first. And we have to read the data into memory to pass to Willow.\n        if hasattr(data, \"temporary_file_path\"):\n            with open(data.temporary_file_path(), \"rb\") as fh:\n                file = BytesIO(fh.read())\n        else:\n            if hasattr(data, \"read\"):\n                file = BytesIO(data.read())\n            else:\n                file = BytesIO(data[\"content\"])\n\n        try:\n            # Annotate the python representation of the FileField with the image\n            # property so subclasses can reuse it for their own validation\n            f.image = willow.Image.open(file)\n            f.content_type = image_format_name_to_content_type(f.image.format_name)\n\n        except Exception as exc:\n            # Willow doesn't recognize it as an image.\n            raise ValidationError(\n                self.error_messages[\"invalid_image\"],\n                code=\"invalid_image\",\n            ) from exc\n\n        if hasattr(f, \"seek\") and callable(f.seek):\n            f.seek(0)\n\n        if f is not None:\n            self.check_image_file_size(f)\n            self.check_image_file_format(f)\n            self.check_image_pixel_size(f)\n\n        return f\n\n\ndef image_format_name_to_content_type(image_format_name):\n    \"\"\"\n    Convert a Willow image format name to a content type.\n    TODO: Replace once https://github.com/wagtail/Willow/pull/102 and\n          a new Willow release is out\n    \"\"\"\n    if image_format_name == \"svg\":\n        return \"image/svg+xml\"\n    elif image_format_name == \"jpeg\":\n        return \"image/jpeg\"\n    elif image_format_name == \"png\":\n        return \"image/png\"\n    elif image_format_name == \"gif\":\n        return \"image/gif\"\n    elif image_format_name == \"bmp\":\n        return \"image/bmp\"\n    elif image_format_name == \"tiff\":\n        return \"image/tiff\"\n    elif image_format_name == \"webp\":\n        return \"image/webp\"\n    else:\n        raise ValueError(\"Unknown image format name\")\n", "path": "wagtail/images/fields.py"}]}