We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Webp images distort in image pipelines
<!--

Thanks for taking an interest in Scrapy!

If you have a question that starts with "How to...", please see the Scrapy Community page: https://scrapy.org/community/.
The GitHub issue tracker's purpose is to deal with bug reports and feature requests for the project itself.

Keep in mind that by filing an issue, you are expected to comply with Scrapy's Code of Conduct, including treating everyone with respect: https://github.com/scrapy/scrapy/blob/master/CODE_OF_CONDUCT.md

The following is a suggested template to structure your issue, you can find more guidelines at https://doc.scrapy.org/en/latest/contributing.html#reporting-bugs

-->

### Description

When a .webp image enters the [convert_image](https://github.com/scrapy/scrapy/blob/2.5/scrapy/pipelines/images.py#L147) routine, it gets distorted adding a black background.

### Steps to Reproduce

1. Get a [webp](https://www.atticadps.gr/images/w544/4/png/files/products/3605521816511/10.webp) image
2. Run a the pipeline
3. ![image](https://user-images.githubusercontent.com/4542013/208651539-1c99ea4c-a1d5-4a15-ab83-cfbe445f9c07.jpeg)


**Expected behavior:** An image without the blacked background

**Actual behavior:** A distorted image

**Reproduces how often:** Everytime for .webp images

### Versions

Please paste here the output of executing `scrapy version --verbose` in the command line.
```
2022-12-20 13:03:32 [scrapy.utils.log] INFO: Scrapy 2.5.1 started (bot: banners)
2022-12-20 13:03:32 [scrapy.utils.log] INFO: Versions: lxml 4.9.1.0, libxml2 2.9.14, cssselect 1.2.0, parsel 1.7.0, w3lib 2.1.0, Twisted 22.10.0, Python 3.9.1 (default, Jun  7 2022, 16:18:41) - [GCC 9.4.0], pyOpenSSL 22.0.0 (OpenSSL 3.0.7 1 Nov 2022), cryptography 38.0.4, Platform Linux-5.14.0-1054-oem-x86_64-with-glibc2.31
2022-12-20 13:03:32 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor
Scrapy       : 2.5.1
lxml         : 4.9.1.0
libxml2      : 2.9.14
cssselect    : 1.2.0
parsel       : 1.7.0
w3lib        : 2.1.0
Twisted      : 22.10.0
Python       : 3.9.1 (default, Jun  7 2022, 16:18:41) - [GCC 9.4.0]
pyOpenSSL    : 22.0.0 (OpenSSL 3.0.7 1 Nov 2022)
cryptography : 38.0.4
Platform     : Linux-5.14.0-1054-oem-x86_64-with-glibc2.31
```

### Additional context

Any additional information, configuration, data or output from commands that might be necessary to reproduce or understand the issue. Please try not to include screenshots of code or the command line, paste the contents as text instead. You can use [GitHub Flavored Markdown](https://help.github.com/en/articles/creating-and-highlighting-code-blocks) to make the text look better.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scrapy/pipelines/images.py`
Content:
```
1 """
2 Images Pipeline
3 
4 See documentation in topics/media-pipeline.rst
5 """
6 import functools
7 import hashlib
8 import warnings
9 from contextlib import suppress
10 from io import BytesIO
11 
12 from itemadapter import ItemAdapter
13 
14 from scrapy.exceptions import DropItem, NotConfigured, ScrapyDeprecationWarning
15 from scrapy.http import Request
16 from scrapy.pipelines.files import FileException, FilesPipeline
17 # TODO: from scrapy.pipelines.media import MediaPipeline
18 from scrapy.settings import Settings
19 from scrapy.utils.misc import md5sum
20 from scrapy.utils.python import get_func_args, to_bytes
21 
22 
23 class NoimagesDrop(DropItem):
24     """Product with no images exception"""
25 
26     def __init__(self, *args, **kwargs):
27         warnings.warn("The NoimagesDrop class is deprecated", category=ScrapyDeprecationWarning, stacklevel=2)
28         super().__init__(*args, **kwargs)
29 
30 
31 class ImageException(FileException):
32     """General image error exception"""
33 
34 
35 class ImagesPipeline(FilesPipeline):
36     """Abstract pipeline that implement the image thumbnail generation logic
37 
38     """
39 
40     MEDIA_NAME = 'image'
41 
42     # Uppercase attributes kept for backward compatibility with code that subclasses
43     # ImagesPipeline. They may be overridden by settings.
44     MIN_WIDTH = 0
45     MIN_HEIGHT = 0
46     EXPIRES = 90
47     THUMBS = {}
48     DEFAULT_IMAGES_URLS_FIELD = 'image_urls'
49     DEFAULT_IMAGES_RESULT_FIELD = 'images'
50 
51     def __init__(self, store_uri, download_func=None, settings=None):
52         try:
53             from PIL import Image
54             self._Image = Image
55         except ImportError:
56             raise NotConfigured(
57                 'ImagesPipeline requires installing Pillow 4.0.0 or later'
58             )
59 
60         super().__init__(store_uri, settings=settings, download_func=download_func)
61 
62         if isinstance(settings, dict) or settings is None:
63             settings = Settings(settings)
64 
65         resolve = functools.partial(self._key_for_pipe,
66                                     base_class_name="ImagesPipeline",
67                                     settings=settings)
68         self.expires = settings.getint(
69             resolve("IMAGES_EXPIRES"), self.EXPIRES
70         )
71 
72         if not hasattr(self, "IMAGES_RESULT_FIELD"):
73             self.IMAGES_RESULT_FIELD = self.DEFAULT_IMAGES_RESULT_FIELD
74         if not hasattr(self, "IMAGES_URLS_FIELD"):
75             self.IMAGES_URLS_FIELD = self.DEFAULT_IMAGES_URLS_FIELD
76 
77         self.images_urls_field = settings.get(
78             resolve('IMAGES_URLS_FIELD'),
79             self.IMAGES_URLS_FIELD
80         )
81         self.images_result_field = settings.get(
82             resolve('IMAGES_RESULT_FIELD'),
83             self.IMAGES_RESULT_FIELD
84         )
85         self.min_width = settings.getint(
86             resolve('IMAGES_MIN_WIDTH'), self.MIN_WIDTH
87         )
88         self.min_height = settings.getint(
89             resolve('IMAGES_MIN_HEIGHT'), self.MIN_HEIGHT
90         )
91         self.thumbs = settings.get(
92             resolve('IMAGES_THUMBS'), self.THUMBS
93         )
94 
95         self._deprecated_convert_image = None
96 
97     @classmethod
98     def from_settings(cls, settings):
99         s3store = cls.STORE_SCHEMES['s3']
100         s3store.AWS_ACCESS_KEY_ID = settings['AWS_ACCESS_KEY_ID']
101         s3store.AWS_SECRET_ACCESS_KEY = settings['AWS_SECRET_ACCESS_KEY']
102         s3store.AWS_SESSION_TOKEN = settings['AWS_SESSION_TOKEN']
103         s3store.AWS_ENDPOINT_URL = settings['AWS_ENDPOINT_URL']
104         s3store.AWS_REGION_NAME = settings['AWS_REGION_NAME']
105         s3store.AWS_USE_SSL = settings['AWS_USE_SSL']
106         s3store.AWS_VERIFY = settings['AWS_VERIFY']
107         s3store.POLICY = settings['IMAGES_STORE_S3_ACL']
108 
109         gcs_store = cls.STORE_SCHEMES['gs']
110         gcs_store.GCS_PROJECT_ID = settings['GCS_PROJECT_ID']
111         gcs_store.POLICY = settings['IMAGES_STORE_GCS_ACL'] or None
112 
113         ftp_store = cls.STORE_SCHEMES['ftp']
114         ftp_store.FTP_USERNAME = settings['FTP_USER']
115         ftp_store.FTP_PASSWORD = settings['FTP_PASSWORD']
116         ftp_store.USE_ACTIVE_MODE = settings.getbool('FEED_STORAGE_FTP_ACTIVE')
117 
118         store_uri = settings['IMAGES_STORE']
119         return cls(store_uri, settings=settings)
120 
121     def file_downloaded(self, response, request, info, *, item=None):
122         return self.image_downloaded(response, request, info, item=item)
123 
124     def image_downloaded(self, response, request, info, *, item=None):
125         checksum = None
126         for path, image, buf in self.get_images(response, request, info, item=item):
127             if checksum is None:
128                 buf.seek(0)
129                 checksum = md5sum(buf)
130             width, height = image.size
131             self.store.persist_file(
132                 path, buf, info,
133                 meta={'width': width, 'height': height},
134                 headers={'Content-Type': 'image/jpeg'})
135         return checksum
136 
137     def get_images(self, response, request, info, *, item=None):
138         path = self.file_path(request, response=response, info=info, item=item)
139         orig_image = self._Image.open(BytesIO(response.body))
140 
141         width, height = orig_image.size
142         if width < self.min_width or height < self.min_height:
143             raise ImageException("Image too small "
144                                  f"({width}x{height} < "
145                                  f"{self.min_width}x{self.min_height})")
146 
147         if self._deprecated_convert_image is None:
148             self._deprecated_convert_image = 'response_body' not in get_func_args(self.convert_image)
149             if self._deprecated_convert_image:
150                 warnings.warn(f'{self.__class__.__name__}.convert_image() method overriden in a deprecated way, '
151                               'overriden method does not accept response_body argument.',
152                               category=ScrapyDeprecationWarning)
153 
154         if self._deprecated_convert_image:
155             image, buf = self.convert_image(orig_image)
156         else:
157             image, buf = self.convert_image(orig_image, response_body=BytesIO(response.body))
158         yield path, image, buf
159 
160         for thumb_id, size in self.thumbs.items():
161             thumb_path = self.thumb_path(request, thumb_id, response=response, info=info, item=item)
162             if self._deprecated_convert_image:
163                 thumb_image, thumb_buf = self.convert_image(image, size)
164             else:
165                 thumb_image, thumb_buf = self.convert_image(image, size, buf)
166             yield thumb_path, thumb_image, thumb_buf
167 
168     def convert_image(self, image, size=None, response_body=None):
169         if response_body is None:
170             warnings.warn(f'{self.__class__.__name__}.convert_image() method called in a deprecated way, '
171                           'method called without response_body argument.',
172                           category=ScrapyDeprecationWarning, stacklevel=2)
173 
174         if image.format == 'PNG' and image.mode == 'RGBA':
175             background = self._Image.new('RGBA', image.size, (255, 255, 255))
176             background.paste(image, image)
177             image = background.convert('RGB')
178         elif image.mode == 'P':
179             image = image.convert("RGBA")
180             background = self._Image.new('RGBA', image.size, (255, 255, 255))
181             background.paste(image, image)
182             image = background.convert('RGB')
183         elif image.mode != 'RGB':
184             image = image.convert('RGB')
185 
186         if size:
187             image = image.copy()
188             try:
189                 # Image.Resampling.LANCZOS was added in Pillow 9.1.0
190                 # remove this try except block,
191                 # when updating the minimum requirements for Pillow.
192                 resampling_filter = self._Image.Resampling.LANCZOS
193             except AttributeError:
194                 resampling_filter = self._Image.ANTIALIAS
195             image.thumbnail(size, resampling_filter)
196         elif response_body is not None and image.format == 'JPEG':
197             return image, response_body
198 
199         buf = BytesIO()
200         image.save(buf, 'JPEG')
201         return image, buf
202 
203     def get_media_requests(self, item, info):
204         urls = ItemAdapter(item).get(self.images_urls_field, [])
205         return [Request(u) for u in urls]
206 
207     def item_completed(self, results, item, info):
208         with suppress(KeyError):
209             ItemAdapter(item)[self.images_result_field] = [x for ok, x in results if ok]
210         return item
211 
212     def file_path(self, request, response=None, info=None, *, item=None):
213         image_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()
214         return f'full/{image_guid}.jpg'
215 
216     def thumb_path(self, request, thumb_id, response=None, info=None, *, item=None):
217         thumb_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()
218         return f'thumbs/{thumb_id}/{thumb_guid}.jpg'
219
```
--- 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/scrapy/pipelines/images.py b/scrapy/pipelines/images.py
--- a/scrapy/pipelines/images.py
+++ b/scrapy/pipelines/images.py
@@ -171,7 +171,7 @@
                           'method called without response_body argument.',
                           category=ScrapyDeprecationWarning, stacklevel=2)
 
-        if image.format == 'PNG' and image.mode == 'RGBA':
+        if image.format in ('PNG', 'WEBP') and image.mode == 'RGBA':
             background = self._Image.new('RGBA', image.size, (255, 255, 255))
             background.paste(image, image)
             image = background.convert('RGB')

{"golden_diff": "diff --git a/scrapy/pipelines/images.py b/scrapy/pipelines/images.py\n--- a/scrapy/pipelines/images.py\n+++ b/scrapy/pipelines/images.py\n@@ -171,7 +171,7 @@\n                           'method called without response_body argument.',\n                           category=ScrapyDeprecationWarning, stacklevel=2)\n \n-        if image.format == 'PNG' and image.mode == 'RGBA':\n+        if image.format in ('PNG', 'WEBP') and image.mode == 'RGBA':\n             background = self._Image.new('RGBA', image.size, (255, 255, 255))\n             background.paste(image, image)\n             image = background.convert('RGB')\n", "issue": "Webp images distort in image pipelines\n<!--\r\n\r\nThanks for taking an interest in Scrapy!\r\n\r\nIf you have a question that starts with \"How to...\", please see the Scrapy Community page: https://scrapy.org/community/.\r\nThe GitHub issue tracker's purpose is to deal with bug reports and feature requests for the project itself.\r\n\r\nKeep in mind that by filing an issue, you are expected to comply with Scrapy's Code of Conduct, including treating everyone with respect: https://github.com/scrapy/scrapy/blob/master/CODE_OF_CONDUCT.md\r\n\r\nThe following is a suggested template to structure your issue, you can find more guidelines at https://doc.scrapy.org/en/latest/contributing.html#reporting-bugs\r\n\r\n-->\r\n\r\n### Description\r\n\r\nWhen a .webp image enters the [convert_image](https://github.com/scrapy/scrapy/blob/2.5/scrapy/pipelines/images.py#L147) routine, it gets distorted adding a black background.\r\n\r\n### Steps to Reproduce\r\n\r\n1. Get a [webp](https://www.atticadps.gr/images/w544/4/png/files/products/3605521816511/10.webp) image\r\n2. Run a the pipeline\r\n3. ![image](https://user-images.githubusercontent.com/4542013/208651539-1c99ea4c-a1d5-4a15-ab83-cfbe445f9c07.jpeg)\r\n\r\n\r\n**Expected behavior:** An image without the blacked background\r\n\r\n**Actual behavior:** A distorted image\r\n\r\n**Reproduces how often:** Everytime for .webp images\r\n\r\n### Versions\r\n\r\nPlease paste here the output of executing `scrapy version --verbose` in the command line.\r\n```\r\n2022-12-20 13:03:32 [scrapy.utils.log] INFO: Scrapy 2.5.1 started (bot: banners)\r\n2022-12-20 13:03:32 [scrapy.utils.log] INFO: Versions: lxml 4.9.1.0, libxml2 2.9.14, cssselect 1.2.0, parsel 1.7.0, w3lib 2.1.0, Twisted 22.10.0, Python 3.9.1 (default, Jun  7 2022, 16:18:41) - [GCC 9.4.0], pyOpenSSL 22.0.0 (OpenSSL 3.0.7 1 Nov 2022), cryptography 38.0.4, Platform Linux-5.14.0-1054-oem-x86_64-with-glibc2.31\r\n2022-12-20 13:03:32 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor\r\nScrapy       : 2.5.1\r\nlxml         : 4.9.1.0\r\nlibxml2      : 2.9.14\r\ncssselect    : 1.2.0\r\nparsel       : 1.7.0\r\nw3lib        : 2.1.0\r\nTwisted      : 22.10.0\r\nPython       : 3.9.1 (default, Jun  7 2022, 16:18:41) - [GCC 9.4.0]\r\npyOpenSSL    : 22.0.0 (OpenSSL 3.0.7 1 Nov 2022)\r\ncryptography : 38.0.4\r\nPlatform     : Linux-5.14.0-1054-oem-x86_64-with-glibc2.31\r\n```\r\n\r\n### Additional context\r\n\r\nAny additional information, configuration, data or output from commands that might be necessary to reproduce or understand the issue. Please try not to include screenshots of code or the command line, paste the contents as text instead. You can use [GitHub Flavored Markdown](https://help.github.com/en/articles/creating-and-highlighting-code-blocks) to make the text look better.\r\n\n", "before_files": [{"content": "\"\"\"\nImages Pipeline\n\nSee documentation in topics/media-pipeline.rst\n\"\"\"\nimport functools\nimport hashlib\nimport warnings\nfrom contextlib import suppress\nfrom io import BytesIO\n\nfrom itemadapter import ItemAdapter\n\nfrom scrapy.exceptions import DropItem, NotConfigured, ScrapyDeprecationWarning\nfrom scrapy.http import Request\nfrom scrapy.pipelines.files import FileException, FilesPipeline\n# TODO: from scrapy.pipelines.media import MediaPipeline\nfrom scrapy.settings import Settings\nfrom scrapy.utils.misc import md5sum\nfrom scrapy.utils.python import get_func_args, to_bytes\n\n\nclass NoimagesDrop(DropItem):\n    \"\"\"Product with no images exception\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        warnings.warn(\"The NoimagesDrop class is deprecated\", category=ScrapyDeprecationWarning, stacklevel=2)\n        super().__init__(*args, **kwargs)\n\n\nclass ImageException(FileException):\n    \"\"\"General image error exception\"\"\"\n\n\nclass ImagesPipeline(FilesPipeline):\n    \"\"\"Abstract pipeline that implement the image thumbnail generation logic\n\n    \"\"\"\n\n    MEDIA_NAME = 'image'\n\n    # Uppercase attributes kept for backward compatibility with code that subclasses\n    # ImagesPipeline. They may be overridden by settings.\n    MIN_WIDTH = 0\n    MIN_HEIGHT = 0\n    EXPIRES = 90\n    THUMBS = {}\n    DEFAULT_IMAGES_URLS_FIELD = 'image_urls'\n    DEFAULT_IMAGES_RESULT_FIELD = 'images'\n\n    def __init__(self, store_uri, download_func=None, settings=None):\n        try:\n            from PIL import Image\n            self._Image = Image\n        except ImportError:\n            raise NotConfigured(\n                'ImagesPipeline requires installing Pillow 4.0.0 or later'\n            )\n\n        super().__init__(store_uri, settings=settings, download_func=download_func)\n\n        if isinstance(settings, dict) or settings is None:\n            settings = Settings(settings)\n\n        resolve = functools.partial(self._key_for_pipe,\n                                    base_class_name=\"ImagesPipeline\",\n                                    settings=settings)\n        self.expires = settings.getint(\n            resolve(\"IMAGES_EXPIRES\"), self.EXPIRES\n        )\n\n        if not hasattr(self, \"IMAGES_RESULT_FIELD\"):\n            self.IMAGES_RESULT_FIELD = self.DEFAULT_IMAGES_RESULT_FIELD\n        if not hasattr(self, \"IMAGES_URLS_FIELD\"):\n            self.IMAGES_URLS_FIELD = self.DEFAULT_IMAGES_URLS_FIELD\n\n        self.images_urls_field = settings.get(\n            resolve('IMAGES_URLS_FIELD'),\n            self.IMAGES_URLS_FIELD\n        )\n        self.images_result_field = settings.get(\n            resolve('IMAGES_RESULT_FIELD'),\n            self.IMAGES_RESULT_FIELD\n        )\n        self.min_width = settings.getint(\n            resolve('IMAGES_MIN_WIDTH'), self.MIN_WIDTH\n        )\n        self.min_height = settings.getint(\n            resolve('IMAGES_MIN_HEIGHT'), self.MIN_HEIGHT\n        )\n        self.thumbs = settings.get(\n            resolve('IMAGES_THUMBS'), self.THUMBS\n        )\n\n        self._deprecated_convert_image = None\n\n    @classmethod\n    def from_settings(cls, settings):\n        s3store = cls.STORE_SCHEMES['s3']\n        s3store.AWS_ACCESS_KEY_ID = settings['AWS_ACCESS_KEY_ID']\n        s3store.AWS_SECRET_ACCESS_KEY = settings['AWS_SECRET_ACCESS_KEY']\n        s3store.AWS_SESSION_TOKEN = settings['AWS_SESSION_TOKEN']\n        s3store.AWS_ENDPOINT_URL = settings['AWS_ENDPOINT_URL']\n        s3store.AWS_REGION_NAME = settings['AWS_REGION_NAME']\n        s3store.AWS_USE_SSL = settings['AWS_USE_SSL']\n        s3store.AWS_VERIFY = settings['AWS_VERIFY']\n        s3store.POLICY = settings['IMAGES_STORE_S3_ACL']\n\n        gcs_store = cls.STORE_SCHEMES['gs']\n        gcs_store.GCS_PROJECT_ID = settings['GCS_PROJECT_ID']\n        gcs_store.POLICY = settings['IMAGES_STORE_GCS_ACL'] or None\n\n        ftp_store = cls.STORE_SCHEMES['ftp']\n        ftp_store.FTP_USERNAME = settings['FTP_USER']\n        ftp_store.FTP_PASSWORD = settings['FTP_PASSWORD']\n        ftp_store.USE_ACTIVE_MODE = settings.getbool('FEED_STORAGE_FTP_ACTIVE')\n\n        store_uri = settings['IMAGES_STORE']\n        return cls(store_uri, settings=settings)\n\n    def file_downloaded(self, response, request, info, *, item=None):\n        return self.image_downloaded(response, request, info, item=item)\n\n    def image_downloaded(self, response, request, info, *, item=None):\n        checksum = None\n        for path, image, buf in self.get_images(response, request, info, item=item):\n            if checksum is None:\n                buf.seek(0)\n                checksum = md5sum(buf)\n            width, height = image.size\n            self.store.persist_file(\n                path, buf, info,\n                meta={'width': width, 'height': height},\n                headers={'Content-Type': 'image/jpeg'})\n        return checksum\n\n    def get_images(self, response, request, info, *, item=None):\n        path = self.file_path(request, response=response, info=info, item=item)\n        orig_image = self._Image.open(BytesIO(response.body))\n\n        width, height = orig_image.size\n        if width < self.min_width or height < self.min_height:\n            raise ImageException(\"Image too small \"\n                                 f\"({width}x{height} < \"\n                                 f\"{self.min_width}x{self.min_height})\")\n\n        if self._deprecated_convert_image is None:\n            self._deprecated_convert_image = 'response_body' not in get_func_args(self.convert_image)\n            if self._deprecated_convert_image:\n                warnings.warn(f'{self.__class__.__name__}.convert_image() method overriden in a deprecated way, '\n                              'overriden method does not accept response_body argument.',\n                              category=ScrapyDeprecationWarning)\n\n        if self._deprecated_convert_image:\n            image, buf = self.convert_image(orig_image)\n        else:\n            image, buf = self.convert_image(orig_image, response_body=BytesIO(response.body))\n        yield path, image, buf\n\n        for thumb_id, size in self.thumbs.items():\n            thumb_path = self.thumb_path(request, thumb_id, response=response, info=info, item=item)\n            if self._deprecated_convert_image:\n                thumb_image, thumb_buf = self.convert_image(image, size)\n            else:\n                thumb_image, thumb_buf = self.convert_image(image, size, buf)\n            yield thumb_path, thumb_image, thumb_buf\n\n    def convert_image(self, image, size=None, response_body=None):\n        if response_body is None:\n            warnings.warn(f'{self.__class__.__name__}.convert_image() method called in a deprecated way, '\n                          'method called without response_body argument.',\n                          category=ScrapyDeprecationWarning, stacklevel=2)\n\n        if image.format == 'PNG' and image.mode == 'RGBA':\n            background = self._Image.new('RGBA', image.size, (255, 255, 255))\n            background.paste(image, image)\n            image = background.convert('RGB')\n        elif image.mode == 'P':\n            image = image.convert(\"RGBA\")\n            background = self._Image.new('RGBA', image.size, (255, 255, 255))\n            background.paste(image, image)\n            image = background.convert('RGB')\n        elif image.mode != 'RGB':\n            image = image.convert('RGB')\n\n        if size:\n            image = image.copy()\n            try:\n                # Image.Resampling.LANCZOS was added in Pillow 9.1.0\n                # remove this try except block,\n                # when updating the minimum requirements for Pillow.\n                resampling_filter = self._Image.Resampling.LANCZOS\n            except AttributeError:\n                resampling_filter = self._Image.ANTIALIAS\n            image.thumbnail(size, resampling_filter)\n        elif response_body is not None and image.format == 'JPEG':\n            return image, response_body\n\n        buf = BytesIO()\n        image.save(buf, 'JPEG')\n        return image, buf\n\n    def get_media_requests(self, item, info):\n        urls = ItemAdapter(item).get(self.images_urls_field, [])\n        return [Request(u) for u in urls]\n\n    def item_completed(self, results, item, info):\n        with suppress(KeyError):\n            ItemAdapter(item)[self.images_result_field] = [x for ok, x in results if ok]\n        return item\n\n    def file_path(self, request, response=None, info=None, *, item=None):\n        image_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()\n        return f'full/{image_guid}.jpg'\n\n    def thumb_path(self, request, thumb_id, response=None, info=None, *, item=None):\n        thumb_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()\n        return f'thumbs/{thumb_id}/{thumb_guid}.jpg'\n", "path": "scrapy/pipelines/images.py"}], "after_files": [{"content": "\"\"\"\nImages Pipeline\n\nSee documentation in topics/media-pipeline.rst\n\"\"\"\nimport functools\nimport hashlib\nimport warnings\nfrom contextlib import suppress\nfrom io import BytesIO\n\nfrom itemadapter import ItemAdapter\n\nfrom scrapy.exceptions import DropItem, NotConfigured, ScrapyDeprecationWarning\nfrom scrapy.http import Request\nfrom scrapy.pipelines.files import FileException, FilesPipeline\n# TODO: from scrapy.pipelines.media import MediaPipeline\nfrom scrapy.settings import Settings\nfrom scrapy.utils.misc import md5sum\nfrom scrapy.utils.python import get_func_args, to_bytes\n\n\nclass NoimagesDrop(DropItem):\n    \"\"\"Product with no images exception\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        warnings.warn(\"The NoimagesDrop class is deprecated\", category=ScrapyDeprecationWarning, stacklevel=2)\n        super().__init__(*args, **kwargs)\n\n\nclass ImageException(FileException):\n    \"\"\"General image error exception\"\"\"\n\n\nclass ImagesPipeline(FilesPipeline):\n    \"\"\"Abstract pipeline that implement the image thumbnail generation logic\n\n    \"\"\"\n\n    MEDIA_NAME = 'image'\n\n    # Uppercase attributes kept for backward compatibility with code that subclasses\n    # ImagesPipeline. They may be overridden by settings.\n    MIN_WIDTH = 0\n    MIN_HEIGHT = 0\n    EXPIRES = 90\n    THUMBS = {}\n    DEFAULT_IMAGES_URLS_FIELD = 'image_urls'\n    DEFAULT_IMAGES_RESULT_FIELD = 'images'\n\n    def __init__(self, store_uri, download_func=None, settings=None):\n        try:\n            from PIL import Image\n            self._Image = Image\n        except ImportError:\n            raise NotConfigured(\n                'ImagesPipeline requires installing Pillow 4.0.0 or later'\n            )\n\n        super().__init__(store_uri, settings=settings, download_func=download_func)\n\n        if isinstance(settings, dict) or settings is None:\n            settings = Settings(settings)\n\n        resolve = functools.partial(self._key_for_pipe,\n                                    base_class_name=\"ImagesPipeline\",\n                                    settings=settings)\n        self.expires = settings.getint(\n            resolve(\"IMAGES_EXPIRES\"), self.EXPIRES\n        )\n\n        if not hasattr(self, \"IMAGES_RESULT_FIELD\"):\n            self.IMAGES_RESULT_FIELD = self.DEFAULT_IMAGES_RESULT_FIELD\n        if not hasattr(self, \"IMAGES_URLS_FIELD\"):\n            self.IMAGES_URLS_FIELD = self.DEFAULT_IMAGES_URLS_FIELD\n\n        self.images_urls_field = settings.get(\n            resolve('IMAGES_URLS_FIELD'),\n            self.IMAGES_URLS_FIELD\n        )\n        self.images_result_field = settings.get(\n            resolve('IMAGES_RESULT_FIELD'),\n            self.IMAGES_RESULT_FIELD\n        )\n        self.min_width = settings.getint(\n            resolve('IMAGES_MIN_WIDTH'), self.MIN_WIDTH\n        )\n        self.min_height = settings.getint(\n            resolve('IMAGES_MIN_HEIGHT'), self.MIN_HEIGHT\n        )\n        self.thumbs = settings.get(\n            resolve('IMAGES_THUMBS'), self.THUMBS\n        )\n\n        self._deprecated_convert_image = None\n\n    @classmethod\n    def from_settings(cls, settings):\n        s3store = cls.STORE_SCHEMES['s3']\n        s3store.AWS_ACCESS_KEY_ID = settings['AWS_ACCESS_KEY_ID']\n        s3store.AWS_SECRET_ACCESS_KEY = settings['AWS_SECRET_ACCESS_KEY']\n        s3store.AWS_SESSION_TOKEN = settings['AWS_SESSION_TOKEN']\n        s3store.AWS_ENDPOINT_URL = settings['AWS_ENDPOINT_URL']\n        s3store.AWS_REGION_NAME = settings['AWS_REGION_NAME']\n        s3store.AWS_USE_SSL = settings['AWS_USE_SSL']\n        s3store.AWS_VERIFY = settings['AWS_VERIFY']\n        s3store.POLICY = settings['IMAGES_STORE_S3_ACL']\n\n        gcs_store = cls.STORE_SCHEMES['gs']\n        gcs_store.GCS_PROJECT_ID = settings['GCS_PROJECT_ID']\n        gcs_store.POLICY = settings['IMAGES_STORE_GCS_ACL'] or None\n\n        ftp_store = cls.STORE_SCHEMES['ftp']\n        ftp_store.FTP_USERNAME = settings['FTP_USER']\n        ftp_store.FTP_PASSWORD = settings['FTP_PASSWORD']\n        ftp_store.USE_ACTIVE_MODE = settings.getbool('FEED_STORAGE_FTP_ACTIVE')\n\n        store_uri = settings['IMAGES_STORE']\n        return cls(store_uri, settings=settings)\n\n    def file_downloaded(self, response, request, info, *, item=None):\n        return self.image_downloaded(response, request, info, item=item)\n\n    def image_downloaded(self, response, request, info, *, item=None):\n        checksum = None\n        for path, image, buf in self.get_images(response, request, info, item=item):\n            if checksum is None:\n                buf.seek(0)\n                checksum = md5sum(buf)\n            width, height = image.size\n            self.store.persist_file(\n                path, buf, info,\n                meta={'width': width, 'height': height},\n                headers={'Content-Type': 'image/jpeg'})\n        return checksum\n\n    def get_images(self, response, request, info, *, item=None):\n        path = self.file_path(request, response=response, info=info, item=item)\n        orig_image = self._Image.open(BytesIO(response.body))\n\n        width, height = orig_image.size\n        if width < self.min_width or height < self.min_height:\n            raise ImageException(\"Image too small \"\n                                 f\"({width}x{height} < \"\n                                 f\"{self.min_width}x{self.min_height})\")\n\n        if self._deprecated_convert_image is None:\n            self._deprecated_convert_image = 'response_body' not in get_func_args(self.convert_image)\n            if self._deprecated_convert_image:\n                warnings.warn(f'{self.__class__.__name__}.convert_image() method overriden in a deprecated way, '\n                              'overriden method does not accept response_body argument.',\n                              category=ScrapyDeprecationWarning)\n\n        if self._deprecated_convert_image:\n            image, buf = self.convert_image(orig_image)\n        else:\n            image, buf = self.convert_image(orig_image, response_body=BytesIO(response.body))\n        yield path, image, buf\n\n        for thumb_id, size in self.thumbs.items():\n            thumb_path = self.thumb_path(request, thumb_id, response=response, info=info, item=item)\n            if self._deprecated_convert_image:\n                thumb_image, thumb_buf = self.convert_image(image, size)\n            else:\n                thumb_image, thumb_buf = self.convert_image(image, size, buf)\n            yield thumb_path, thumb_image, thumb_buf\n\n    def convert_image(self, image, size=None, response_body=None):\n        if response_body is None:\n            warnings.warn(f'{self.__class__.__name__}.convert_image() method called in a deprecated way, '\n                          'method called without response_body argument.',\n                          category=ScrapyDeprecationWarning, stacklevel=2)\n\n        if image.format in ('PNG', 'WEBP') and image.mode == 'RGBA':\n            background = self._Image.new('RGBA', image.size, (255, 255, 255))\n            background.paste(image, image)\n            image = background.convert('RGB')\n        elif image.mode == 'P':\n            image = image.convert(\"RGBA\")\n            background = self._Image.new('RGBA', image.size, (255, 255, 255))\n            background.paste(image, image)\n            image = background.convert('RGB')\n        elif image.mode != 'RGB':\n            image = image.convert('RGB')\n\n        if size:\n            image = image.copy()\n            try:\n                # Image.Resampling.LANCZOS was added in Pillow 9.1.0\n                # remove this try except block,\n                # when updating the minimum requirements for Pillow.\n                resampling_filter = self._Image.Resampling.LANCZOS\n            except AttributeError:\n                resampling_filter = self._Image.ANTIALIAS\n            image.thumbnail(size, resampling_filter)\n        elif response_body is not None and image.format == 'JPEG':\n            return image, response_body\n\n        buf = BytesIO()\n        image.save(buf, 'JPEG')\n        return image, buf\n\n    def get_media_requests(self, item, info):\n        urls = ItemAdapter(item).get(self.images_urls_field, [])\n        return [Request(u) for u in urls]\n\n    def item_completed(self, results, item, info):\n        with suppress(KeyError):\n            ItemAdapter(item)[self.images_result_field] = [x for ok, x in results if ok]\n        return item\n\n    def file_path(self, request, response=None, info=None, *, item=None):\n        image_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()\n        return f'full/{image_guid}.jpg'\n\n    def thumb_path(self, request, thumb_id, response=None, info=None, *, item=None):\n        thumb_guid = hashlib.sha1(to_bytes(request.url)).hexdigest()\n        return f'thumbs/{thumb_id}/{thumb_guid}.jpg'\n", "path": "scrapy/pipelines/images.py"}]}