{
    "file_diffs": [
        {
            "old_file_content": "import io\nimport re\nimport sys\n\nimport pytest\n\nfrom PIL import Image, WebPImagePlugin, features\n\nfrom .helper import (\n    assert_image_similar,\n    assert_image_similar_tofile,\n    hopper,\n    skip_unless_feature,\n)\n\ntry:\n    from PIL import _webp\n\n    HAVE_WEBP = True\nexcept ImportError:\n    HAVE_WEBP = False\n\n\nclass TestUnsupportedWebp:\n    def test_unsupported(self):\n        if HAVE_WEBP:\n            WebPImagePlugin.SUPPORTED = False\n\n        file_path = \"Tests/images/hopper.webp\"\n        pytest.warns(UserWarning, lambda: pytest.raises(OSError, Image.open, file_path))\n\n        if HAVE_WEBP:\n            WebPImagePlugin.SUPPORTED = True\n\n\n@skip_unless_feature(\"webp\")\nclass TestFileWebp:\n    def setup_method(self):\n        self.rgb_mode = \"RGB\"\n\n    def test_version(self):\n        _webp.WebPDecoderVersion()\n        _webp.WebPDecoderBuggyAlpha()\n        assert re.search(r\"\\d+\\.\\d+\\.\\d+$\", features.version_module(\"webp\"))\n\n    def test_read_rgb(self):\n        \"\"\"\n        Can we read a RGB mode WebP file without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        with Image.open(\"Tests/images/hopper.webp\") as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            # generated with:\n            # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm\n            assert_image_similar_tofile(image, \"Tests/images/hopper_webp_bits.ppm\", 1.0)\n\n    def _roundtrip(self, tmp_path, mode, epsilon, args={}):\n        temp_file = str(tmp_path / \"temp.webp\")\n\n        hopper(mode).save(temp_file, **args)\n        with Image.open(temp_file) as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            if mode == self.rgb_mode:\n                # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm\n                assert_image_similar_tofile(\n                    image, \"Tests/images/hopper_webp_write.ppm\", 12.0\n                )\n\n            # This test asserts that the images are similar. If the average pixel\n            # difference between the two images is less than the epsilon value,\n            # then we're going to accept that it's a reasonable lossy version of\n            # the image.\n            target = hopper(mode)\n            if mode != self.rgb_mode:\n                target = target.convert(self.rgb_mode)\n            assert_image_similar(image, target, epsilon)\n\n    def test_write_rgb(self, tmp_path):\n        \"\"\"\n        Can we write a RGB mode file to webp without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5)\n\n    def test_write_method(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.0, {\"method\": 6})\n\n        buffer_no_args = io.BytesIO()\n        hopper().save(buffer_no_args, format=\"WEBP\")\n\n        buffer_method = io.BytesIO()\n        hopper().save(buffer_method, format=\"WEBP\", method=6)\n        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()\n\n    def test_write_unsupported_mode_L(self, tmp_path):\n        \"\"\"\n        Saving a black-and-white file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"L\", 10.0)\n\n    def test_write_unsupported_mode_P(self, tmp_path):\n        \"\"\"\n        Saving a palette-based file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"P\", 50.0)\n\n    @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason=\"Requires 64-bit system\")\n    def test_write_encoding_error_message(self, tmp_path):\n        temp_file = str(tmp_path / \"temp.webp\")\n        im = Image.new(\"RGB\", (15000, 15000))\n        with pytest.raises(ValueError) as e:\n            im.save(temp_file, method=0)\n        assert str(e.value) == \"encoding error 6\"\n\n    def test_WebPEncode_with_invalid_args(self):\n        \"\"\"\n        Calling encoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimEncoder()\n        with pytest.raises(TypeError):\n            _webp.WebPEncode()\n\n    def test_WebPDecode_with_invalid_args(self):\n        \"\"\"\n        Calling decoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimDecoder()\n        with pytest.raises(TypeError):\n            _webp.WebPDecode()\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n            with pytest.warns(None) as record:\n                image.save(temp_file)\n            assert not record\n\n    def test_file_pointer_could_be_reused(self):\n        file_path = \"Tests/images/hopper.webp\"\n        with open(file_path, \"rb\") as blob:\n            Image.open(blob).load()\n            Image.open(blob).load()\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_background_from_gif(self, tmp_path):\n        with Image.open(\"Tests/images/chi.gif\") as im:\n            original_value = im.convert(\"RGB\").getpixel((1, 1))\n\n            # Save as WEBP\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        # Save as GIF\n        out_gif = str(tmp_path / \"temp.gif\")\n        with Image.open(out_webp) as im:\n            im.save(out_gif)\n\n        with Image.open(out_gif) as reread:\n            reread_value = reread.convert(\"RGB\").getpixel((1, 1))\n        difference = sum(\n            [abs(original_value[i] - reread_value[i]) for i in range(0, 3)]\n        )\n        assert difference < 5\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_duration(self, tmp_path):\n        with Image.open(\"Tests/images/dispose_bgnd.gif\") as im:\n            assert im.info[\"duration\"] == 1000\n\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        with Image.open(out_webp) as reloaded:\n            reloaded.load()\n            assert reloaded.info[\"duration\"] == 1000\n",
            "new_file_content": "import io\nimport re\nimport sys\n\nimport pytest\n\nfrom PIL import Image, WebPImagePlugin, features\n\nfrom .helper import (\n    assert_image_similar,\n    assert_image_similar_tofile,\n    hopper,\n    skip_unless_feature,\n)\n\ntry:\n    from PIL import _webp\n\n    HAVE_WEBP = True\nexcept ImportError:\n    HAVE_WEBP = False\n\n\nclass TestUnsupportedWebp:\n    def test_unsupported(self):\n        if HAVE_WEBP:\n            WebPImagePlugin.SUPPORTED = False\n\n        file_path = \"Tests/images/hopper.webp\"\n        pytest.warns(UserWarning, lambda: pytest.raises(OSError, Image.open, file_path))\n\n        if HAVE_WEBP:\n            WebPImagePlugin.SUPPORTED = True\n\n\n@skip_unless_feature(\"webp\")\nclass TestFileWebp:\n    def setup_method(self):\n        self.rgb_mode = \"RGB\"\n\n    def test_version(self):\n        _webp.WebPDecoderVersion()\n        _webp.WebPDecoderBuggyAlpha()\n        assert re.search(r\"\\d+\\.\\d+\\.\\d+$\", features.version_module(\"webp\"))\n\n    def test_read_rgb(self):\n        \"\"\"\n        Can we read a RGB mode WebP file without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        with Image.open(\"Tests/images/hopper.webp\") as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            # generated with:\n            # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm\n            assert_image_similar_tofile(image, \"Tests/images/hopper_webp_bits.ppm\", 1.0)\n\n    def _roundtrip(self, tmp_path, mode, epsilon, args={}):\n        temp_file = str(tmp_path / \"temp.webp\")\n\n        hopper(mode).save(temp_file, **args)\n        with Image.open(temp_file) as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            if mode == self.rgb_mode:\n                # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm\n                assert_image_similar_tofile(\n                    image, \"Tests/images/hopper_webp_write.ppm\", 12.0\n                )\n\n            # This test asserts that the images are similar. If the average pixel\n            # difference between the two images is less than the epsilon value,\n            # then we're going to accept that it's a reasonable lossy version of\n            # the image.\n            target = hopper(mode)\n            if mode != self.rgb_mode:\n                target = target.convert(self.rgb_mode)\n            assert_image_similar(image, target, epsilon)\n\n    def test_write_rgb(self, tmp_path):\n        \"\"\"\n        Can we write a RGB mode file to webp without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5)\n\n    def test_write_method(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.0, {\"method\": 6})\n\n        buffer_no_args = io.BytesIO()\n        hopper().save(buffer_no_args, format=\"WEBP\")\n\n        buffer_method = io.BytesIO()\n        hopper().save(buffer_method, format=\"WEBP\", method=6)\n        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()\n\n    def test_icc_profile(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})\n        if _webp.HAVE_WEBPANIM:\n            self._roundtrip(\n                tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None, \"save_all\": True}\n            )\n\n    def test_write_unsupported_mode_L(self, tmp_path):\n        \"\"\"\n        Saving a black-and-white file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"L\", 10.0)\n\n    def test_write_unsupported_mode_P(self, tmp_path):\n        \"\"\"\n        Saving a palette-based file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"P\", 50.0)\n\n    @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason=\"Requires 64-bit system\")\n    def test_write_encoding_error_message(self, tmp_path):\n        temp_file = str(tmp_path / \"temp.webp\")\n        im = Image.new(\"RGB\", (15000, 15000))\n        with pytest.raises(ValueError) as e:\n            im.save(temp_file, method=0)\n        assert str(e.value) == \"encoding error 6\"\n\n    def test_WebPEncode_with_invalid_args(self):\n        \"\"\"\n        Calling encoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimEncoder()\n        with pytest.raises(TypeError):\n            _webp.WebPEncode()\n\n    def test_WebPDecode_with_invalid_args(self):\n        \"\"\"\n        Calling decoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimDecoder()\n        with pytest.raises(TypeError):\n            _webp.WebPDecode()\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n            with pytest.warns(None) as record:\n                image.save(temp_file)\n            assert not record\n\n    def test_file_pointer_could_be_reused(self):\n        file_path = \"Tests/images/hopper.webp\"\n        with open(file_path, \"rb\") as blob:\n            Image.open(blob).load()\n            Image.open(blob).load()\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_background_from_gif(self, tmp_path):\n        with Image.open(\"Tests/images/chi.gif\") as im:\n            original_value = im.convert(\"RGB\").getpixel((1, 1))\n\n            # Save as WEBP\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        # Save as GIF\n        out_gif = str(tmp_path / \"temp.gif\")\n        with Image.open(out_webp) as im:\n            im.save(out_gif)\n\n        with Image.open(out_gif) as reread:\n            reread_value = reread.convert(\"RGB\").getpixel((1, 1))\n        difference = sum(\n            [abs(original_value[i] - reread_value[i]) for i in range(0, 3)]\n        )\n        assert difference < 5\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_duration(self, tmp_path):\n        with Image.open(\"Tests/images/dispose_bgnd.gif\") as im:\n            assert im.info[\"duration\"] == 1000\n\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        with Image.open(out_webp) as reloaded:\n            reloaded.load()\n            assert reloaded.info[\"duration\"] == 1000\n",
            "header": {
                "file": {
                    "path": "Tests/test_file_webp.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "7fdb32ef4",
                "new_commit_hash": "420594b0c",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_file_webp.py"
            },
            "plus_file": {
                "path": "b/Tests/test_file_webp.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 104,
                            "length": 6
                        },
                        "new_range": {
                            "start": 104,
                            "length": 13
                        },
                        "section": "class TestFileWebp:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        hopper().save(buffer_method, format=\"WEBP\", method=6)",
                                "type": "context"
                            },
                            {
                                "content": "        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_icc_profile(self, tmp_path):",
                                "type": "added"
                            },
                            {
                                "content": "        self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})",
                                "type": "added"
                            },
                            {
                                "content": "        if _webp.HAVE_WEBPANIM:",
                                "type": "added"
                            },
                            {
                                "content": "            self._roundtrip(",
                                "type": "added"
                            },
                            {
                                "content": "                tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None, \"save_all\": True}",
                                "type": "added"
                            },
                            {
                                "content": "            )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_write_unsupported_mode_L(self, tmp_path):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        Saving a black-and-white file to WebP format should work, and be",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_file_webp.py",
                            "type": "class",
                            "name": "TestFileWebp",
                            "content": "class TestFileWebp:\n    def setup_method(self):\n        self.rgb_mode = \"RGB\"\n\n    def test_version(self):\n        _webp.WebPDecoderVersion()\n        _webp.WebPDecoderBuggyAlpha()\n        assert re.search(r\"\\d+\\.\\d+\\.\\d+$\", features.version_module(\"webp\"))\n\n    def test_read_rgb(self):\n        \"\"\"\n        Can we read a RGB mode WebP file without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        with Image.open(\"Tests/images/hopper.webp\") as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            # generated with:\n            # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm\n            assert_image_similar_tofile(image, \"Tests/images/hopper_webp_bits.ppm\", 1.0)\n\n    def _roundtrip(self, tmp_path, mode, epsilon, args={}):\n        temp_file = str(tmp_path / \"temp.webp\")\n\n        hopper(mode).save(temp_file, **args)\n        with Image.open(temp_file) as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            if mode == self.rgb_mode:\n                # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm\n                assert_image_similar_tofile(\n                    image, \"Tests/images/hopper_webp_write.ppm\", 12.0\n                )\n\n            # This test asserts that the images are similar. If the average pixel\n            # difference between the two images is less than the epsilon value,\n            # then we're going to accept that it's a reasonable lossy version of\n            # the image.\n            target = hopper(mode)\n            if mode != self.rgb_mode:\n                target = target.convert(self.rgb_mode)\n            assert_image_similar(image, target, epsilon)\n\n    def test_write_rgb(self, tmp_path):\n        \"\"\"\n        Can we write a RGB mode file to webp without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5)\n\n    def test_write_method(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.0, {\"method\": 6})\n\n        buffer_no_args = io.BytesIO()\n        hopper().save(buffer_no_args, format=\"WEBP\")\n\n        buffer_method = io.BytesIO()\n        hopper().save(buffer_method, format=\"WEBP\", method=6)\n        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()\n\n    def test_icc_profile(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})\n        if _webp.HAVE_WEBPANIM:\n            self._roundtrip(\n                tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None, \"save_all\": True}\n            )\n\n    def test_write_unsupported_mode_L(self, tmp_path):\n        \"\"\"\n        Saving a black-and-white file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"L\", 10.0)\n\n    def test_write_unsupported_mode_P(self, tmp_path):\n        \"\"\"\n        Saving a palette-based file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"P\", 50.0)\n\n    @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason=\"Requires 64-bit system\")\n    def test_write_encoding_error_message(self, tmp_path):\n        temp_file = str(tmp_path / \"temp.webp\")\n        im = Image.new(\"RGB\", (15000, 15000))\n        with pytest.raises(ValueError) as e:\n            im.save(temp_file, method=0)\n        assert str(e.value) == \"encoding error 6\"\n\n    def test_WebPEncode_with_invalid_args(self):\n        \"\"\"\n        Calling encoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimEncoder()\n        with pytest.raises(TypeError):\n            _webp.WebPEncode()\n\n    def test_WebPDecode_with_invalid_args(self):\n        \"\"\"\n        Calling decoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimDecoder()\n        with pytest.raises(TypeError):\n            _webp.WebPDecode()\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n            with pytest.warns(None) as record:\n                image.save(temp_file)\n            assert not record\n\n    def test_file_pointer_could_be_reused(self):\n        file_path = \"Tests/images/hopper.webp\"\n        with open(file_path, \"rb\") as blob:\n            Image.open(blob).load()\n            Image.open(blob).load()\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_background_from_gif(self, tmp_path):\n        with Image.open(\"Tests/images/chi.gif\") as im:\n            original_value = im.convert(\"RGB\").getpixel((1, 1))\n\n            # Save as WEBP\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        # Save as GIF\n        out_gif = str(tmp_path / \"temp.gif\")\n        with Image.open(out_webp) as im:\n            im.save(out_gif)\n\n        with Image.open(out_gif) as reread:\n            reread_value = reread.convert(\"RGB\").getpixel((1, 1))\n        difference = sum(\n            [abs(original_value[i] - reread_value[i]) for i in range(0, 3)]\n        )\n        assert difference < 5\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_duration(self, tmp_path):\n        with Image.open(\"Tests/images/dispose_bgnd.gif\") as im:\n            assert im.info[\"duration\"] == 1000\n\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        with Image.open(out_webp) as reloaded:\n            reloaded.load()\n            assert reloaded.info[\"duration\"] == 1000",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 37,
                            "end_lineno": 207,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Tests/test_file_webp.py",
                            "type": "method",
                            "name": "TestFileWebp.test_icc_profile",
                            "content": "class TestFileWebp:\n    def setup_method(self):\n        self.rgb_mode = \"RGB\"\n\n    def test_version(self):\n        _webp.WebPDecoderVersion()\n        _webp.WebPDecoderBuggyAlpha()\n        assert re.search(r\"\\d+\\.\\d+\\.\\d+$\", features.version_module(\"webp\"))\n\n    def test_read_rgb(self):\n        \"\"\"\n        Can we read a RGB mode WebP file without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        with Image.open(\"Tests/images/hopper.webp\") as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            # generated with:\n            # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm\n            assert_image_similar_tofile(image, \"Tests/images/hopper_webp_bits.ppm\", 1.0)\n\n    def _roundtrip(self, tmp_path, mode, epsilon, args={}):\n        temp_file = str(tmp_path / \"temp.webp\")\n\n        hopper(mode).save(temp_file, **args)\n        with Image.open(temp_file) as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            if mode == self.rgb_mode:\n                # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm\n                assert_image_similar_tofile(\n                    image, \"Tests/images/hopper_webp_write.ppm\", 12.0\n                )\n\n            # This test asserts that the images are similar. If the average pixel\n            # difference between the two images is less than the epsilon value,\n            # then we're going to accept that it's a reasonable lossy version of\n            # the image.\n            target = hopper(mode)\n            if mode != self.rgb_mode:\n                target = target.convert(self.rgb_mode)\n            assert_image_similar(image, target, epsilon)\n\n    def test_write_rgb(self, tmp_path):\n        \"\"\"\n        Can we write a RGB mode file to webp without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5)\n\n    def test_write_method(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.0, {\"method\": 6})\n\n        buffer_no_args = io.BytesIO()\n        hopper().save(buffer_no_args, format=\"WEBP\")\n\n        buffer_method = io.BytesIO()\n        hopper().save(buffer_method, format=\"WEBP\", method=6)\n        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()\n\n    def test_icc_profile(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})\n        if _webp.HAVE_WEBPANIM:\n            self._roundtrip(\n                tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None, \"save_all\": True}\n            )\n\n    def test_write_unsupported_mode_L(self, tmp_path):\n        \"\"\"\n        Saving a black-and-white file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"L\", 10.0)\n\n    def test_write_unsupported_mode_P(self, tmp_path):\n        \"\"\"\n        Saving a palette-based file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"P\", 50.0)\n\n    @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason=\"Requires 64-bit system\")\n    def test_write_encoding_error_message(self, tmp_path):\n        temp_file = str(tmp_path / \"temp.webp\")\n        im = Image.new(\"RGB\", (15000, 15000))\n        with pytest.raises(ValueError) as e:\n            im.save(temp_file, method=0)\n        assert str(e.value) == \"encoding error 6\"\n\n    def test_WebPEncode_with_invalid_args(self):\n        \"\"\"\n        Calling encoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimEncoder()\n        with pytest.raises(TypeError):\n            _webp.WebPEncode()\n\n    def test_WebPDecode_with_invalid_args(self):\n        \"\"\"\n        Calling decoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimDecoder()\n        with pytest.raises(TypeError):\n            _webp.WebPDecode()\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n            with pytest.warns(None) as record:\n                image.save(temp_file)\n            assert not record\n\n    def test_file_pointer_could_be_reused(self):\n        file_path = \"Tests/images/hopper.webp\"\n        with open(file_path, \"rb\") as blob:\n            Image.open(blob).load()\n            Image.open(blob).load()\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_background_from_gif(self, tmp_path):\n        with Image.open(\"Tests/images/chi.gif\") as im:\n            original_value = im.convert(\"RGB\").getpixel((1, 1))\n\n            # Save as WEBP\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        # Save as GIF\n        out_gif = str(tmp_path / \"temp.gif\")\n        with Image.open(out_webp) as im:\n            im.save(out_gif)\n\n        with Image.open(out_gif) as reread:\n            reread_value = reread.convert(\"RGB\").getpixel((1, 1))\n        difference = sum(\n            [abs(original_value[i] - reread_value[i]) for i in range(0, 3)]\n        )\n        assert difference < 5\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_duration(self, tmp_path):\n        with Image.open(\"Tests/images/dispose_bgnd.gif\") as im:\n            assert im.info[\"duration\"] == 1000\n\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        with Image.open(out_webp) as reloaded:\n            reloaded.load()\n            assert reloaded.info[\"duration\"] == 1000",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 107,
                            "end_lineno": 112,
                            "parent": {
                                "file_name": "Tests/test_file_webp.py",
                                "type": "class",
                                "name": "TestFileWebp",
                                "content": "class TestFileWebp:\n    def setup_method(self):\n        self.rgb_mode = \"RGB\"\n\n    def test_version(self):\n        _webp.WebPDecoderVersion()\n        _webp.WebPDecoderBuggyAlpha()\n        assert re.search(r\"\\d+\\.\\d+\\.\\d+$\", features.version_module(\"webp\"))\n\n    def test_read_rgb(self):\n        \"\"\"\n        Can we read a RGB mode WebP file without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        with Image.open(\"Tests/images/hopper.webp\") as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            # generated with:\n            # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm\n            assert_image_similar_tofile(image, \"Tests/images/hopper_webp_bits.ppm\", 1.0)\n\n    def _roundtrip(self, tmp_path, mode, epsilon, args={}):\n        temp_file = str(tmp_path / \"temp.webp\")\n\n        hopper(mode).save(temp_file, **args)\n        with Image.open(temp_file) as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            if mode == self.rgb_mode:\n                # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm\n                assert_image_similar_tofile(\n                    image, \"Tests/images/hopper_webp_write.ppm\", 12.0\n                )\n\n            # This test asserts that the images are similar. If the average pixel\n            # difference between the two images is less than the epsilon value,\n            # then we're going to accept that it's a reasonable lossy version of\n            # the image.\n            target = hopper(mode)\n            if mode != self.rgb_mode:\n                target = target.convert(self.rgb_mode)\n            assert_image_similar(image, target, epsilon)\n\n    def test_write_rgb(self, tmp_path):\n        \"\"\"\n        Can we write a RGB mode file to webp without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5)\n\n    def test_write_method(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.0, {\"method\": 6})\n\n        buffer_no_args = io.BytesIO()\n        hopper().save(buffer_no_args, format=\"WEBP\")\n\n        buffer_method = io.BytesIO()\n        hopper().save(buffer_method, format=\"WEBP\", method=6)\n        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()\n\n    def test_icc_profile(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})\n        if _webp.HAVE_WEBPANIM:\n            self._roundtrip(\n                tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None, \"save_all\": True}\n            )\n\n    def test_write_unsupported_mode_L(self, tmp_path):\n        \"\"\"\n        Saving a black-and-white file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"L\", 10.0)\n\n    def test_write_unsupported_mode_P(self, tmp_path):\n        \"\"\"\n        Saving a palette-based file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"P\", 50.0)\n\n    @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason=\"Requires 64-bit system\")\n    def test_write_encoding_error_message(self, tmp_path):\n        temp_file = str(tmp_path / \"temp.webp\")\n        im = Image.new(\"RGB\", (15000, 15000))\n        with pytest.raises(ValueError) as e:\n            im.save(temp_file, method=0)\n        assert str(e.value) == \"encoding error 6\"\n\n    def test_WebPEncode_with_invalid_args(self):\n        \"\"\"\n        Calling encoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimEncoder()\n        with pytest.raises(TypeError):\n            _webp.WebPEncode()\n\n    def test_WebPDecode_with_invalid_args(self):\n        \"\"\"\n        Calling decoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimDecoder()\n        with pytest.raises(TypeError):\n            _webp.WebPDecode()\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n            with pytest.warns(None) as record:\n                image.save(temp_file)\n            assert not record\n\n    def test_file_pointer_could_be_reused(self):\n        file_path = \"Tests/images/hopper.webp\"\n        with open(file_path, \"rb\") as blob:\n            Image.open(blob).load()\n            Image.open(blob).load()\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_background_from_gif(self, tmp_path):\n        with Image.open(\"Tests/images/chi.gif\") as im:\n            original_value = im.convert(\"RGB\").getpixel((1, 1))\n\n            # Save as WEBP\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        # Save as GIF\n        out_gif = str(tmp_path / \"temp.gif\")\n        with Image.open(out_webp) as im:\n            im.save(out_gif)\n\n        with Image.open(out_gif) as reread:\n            reread_value = reread.convert(\"RGB\").getpixel((1, 1))\n        difference = sum(\n            [abs(original_value[i] - reread_value[i]) for i in range(0, 3)]\n        )\n        assert difference < 5\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_duration(self, tmp_path):\n        with Image.open(\"Tests/images/dispose_bgnd.gif\") as im:\n            assert im.info[\"duration\"] == 1000\n\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        with Image.open(out_webp) as reloaded:\n            reloaded.load()\n            assert reloaded.info[\"duration\"] == 1000",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 37,
                                "end_lineno": 207,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "from io import BytesIO\n\nfrom . import Image, ImageFile\n\ntry:\n    from . import _webp\n\n    SUPPORTED = True\nexcept ImportError:\n    SUPPORTED = False\n\n\n_VALID_WEBP_MODES = {\"RGBX\": True, \"RGBA\": True, \"RGB\": True}\n\n_VALID_WEBP_LEGACY_MODES = {\"RGB\": True, \"RGBA\": True}\n\n_VP8_MODES_BY_IDENTIFIER = {\n    b\"VP8 \": \"RGB\",\n    b\"VP8X\": \"RGBA\",\n    b\"VP8L\": \"RGBA\",  # lossless\n}\n\n\ndef _accept(prefix):\n    is_riff_file_format = prefix[:4] == b\"RIFF\"\n    is_webp_file = prefix[8:12] == b\"WEBP\"\n    is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER\n\n    if is_riff_file_format and is_webp_file and is_valid_vp8_mode:\n        if not SUPPORTED:\n            return (\n                \"image file could not be identified because WEBP support not installed\"\n            )\n        return True\n\n\nclass WebPImageFile(ImageFile.ImageFile):\n\n    format = \"WEBP\"\n    format_description = \"WebP image\"\n    __loaded = 0\n    __logical_frame = 0\n\n    def _open(self):\n        if not _webp.HAVE_WEBPANIM:\n            # Legacy mode\n            data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(\n                self.fp.read()\n            )\n            if icc_profile:\n                self.info[\"icc_profile\"] = icc_profile\n            if exif:\n                self.info[\"exif\"] = exif\n            self._size = width, height\n            self.fp = BytesIO(data)\n            self.tile = [(\"raw\", (0, 0) + self.size, 0, self.mode)]\n            self.n_frames = 1\n            self.is_animated = False\n            return\n\n        # Use the newer AnimDecoder API to parse the (possibly) animated file,\n        # and access muxed chunks like ICC/EXIF/XMP.\n        self._decoder = _webp.WebPAnimDecoder(self.fp.read())\n\n        # Get info from decoder\n        width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()\n        self._size = width, height\n        self.info[\"loop\"] = loop_count\n        bg_a, bg_r, bg_g, bg_b = (\n            (bgcolor >> 24) & 0xFF,\n            (bgcolor >> 16) & 0xFF,\n            (bgcolor >> 8) & 0xFF,\n            bgcolor & 0xFF,\n        )\n        self.info[\"background\"] = (bg_r, bg_g, bg_b, bg_a)\n        self.n_frames = frame_count\n        self.is_animated = self.n_frames > 1\n        self.mode = \"RGB\" if mode == \"RGBX\" else mode\n        self.rawmode = mode\n        self.tile = []\n\n        # Attempt to read ICC / EXIF / XMP chunks from file\n        icc_profile = self._decoder.get_chunk(\"ICCP\")\n        exif = self._decoder.get_chunk(\"EXIF\")\n        xmp = self._decoder.get_chunk(\"XMP \")\n        if icc_profile:\n            self.info[\"icc_profile\"] = icc_profile\n        if exif:\n            self.info[\"exif\"] = exif\n        if xmp:\n            self.info[\"xmp\"] = xmp\n\n        # Initialize seek state\n        self._reset(reset=False)\n\n    def _getexif(self):\n        if \"exif\" not in self.info:\n            return None\n        return self.getexif()._get_merged_dict()\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n\n        # Set logical frame to requested position\n        self.__logical_frame = frame\n\n    def _reset(self, reset=True):\n        if reset:\n            self._decoder.reset()\n        self.__physical_frame = 0\n        self.__loaded = -1\n        self.__timestamp = 0\n\n    def _get_next(self):\n        # Get next frame\n        ret = self._decoder.get_next()\n        self.__physical_frame += 1\n\n        # Check if an error occurred\n        if ret is None:\n            self._reset()  # Reset just to be safe\n            self.seek(0)\n            raise EOFError(\"failed to decode next frame in WebP file\")\n\n        # Compute duration\n        data, timestamp = ret\n        duration = timestamp - self.__timestamp\n        self.__timestamp = timestamp\n\n        # libwebp gives frame end, adjust to start of frame\n        timestamp -= duration\n        return data, timestamp, duration\n\n    def _seek(self, frame):\n        if self.__physical_frame == frame:\n            return  # Nothing to do\n        if frame < self.__physical_frame:\n            self._reset()  # Rewind to beginning\n        while self.__physical_frame < frame:\n            self._get_next()  # Advance to the requested frame\n\n    def load(self):\n        if _webp.HAVE_WEBPANIM:\n            if self.__loaded != self.__logical_frame:\n                self._seek(self.__logical_frame)\n\n                # We need to load the image data for this frame\n                data, timestamp, duration = self._get_next()\n                self.info[\"timestamp\"] = timestamp\n                self.info[\"duration\"] = duration\n                self.__loaded = self.__logical_frame\n\n                # Set tile\n                if self.fp and self._exclusive_fp:\n                    self.fp.close()\n                self.fp = BytesIO(data)\n                self.tile = [(\"raw\", (0, 0) + self.size, 0, self.rawmode)]\n\n        return super().load()\n\n    def tell(self):\n        if not _webp.HAVE_WEBPANIM:\n            return super().tell()\n\n        return self.__logical_frame\n\n\ndef _save_all(im, fp, filename):\n    encoderinfo = im.encoderinfo.copy()\n    append_images = list(encoderinfo.get(\"append_images\", []))\n\n    # If total frame count is 1, then save using the legacy API, which\n    # will preserve non-alpha modes\n    total = 0\n    for ims in [im] + append_images:\n        total += getattr(ims, \"n_frames\", 1)\n    if total == 1:\n        _save(im, fp, filename)\n        return\n\n    background = (0, 0, 0, 0)\n    if \"background\" in encoderinfo:\n        background = encoderinfo[\"background\"]\n    elif \"background\" in im.info:\n        background = im.info[\"background\"]\n        if isinstance(background, int):\n            # GifImagePlugin stores a global color table index in\n            # info[\"background\"]. So it must be converted to an RGBA value\n            palette = im.getpalette()\n            if palette:\n                r, g, b = palette[background * 3 : (background + 1) * 3]\n                background = (r, g, b, 0)\n\n    duration = im.encoderinfo.get(\"duration\", im.info.get(\"duration\"))\n    loop = im.encoderinfo.get(\"loop\", 0)\n    minimize_size = im.encoderinfo.get(\"minimize_size\", False)\n    kmin = im.encoderinfo.get(\"kmin\", None)\n    kmax = im.encoderinfo.get(\"kmax\", None)\n    allow_mixed = im.encoderinfo.get(\"allow_mixed\", False)\n    verbose = False\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    method = im.encoderinfo.get(\"method\", 0)\n    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    if allow_mixed:\n        lossless = False\n\n    # Sensible keyframe defaults are from gif2webp.c script\n    if kmin is None:\n        kmin = 9 if lossless else 3\n    if kmax is None:\n        kmax = 17 if lossless else 5\n\n    # Validate background color\n    if (\n        not isinstance(background, (list, tuple))\n        or len(background) != 4\n        or not all(v >= 0 and v < 256 for v in background)\n    ):\n        raise OSError(\n            \"Background color is not an RGBA tuple clamped to (0-255): %s\"\n            % str(background)\n        )\n\n    # Convert to packed uint\n    bg_r, bg_g, bg_b, bg_a = background\n    background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)\n\n    # Setup the WebP animation encoder\n    enc = _webp.WebPAnimEncoder(\n        im.size[0],\n        im.size[1],\n        background,\n        loop,\n        minimize_size,\n        kmin,\n        kmax,\n        allow_mixed,\n        verbose,\n    )\n\n    # Add each frame\n    frame_idx = 0\n    timestamp = 0\n    cur_idx = im.tell()\n    try:\n        for ims in [im] + append_images:\n            # Get # of frames in this image\n            nfr = getattr(ims, \"n_frames\", 1)\n\n            for idx in range(nfr):\n                ims.seek(idx)\n                ims.load()\n\n                # Make sure image mode is supported\n                frame = ims\n                rawmode = ims.mode\n                if ims.mode not in _VALID_WEBP_MODES:\n                    alpha = (\n                        \"A\" in ims.mode\n                        or \"a\" in ims.mode\n                        or (ims.mode == \"P\" and \"A\" in ims.im.getpalettemode())\n                    )\n                    rawmode = \"RGBA\" if alpha else \"RGB\"\n                    frame = ims.convert(rawmode)\n\n                if rawmode == \"RGB\":\n                    # For faster conversion, use RGBX\n                    rawmode = \"RGBX\"\n\n                # Append the frame to the animation encoder\n                enc.add(\n                    frame.tobytes(\"raw\", rawmode),\n                    timestamp,\n                    frame.size[0],\n                    frame.size[1],\n                    rawmode,\n                    lossless,\n                    quality,\n                    method,\n                )\n\n                # Update timestamp and frame index\n                if isinstance(duration, (list, tuple)):\n                    timestamp += duration[frame_idx]\n                else:\n                    timestamp += duration\n                frame_idx += 1\n\n    finally:\n        im.seek(cur_idx)\n\n    # Force encoder to flush frames\n    enc.add(None, timestamp, 0, 0, \"\", lossless, quality, 0)\n\n    # Get the final output from the encoder\n    data = enc.assemble(icc_profile, exif, xmp)\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)\n\n\ndef _save(im, fp, filename):\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    method = im.encoderinfo.get(\"method\", 4)\n\n    if im.mode not in _VALID_WEBP_LEGACY_MODES:\n        alpha = (\n            \"A\" in im.mode\n            or \"a\" in im.mode\n            or (im.mode == \"P\" and \"transparency\" in im.info)\n        )\n        im = im.convert(\"RGBA\" if alpha else \"RGB\")\n\n    data = _webp.WebPEncode(\n        im.tobytes(),\n        im.size[0],\n        im.size[1],\n        lossless,\n        float(quality),\n        im.mode,\n        icc_profile,\n        method,\n        exif,\n        xmp,\n    )\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)\n\n\nImage.register_open(WebPImageFile.format, WebPImageFile, _accept)\nif SUPPORTED:\n    Image.register_save(WebPImageFile.format, _save)\n    if _webp.HAVE_WEBPANIM:\n        Image.register_save_all(WebPImageFile.format, _save_all)\n    Image.register_extension(WebPImageFile.format, \".webp\")\n    Image.register_mime(WebPImageFile.format, \"image/webp\")\n",
            "new_file_content": "from io import BytesIO\n\nfrom . import Image, ImageFile\n\ntry:\n    from . import _webp\n\n    SUPPORTED = True\nexcept ImportError:\n    SUPPORTED = False\n\n\n_VALID_WEBP_MODES = {\"RGBX\": True, \"RGBA\": True, \"RGB\": True}\n\n_VALID_WEBP_LEGACY_MODES = {\"RGB\": True, \"RGBA\": True}\n\n_VP8_MODES_BY_IDENTIFIER = {\n    b\"VP8 \": \"RGB\",\n    b\"VP8X\": \"RGBA\",\n    b\"VP8L\": \"RGBA\",  # lossless\n}\n\n\ndef _accept(prefix):\n    is_riff_file_format = prefix[:4] == b\"RIFF\"\n    is_webp_file = prefix[8:12] == b\"WEBP\"\n    is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER\n\n    if is_riff_file_format and is_webp_file and is_valid_vp8_mode:\n        if not SUPPORTED:\n            return (\n                \"image file could not be identified because WEBP support not installed\"\n            )\n        return True\n\n\nclass WebPImageFile(ImageFile.ImageFile):\n\n    format = \"WEBP\"\n    format_description = \"WebP image\"\n    __loaded = 0\n    __logical_frame = 0\n\n    def _open(self):\n        if not _webp.HAVE_WEBPANIM:\n            # Legacy mode\n            data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(\n                self.fp.read()\n            )\n            if icc_profile:\n                self.info[\"icc_profile\"] = icc_profile\n            if exif:\n                self.info[\"exif\"] = exif\n            self._size = width, height\n            self.fp = BytesIO(data)\n            self.tile = [(\"raw\", (0, 0) + self.size, 0, self.mode)]\n            self.n_frames = 1\n            self.is_animated = False\n            return\n\n        # Use the newer AnimDecoder API to parse the (possibly) animated file,\n        # and access muxed chunks like ICC/EXIF/XMP.\n        self._decoder = _webp.WebPAnimDecoder(self.fp.read())\n\n        # Get info from decoder\n        width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()\n        self._size = width, height\n        self.info[\"loop\"] = loop_count\n        bg_a, bg_r, bg_g, bg_b = (\n            (bgcolor >> 24) & 0xFF,\n            (bgcolor >> 16) & 0xFF,\n            (bgcolor >> 8) & 0xFF,\n            bgcolor & 0xFF,\n        )\n        self.info[\"background\"] = (bg_r, bg_g, bg_b, bg_a)\n        self.n_frames = frame_count\n        self.is_animated = self.n_frames > 1\n        self.mode = \"RGB\" if mode == \"RGBX\" else mode\n        self.rawmode = mode\n        self.tile = []\n\n        # Attempt to read ICC / EXIF / XMP chunks from file\n        icc_profile = self._decoder.get_chunk(\"ICCP\")\n        exif = self._decoder.get_chunk(\"EXIF\")\n        xmp = self._decoder.get_chunk(\"XMP \")\n        if icc_profile:\n            self.info[\"icc_profile\"] = icc_profile\n        if exif:\n            self.info[\"exif\"] = exif\n        if xmp:\n            self.info[\"xmp\"] = xmp\n\n        # Initialize seek state\n        self._reset(reset=False)\n\n    def _getexif(self):\n        if \"exif\" not in self.info:\n            return None\n        return self.getexif()._get_merged_dict()\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n\n        # Set logical frame to requested position\n        self.__logical_frame = frame\n\n    def _reset(self, reset=True):\n        if reset:\n            self._decoder.reset()\n        self.__physical_frame = 0\n        self.__loaded = -1\n        self.__timestamp = 0\n\n    def _get_next(self):\n        # Get next frame\n        ret = self._decoder.get_next()\n        self.__physical_frame += 1\n\n        # Check if an error occurred\n        if ret is None:\n            self._reset()  # Reset just to be safe\n            self.seek(0)\n            raise EOFError(\"failed to decode next frame in WebP file\")\n\n        # Compute duration\n        data, timestamp = ret\n        duration = timestamp - self.__timestamp\n        self.__timestamp = timestamp\n\n        # libwebp gives frame end, adjust to start of frame\n        timestamp -= duration\n        return data, timestamp, duration\n\n    def _seek(self, frame):\n        if self.__physical_frame == frame:\n            return  # Nothing to do\n        if frame < self.__physical_frame:\n            self._reset()  # Rewind to beginning\n        while self.__physical_frame < frame:\n            self._get_next()  # Advance to the requested frame\n\n    def load(self):\n        if _webp.HAVE_WEBPANIM:\n            if self.__loaded != self.__logical_frame:\n                self._seek(self.__logical_frame)\n\n                # We need to load the image data for this frame\n                data, timestamp, duration = self._get_next()\n                self.info[\"timestamp\"] = timestamp\n                self.info[\"duration\"] = duration\n                self.__loaded = self.__logical_frame\n\n                # Set tile\n                if self.fp and self._exclusive_fp:\n                    self.fp.close()\n                self.fp = BytesIO(data)\n                self.tile = [(\"raw\", (0, 0) + self.size, 0, self.rawmode)]\n\n        return super().load()\n\n    def tell(self):\n        if not _webp.HAVE_WEBPANIM:\n            return super().tell()\n\n        return self.__logical_frame\n\n\ndef _save_all(im, fp, filename):\n    encoderinfo = im.encoderinfo.copy()\n    append_images = list(encoderinfo.get(\"append_images\", []))\n\n    # If total frame count is 1, then save using the legacy API, which\n    # will preserve non-alpha modes\n    total = 0\n    for ims in [im] + append_images:\n        total += getattr(ims, \"n_frames\", 1)\n    if total == 1:\n        _save(im, fp, filename)\n        return\n\n    background = (0, 0, 0, 0)\n    if \"background\" in encoderinfo:\n        background = encoderinfo[\"background\"]\n    elif \"background\" in im.info:\n        background = im.info[\"background\"]\n        if isinstance(background, int):\n            # GifImagePlugin stores a global color table index in\n            # info[\"background\"]. So it must be converted to an RGBA value\n            palette = im.getpalette()\n            if palette:\n                r, g, b = palette[background * 3 : (background + 1) * 3]\n                background = (r, g, b, 0)\n\n    duration = im.encoderinfo.get(\"duration\", im.info.get(\"duration\"))\n    loop = im.encoderinfo.get(\"loop\", 0)\n    minimize_size = im.encoderinfo.get(\"minimize_size\", False)\n    kmin = im.encoderinfo.get(\"kmin\", None)\n    kmax = im.encoderinfo.get(\"kmax\", None)\n    allow_mixed = im.encoderinfo.get(\"allow_mixed\", False)\n    verbose = False\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    method = im.encoderinfo.get(\"method\", 0)\n    icc_profile = im.encoderinfo.get(\"icc_profile\") or \"\"\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    if allow_mixed:\n        lossless = False\n\n    # Sensible keyframe defaults are from gif2webp.c script\n    if kmin is None:\n        kmin = 9 if lossless else 3\n    if kmax is None:\n        kmax = 17 if lossless else 5\n\n    # Validate background color\n    if (\n        not isinstance(background, (list, tuple))\n        or len(background) != 4\n        or not all(v >= 0 and v < 256 for v in background)\n    ):\n        raise OSError(\n            \"Background color is not an RGBA tuple clamped to (0-255): %s\"\n            % str(background)\n        )\n\n    # Convert to packed uint\n    bg_r, bg_g, bg_b, bg_a = background\n    background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)\n\n    # Setup the WebP animation encoder\n    enc = _webp.WebPAnimEncoder(\n        im.size[0],\n        im.size[1],\n        background,\n        loop,\n        minimize_size,\n        kmin,\n        kmax,\n        allow_mixed,\n        verbose,\n    )\n\n    # Add each frame\n    frame_idx = 0\n    timestamp = 0\n    cur_idx = im.tell()\n    try:\n        for ims in [im] + append_images:\n            # Get # of frames in this image\n            nfr = getattr(ims, \"n_frames\", 1)\n\n            for idx in range(nfr):\n                ims.seek(idx)\n                ims.load()\n\n                # Make sure image mode is supported\n                frame = ims\n                rawmode = ims.mode\n                if ims.mode not in _VALID_WEBP_MODES:\n                    alpha = (\n                        \"A\" in ims.mode\n                        or \"a\" in ims.mode\n                        or (ims.mode == \"P\" and \"A\" in ims.im.getpalettemode())\n                    )\n                    rawmode = \"RGBA\" if alpha else \"RGB\"\n                    frame = ims.convert(rawmode)\n\n                if rawmode == \"RGB\":\n                    # For faster conversion, use RGBX\n                    rawmode = \"RGBX\"\n\n                # Append the frame to the animation encoder\n                enc.add(\n                    frame.tobytes(\"raw\", rawmode),\n                    timestamp,\n                    frame.size[0],\n                    frame.size[1],\n                    rawmode,\n                    lossless,\n                    quality,\n                    method,\n                )\n\n                # Update timestamp and frame index\n                if isinstance(duration, (list, tuple)):\n                    timestamp += duration[frame_idx]\n                else:\n                    timestamp += duration\n                frame_idx += 1\n\n    finally:\n        im.seek(cur_idx)\n\n    # Force encoder to flush frames\n    enc.add(None, timestamp, 0, 0, \"\", lossless, quality, 0)\n\n    # Get the final output from the encoder\n    data = enc.assemble(icc_profile, exif, xmp)\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)\n\n\ndef _save(im, fp, filename):\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    icc_profile = im.encoderinfo.get(\"icc_profile\") or \"\"\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    method = im.encoderinfo.get(\"method\", 4)\n\n    if im.mode not in _VALID_WEBP_LEGACY_MODES:\n        alpha = (\n            \"A\" in im.mode\n            or \"a\" in im.mode\n            or (im.mode == \"P\" and \"transparency\" in im.info)\n        )\n        im = im.convert(\"RGBA\" if alpha else \"RGB\")\n\n    data = _webp.WebPEncode(\n        im.tobytes(),\n        im.size[0],\n        im.size[1],\n        lossless,\n        float(quality),\n        im.mode,\n        icc_profile,\n        method,\n        exif,\n        xmp,\n    )\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)\n\n\nImage.register_open(WebPImageFile.format, WebPImageFile, _accept)\nif SUPPORTED:\n    Image.register_save(WebPImageFile.format, _save)\n    if _webp.HAVE_WEBPANIM:\n        Image.register_save_all(WebPImageFile.format, _save_all)\n    Image.register_extension(WebPImageFile.format, \".webp\")\n    Image.register_mime(WebPImageFile.format, \"image/webp\")\n",
            "header": {
                "file": {
                    "path": "src/PIL/WebPImagePlugin.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "b63a07ca8",
                "new_commit_hash": "590161f3e",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/WebPImagePlugin.py"
            },
            "plus_file": {
                "path": "b/src/PIL/WebPImagePlugin.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 202,
                            "length": 7
                        },
                        "new_range": {
                            "start": 202,
                            "length": 7
                        },
                        "section": "def _save_all(im, fp, filename):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    lossless = im.encoderinfo.get(\"lossless\", False)",
                                "type": "context"
                            },
                            {
                                "content": "    quality = im.encoderinfo.get(\"quality\", 80)",
                                "type": "context"
                            },
                            {
                                "content": "    method = im.encoderinfo.get(\"method\", 0)",
                                "type": "context"
                            },
                            {
                                "content": "    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")",
                                "type": "deleted"
                            },
                            {
                                "content": "    icc_profile = im.encoderinfo.get(\"icc_profile\") or \"\"",
                                "type": "added"
                            },
                            {
                                "content": "    exif = im.encoderinfo.get(\"exif\", \"\")",
                                "type": "context"
                            },
                            {
                                "content": "    if isinstance(exif, Image.Exif):",
                                "type": "context"
                            },
                            {
                                "content": "        exif = exif.tobytes()",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/WebPImagePlugin.py",
                            "type": "function",
                            "name": "_save_all",
                            "content": "def _save_all(im, fp, filename):\n    encoderinfo = im.encoderinfo.copy()\n    append_images = list(encoderinfo.get(\"append_images\", []))\n\n    # If total frame count is 1, then save using the legacy API, which\n    # will preserve non-alpha modes\n    total = 0\n    for ims in [im] + append_images:\n        total += getattr(ims, \"n_frames\", 1)\n    if total == 1:\n        _save(im, fp, filename)\n        return\n\n    background = (0, 0, 0, 0)\n    if \"background\" in encoderinfo:\n        background = encoderinfo[\"background\"]\n    elif \"background\" in im.info:\n        background = im.info[\"background\"]\n        if isinstance(background, int):\n            # GifImagePlugin stores a global color table index in\n            # info[\"background\"]. So it must be converted to an RGBA value\n            palette = im.getpalette()\n            if palette:\n                r, g, b = palette[background * 3 : (background + 1) * 3]\n                background = (r, g, b, 0)\n\n    duration = im.encoderinfo.get(\"duration\", im.info.get(\"duration\"))\n    loop = im.encoderinfo.get(\"loop\", 0)\n    minimize_size = im.encoderinfo.get(\"minimize_size\", False)\n    kmin = im.encoderinfo.get(\"kmin\", None)\n    kmax = im.encoderinfo.get(\"kmax\", None)\n    allow_mixed = im.encoderinfo.get(\"allow_mixed\", False)\n    verbose = False\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    method = im.encoderinfo.get(\"method\", 0)\n    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    if allow_mixed:\n        lossless = False\n\n    # Sensible keyframe defaults are from gif2webp.c script\n    if kmin is None:\n        kmin = 9 if lossless else 3\n    if kmax is None:\n        kmax = 17 if lossless else 5\n\n    # Validate background color\n    if (\n        not isinstance(background, (list, tuple))\n        or len(background) != 4\n        or not all(v >= 0 and v < 256 for v in background)\n    ):\n        raise OSError(\n            \"Background color is not an RGBA tuple clamped to (0-255): %s\"\n            % str(background)\n        )\n\n    # Convert to packed uint\n    bg_r, bg_g, bg_b, bg_a = background\n    background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)\n\n    # Setup the WebP animation encoder\n    enc = _webp.WebPAnimEncoder(\n        im.size[0],\n        im.size[1],\n        background,\n        loop,\n        minimize_size,\n        kmin,\n        kmax,\n        allow_mixed,\n        verbose,\n    )\n\n    # Add each frame\n    frame_idx = 0\n    timestamp = 0\n    cur_idx = im.tell()\n    try:\n        for ims in [im] + append_images:\n            # Get # of frames in this image\n            nfr = getattr(ims, \"n_frames\", 1)\n\n            for idx in range(nfr):\n                ims.seek(idx)\n                ims.load()\n\n                # Make sure image mode is supported\n                frame = ims\n                rawmode = ims.mode\n                if ims.mode not in _VALID_WEBP_MODES:\n                    alpha = (\n                        \"A\" in ims.mode\n                        or \"a\" in ims.mode\n                        or (ims.mode == \"P\" and \"A\" in ims.im.getpalettemode())\n                    )\n                    rawmode = \"RGBA\" if alpha else \"RGB\"\n                    frame = ims.convert(rawmode)\n\n                if rawmode == \"RGB\":\n                    # For faster conversion, use RGBX\n                    rawmode = \"RGBX\"\n\n                # Append the frame to the animation encoder\n                enc.add(\n                    frame.tobytes(\"raw\", rawmode),\n                    timestamp,\n                    frame.size[0],\n                    frame.size[1],\n                    rawmode,\n                    lossless,\n                    quality,\n                    method,\n                )\n\n                # Update timestamp and frame index\n                if isinstance(duration, (list, tuple)):\n                    timestamp += duration[frame_idx]\n                else:\n                    timestamp += duration\n                frame_idx += 1\n\n    finally:\n        im.seek(cur_idx)\n\n    # Force encoder to flush frames\n    enc.add(None, timestamp, 0, 0, \"\", lossless, quality, 0)\n\n    # Get the final output from the encoder\n    data = enc.assemble(icc_profile, exif, xmp)\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 169,
                            "end_lineno": 306,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 309,
                            "length": 7
                        },
                        "new_range": {
                            "start": 309,
                            "length": 7
                        },
                        "section": "def _save_all(im, fp, filename):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "def _save(im, fp, filename):",
                                "type": "context"
                            },
                            {
                                "content": "    lossless = im.encoderinfo.get(\"lossless\", False)",
                                "type": "context"
                            },
                            {
                                "content": "    quality = im.encoderinfo.get(\"quality\", 80)",
                                "type": "context"
                            },
                            {
                                "content": "    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")",
                                "type": "deleted"
                            },
                            {
                                "content": "    icc_profile = im.encoderinfo.get(\"icc_profile\") or \"\"",
                                "type": "added"
                            },
                            {
                                "content": "    exif = im.encoderinfo.get(\"exif\", \"\")",
                                "type": "context"
                            },
                            {
                                "content": "    if isinstance(exif, Image.Exif):",
                                "type": "context"
                            },
                            {
                                "content": "        exif = exif.tobytes()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/WebPImagePlugin.py",
                            "type": "function",
                            "name": "_save",
                            "content": "def _save(im, fp, filename):\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    method = im.encoderinfo.get(\"method\", 4)\n\n    if im.mode not in _VALID_WEBP_LEGACY_MODES:\n        alpha = (\n            \"A\" in im.mode\n            or \"a\" in im.mode\n            or (im.mode == \"P\" and \"transparency\" in im.info)\n        )\n        im = im.convert(\"RGBA\" if alpha else \"RGB\")\n\n    data = _webp.WebPEncode(\n        im.tobytes(),\n        im.size[0],\n        im.size[1],\n        lossless,\n        float(quality),\n        im.mode,\n        icc_profile,\n        method,\n        exif,\n        xmp,\n    )\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 309,
                            "end_lineno": 342,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "faaeee1e7ddbb7938be51268c2f4da070b2a0c13^",
    "new_commit_hash": "faaeee1e7ddbb7938be51268c2f4da070b2a0c13",
    "commit_message": "Merge pull request #5601 from radarhere/webp_icc_profile\n\nAllow saving WebP with icc_profile None",
    "commit_date": "2021-07-28T13:10:36+03:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "faaeee1e7ddbb7938be51268c2f4da070b2a0c13",
    "test_file_codes": [
        "import io\nimport re\nimport sys\n\nimport pytest\n\nfrom PIL import Image, WebPImagePlugin, features\n\nfrom .helper import (\n    assert_image_similar,\n    assert_image_similar_tofile,\n    hopper,\n    skip_unless_feature,\n)\n\ntry:\n    from PIL import _webp\n\n    HAVE_WEBP = True\nexcept ImportError:\n    HAVE_WEBP = False\n\n\nclass TestUnsupportedWebp:\n    def test_unsupported(self):\n        if HAVE_WEBP:\n            WebPImagePlugin.SUPPORTED = False\n\n        file_path = \"Tests/images/hopper.webp\"\n        pytest.warns(UserWarning, lambda: pytest.raises(OSError, Image.open, file_path))\n\n        if HAVE_WEBP:\n            WebPImagePlugin.SUPPORTED = True\n\n\n@skip_unless_feature(\"webp\")\nclass TestFileWebp:\n    def setup_method(self):\n        self.rgb_mode = \"RGB\"\n\n    def test_version(self):\n        _webp.WebPDecoderVersion()\n        _webp.WebPDecoderBuggyAlpha()\n        assert re.search(r\"\\d+\\.\\d+\\.\\d+$\", features.version_module(\"webp\"))\n\n    def test_read_rgb(self):\n        \"\"\"\n        Can we read a RGB mode WebP file without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        with Image.open(\"Tests/images/hopper.webp\") as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            # generated with:\n            # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm\n            assert_image_similar_tofile(image, \"Tests/images/hopper_webp_bits.ppm\", 1.0)\n\n    def _roundtrip(self, tmp_path, mode, epsilon, args={}):\n        temp_file = str(tmp_path / \"temp.webp\")\n\n        hopper(mode).save(temp_file, **args)\n        with Image.open(temp_file) as image:\n            assert image.mode == self.rgb_mode\n            assert image.size == (128, 128)\n            assert image.format == \"WEBP\"\n            image.load()\n            image.getdata()\n\n            if mode == self.rgb_mode:\n                # generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm\n                assert_image_similar_tofile(\n                    image, \"Tests/images/hopper_webp_write.ppm\", 12.0\n                )\n\n            # This test asserts that the images are similar. If the average pixel\n            # difference between the two images is less than the epsilon value,\n            # then we're going to accept that it's a reasonable lossy version of\n            # the image.\n            target = hopper(mode)\n            if mode != self.rgb_mode:\n                target = target.convert(self.rgb_mode)\n            assert_image_similar(image, target, epsilon)\n\n    def test_write_rgb(self, tmp_path):\n        \"\"\"\n        Can we write a RGB mode file to webp without error?\n        Does it have the bits we expect?\n        \"\"\"\n\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5)\n\n    def test_write_method(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.0, {\"method\": 6})\n\n        buffer_no_args = io.BytesIO()\n        hopper().save(buffer_no_args, format=\"WEBP\")\n\n        buffer_method = io.BytesIO()\n        hopper().save(buffer_method, format=\"WEBP\", method=6)\n        assert buffer_no_args.getbuffer() != buffer_method.getbuffer()\n\n    def test_icc_profile(self, tmp_path):\n        self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})\n        if _webp.HAVE_WEBPANIM:\n            self._roundtrip(\n                tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None, \"save_all\": True}\n            )\n\n    def test_write_unsupported_mode_L(self, tmp_path):\n        \"\"\"\n        Saving a black-and-white file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"L\", 10.0)\n\n    def test_write_unsupported_mode_P(self, tmp_path):\n        \"\"\"\n        Saving a palette-based file to WebP format should work, and be\n        similar to the original file.\n        \"\"\"\n\n        self._roundtrip(tmp_path, \"P\", 50.0)\n\n    @pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason=\"Requires 64-bit system\")\n    def test_write_encoding_error_message(self, tmp_path):\n        temp_file = str(tmp_path / \"temp.webp\")\n        im = Image.new(\"RGB\", (15000, 15000))\n        with pytest.raises(ValueError) as e:\n            im.save(temp_file, method=0)\n        assert str(e.value) == \"encoding error 6\"\n\n    def test_WebPEncode_with_invalid_args(self):\n        \"\"\"\n        Calling encoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimEncoder()\n        with pytest.raises(TypeError):\n            _webp.WebPEncode()\n\n    def test_WebPDecode_with_invalid_args(self):\n        \"\"\"\n        Calling decoder functions with no arguments should result in an error.\n        \"\"\"\n\n        if _webp.HAVE_WEBPANIM:\n            with pytest.raises(TypeError):\n                _webp.WebPAnimDecoder()\n        with pytest.raises(TypeError):\n            _webp.WebPDecode()\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n            with pytest.warns(None) as record:\n                image.save(temp_file)\n            assert not record\n\n    def test_file_pointer_could_be_reused(self):\n        file_path = \"Tests/images/hopper.webp\"\n        with open(file_path, \"rb\") as blob:\n            Image.open(blob).load()\n            Image.open(blob).load()\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_background_from_gif(self, tmp_path):\n        with Image.open(\"Tests/images/chi.gif\") as im:\n            original_value = im.convert(\"RGB\").getpixel((1, 1))\n\n            # Save as WEBP\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        # Save as GIF\n        out_gif = str(tmp_path / \"temp.gif\")\n        with Image.open(out_webp) as im:\n            im.save(out_gif)\n\n        with Image.open(out_gif) as reread:\n            reread_value = reread.convert(\"RGB\").getpixel((1, 1))\n        difference = sum(\n            [abs(original_value[i] - reread_value[i]) for i in range(0, 3)]\n        )\n        assert difference < 5\n\n    @skip_unless_feature(\"webp\")\n    @skip_unless_feature(\"webp_anim\")\n    def test_duration(self, tmp_path):\n        with Image.open(\"Tests/images/dispose_bgnd.gif\") as im:\n            assert im.info[\"duration\"] == 1000\n\n            out_webp = str(tmp_path / \"temp.webp\")\n            im.save(out_webp, save_all=True)\n\n        with Image.open(out_webp) as reloaded:\n            reloaded.load()\n            assert reloaded.info[\"duration\"] == 1000\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Pillow installation attempts...\nVerifying Pillow installation...\n✅ Pillow installation successful!\nSuccessfully installed Pillow\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 12 packages in 10ms\nInstalled 12 packages in 166ms\n + coverage==7.6.10\n + exceptiongroup==1.2.2\n + iniconfig==2.0.0\n + packaging==24.2\n + pluggy==1.5.0\n + pyqt5==5.15.11\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.16.1\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + setuptools==75.8.0\n + tomli==2.2.1\nResolved 1 package in 777ms\nPrepared 1 package in 34.81s\nInstalled 1 package in 1ms\n + pillow==8.4.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_faaeee1e7ddbb7938be51268c2f4da070b2a0c13)\n",
    "new_commit_res_code": 1,
    "new_commit_res_stdout": "\u001b[1m============================= test session starts ==============================\u001b[0m\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_faaeee1e7ddbb7938be51268c2f4da070b2a0c13\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 15 items\n\nr2e_tests/test_1.py \u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31m                                      [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m____________________ TestFileWebp.test_no_resource_warning _____________________\u001b[0m\n\nself = <r2e_tests.test_1.TestFileWebp object at 0x7b17415aa340>\ntmp_path = PosixPath('/tmp/pytest-of-gcpuser/pytest-742/test_no_resource_warning0')\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n>           with pytest.warns(None) as record:\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:164: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = WarningsChecker(record=True), expected_warning = None, match_expr = None\n\n    def __init__(\n        self,\n        expected_warning: type[Warning] | tuple[type[Warning], ...] = Warning,\n        match_expr: str | Pattern[str] | None = None,\n        *,\n        _ispytest: bool = False,\n    ) -> None:\n        check_ispytest(_ispytest)\n        super().__init__(_ispytest=True)\n    \n        msg = \"exceptions must be derived from Warning, not %s\"\n        if isinstance(expected_warning, tuple):\n            for exc in expected_warning:\n                if not issubclass(exc, Warning):\n                    raise TypeError(msg % type(exc))\n            expected_warning_tup = expected_warning\n        elif isinstance(expected_warning, type) and issubclass(\n            expected_warning, Warning\n        ):\n            expected_warning_tup = (expected_warning,)\n        else:\n>           raise TypeError(msg % type(expected_warning))\n\u001b[1m\u001b[31mE           TypeError: exceptions must be derived from Warning, not <class 'NoneType'>\u001b[0m\n\n\u001b[1m\u001b[31m.venv/lib/python3.9/site-packages/_pytest/recwarn.py\u001b[0m:279: TypeError\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestUnsupportedWebp::test_unsupported\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_version\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_read_rgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_rgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_method\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_icc_profile\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_unsupported_mode_L\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_unsupported_mode_P\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_encoding_error_message\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_WebPEncode_with_invalid_args\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_WebPDecode_with_invalid_args\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_file_pointer_could_be_reused\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_background_from_gif\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_duration\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_no_resource_warning\u001b[0m - TypeError: exceptions must be derived from Warning, not <class 'NoneType'>\n\u001b[31m========================= \u001b[31m\u001b[1m1 failed\u001b[0m, \u001b[32m14 passed\u001b[0m\u001b[31m in 6.26s\u001b[0m\u001b[31m =========================\u001b[0m\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "\u001b[1m============================= test session starts ==============================\u001b[0m\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_faaeee1e7ddbb7938be51268c2f4da070b2a0c13\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 15 items\n\nr2e_tests/test_1.py \u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31m                                      [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m________________________ TestFileWebp.test_icc_profile _________________________\u001b[0m\n\nself = <r2e_tests.test_1.TestFileWebp object at 0x74d5e3bbf250>\ntmp_path = PosixPath('/tmp/pytest-of-gcpuser/pytest-775/test_icc_profile0')\n\n    def test_icc_profile(self, tmp_path):\n>       self._roundtrip(tmp_path, self.rgb_mode, 12.5, {\"icc_profile\": None})\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:108: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:66: in _roundtrip\n    hopper(mode).save(temp_file, **args)\n\u001b[1m\u001b[31msrc/PIL/Image.py\u001b[0m:2233: in save\n    save_handler(self, fp, filename)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nim = <PIL.Image.Image image mode=RGB size=128x128 at 0x74D5E3A59520>\nfp = <_io.BufferedRandom name='/tmp/pytest-of-gcpuser/pytest-775/test_icc_profile0/temp.webp'>\nfilename = '/tmp/pytest-of-gcpuser/pytest-775/test_icc_profile0/temp.webp'\n\n    def _save(im, fp, filename):\n        lossless = im.encoderinfo.get(\"lossless\", False)\n        quality = im.encoderinfo.get(\"quality\", 80)\n        icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n        exif = im.encoderinfo.get(\"exif\", \"\")\n        if isinstance(exif, Image.Exif):\n            exif = exif.tobytes()\n        xmp = im.encoderinfo.get(\"xmp\", \"\")\n        method = im.encoderinfo.get(\"method\", 4)\n    \n        if im.mode not in _VALID_WEBP_LEGACY_MODES:\n            alpha = (\n                \"A\" in im.mode\n                or \"a\" in im.mode\n                or (im.mode == \"P\" and \"transparency\" in im.info)\n            )\n            im = im.convert(\"RGBA\" if alpha else \"RGB\")\n    \n>       data = _webp.WebPEncode(\n            im.tobytes(),\n            im.size[0],\n            im.size[1],\n            lossless,\n            float(quality),\n            im.mode,\n            icc_profile,\n            method,\n            exif,\n            xmp,\n        )\n\u001b[1m\u001b[31mE       TypeError: a bytes-like object is required, not 'NoneType'\u001b[0m\n\n\u001b[1m\u001b[31msrc/PIL/WebPImagePlugin.py\u001b[0m:327: TypeError\n\u001b[31m\u001b[1m____________________ TestFileWebp.test_no_resource_warning _____________________\u001b[0m\n\nself = <r2e_tests.test_1.TestFileWebp object at 0x74d5e3baa940>\ntmp_path = PosixPath('/tmp/pytest-of-gcpuser/pytest-775/test_no_resource_warning0')\n\n    def test_no_resource_warning(self, tmp_path):\n        file_path = \"Tests/images/hopper.webp\"\n        with Image.open(file_path) as image:\n            temp_file = str(tmp_path / \"temp.webp\")\n>           with pytest.warns(None) as record:\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:164: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = WarningsChecker(record=True), expected_warning = None, match_expr = None\n\n    def __init__(\n        self,\n        expected_warning: type[Warning] | tuple[type[Warning], ...] = Warning,\n        match_expr: str | Pattern[str] | None = None,\n        *,\n        _ispytest: bool = False,\n    ) -> None:\n        check_ispytest(_ispytest)\n        super().__init__(_ispytest=True)\n    \n        msg = \"exceptions must be derived from Warning, not %s\"\n        if isinstance(expected_warning, tuple):\n            for exc in expected_warning:\n                if not issubclass(exc, Warning):\n                    raise TypeError(msg % type(exc))\n            expected_warning_tup = expected_warning\n        elif isinstance(expected_warning, type) and issubclass(\n            expected_warning, Warning\n        ):\n            expected_warning_tup = (expected_warning,)\n        else:\n>           raise TypeError(msg % type(expected_warning))\n\u001b[1m\u001b[31mE           TypeError: exceptions must be derived from Warning, not <class 'NoneType'>\u001b[0m\n\n\u001b[1m\u001b[31m.venv/lib/python3.9/site-packages/_pytest/recwarn.py\u001b[0m:279: TypeError\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestUnsupportedWebp::test_unsupported\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_version\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_read_rgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_rgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_method\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_unsupported_mode_L\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_unsupported_mode_P\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_write_encoding_error_message\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_WebPEncode_with_invalid_args\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_WebPDecode_with_invalid_args\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_file_pointer_could_be_reused\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_background_from_gif\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_duration\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_icc_profile\u001b[0m - TypeError: a bytes-like object is required, not 'NoneType'\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mTestFileWebp::test_no_resource_warning\u001b[0m - TypeError: exceptions must be derived from Warning, not <class 'NoneType'>\n\u001b[31m========================= \u001b[31m\u001b[1m2 failed\u001b[0m, \u001b[32m13 passed\u001b[0m\u001b[31m in 5.98s\u001b[0m\u001b[31m =========================\u001b[0m\n",
    "old_commit_res_stderr": ""
}
Tests/test_file_webp.py src/PIL/WebPImagePlugin.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Saving WebP Image with `icc_profile=None` Raises TypeError

**Description:**
When attempting to save a WebP image and setting the `icc_profile` parameter to `None`, a `TypeError` is raised. This issue prevents saving WebP images without an ICC profile, which should be a valid use case.

**Example Code:**
```python
from PIL import Image

# Create a simple RGB image
image = Image.new("RGB", (100, 100), color="red")

# Attempt to save the image with icc_profile set to None
image.save("output.webp", icc_profile=None)
```

**Expected Behavior:**
The WebP image is saved successfully without embedding an ICC profile.

**Actual Behavior:**
A `TypeError` is raised with the message:
```
TypeError: a bytes-like object is required, not 'NoneType'
```
This error occurs because the `icc_profile` parameter receives `None` instead of a bytes-like object or an empty string.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/WebPImagePlugin.py
from io import BytesIO

from . import Image, ImageFile

try:
    from . import _webp

    SUPPORTED = True
except ImportError:
    SUPPORTED = False


_VALID_WEBP_MODES = {"RGBX": True, "RGBA": True, "RGB": True}

_VALID_WEBP_LEGACY_MODES = {"RGB": True, "RGBA": True}

_VP8_MODES_BY_IDENTIFIER = {
    b"VP8 ": "RGB",
    b"VP8X": "RGBA",
    b"VP8L": "RGBA",  # lossless
}


def _accept(prefix):
    is_riff_file_format = prefix[:4] == b"RIFF"
    is_webp_file = prefix[8:12] == b"WEBP"
    is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER

    if is_riff_file_format and is_webp_file and is_valid_vp8_mode:
        if not SUPPORTED:
            return (
                "image file could not be identified because WEBP support not installed"
            )
        return True


class WebPImageFile(ImageFile.ImageFile):

    format = "WEBP"
    format_description = "WebP image"
    __loaded = 0
    __logical_frame = 0

    def _open(self):
        if not _webp.HAVE_WEBPANIM:
            # Legacy mode
            data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(
                self.fp.read()
            )
            if icc_profile:
                self.info["icc_profile"] = icc_profile
            if exif:
                self.info["exif"] = exif
            self._size = width, height
            self.fp = BytesIO(data)
            self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
            self.n_frames = 1
            self.is_animated = False
            return

        # Use the newer AnimDecoder API to parse the (possibly) animated file,
        # and access muxed chunks like ICC/EXIF/XMP.
        self._decoder = _webp.WebPAnimDecoder(self.fp.read())

        # Get info from decoder
        width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()
        self._size = width, height
        self.info["loop"] = loop_count
        bg_a, bg_r, bg_g, bg_b = (
            (bgcolor >> 24) & 0xFF,
            (bgcolor >> 16) & 0xFF,
            (bgcolor >> 8) & 0xFF,
            bgcolor & 0xFF,
        )
        self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
        self.n_frames = frame_count
        self.is_animated = self.n_frames > 1
        self.mode = "RGB" if mode == "RGBX" else mode
        self.rawmode = mode
        self.tile = []

        # Attempt to read ICC / EXIF / XMP chunks from file
        icc_profile = self._decoder.get_chunk("ICCP")
        exif = self._decoder.get_chunk("EXIF")
        xmp = self._decoder.get_chunk("XMP ")
        if icc_profile:
            self.info["icc_profile"] = icc_profile
        if exif:
            self.info["exif"] = exif
        if xmp:
            self.info["xmp"] = xmp

        # Initialize seek state
        self._reset(reset=False)

    def _getexif(self):
        if "exif" not in self.info:
            return None
        return self.getexif()._get_merged_dict()

    def seek(self, frame):
        if not self._seek_check(frame):
            return

        # Set logical frame to requested position
        self.__logical_frame = frame

    def _reset(self, reset=True):
        if reset:
            self._decoder.reset()
        self.__physical_frame = 0
        self.__loaded = -1
        self.__timestamp = 0

    def _get_next(self):
        # Get next frame
        ret = self._decoder.get_next()
        self.__physical_frame += 1

        # Check if an error occurred
        if ret is None:
            self._reset()  # Reset just to be safe
            self.seek(0)
            raise EOFError("failed to decode next frame in WebP file")

        # Compute duration
        data, timestamp = ret
        duration = timestamp - self.__timestamp
        self.__timestamp = timestamp

        # libwebp gives frame end, adjust to start of frame
        timestamp -= duration
        return data, timestamp, duration

    def _seek(self, frame):
        if self.__physical_frame == frame:
            return  # Nothing to do
        if frame < self.__physical_frame:
            self._reset()  # Rewind to beginning
        while self.__physical_frame < frame:
            self._get_next()  # Advance to the requested frame

    def load(self):
        if _webp.HAVE_WEBPANIM:
            if self.__loaded != self.__logical_frame:
                self._seek(self.__logical_frame)

                # We need to load the image data for this frame
                data, timestamp, duration = self._get_next()
                self.info["timestamp"] = timestamp
                self.info["duration"] = duration
                self.__loaded = self.__logical_frame

                # Set tile
                if self.fp and self._exclusive_fp:
                    self.fp.close()
                self.fp = BytesIO(data)
                self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)]

        return super().load()

    def tell(self):
        if not _webp.HAVE_WEBPANIM:
            return super().tell()

        return self.__logical_frame


def _save_all(im, fp, filename):
    encoderinfo = im.encoderinfo.copy()
    append_images = list(encoderinfo.get("append_images", []))

    # If total frame count is 1, then save using the legacy API, which
    # will preserve non-alpha modes
    total = 0
    for ims in [im] + append_images:
        total += getattr(ims, "n_frames", 1)
    if total == 1:
        _save(im, fp, filename)
        return

    background = (0, 0, 0, 0)
    if "background" in encoderinfo:
        background = encoderinfo["background"]
    elif "background" in im.info:
        background = im.info["background"]
        if isinstance(background, int):
            # GifImagePlugin stores a global color table index in
            # info["background"]. So it must be converted to an RGBA value
            palette = im.getpalette()
            if palette:
                r, g, b = palette[background * 3 : (background + 1) * 3]
                background = (r, g, b, 0)

    duration = im.encoderinfo.get("duration", im.info.get("duration"))
    loop = im.encoderinfo.get("loop", 0)
    minimize_size = im.encoderinfo.get("minimize_size", False)
    kmin = im.encoderinfo.get("kmin", None)
    kmax = im.encoderinfo.get("kmax", None)
    allow_mixed = im.encoderinfo.get("allow_mixed", False)
    verbose = False
    lossless = im.encoderinfo.get("lossless", False)
    quality = im.encoderinfo.get("quality", 80)
    method = im.encoderinfo.get("method", 0)
    icc_profile = im.encoderinfo.get("icc_profile", "")
    exif = im.encoderinfo.get("exif", "")
    if isinstance(exif, Image.Exif):
        exif = exif.tobytes()
    xmp = im.encoderinfo.get("xmp", "")
    if allow_mixed:
        lossless = False

    # Sensible keyframe defaults are from gif2webp.c script
    if kmin is None:
        kmin = 9 if lossless else 3
    if kmax is None:
        kmax = 17 if lossless else 5

    # Validate background color
    if (
        not isinstance(background, (list, tuple))
        or len(background) != 4
        or not all(v >= 0 and v < 256 for v in background)
    ):
        raise OSError(
            "Background color is not an RGBA tuple clamped to (0-255): %s"
            % str(background)
        )

    # Convert to packed uint
    bg_r, bg_g, bg_b, bg_a = background
    background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)

    # Setup the WebP animation encoder
    enc = _webp.WebPAnimEncoder(
        im.size[0],
        im.size[1],
        background,
        loop,
        minimize_size,
        kmin,
        kmax,
        allow_mixed,
        verbose,
    )

    # Add each frame
    frame_idx = 0
    timestamp = 0
    cur_idx = im.tell()
    try:
        for ims in [im] + append_images:
            # Get # of frames in this image
            nfr = getattr(ims, "n_frames", 1)

            for idx in range(nfr):
                ims.seek(idx)
                ims.load()

                # Make sure image mode is supported
                frame = ims
                rawmode = ims.mode
                if ims.mode not in _VALID_WEBP_MODES:
                    alpha = (
                        "A" in ims.mode
                        or "a" in ims.mode
                        or (ims.mode == "P" and "A" in ims.im.getpalettemode())
                    )
                    rawmode = "RGBA" if alpha else "RGB"
                    frame = ims.convert(rawmode)

                if rawmode == "RGB":
                    # For faster conversion, use RGBX
                    rawmode = "RGBX"

                # Append the frame to the animation encoder
                enc.add(
                    frame.tobytes("raw", rawmode),
                    timestamp,
                    frame.size[0],
                    frame.size[1],
                    rawmode,
                    lossless,
                    quality,
                    method,
                )

                # Update timestamp and frame index
                if isinstance(duration, (list, tuple)):
                    timestamp += duration[frame_idx]
                else:
                    timestamp += duration
                frame_idx += 1

    finally:
        im.seek(cur_idx)

    # Force encoder to flush frames
    enc.add(None, timestamp, 0, 0, "", lossless, quality, 0)

    # Get the final output from the encoder
    data = enc.assemble(icc_profile, exif, xmp)
    if data is None:
        raise OSError("cannot write file as WebP (encoder returned None)")

    fp.write(data)


def _save(im, fp, filename):
    lossless = im.encoderinfo.get("lossless", False)
    quality = im.encoderinfo.get("quality", 80)
    icc_profile = im.encoderinfo.get("icc_profile", "")
    exif = im.encoderinfo.get("exif", "")
    if isinstance(exif, Image.Exif):
        exif = exif.tobytes()
    xmp = im.encoderinfo.get("xmp", "")
    method = im.encoderinfo.get("method", 4)

    if im.mode not in _VALID_WEBP_LEGACY_MODES:
        alpha = (
            "A" in im.mode
            or "a" in im.mode
            or (im.mode == "P" and "transparency" in im.info)
        )
        im = im.convert("RGBA" if alpha else "RGB")

    data = _webp.WebPEncode(
        im.tobytes(),
        im.size[0],
        im.size[1],
        lossless,
        float(quality),
        im.mode,
        icc_profile,
        method,
        exif,
        xmp,
    )
    if data is None:
        raise OSError("cannot write file as WebP (encoder returned None)")

    fp.write(data)


Image.register_open(WebPImageFile.format, WebPImageFile, _accept)
if SUPPORTED:
    Image.register_save(WebPImageFile.format, _save)
    if _webp.HAVE_WEBPANIM:
        Image.register_save_all(WebPImageFile.format, _save_all)
    Image.register_extension(WebPImageFile.format, ".webp")
    Image.register_mime(WebPImageFile.format, "image/webp")

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Saving WebP Image with `icc_profile=None` Raises TypeError

**Description:**
When attempting to save a WebP image and setting the `icc_profile` parameter to `None`, a `TypeError` is raised. This issue prevents saving WebP images without an ICC profile, which should be a valid use case.

**Example Code:**
```python
from PIL import Image

# Create a simple RGB image
image = Image.new("RGB", (100, 100), color="red")

# Attempt to save the image with icc_profile set to None
image.save("output.webp", icc_profile=None)
```

**Expected Behavior:**
The WebP image is saved successfully without embedding an ICC profile.

**Actual Behavior:**
A `TypeError` is raised with the message:
```
TypeError: a bytes-like object is required, not 'NoneType'
```
This error occurs because the `icc_profile` parameter receives `None` instead of a bytes-like object or an empty string.

[/ISSUE]
{
    "\u001b[1mTestUnsupportedWebp.test_unsupported\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_version\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_read_rgb\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_write_rgb\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_write_method\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_icc_profile\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_write_unsupported_mode_L\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_write_unsupported_mode_P\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_write_encoding_error_message\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_WebPEncode_with_invalid_args\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_WebPDecode_with_invalid_args\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_file_pointer_could_be_reused\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_background_from_gif\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_duration\u001b[0m": "PASSED",
    "\u001b[1mTestFileWebp.test_no_resource_warning\u001b[0m": "FAILED"
}
diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py
index b63a07ca8..590161f3e 100644
--- a/src/PIL/WebPImagePlugin.py
+++ b/src/PIL/WebPImagePlugin.py
@@ -202,7 +202,7 @@ def _save_all(im, fp, filename):
     lossless = im.encoderinfo.get("lossless", False)
     quality = im.encoderinfo.get("quality", 80)
     method = im.encoderinfo.get("method", 0)
-    icc_profile = im.encoderinfo.get("icc_profile", "")
+    icc_profile = im.encoderinfo.get("icc_profile") or ""
     exif = im.encoderinfo.get("exif", "")
     if isinstance(exif, Image.Exif):
         exif = exif.tobytes()
@@ -309,7 +309,7 @@ def _save_all(im, fp, filename):
 def _save(im, fp, filename):
     lossless = im.encoderinfo.get("lossless", False)
     quality = im.encoderinfo.get("quality", 80)
-    icc_profile = im.encoderinfo.get("icc_profile", "")
+    icc_profile = im.encoderinfo.get("icc_profile") or ""
     exif = im.encoderinfo.get("exif", "")
     if isinstance(exif, Image.Exif):
         exif = exif.tobytes()
 

{"src/PIL/WebPImagePlugin.py": "from io import BytesIO\n\nfrom . import Image, ImageFile\n\ntry:\n    from . import _webp\n\n    SUPPORTED = True\nexcept ImportError:\n    SUPPORTED = False\n\n\n_VALID_WEBP_MODES = {\"RGBX\": True, \"RGBA\": True, \"RGB\": True}\n\n_VALID_WEBP_LEGACY_MODES = {\"RGB\": True, \"RGBA\": True}\n\n_VP8_MODES_BY_IDENTIFIER = {\n    b\"VP8 \": \"RGB\",\n    b\"VP8X\": \"RGBA\",\n    b\"VP8L\": \"RGBA\",  # lossless\n}\n\n\ndef _accept(prefix):\n    is_riff_file_format = prefix[:4] == b\"RIFF\"\n    is_webp_file = prefix[8:12] == b\"WEBP\"\n    is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER\n\n    if is_riff_file_format and is_webp_file and is_valid_vp8_mode:\n        if not SUPPORTED:\n            return (\n                \"image file could not be identified because WEBP support not installed\"\n            )\n        return True\n\n\nclass WebPImageFile(ImageFile.ImageFile):\n\n    format = \"WEBP\"\n    format_description = \"WebP image\"\n    __loaded = 0\n    __logical_frame = 0\n\n    def _open(self):\n        if not _webp.HAVE_WEBPANIM:\n            # Legacy mode\n            data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(\n                self.fp.read()\n            )\n            if icc_profile:\n                self.info[\"icc_profile\"] = icc_profile\n            if exif:\n                self.info[\"exif\"] = exif\n            self._size = width, height\n            self.fp = BytesIO(data)\n            self.tile = [(\"raw\", (0, 0) + self.size, 0, self.mode)]\n            self.n_frames = 1\n            self.is_animated = False\n            return\n\n        # Use the newer AnimDecoder API to parse the (possibly) animated file,\n        # and access muxed chunks like ICC/EXIF/XMP.\n        self._decoder = _webp.WebPAnimDecoder(self.fp.read())\n\n        # Get info from decoder\n        width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()\n        self._size = width, height\n        self.info[\"loop\"] = loop_count\n        bg_a, bg_r, bg_g, bg_b = (\n            (bgcolor >> 24) & 0xFF,\n            (bgcolor >> 16) & 0xFF,\n            (bgcolor >> 8) & 0xFF,\n            bgcolor & 0xFF,\n        )\n        self.info[\"background\"] = (bg_r, bg_g, bg_b, bg_a)\n        self.n_frames = frame_count\n        self.is_animated = self.n_frames > 1\n        self.mode = \"RGB\" if mode == \"RGBX\" else mode\n        self.rawmode = mode\n        self.tile = []\n\n        # Attempt to read ICC / EXIF / XMP chunks from file\n        icc_profile = self._decoder.get_chunk(\"ICCP\")\n        exif = self._decoder.get_chunk(\"EXIF\")\n        xmp = self._decoder.get_chunk(\"XMP \")\n        if icc_profile:\n            self.info[\"icc_profile\"] = icc_profile\n        if exif:\n            self.info[\"exif\"] = exif\n        if xmp:\n            self.info[\"xmp\"] = xmp\n\n        # Initialize seek state\n        self._reset(reset=False)\n\n    def _getexif(self):\n        if \"exif\" not in self.info:\n            return None\n        return self.getexif()._get_merged_dict()\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n\n        # Set logical frame to requested position\n        self.__logical_frame = frame\n\n    def _reset(self, reset=True):\n        if reset:\n            self._decoder.reset()\n        self.__physical_frame = 0\n        self.__loaded = -1\n        self.__timestamp = 0\n\n    def _get_next(self):\n        # Get next frame\n        ret = self._decoder.get_next()\n        self.__physical_frame += 1\n\n        # Check if an error occurred\n        if ret is None:\n            self._reset()  # Reset just to be safe\n            self.seek(0)\n            raise EOFError(\"failed to decode next frame in WebP file\")\n\n        # Compute duration\n        data, timestamp = ret\n        duration = timestamp - self.__timestamp\n        self.__timestamp = timestamp\n\n        # libwebp gives frame end, adjust to start of frame\n        timestamp -= duration\n        return data, timestamp, duration\n\n    def _seek(self, frame):\n        if self.__physical_frame == frame:\n            return  # Nothing to do\n        if frame < self.__physical_frame:\n            self._reset()  # Rewind to beginning\n        while self.__physical_frame < frame:\n            self._get_next()  # Advance to the requested frame\n\n    def load(self):\n        if _webp.HAVE_WEBPANIM:\n            if self.__loaded != self.__logical_frame:\n                self._seek(self.__logical_frame)\n\n                # We need to load the image data for this frame\n                data, timestamp, duration = self._get_next()\n                self.info[\"timestamp\"] = timestamp\n                self.info[\"duration\"] = duration\n                self.__loaded = self.__logical_frame\n\n                # Set tile\n                if self.fp and self._exclusive_fp:\n                    self.fp.close()\n                self.fp = BytesIO(data)\n                self.tile = [(\"raw\", (0, 0) + self.size, 0, self.rawmode)]\n\n        return super().load()\n\n    def tell(self):\n        if not _webp.HAVE_WEBPANIM:\n            return super().tell()\n\n        return self.__logical_frame\n\n\ndef _save_all(im, fp, filename):\n    encoderinfo = im.encoderinfo.copy()\n    append_images = list(encoderinfo.get(\"append_images\", []))\n\n    # If total frame count is 1, then save using the legacy API, which\n    # will preserve non-alpha modes\n    total = 0\n    for ims in [im] + append_images:\n        total += getattr(ims, \"n_frames\", 1)\n    if total == 1:\n        _save(im, fp, filename)\n        return\n\n    background = (0, 0, 0, 0)\n    if \"background\" in encoderinfo:\n        background = encoderinfo[\"background\"]\n    elif \"background\" in im.info:\n        background = im.info[\"background\"]\n        if isinstance(background, int):\n            # GifImagePlugin stores a global color table index in\n            # info[\"background\"]. So it must be converted to an RGBA value\n            palette = im.getpalette()\n            if palette:\n                r, g, b = palette[background * 3 : (background + 1) * 3]\n                background = (r, g, b, 0)\n\n    duration = im.encoderinfo.get(\"duration\", im.info.get(\"duration\"))\n    loop = im.encoderinfo.get(\"loop\", 0)\n    minimize_size = im.encoderinfo.get(\"minimize_size\", False)\n    kmin = im.encoderinfo.get(\"kmin\", None)\n    kmax = im.encoderinfo.get(\"kmax\", None)\n    allow_mixed = im.encoderinfo.get(\"allow_mixed\", False)\n    verbose = False\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    method = im.encoderinfo.get(\"method\", 0)\n    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    if allow_mixed:\n        lossless = False\n\n    # Sensible keyframe defaults are from gif2webp.c script\n    if kmin is None:\n        kmin = 9 if lossless else 3\n    if kmax is None:\n        kmax = 17 if lossless else 5\n\n    # Validate background color\n    if (\n        not isinstance(background, (list, tuple))\n        or len(background) != 4\n        or not all(v >= 0 and v < 256 for v in background)\n    ):\n        raise OSError(\n            \"Background color is not an RGBA tuple clamped to (0-255): %s\"\n            % str(background)\n        )\n\n    # Convert to packed uint\n    bg_r, bg_g, bg_b, bg_a = background\n    background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)\n\n    # Setup the WebP animation encoder\n    enc = _webp.WebPAnimEncoder(\n        im.size[0],\n        im.size[1],\n        background,\n        loop,\n        minimize_size,\n        kmin,\n        kmax,\n        allow_mixed,\n        verbose,\n    )\n\n    # Add each frame\n    frame_idx = 0\n    timestamp = 0\n    cur_idx = im.tell()\n    try:\n        for ims in [im] + append_images:\n            # Get # of frames in this image\n            nfr = getattr(ims, \"n_frames\", 1)\n\n            for idx in range(nfr):\n                ims.seek(idx)\n                ims.load()\n\n                # Make sure image mode is supported\n                frame = ims\n                rawmode = ims.mode\n                if ims.mode not in _VALID_WEBP_MODES:\n                    alpha = (\n                        \"A\" in ims.mode\n                        or \"a\" in ims.mode\n                        or (ims.mode == \"P\" and \"A\" in ims.im.getpalettemode())\n                    )\n                    rawmode = \"RGBA\" if alpha else \"RGB\"\n                    frame = ims.convert(rawmode)\n\n                if rawmode == \"RGB\":\n                    # For faster conversion, use RGBX\n                    rawmode = \"RGBX\"\n\n                # Append the frame to the animation encoder\n                enc.add(\n                    frame.tobytes(\"raw\", rawmode),\n                    timestamp,\n                    frame.size[0],\n                    frame.size[1],\n                    rawmode,\n                    lossless,\n                    quality,\n                    method,\n                )\n\n                # Update timestamp and frame index\n                if isinstance(duration, (list, tuple)):\n                    timestamp += duration[frame_idx]\n                else:\n                    timestamp += duration\n                frame_idx += 1\n\n    finally:\n        im.seek(cur_idx)\n\n    # Force encoder to flush frames\n    enc.add(None, timestamp, 0, 0, \"\", lossless, quality, 0)\n\n    # Get the final output from the encoder\n    data = enc.assemble(icc_profile, exif, xmp)\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)\n\n\ndef _save(im, fp, filename):\n    lossless = im.encoderinfo.get(\"lossless\", False)\n    quality = im.encoderinfo.get(\"quality\", 80)\n    icc_profile = im.encoderinfo.get(\"icc_profile\", \"\")\n    exif = im.encoderinfo.get(\"exif\", \"\")\n    if isinstance(exif, Image.Exif):\n        exif = exif.tobytes()\n    xmp = im.encoderinfo.get(\"xmp\", \"\")\n    method = im.encoderinfo.get(\"method\", 4)\n\n    if im.mode not in _VALID_WEBP_LEGACY_MODES:\n        alpha = (\n            \"A\" in im.mode\n            or \"a\" in im.mode\n            or (im.mode == \"P\" and \"transparency\" in im.info)\n        )\n        im = im.convert(\"RGBA\" if alpha else \"RGB\")\n\n    data = _webp.WebPEncode(\n        im.tobytes(),\n        im.size[0],\n        im.size[1],\n        lossless,\n        float(quality),\n        im.mode,\n        icc_profile,\n        method,\n        exif,\n        xmp,\n    )\n    if data is None:\n        raise OSError(\"cannot write file as WebP (encoder returned None)\")\n\n    fp.write(data)\n\n\nImage.register_open(WebPImageFile.format, WebPImageFile, _accept)\nif SUPPORTED:\n    Image.register_save(WebPImageFile.format, _save)\n    if _webp.HAVE_WEBPANIM:\n        Image.register_save_all(WebPImageFile.format, _save_all)\n    Image.register_extension(WebPImageFile.format, \".webp\")\n    Image.register_mime(WebPImageFile.format, \"image/webp\")\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Saving WebP Image with `icc_profile=None` Raises TypeError

**Description:**
When attempting to save a WebP image and setting the `icc_profile` parameter to `None`, a `TypeError` is raised. This issue prevents saving WebP images without an ICC profile, which should be a valid use case.

**Example Code:**
```python
from PIL import Image

# Create a simple RGB image
image = Image.new("RGB", (100, 100), color="red")

# Attempt to save the image with icc_profile set to None
image.save("output.webp", icc_profile=None)
```

**Expected Behavior:**
The WebP image is saved successfully without embedding an ICC profile.

**Actual Behavior:**
A `TypeError` is raised with the message:
```
TypeError: a bytes-like object is required, not 'NoneType'
```
This error occurs because the `icc_profile` parameter receives `None` instead of a bytes-like object or an empty string.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/WebPImagePlugin.py
from io import BytesIO

from . import Image, ImageFile

try:
    from . import _webp

    SUPPORTED = True
except ImportError:
    SUPPORTED = False


_VALID_WEBP_MODES = {"RGBX": True, "RGBA": True, "RGB": True}

_VALID_WEBP_LEGACY_MODES = {"RGB": True, "RGBA": True}

_VP8_MODES_BY_IDENTIFIER = {
    b"VP8 ": "RGB",
    b"VP8X": "RGBA",
    b"VP8L": "RGBA",  # lossless
}


def _accept(prefix):
    is_riff_file_format = prefix[:4] == b"RIFF"
    is_webp_file = prefix[8:12] == b"WEBP"
    is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER

    if is_riff_file_format and is_webp_file and is_valid_vp8_mode:
        if not SUPPORTED:
            return (
                "image file could not be identified because WEBP support not installed"
            )
        return True


class WebPImageFile(ImageFile.ImageFile):

    format = "WEBP"
    format_description = "WebP image"
    __loaded = 0
    __logical_frame = 0

    def _open(self):
        if not _webp.HAVE_WEBPANIM:
            # Legacy mode
            data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(
                self.fp.read()
            )
            if icc_profile:
                self.info["icc_profile"] = icc_profile
            if exif:
                self.info["exif"] = exif
            self._size = width, height
            self.fp = BytesIO(data)
            self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
            self.n_frames = 1
            self.is_animated = False
            return

        # Use the newer AnimDecoder API to parse the (possibly) animated file,
        # and access muxed chunks like ICC/EXIF/XMP.
        self._decoder = _webp.WebPAnimDecoder(self.fp.read())

        # Get info from decoder
        width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()
        self._size = width, height
        self.info["loop"] = loop_count
        bg_a, bg_r, bg_g, bg_b = (
            (bgcolor >> 24) & 0xFF,
            (bgcolor >> 16) & 0xFF,
            (bgcolor >> 8) & 0xFF,
            bgcolor & 0xFF,
        )
        self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
        self.n_frames = frame_count
        self.is_animated = self.n_frames > 1
        self.mode = "RGB" if mode == "RGBX" else mode
        self.rawmode = mode
        self.tile = []

        # Attempt to read ICC / EXIF / XMP chunks from file
        icc_profile = self._decoder.get_chunk("ICCP")
        exif = self._decoder.get_chunk("EXIF")
        xmp = self._decoder.get_chunk("XMP ")
        if icc_profile:
            self.info["icc_profile"] = icc_profile
        if exif:
            self.info["exif"] = exif
        if xmp:
            self.info["xmp"] = xmp

        # Initialize seek state
        self._reset(reset=False)

    def _getexif(self):
        if "exif" not in self.info:
            return None
        return self.getexif()._get_merged_dict()

    def seek(self, frame):
        if not self._seek_check(frame):
            return

        # Set logical frame to requested position
        self.__logical_frame = frame

    def _reset(self, reset=True):
        if reset:
            self._decoder.reset()
        self.__physical_frame = 0
        self.__loaded = -1
        self.__timestamp = 0

    def _get_next(self):
        # Get next frame
        ret = self._decoder.get_next()
        self.__physical_frame += 1

        # Check if an error occurred
        if ret is None:
            self._reset()  # Reset just to be safe
            self.seek(0)
            raise EOFError("failed to decode next frame in WebP file")

        # Compute duration
        data, timestamp = ret
        duration = timestamp - self.__timestamp
        self.__timestamp = timestamp

        # libwebp gives frame end, adjust to start of frame
        timestamp -= duration
        return data, timestamp, duration

    def _seek(self, frame):
        if self.__physical_frame == frame:
            return  # Nothing to do
        if frame < self.__physical_frame:
            self._reset()  # Rewind to beginning
        while self.__physical_frame < frame:
            self._get_next()  # Advance to the requested frame

    def load(self):
        if _webp.HAVE_WEBPANIM:
            if self.__loaded != self.__logical_frame:
                self._seek(self.__logical_frame)

                # We need to load the image data for this frame
                data, timestamp, duration = self._get_next()
                self.info["timestamp"] = timestamp
                self.info["duration"] = duration
                self.__loaded = self.__logical_frame

                # Set tile
                if self.fp and self._exclusive_fp:
                    self.fp.close()
                self.fp = BytesIO(data)
                self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)]

        return super().load()

    def tell(self):
        if not _webp.HAVE_WEBPANIM:
            return super().tell()

        return self.__logical_frame


def _save_all(im, fp, filename):
    encoderinfo = im.encoderinfo.copy()
    append_images = list(encoderinfo.get("append_images", []))

    # If total frame count is 1, then save using the legacy API, which
    # will preserve non-alpha modes
    total = 0
    for ims in [im] + append_images:
        total += getattr(ims, "n_frames", 1)
    if total == 1:
        _save(im, fp, filename)
        return

    background = (0, 0, 0, 0)
    if "background" in encoderinfo:
        background = encoderinfo["background"]
    elif "background" in im.info:
        background = im.info["background"]
        if isinstance(background, int):
            # GifImagePlugin stores a global color table index in
            # info["background"]. So it must be converted to an RGBA value
            palette = im.getpalette()
            if palette:
                r, g, b = palette[background * 3 : (background + 1) * 3]
                background = (r, g, b, 0)

    duration = im.encoderinfo.get("duration", im.info.get("duration"))
    loop = im.encoderinfo.get("loop", 0)
    minimize_size = im.encoderinfo.get("minimize_size", False)
    kmin = im.encoderinfo.get("kmin", None)
    kmax = im.encoderinfo.get("kmax", None)
    allow_mixed = im.encoderinfo.get("allow_mixed", False)
    verbose = False
    lossless = im.encoderinfo.get("lossless", False)
    quality = im.encoderinfo.get("quality", 80)
    method = im.encoderinfo.get("method", 0)
    icc_profile = im.encoderinfo.get("icc_profile", "")
    exif = im.encoderinfo.get("exif", "")
    if isinstance(exif, Image.Exif):
        exif = exif.tobytes()
    xmp = im.encoderinfo.get("xmp", "")
    if allow_mixed:
        lossless = False

    # Sensible keyframe defaults are from gif2webp.c script
    if kmin is None:
        kmin = 9 if lossless else 3
    if kmax is None:
        kmax = 17 if lossless else 5

    # Validate background color
    if (
        not isinstance(background, (list, tuple))
        or len(background) != 4
        or not all(v >= 0 and v < 256 for v in background)
    ):
        raise OSError(
            "Background color is not an RGBA tuple clamped to (0-255): %s"
            % str(background)
        )

    # Convert to packed uint
    bg_r, bg_g, bg_b, bg_a = background
    background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)

    # Setup the WebP animation encoder
    enc = _webp.WebPAnimEncoder(
        im.size[0],
        im.size[1],
        background,
        loop,
        minimize_size,
        kmin,
        kmax,
        allow_mixed,
        verbose,
    )

    # Add each frame
    frame_idx = 0
    timestamp = 0
    cur_idx = im.tell()
    try:
        for ims in [im] + append_images:
            # Get # of frames in this image
            nfr = getattr(ims, "n_frames", 1)

            for idx in range(nfr):
                ims.seek(idx)
                ims.load()

                # Make sure image mode is supported
                frame = ims
                rawmode = ims.mode
                if ims.mode not in _VALID_WEBP_MODES:
                    alpha = (
                        "A" in ims.mode
                        or "a" in ims.mode
                        or (ims.mode == "P" and "A" in ims.im.getpalettemode())
                    )
                    rawmode = "RGBA" if alpha else "RGB"
                    frame = ims.convert(rawmode)

                if rawmode == "RGB":
                    # For faster conversion, use RGBX
                    rawmode = "RGBX"

                # Append the frame to the animation encoder
                enc.add(
                    frame.tobytes("raw", rawmode),
                    timestamp,
                    frame.size[0],
                    frame.size[1],
                    rawmode,
                    lossless,
                    quality,
                    method,
                )

                # Update timestamp and frame index
                if isinstance(duration, (list, tuple)):
                    timestamp += duration[frame_idx]
                else:
                    timestamp += duration
                frame_idx += 1

    finally:
        im.seek(cur_idx)

    # Force encoder to flush frames
    enc.add(None, timestamp, 0, 0, "", lossless, quality, 0)

    # Get the final output from the encoder
    data = enc.assemble(icc_profile, exif, xmp)
    if data is None:
        raise OSError("cannot write file as WebP (encoder returned None)")

    fp.write(data)


def _save(im, fp, filename):
    lossless = im.encoderinfo.get("lossless", False)
    quality = im.encoderinfo.get("quality", 80)
    icc_profile = im.encoderinfo.get("icc_profile", "")
    exif = im.encoderinfo.get("exif", "")
    if isinstance(exif, Image.Exif):
        exif = exif.tobytes()
    xmp = im.encoderinfo.get("xmp", "")
    method = im.encoderinfo.get("method", 4)

    if im.mode not in _VALID_WEBP_LEGACY_MODES:
        alpha = (
            "A" in im.mode
            or "a" in im.mode
            or (im.mode == "P" and "transparency" in im.info)
        )
        im = im.convert("RGBA" if alpha else "RGB")

    data = _webp.WebPEncode(
        im.tobytes(),
        im.size[0],
        im.size[1],
        lossless,
        float(quality),
        im.mode,
        icc_profile,
        method,
        exif,
        xmp,
    )
    if data is None:
        raise OSError("cannot write file as WebP (encoder returned None)")

    fp.write(data)


Image.register_open(WebPImageFile.format, WebPImageFile, _accept)
if SUPPORTED:
    Image.register_save(WebPImageFile.format, _save)
    if _webp.HAVE_WEBPANIM:
        Image.register_save_all(WebPImageFile.format, _save_all)
    Image.register_extension(WebPImageFile.format, ".webp")
    Image.register_mime(WebPImageFile.format, "image/webp")

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user