{
    "file_diffs": [
        {
            "old_file_content": "\"\"\"Test DdsImagePlugin\"\"\"\nfrom io import BytesIO\n\nimport pytest\n\nfrom PIL import DdsImagePlugin, Image\n\nfrom .helper import assert_image_equal, assert_image_equal_tofile, hopper\n\nTEST_FILE_DXT1 = \"Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds\"\nTEST_FILE_DXT3 = \"Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds\"\nTEST_FILE_DXT5 = \"Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds\"\nTEST_FILE_DX10_BC5_TYPELESS = \"Tests/images/bc5_typeless.dds\"\nTEST_FILE_DX10_BC5_UNORM = \"Tests/images/bc5_unorm.dds\"\nTEST_FILE_DX10_BC5_SNORM = \"Tests/images/bc5_snorm.dds\"\nTEST_FILE_BC5S = \"Tests/images/bc5s.dds\"\nTEST_FILE_DX10_BC7 = \"Tests/images/bc7-argb-8bpp_MipMaps-1.dds\"\nTEST_FILE_DX10_BC7_UNORM_SRGB = \"Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds\"\nTEST_FILE_DX10_R8G8B8A8 = \"Tests/images/argb-32bpp_MipMaps-1.dds\"\nTEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = \"Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds\"\nTEST_FILE_UNCOMPRESSED_RGB = \"Tests/images/hopper.dds\"\nTEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = \"Tests/images/uncompressed_rgb.dds\"\n\n\ndef test_sanity_dxt1():\n    \"\"\"Check DXT1 images can be opened\"\"\"\n    with Image.open(TEST_FILE_DXT1.replace(\".dds\", \".png\")) as target:\n        target = target.convert(\"RGBA\")\n    with Image.open(TEST_FILE_DXT1) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal(im, target)\n\n\ndef test_sanity_dxt3():\n    \"\"\"Check DXT3 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DXT3) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(\".dds\", \".png\"))\n\n\ndef test_sanity_dxt5():\n    \"\"\"Check DXT5 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DXT5) as im:\n        im.load()\n\n    assert im.format == \"DDS\"\n    assert im.mode == \"RGBA\"\n    assert im.size == (256, 256)\n\n    assert_image_equal_tofile(im, TEST_FILE_DXT5.replace(\".dds\", \".png\"))\n\n\n@pytest.mark.parametrize(\n    (\"image_path\", \"expected_path\"),\n    (\n        # hexeditted to be typeless\n        (TEST_FILE_DX10_BC5_TYPELESS, TEST_FILE_DX10_BC5_UNORM),\n        (TEST_FILE_DX10_BC5_UNORM, TEST_FILE_DX10_BC5_UNORM),\n        # hexeditted to use DX10 FourCC\n        (TEST_FILE_DX10_BC5_SNORM, TEST_FILE_BC5S),\n        (TEST_FILE_BC5S, TEST_FILE_BC5S),\n    ),\n)\ndef test_dx10_bc5(image_path, expected_path):\n    \"\"\"Check DX10 BC5 images can be opened\"\"\"\n\n    with Image.open(image_path) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGB\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, expected_path.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_bc7():\n    \"\"\"Check DX10 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_BC7) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_bc7_unorm_srgb():\n    \"\"\"Check DX10 unsigned normalized integer images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (16, 16)\n        assert im.info[\"gamma\"] == 1 / 2.2\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_DX10_BC7_UNORM_SRGB.replace(\".dds\", \".png\")\n        )\n\n\ndef test_dx10_r8g8b8a8():\n    \"\"\"Check DX10 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_R8G8B8A8) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_r8g8b8a8_unorm_srgb():\n    \"\"\"Check DX10 unsigned normalized integer images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (16, 16)\n        assert im.info[\"gamma\"] == 1 / 2.2\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB.replace(\".dds\", \".png\")\n        )\n\n\ndef test_unimplemented_dxgi_format():\n    with pytest.raises(NotImplementedError):\n        with Image.open(\"Tests/images/unimplemented_dxgi_format.dds\"):\n            pass\n\n\ndef test_uncompressed_rgb():\n    \"\"\"Check uncompressed RGB images can be opened\"\"\"\n\n    # convert -format dds -define dds:compression=none hopper.jpg hopper.dds\n    with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGB\"\n        assert im.size == (128, 128)\n\n        assert_image_equal_tofile(im, \"Tests/images/hopper.png\")\n\n    # Test image with alpha\n    with Image.open(TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA) as im:\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (800, 600)\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA.replace(\".dds\", \".png\")\n        )\n\n\ndef test__accept_true():\n    \"\"\"Check valid prefix\"\"\"\n    # Arrange\n    prefix = b\"DDS etc\"\n\n    # Act\n    output = DdsImagePlugin._accept(prefix)\n\n    # Assert\n    assert output\n\n\ndef test__accept_false():\n    \"\"\"Check invalid prefix\"\"\"\n    # Arrange\n    prefix = b\"something invalid\"\n\n    # Act\n    output = DdsImagePlugin._accept(prefix)\n\n    # Assert\n    assert not output\n\n\ndef test_short_header():\n    \"\"\" Check a short header\"\"\"\n    with open(TEST_FILE_DXT5, \"rb\") as f:\n        img_file = f.read()\n\n    def short_header():\n        with Image.open(BytesIO(img_file[:119])):\n            pass  # pragma: no cover\n\n    with pytest.raises(OSError):\n        short_header()\n\n\ndef test_short_file():\n    \"\"\" Check that the appropriate error is thrown for a short file\"\"\"\n\n    with open(TEST_FILE_DXT5, \"rb\") as f:\n        img_file = f.read()\n\n    def short_file():\n        with Image.open(BytesIO(img_file[:-100])) as im:\n            im.load()\n\n    with pytest.raises(OSError):\n        short_file()\n\n\ndef test_dxt5_colorblock_alpha_issue_4142():\n    \"\"\" Check that colorblocks are decoded correctly in DXT5\"\"\"\n\n    with Image.open(\"Tests/images/dxt5-colorblock-alpha-issue-4142.dds\") as im:\n        px = im.getpixel((0, 0))\n        assert px[0] != 0\n        assert px[1] != 0\n        assert px[2] != 0\n\n        px = im.getpixel((1, 0))\n        assert px[0] != 0\n        assert px[1] != 0\n        assert px[2] != 0\n\n\ndef test_unimplemented_pixel_format():\n    with pytest.raises(NotImplementedError):\n        with Image.open(\"Tests/images/unimplemented_pixel_format.dds\"):\n            pass\n\n\ndef test_save_unsupported_mode(tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    im = hopper(\"HSV\")\n    with pytest.raises(OSError):\n        im.save(out)\n\n\ndef test_save(tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    im = hopper()\n    im.save(out)\n\n    with Image.open(out) as reloaded:\n        assert_image_equal(im, reloaded)\n",
            "new_file_content": "\"\"\"Test DdsImagePlugin\"\"\"\nfrom io import BytesIO\n\nimport pytest\n\nfrom PIL import DdsImagePlugin, Image\n\nfrom .helper import assert_image_equal, assert_image_equal_tofile, hopper\n\nTEST_FILE_DXT1 = \"Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds\"\nTEST_FILE_DXT3 = \"Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds\"\nTEST_FILE_DXT5 = \"Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds\"\nTEST_FILE_DX10_BC5_TYPELESS = \"Tests/images/bc5_typeless.dds\"\nTEST_FILE_DX10_BC5_UNORM = \"Tests/images/bc5_unorm.dds\"\nTEST_FILE_DX10_BC5_SNORM = \"Tests/images/bc5_snorm.dds\"\nTEST_FILE_BC5S = \"Tests/images/bc5s.dds\"\nTEST_FILE_DX10_BC7 = \"Tests/images/bc7-argb-8bpp_MipMaps-1.dds\"\nTEST_FILE_DX10_BC7_UNORM_SRGB = \"Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds\"\nTEST_FILE_DX10_R8G8B8A8 = \"Tests/images/argb-32bpp_MipMaps-1.dds\"\nTEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = \"Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds\"\nTEST_FILE_UNCOMPRESSED_RGB = \"Tests/images/hopper.dds\"\nTEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = \"Tests/images/uncompressed_rgb.dds\"\n\n\ndef test_sanity_dxt1():\n    \"\"\"Check DXT1 images can be opened\"\"\"\n    with Image.open(TEST_FILE_DXT1.replace(\".dds\", \".png\")) as target:\n        target = target.convert(\"RGBA\")\n    with Image.open(TEST_FILE_DXT1) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal(im, target)\n\n\ndef test_sanity_dxt3():\n    \"\"\"Check DXT3 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DXT3) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(\".dds\", \".png\"))\n\n\ndef test_sanity_dxt5():\n    \"\"\"Check DXT5 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DXT5) as im:\n        im.load()\n\n    assert im.format == \"DDS\"\n    assert im.mode == \"RGBA\"\n    assert im.size == (256, 256)\n\n    assert_image_equal_tofile(im, TEST_FILE_DXT5.replace(\".dds\", \".png\"))\n\n\n@pytest.mark.parametrize(\n    (\"image_path\", \"expected_path\"),\n    (\n        # hexeditted to be typeless\n        (TEST_FILE_DX10_BC5_TYPELESS, TEST_FILE_DX10_BC5_UNORM),\n        (TEST_FILE_DX10_BC5_UNORM, TEST_FILE_DX10_BC5_UNORM),\n        # hexeditted to use DX10 FourCC\n        (TEST_FILE_DX10_BC5_SNORM, TEST_FILE_BC5S),\n        (TEST_FILE_BC5S, TEST_FILE_BC5S),\n    ),\n)\ndef test_dx10_bc5(image_path, expected_path):\n    \"\"\"Check DX10 BC5 images can be opened\"\"\"\n\n    with Image.open(image_path) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGB\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, expected_path.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_bc7():\n    \"\"\"Check DX10 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_BC7) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_bc7_unorm_srgb():\n    \"\"\"Check DX10 unsigned normalized integer images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (16, 16)\n        assert im.info[\"gamma\"] == 1 / 2.2\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_DX10_BC7_UNORM_SRGB.replace(\".dds\", \".png\")\n        )\n\n\ndef test_dx10_r8g8b8a8():\n    \"\"\"Check DX10 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_R8G8B8A8) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_r8g8b8a8_unorm_srgb():\n    \"\"\"Check DX10 unsigned normalized integer images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (16, 16)\n        assert im.info[\"gamma\"] == 1 / 2.2\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB.replace(\".dds\", \".png\")\n        )\n\n\ndef test_unimplemented_dxgi_format():\n    with pytest.raises(NotImplementedError):\n        with Image.open(\"Tests/images/unimplemented_dxgi_format.dds\"):\n            pass\n\n\ndef test_uncompressed_rgb():\n    \"\"\"Check uncompressed RGB images can be opened\"\"\"\n\n    # convert -format dds -define dds:compression=none hopper.jpg hopper.dds\n    with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGB\"\n        assert im.size == (128, 128)\n\n        assert_image_equal_tofile(im, \"Tests/images/hopper.png\")\n\n    # Test image with alpha\n    with Image.open(TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA) as im:\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (800, 600)\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA.replace(\".dds\", \".png\")\n        )\n\n\ndef test__accept_true():\n    \"\"\"Check valid prefix\"\"\"\n    # Arrange\n    prefix = b\"DDS etc\"\n\n    # Act\n    output = DdsImagePlugin._accept(prefix)\n\n    # Assert\n    assert output\n\n\ndef test__accept_false():\n    \"\"\"Check invalid prefix\"\"\"\n    # Arrange\n    prefix = b\"something invalid\"\n\n    # Act\n    output = DdsImagePlugin._accept(prefix)\n\n    # Assert\n    assert not output\n\n\ndef test_short_header():\n    \"\"\" Check a short header\"\"\"\n    with open(TEST_FILE_DXT5, \"rb\") as f:\n        img_file = f.read()\n\n    def short_header():\n        with Image.open(BytesIO(img_file[:119])):\n            pass  # pragma: no cover\n\n    with pytest.raises(OSError):\n        short_header()\n\n\ndef test_short_file():\n    \"\"\" Check that the appropriate error is thrown for a short file\"\"\"\n\n    with open(TEST_FILE_DXT5, \"rb\") as f:\n        img_file = f.read()\n\n    def short_file():\n        with Image.open(BytesIO(img_file[:-100])) as im:\n            im.load()\n\n    with pytest.raises(OSError):\n        short_file()\n\n\ndef test_dxt5_colorblock_alpha_issue_4142():\n    \"\"\" Check that colorblocks are decoded correctly in DXT5\"\"\"\n\n    with Image.open(\"Tests/images/dxt5-colorblock-alpha-issue-4142.dds\") as im:\n        px = im.getpixel((0, 0))\n        assert px[0] != 0\n        assert px[1] != 0\n        assert px[2] != 0\n\n        px = im.getpixel((1, 0))\n        assert px[0] != 0\n        assert px[1] != 0\n        assert px[2] != 0\n\n\ndef test_unimplemented_pixel_format():\n    with pytest.raises(NotImplementedError):\n        with Image.open(\"Tests/images/unimplemented_pixel_format.dds\"):\n            pass\n\n\ndef test_save_unsupported_mode(tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    im = hopper(\"HSV\")\n    with pytest.raises(OSError):\n        im.save(out)\n\n\n@pytest.mark.parametrize(\n    (\"mode\", \"test_file\"),\n    [\n        (\"RGB\", \"Tests/images/hopper.png\"),\n        (\"RGBA\", \"Tests/images/pil123rgba.png\"),\n    ],\n)\ndef test_save(mode, test_file, tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    with Image.open(test_file) as im:\n        assert im.mode == mode\n        im.save(out)\n\n        with Image.open(out) as reloaded:\n            assert_image_equal(im, reloaded)\n",
            "header": {
                "file": {
                    "path": "Tests/test_file_dds.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "b44afff3a",
                "new_commit_hash": "46ebcad0c",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_file_dds.py"
            },
            "plus_file": {
                "path": "b/Tests/test_file_dds.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 251,
                            "length": 10
                        },
                        "new_range": {
                            "start": 251,
                            "length": 18
                        },
                        "section": "def test_save_unsupported_mode(tmp_path):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        im.save(out)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_save(tmp_path):",
                                "type": "deleted"
                            },
                            {
                                "content": "@pytest.mark.parametrize(",
                                "type": "added"
                            },
                            {
                                "content": "    (\"mode\", \"test_file\"),",
                                "type": "added"
                            },
                            {
                                "content": "    [",
                                "type": "added"
                            },
                            {
                                "content": "        (\"RGB\", \"Tests/images/hopper.png\"),",
                                "type": "added"
                            },
                            {
                                "content": "        (\"RGBA\", \"Tests/images/pil123rgba.png\"),",
                                "type": "added"
                            },
                            {
                                "content": "    ],",
                                "type": "added"
                            },
                            {
                                "content": ")",
                                "type": "added"
                            },
                            {
                                "content": "def test_save(mode, test_file, tmp_path):",
                                "type": "added"
                            },
                            {
                                "content": "    out = str(tmp_path / \"temp.dds\")",
                                "type": "context"
                            },
                            {
                                "content": "    im = hopper()",
                                "type": "deleted"
                            },
                            {
                                "content": "    im.save(out)",
                                "type": "deleted"
                            },
                            {
                                "content": "    with Image.open(test_file) as im:",
                                "type": "added"
                            },
                            {
                                "content": "        assert im.mode == mode",
                                "type": "added"
                            },
                            {
                                "content": "        im.save(out)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    with Image.open(out) as reloaded:",
                                "type": "deleted"
                            },
                            {
                                "content": "        assert_image_equal(im, reloaded)",
                                "type": "deleted"
                            },
                            {
                                "content": "        with Image.open(out) as reloaded:",
                                "type": "added"
                            },
                            {
                                "content": "            assert_image_equal(im, reloaded)",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_file_dds.py",
                            "type": "function",
                            "name": "test_save",
                            "content": "def test_save(tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    im = hopper()\n    im.save(out)\n\n    with Image.open(out) as reloaded:\n        assert_image_equal(im, reloaded)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 254,
                            "end_lineno": 260,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "\"\"\"\nA Pillow loader for .dds files (S3TC-compressed aka DXTC)\nJerome Leclanche <jerome@leclan.ch>\n\nDocumentation:\n  https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt\n\nThe contents of this file are hereby released in the public domain (CC0)\nFull text of the CC0 license:\n  https://creativecommons.org/publicdomain/zero/1.0/\n\"\"\"\n\nimport struct\nfrom io import BytesIO\n\nfrom . import Image, ImageFile\nfrom ._binary import o32le as o32\n\n# Magic (\"DDS \")\nDDS_MAGIC = 0x20534444\n\n# DDS flags\nDDSD_CAPS = 0x1\nDDSD_HEIGHT = 0x2\nDDSD_WIDTH = 0x4\nDDSD_PITCH = 0x8\nDDSD_PIXELFORMAT = 0x1000\nDDSD_MIPMAPCOUNT = 0x20000\nDDSD_LINEARSIZE = 0x80000\nDDSD_DEPTH = 0x800000\n\n# DDS caps\nDDSCAPS_COMPLEX = 0x8\nDDSCAPS_TEXTURE = 0x1000\nDDSCAPS_MIPMAP = 0x400000\n\nDDSCAPS2_CUBEMAP = 0x200\nDDSCAPS2_CUBEMAP_POSITIVEX = 0x400\nDDSCAPS2_CUBEMAP_NEGATIVEX = 0x800\nDDSCAPS2_CUBEMAP_POSITIVEY = 0x1000\nDDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000\nDDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000\nDDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000\nDDSCAPS2_VOLUME = 0x200000\n\n# Pixel Format\nDDPF_ALPHAPIXELS = 0x1\nDDPF_ALPHA = 0x2\nDDPF_FOURCC = 0x4\nDDPF_PALETTEINDEXED8 = 0x20\nDDPF_RGB = 0x40\nDDPF_LUMINANCE = 0x20000\n\n\n# dds.h\n\nDDS_FOURCC = DDPF_FOURCC\nDDS_RGB = DDPF_RGB\nDDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS\nDDS_LUMINANCE = DDPF_LUMINANCE\nDDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS\nDDS_ALPHA = DDPF_ALPHA\nDDS_PAL8 = DDPF_PALETTEINDEXED8\n\nDDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT\nDDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT\nDDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH\nDDS_HEADER_FLAGS_PITCH = DDSD_PITCH\nDDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE\n\nDDS_HEIGHT = DDSD_HEIGHT\nDDS_WIDTH = DDSD_WIDTH\n\nDDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE\nDDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\nDDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX\n\nDDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\nDDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\nDDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\nDDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\nDDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\nDDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n\n# DXT1\nDXT1_FOURCC = 0x31545844\n\n# DXT3\nDXT3_FOURCC = 0x33545844\n\n# DXT5\nDXT5_FOURCC = 0x35545844\n\n\n# dxgiformat.h\n\nDXGI_FORMAT_R8G8B8A8_TYPELESS = 27\nDXGI_FORMAT_R8G8B8A8_UNORM = 28\nDXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29\nDXGI_FORMAT_BC5_TYPELESS = 82\nDXGI_FORMAT_BC5_UNORM = 83\nDXGI_FORMAT_BC5_SNORM = 84\nDXGI_FORMAT_BC7_TYPELESS = 97\nDXGI_FORMAT_BC7_UNORM = 98\nDXGI_FORMAT_BC7_UNORM_SRGB = 99\n\n\nclass DdsImageFile(ImageFile.ImageFile):\n    format = \"DDS\"\n    format_description = \"DirectDraw Surface\"\n\n    def _open(self):\n        magic, header_size = struct.unpack(\"<II\", self.fp.read(8))\n        if header_size != 124:\n            raise OSError(f\"Unsupported header size {repr(header_size)}\")\n        header_bytes = self.fp.read(header_size - 4)\n        if len(header_bytes) != 120:\n            raise OSError(f\"Incomplete header: {len(header_bytes)} bytes\")\n        header = BytesIO(header_bytes)\n\n        flags, height, width = struct.unpack(\"<3I\", header.read(12))\n        self._size = (width, height)\n        self.mode = \"RGBA\"\n\n        pitch, depth, mipmaps = struct.unpack(\"<3I\", header.read(12))\n        struct.unpack(\"<11I\", header.read(44))  # reserved\n\n        # pixel format\n        pfsize, pfflags = struct.unpack(\"<2I\", header.read(8))\n        fourcc = header.read(4)\n        (bitcount,) = struct.unpack(\"<I\", header.read(4))\n        masks = struct.unpack(\"<4I\", header.read(16))\n        if pfflags & DDPF_RGB:\n            # Texture contains uncompressed RGB data\n            masks = {mask: [\"R\", \"G\", \"B\", \"A\"][i] for i, mask in enumerate(masks)}\n            rawmode = \"\"\n            if bitcount == 32:\n                rawmode += masks[0xFF000000]\n            else:\n                self.mode = \"RGB\"\n            rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]\n\n            self.tile = [(\"raw\", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]\n        else:\n            data_start = header_size + 4\n            n = 0\n            if fourcc == b\"DXT1\":\n                self.pixel_format = \"DXT1\"\n                n = 1\n            elif fourcc == b\"DXT3\":\n                self.pixel_format = \"DXT3\"\n                n = 2\n            elif fourcc == b\"DXT5\":\n                self.pixel_format = \"DXT5\"\n                n = 3\n            elif fourcc == b\"BC5S\":\n                self.pixel_format = \"BC5S\"\n                n = 5\n                self.mode = \"RGB\"\n            elif fourcc == b\"DX10\":\n                data_start += 20\n                # ignoring flags which pertain to volume textures and cubemaps\n                (dxgi_format,) = struct.unpack(\"<I\", self.fp.read(4))\n                self.fp.read(16)\n                if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):\n                    self.pixel_format = \"BC5\"\n                    n = 5\n                    self.mode = \"RGB\"\n                elif dxgi_format == DXGI_FORMAT_BC5_SNORM:\n                    self.pixel_format = \"BC5S\"\n                    n = 5\n                    self.mode = \"RGB\"\n                elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):\n                    self.pixel_format = \"BC7\"\n                    n = 7\n                elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:\n                    self.pixel_format = \"BC7\"\n                    self.info[\"gamma\"] = 1 / 2.2\n                    n = 7\n                elif dxgi_format in (\n                    DXGI_FORMAT_R8G8B8A8_TYPELESS,\n                    DXGI_FORMAT_R8G8B8A8_UNORM,\n                    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,\n                ):\n                    self.tile = [(\"raw\", (0, 0) + self.size, 0, (\"RGBA\", 0, 1))]\n                    if dxgi_format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n                        self.info[\"gamma\"] = 1 / 2.2\n                    return\n                else:\n                    raise NotImplementedError(\n                        f\"Unimplemented DXGI format {dxgi_format}\"\n                    )\n            else:\n                raise NotImplementedError(f\"Unimplemented pixel format {repr(fourcc)}\")\n\n            self.tile = [\n                (\"bcn\", (0, 0) + self.size, data_start, (n, self.pixel_format))\n            ]\n\n    def load_seek(self, pos):\n        pass\n\n\ndef _save(im, fp, filename):\n    if im.mode != \"RGB\":\n        raise OSError(f\"cannot write mode {im.mode} as DDS\")\n\n    fp.write(\n        o32(DDS_MAGIC)\n        + o32(124)  # header size\n        + o32(\n            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT\n        )  # flags\n        + o32(im.height)\n        + o32(im.width)\n        + o32((im.width * 24 + 7) // 8)  # pitch\n        + o32(0)  # depth\n        + o32(0)  # mipmaps\n        + o32(0) * 11  # reserved\n        + o32(32)  # pfsize\n        + o32(DDPF_RGB)  # pfflags\n        + o32(0)  # fourcc\n        + o32(24)  # bitcount\n        + o32(0xFF0000)  # rbitmask\n        + o32(0xFF00)  # gbitmask\n        + o32(0xFF)  # bbitmask\n        + o32(0)  # abitmask\n        + o32(DDSCAPS_TEXTURE)  # dwCaps\n        + o32(0)  # dwCaps2\n        + o32(0)  # dwCaps3\n        + o32(0)  # dwCaps4\n        + o32(0)  # dwReserved2\n    )\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])\n\n\ndef _accept(prefix):\n    return prefix[:4] == b\"DDS \"\n\n\nImage.register_open(DdsImageFile.format, DdsImageFile, _accept)\nImage.register_save(DdsImageFile.format, _save)\nImage.register_extension(DdsImageFile.format, \".dds\")\n",
            "new_file_content": "\"\"\"\nA Pillow loader for .dds files (S3TC-compressed aka DXTC)\nJerome Leclanche <jerome@leclan.ch>\n\nDocumentation:\n  https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt\n\nThe contents of this file are hereby released in the public domain (CC0)\nFull text of the CC0 license:\n  https://creativecommons.org/publicdomain/zero/1.0/\n\"\"\"\n\nimport struct\nfrom io import BytesIO\n\nfrom . import Image, ImageFile\nfrom ._binary import o32le as o32\n\n# Magic (\"DDS \")\nDDS_MAGIC = 0x20534444\n\n# DDS flags\nDDSD_CAPS = 0x1\nDDSD_HEIGHT = 0x2\nDDSD_WIDTH = 0x4\nDDSD_PITCH = 0x8\nDDSD_PIXELFORMAT = 0x1000\nDDSD_MIPMAPCOUNT = 0x20000\nDDSD_LINEARSIZE = 0x80000\nDDSD_DEPTH = 0x800000\n\n# DDS caps\nDDSCAPS_COMPLEX = 0x8\nDDSCAPS_TEXTURE = 0x1000\nDDSCAPS_MIPMAP = 0x400000\n\nDDSCAPS2_CUBEMAP = 0x200\nDDSCAPS2_CUBEMAP_POSITIVEX = 0x400\nDDSCAPS2_CUBEMAP_NEGATIVEX = 0x800\nDDSCAPS2_CUBEMAP_POSITIVEY = 0x1000\nDDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000\nDDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000\nDDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000\nDDSCAPS2_VOLUME = 0x200000\n\n# Pixel Format\nDDPF_ALPHAPIXELS = 0x1\nDDPF_ALPHA = 0x2\nDDPF_FOURCC = 0x4\nDDPF_PALETTEINDEXED8 = 0x20\nDDPF_RGB = 0x40\nDDPF_LUMINANCE = 0x20000\n\n\n# dds.h\n\nDDS_FOURCC = DDPF_FOURCC\nDDS_RGB = DDPF_RGB\nDDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS\nDDS_LUMINANCE = DDPF_LUMINANCE\nDDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS\nDDS_ALPHA = DDPF_ALPHA\nDDS_PAL8 = DDPF_PALETTEINDEXED8\n\nDDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT\nDDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT\nDDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH\nDDS_HEADER_FLAGS_PITCH = DDSD_PITCH\nDDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE\n\nDDS_HEIGHT = DDSD_HEIGHT\nDDS_WIDTH = DDSD_WIDTH\n\nDDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE\nDDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\nDDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX\n\nDDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\nDDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\nDDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\nDDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\nDDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\nDDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n\n# DXT1\nDXT1_FOURCC = 0x31545844\n\n# DXT3\nDXT3_FOURCC = 0x33545844\n\n# DXT5\nDXT5_FOURCC = 0x35545844\n\n\n# dxgiformat.h\n\nDXGI_FORMAT_R8G8B8A8_TYPELESS = 27\nDXGI_FORMAT_R8G8B8A8_UNORM = 28\nDXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29\nDXGI_FORMAT_BC5_TYPELESS = 82\nDXGI_FORMAT_BC5_UNORM = 83\nDXGI_FORMAT_BC5_SNORM = 84\nDXGI_FORMAT_BC7_TYPELESS = 97\nDXGI_FORMAT_BC7_UNORM = 98\nDXGI_FORMAT_BC7_UNORM_SRGB = 99\n\n\nclass DdsImageFile(ImageFile.ImageFile):\n    format = \"DDS\"\n    format_description = \"DirectDraw Surface\"\n\n    def _open(self):\n        magic, header_size = struct.unpack(\"<II\", self.fp.read(8))\n        if header_size != 124:\n            raise OSError(f\"Unsupported header size {repr(header_size)}\")\n        header_bytes = self.fp.read(header_size - 4)\n        if len(header_bytes) != 120:\n            raise OSError(f\"Incomplete header: {len(header_bytes)} bytes\")\n        header = BytesIO(header_bytes)\n\n        flags, height, width = struct.unpack(\"<3I\", header.read(12))\n        self._size = (width, height)\n        self.mode = \"RGBA\"\n\n        pitch, depth, mipmaps = struct.unpack(\"<3I\", header.read(12))\n        struct.unpack(\"<11I\", header.read(44))  # reserved\n\n        # pixel format\n        pfsize, pfflags = struct.unpack(\"<2I\", header.read(8))\n        fourcc = header.read(4)\n        (bitcount,) = struct.unpack(\"<I\", header.read(4))\n        masks = struct.unpack(\"<4I\", header.read(16))\n        if pfflags & DDPF_RGB:\n            # Texture contains uncompressed RGB data\n            masks = {mask: [\"R\", \"G\", \"B\", \"A\"][i] for i, mask in enumerate(masks)}\n            rawmode = \"\"\n            if bitcount == 32:\n                rawmode += masks[0xFF000000]\n            else:\n                self.mode = \"RGB\"\n            rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]\n\n            self.tile = [(\"raw\", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]\n        else:\n            data_start = header_size + 4\n            n = 0\n            if fourcc == b\"DXT1\":\n                self.pixel_format = \"DXT1\"\n                n = 1\n            elif fourcc == b\"DXT3\":\n                self.pixel_format = \"DXT3\"\n                n = 2\n            elif fourcc == b\"DXT5\":\n                self.pixel_format = \"DXT5\"\n                n = 3\n            elif fourcc == b\"BC5S\":\n                self.pixel_format = \"BC5S\"\n                n = 5\n                self.mode = \"RGB\"\n            elif fourcc == b\"DX10\":\n                data_start += 20\n                # ignoring flags which pertain to volume textures and cubemaps\n                (dxgi_format,) = struct.unpack(\"<I\", self.fp.read(4))\n                self.fp.read(16)\n                if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):\n                    self.pixel_format = \"BC5\"\n                    n = 5\n                    self.mode = \"RGB\"\n                elif dxgi_format == DXGI_FORMAT_BC5_SNORM:\n                    self.pixel_format = \"BC5S\"\n                    n = 5\n                    self.mode = \"RGB\"\n                elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):\n                    self.pixel_format = \"BC7\"\n                    n = 7\n                elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:\n                    self.pixel_format = \"BC7\"\n                    self.info[\"gamma\"] = 1 / 2.2\n                    n = 7\n                elif dxgi_format in (\n                    DXGI_FORMAT_R8G8B8A8_TYPELESS,\n                    DXGI_FORMAT_R8G8B8A8_UNORM,\n                    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,\n                ):\n                    self.tile = [(\"raw\", (0, 0) + self.size, 0, (\"RGBA\", 0, 1))]\n                    if dxgi_format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n                        self.info[\"gamma\"] = 1 / 2.2\n                    return\n                else:\n                    raise NotImplementedError(\n                        f\"Unimplemented DXGI format {dxgi_format}\"\n                    )\n            else:\n                raise NotImplementedError(f\"Unimplemented pixel format {repr(fourcc)}\")\n\n            self.tile = [\n                (\"bcn\", (0, 0) + self.size, data_start, (n, self.pixel_format))\n            ]\n\n    def load_seek(self, pos):\n        pass\n\n\ndef _save(im, fp, filename):\n    if im.mode not in (\"RGB\", \"RGBA\"):\n        raise OSError(f\"cannot write mode {im.mode} as DDS\")\n\n    fp.write(\n        o32(DDS_MAGIC)\n        + o32(124)  # header size\n        + o32(\n            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT\n        )  # flags\n        + o32(im.height)\n        + o32(im.width)\n        + o32((im.width * (32 if im.mode == \"RGBA\" else 24) + 7) // 8)  # pitch\n        + o32(0)  # depth\n        + o32(0)  # mipmaps\n        + o32(0) * 11  # reserved\n        + o32(32)  # pfsize\n        + o32(DDS_RGBA if im.mode == \"RGBA\" else DDPF_RGB)  # pfflags\n        + o32(0)  # fourcc\n        + o32(32 if im.mode == \"RGBA\" else 24)  # bitcount\n        + o32(0xFF0000)  # rbitmask\n        + o32(0xFF00)  # gbitmask\n        + o32(0xFF)  # bbitmask\n        + o32(0xFF000000 if im.mode == \"RGBA\" else 0)  # abitmask\n        + o32(DDSCAPS_TEXTURE)  # dwCaps\n        + o32(0)  # dwCaps2\n        + o32(0)  # dwCaps3\n        + o32(0)  # dwCaps4\n        + o32(0)  # dwReserved2\n    )\n    if im.mode == \"RGBA\":\n        r, g, b, a = im.split()\n        im = Image.merge(\"RGBA\", (a, r, g, b))\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])\n\n\ndef _accept(prefix):\n    return prefix[:4] == b\"DDS \"\n\n\nImage.register_open(DdsImageFile.format, DdsImageFile, _accept)\nImage.register_save(DdsImageFile.format, _save)\nImage.register_extension(DdsImageFile.format, \".dds\")\n",
            "header": {
                "file": {
                    "path": "src/PIL/DdsImagePlugin.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "e8a41c045",
                "new_commit_hash": "260924fca",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/DdsImagePlugin.py"
            },
            "plus_file": {
                "path": "b/src/PIL/DdsImagePlugin.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 203,
                            "length": 7
                        },
                        "new_range": {
                            "start": 203,
                            "length": 7
                        },
                        "section": "class DdsImageFile(ImageFile.ImageFile):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def _save(im, fp, filename):",
                                "type": "context"
                            },
                            {
                                "content": "    if im.mode != \"RGB\":",
                                "type": "deleted"
                            },
                            {
                                "content": "    if im.mode not in (\"RGB\", \"RGBA\"):",
                                "type": "added"
                            },
                            {
                                "content": "        raise OSError(f\"cannot write mode {im.mode} as DDS\")",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    fp.write(",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/DdsImagePlugin.py",
                            "type": "function",
                            "name": "_save",
                            "content": "def _save(im, fp, filename):\n    if im.mode != \"RGB\":\n        raise OSError(f\"cannot write mode {im.mode} as DDS\")\n\n    fp.write(\n        o32(DDS_MAGIC)\n        + o32(124)  # header size\n        + o32(\n            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT\n        )  # flags\n        + o32(im.height)\n        + o32(im.width)\n        + o32((im.width * 24 + 7) // 8)  # pitch\n        + o32(0)  # depth\n        + o32(0)  # mipmaps\n        + o32(0) * 11  # reserved\n        + o32(32)  # pfsize\n        + o32(DDPF_RGB)  # pfflags\n        + o32(0)  # fourcc\n        + o32(24)  # bitcount\n        + o32(0xFF0000)  # rbitmask\n        + o32(0xFF00)  # gbitmask\n        + o32(0xFF)  # bbitmask\n        + o32(0)  # abitmask\n        + o32(DDSCAPS_TEXTURE)  # dwCaps\n        + o32(0)  # dwCaps2\n        + o32(0)  # dwCaps3\n        + o32(0)  # dwCaps4\n        + o32(0)  # dwReserved2\n    )\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 205,
                            "end_lineno": 235,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 214,
                            "length": 24
                        },
                        "new_range": {
                            "start": 214,
                            "length": 27
                        },
                        "section": "def _save(im, fp, filename):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        )  # flags",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(im.height)",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(im.width)",
                                "type": "context"
                            },
                            {
                                "content": "        + o32((im.width * 24 + 7) // 8)  # pitch",
                                "type": "deleted"
                            },
                            {
                                "content": "        + o32((im.width * (32 if im.mode == \"RGBA\" else 24) + 7) // 8)  # pitch",
                                "type": "added"
                            },
                            {
                                "content": "        + o32(0)  # depth",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0)  # mipmaps",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0) * 11  # reserved",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(32)  # pfsize",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(DDPF_RGB)  # pfflags",
                                "type": "deleted"
                            },
                            {
                                "content": "        + o32(DDS_RGBA if im.mode == \"RGBA\" else DDPF_RGB)  # pfflags",
                                "type": "added"
                            },
                            {
                                "content": "        + o32(0)  # fourcc",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(24)  # bitcount",
                                "type": "deleted"
                            },
                            {
                                "content": "        + o32(32 if im.mode == \"RGBA\" else 24)  # bitcount",
                                "type": "added"
                            },
                            {
                                "content": "        + o32(0xFF0000)  # rbitmask",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0xFF00)  # gbitmask",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0xFF)  # bbitmask",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0)  # abitmask",
                                "type": "deleted"
                            },
                            {
                                "content": "        + o32(0xFF000000 if im.mode == \"RGBA\" else 0)  # abitmask",
                                "type": "added"
                            },
                            {
                                "content": "        + o32(DDSCAPS_TEXTURE)  # dwCaps",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0)  # dwCaps2",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0)  # dwCaps3",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0)  # dwCaps4",
                                "type": "context"
                            },
                            {
                                "content": "        + o32(0)  # dwReserved2",
                                "type": "context"
                            },
                            {
                                "content": "    )",
                                "type": "context"
                            },
                            {
                                "content": "    if im.mode == \"RGBA\":",
                                "type": "added"
                            },
                            {
                                "content": "        r, g, b, a = im.split()",
                                "type": "added"
                            },
                            {
                                "content": "        im = Image.merge(\"RGBA\", (a, r, g, b))",
                                "type": "added"
                            },
                            {
                                "content": "    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/DdsImagePlugin.py",
                            "type": "function",
                            "name": "_save",
                            "content": "def _save(im, fp, filename):\n    if im.mode != \"RGB\":\n        raise OSError(f\"cannot write mode {im.mode} as DDS\")\n\n    fp.write(\n        o32(DDS_MAGIC)\n        + o32(124)  # header size\n        + o32(\n            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT\n        )  # flags\n        + o32(im.height)\n        + o32(im.width)\n        + o32((im.width * 24 + 7) // 8)  # pitch\n        + o32(0)  # depth\n        + o32(0)  # mipmaps\n        + o32(0) * 11  # reserved\n        + o32(32)  # pfsize\n        + o32(DDPF_RGB)  # pfflags\n        + o32(0)  # fourcc\n        + o32(24)  # bitcount\n        + o32(0xFF0000)  # rbitmask\n        + o32(0xFF00)  # gbitmask\n        + o32(0xFF)  # bbitmask\n        + o32(0)  # abitmask\n        + o32(DDSCAPS_TEXTURE)  # dwCaps\n        + o32(0)  # dwCaps2\n        + o32(0)  # dwCaps3\n        + o32(0)  # dwCaps4\n        + o32(0)  # dwReserved2\n    )\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 205,
                            "end_lineno": 235,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "6449cdc1a3d3c8ddc436aca766198d149add486a^",
    "new_commit_hash": "6449cdc1a3d3c8ddc436aca766198d149add486a",
    "commit_message": "Added RGBA saving",
    "commit_date": "2021-06-14T18:14:28+10:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "6449cdc1a3d3c8ddc436aca766198d149add486a",
    "test_file_codes": [
        "\"\"\"Test DdsImagePlugin\"\"\"\nfrom io import BytesIO\n\nimport pytest\n\nfrom PIL import DdsImagePlugin, Image\n\nfrom .helper import assert_image_equal, assert_image_equal_tofile, hopper\n\nTEST_FILE_DXT1 = \"Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds\"\nTEST_FILE_DXT3 = \"Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds\"\nTEST_FILE_DXT5 = \"Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds\"\nTEST_FILE_DX10_BC5_TYPELESS = \"Tests/images/bc5_typeless.dds\"\nTEST_FILE_DX10_BC5_UNORM = \"Tests/images/bc5_unorm.dds\"\nTEST_FILE_DX10_BC5_SNORM = \"Tests/images/bc5_snorm.dds\"\nTEST_FILE_BC5S = \"Tests/images/bc5s.dds\"\nTEST_FILE_DX10_BC7 = \"Tests/images/bc7-argb-8bpp_MipMaps-1.dds\"\nTEST_FILE_DX10_BC7_UNORM_SRGB = \"Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds\"\nTEST_FILE_DX10_R8G8B8A8 = \"Tests/images/argb-32bpp_MipMaps-1.dds\"\nTEST_FILE_DX10_R8G8B8A8_UNORM_SRGB = \"Tests/images/DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.dds\"\nTEST_FILE_UNCOMPRESSED_RGB = \"Tests/images/hopper.dds\"\nTEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = \"Tests/images/uncompressed_rgb.dds\"\n\n\ndef test_sanity_dxt1():\n    \"\"\"Check DXT1 images can be opened\"\"\"\n    with Image.open(TEST_FILE_DXT1.replace(\".dds\", \".png\")) as target:\n        target = target.convert(\"RGBA\")\n    with Image.open(TEST_FILE_DXT1) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal(im, target)\n\n\ndef test_sanity_dxt3():\n    \"\"\"Check DXT3 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DXT3) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(\".dds\", \".png\"))\n\n\ndef test_sanity_dxt5():\n    \"\"\"Check DXT5 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DXT5) as im:\n        im.load()\n\n    assert im.format == \"DDS\"\n    assert im.mode == \"RGBA\"\n    assert im.size == (256, 256)\n\n    assert_image_equal_tofile(im, TEST_FILE_DXT5.replace(\".dds\", \".png\"))\n\n\n@pytest.mark.parametrize(\n    (\"image_path\", \"expected_path\"),\n    (\n        # hexeditted to be typeless\n        (TEST_FILE_DX10_BC5_TYPELESS, TEST_FILE_DX10_BC5_UNORM),\n        (TEST_FILE_DX10_BC5_UNORM, TEST_FILE_DX10_BC5_UNORM),\n        # hexeditted to use DX10 FourCC\n        (TEST_FILE_DX10_BC5_SNORM, TEST_FILE_BC5S),\n        (TEST_FILE_BC5S, TEST_FILE_BC5S),\n    ),\n)\ndef test_dx10_bc5(image_path, expected_path):\n    \"\"\"Check DX10 BC5 images can be opened\"\"\"\n\n    with Image.open(image_path) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGB\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, expected_path.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_bc7():\n    \"\"\"Check DX10 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_BC7) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_bc7_unorm_srgb():\n    \"\"\"Check DX10 unsigned normalized integer images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (16, 16)\n        assert im.info[\"gamma\"] == 1 / 2.2\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_DX10_BC7_UNORM_SRGB.replace(\".dds\", \".png\")\n        )\n\n\ndef test_dx10_r8g8b8a8():\n    \"\"\"Check DX10 images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_R8G8B8A8) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (256, 256)\n\n        assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(\".dds\", \".png\"))\n\n\ndef test_dx10_r8g8b8a8_unorm_srgb():\n    \"\"\"Check DX10 unsigned normalized integer images can be opened\"\"\"\n\n    with Image.open(TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB) as im:\n        im.load()\n\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (16, 16)\n        assert im.info[\"gamma\"] == 1 / 2.2\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB.replace(\".dds\", \".png\")\n        )\n\n\ndef test_unimplemented_dxgi_format():\n    with pytest.raises(NotImplementedError):\n        with Image.open(\"Tests/images/unimplemented_dxgi_format.dds\"):\n            pass\n\n\ndef test_uncompressed_rgb():\n    \"\"\"Check uncompressed RGB images can be opened\"\"\"\n\n    # convert -format dds -define dds:compression=none hopper.jpg hopper.dds\n    with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGB\"\n        assert im.size == (128, 128)\n\n        assert_image_equal_tofile(im, \"Tests/images/hopper.png\")\n\n    # Test image with alpha\n    with Image.open(TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA) as im:\n        assert im.format == \"DDS\"\n        assert im.mode == \"RGBA\"\n        assert im.size == (800, 600)\n\n        assert_image_equal_tofile(\n            im, TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA.replace(\".dds\", \".png\")\n        )\n\n\ndef test__accept_true():\n    \"\"\"Check valid prefix\"\"\"\n    # Arrange\n    prefix = b\"DDS etc\"\n\n    # Act\n    output = DdsImagePlugin._accept(prefix)\n\n    # Assert\n    assert output\n\n\ndef test__accept_false():\n    \"\"\"Check invalid prefix\"\"\"\n    # Arrange\n    prefix = b\"something invalid\"\n\n    # Act\n    output = DdsImagePlugin._accept(prefix)\n\n    # Assert\n    assert not output\n\n\ndef test_short_header():\n    \"\"\" Check a short header\"\"\"\n    with open(TEST_FILE_DXT5, \"rb\") as f:\n        img_file = f.read()\n\n    def short_header():\n        with Image.open(BytesIO(img_file[:119])):\n            pass  # pragma: no cover\n\n    with pytest.raises(OSError):\n        short_header()\n\n\ndef test_short_file():\n    \"\"\" Check that the appropriate error is thrown for a short file\"\"\"\n\n    with open(TEST_FILE_DXT5, \"rb\") as f:\n        img_file = f.read()\n\n    def short_file():\n        with Image.open(BytesIO(img_file[:-100])) as im:\n            im.load()\n\n    with pytest.raises(OSError):\n        short_file()\n\n\ndef test_dxt5_colorblock_alpha_issue_4142():\n    \"\"\" Check that colorblocks are decoded correctly in DXT5\"\"\"\n\n    with Image.open(\"Tests/images/dxt5-colorblock-alpha-issue-4142.dds\") as im:\n        px = im.getpixel((0, 0))\n        assert px[0] != 0\n        assert px[1] != 0\n        assert px[2] != 0\n\n        px = im.getpixel((1, 0))\n        assert px[0] != 0\n        assert px[1] != 0\n        assert px[2] != 0\n\n\ndef test_unimplemented_pixel_format():\n    with pytest.raises(NotImplementedError):\n        with Image.open(\"Tests/images/unimplemented_pixel_format.dds\"):\n            pass\n\n\ndef test_save_unsupported_mode(tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    im = hopper(\"HSV\")\n    with pytest.raises(OSError):\n        im.save(out)\n\n\n@pytest.mark.parametrize(\n    (\"mode\", \"test_file\"),\n    [\n        (\"RGB\", \"Tests/images/hopper.png\"),\n        (\"RGBA\", \"Tests/images/pil123rgba.png\"),\n    ],\n)\ndef test_save(mode, test_file, tmp_path):\n    out = str(tmp_path / \"temp.dds\")\n    with Image.open(test_file) as im:\n        assert im.mode == mode\n        im.save(out)\n\n        with Image.open(out) as reloaded:\n            assert_image_equal(im, reloaded)\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 16ms\nInstalled 12 packages in 140ms\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 766ms\nPrepared 1 package in 31.63s\nInstalled 1 package in 1ms\n + pillow==8.3.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_6449cdc1a3d3c8ddc436aca766198d149add486a)\n",
    "new_commit_res_code": 0,
    "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_6449cdc1a3d3c8ddc436aca766198d149add486a\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 22 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[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[32m                               [100%]\u001b[0m\n\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity_dxt1\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity_dxt3\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity_dxt5\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5_typeless.dds-Tests/images/bc5_unorm.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5_unorm.dds-Tests/images/bc5_unorm.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5_snorm.dds-Tests/images/bc5s.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5s.dds-Tests/images/bc5s.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc7\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc7_unorm_srgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_r8g8b8a8\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_r8g8b8a8_unorm_srgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_unimplemented_dxgi_format\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_uncompressed_rgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest__accept_true\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest__accept_false\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_short_header\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_short_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dxt5_colorblock_alpha_issue_4142\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_unimplemented_pixel_format\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save_unsupported_mode\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[RGB-Tests/images/hopper.png]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[RGBA-Tests/images/pil123rgba.png]\u001b[0m\n\u001b[32m============================== \u001b[32m\u001b[1m22 passed\u001b[0m\u001b[32m in 0.17s\u001b[0m\u001b[32m ==============================\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_6449cdc1a3d3c8ddc436aca766198d149add486a\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 22 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[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[31m                               [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m_________________ test_save[RGBA-Tests/images/pil123rgba.png] __________________\u001b[0m\n\nmode = 'RGBA', test_file = 'Tests/images/pil123rgba.png'\ntmp_path = PosixPath('/tmp/pytest-of-gcpuser/pytest-278/test_save_RGBA_Tests_images_pi0')\n\n    @pytest.mark.parametrize(\n        (\"mode\", \"test_file\"),\n        [\n            (\"RGB\", \"Tests/images/hopper.png\"),\n            (\"RGBA\", \"Tests/images/pil123rgba.png\"),\n        ],\n    )\n    def test_save(mode, test_file, tmp_path):\n        out = str(tmp_path / \"temp.dds\")\n        with Image.open(test_file) as im:\n            assert im.mode == mode\n>           im.save(out)\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:265: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\u001b[1m\u001b[31msrc/PIL/Image.py\u001b[0m:2187: in save\n    save_handler(self, fp, filename)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nim = <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=162x150 at 0x78C1A485A130>\nfp = <_io.BufferedRandom name='/tmp/pytest-of-gcpuser/pytest-278/test_save_RGBA_Tests_images_pi0/temp.dds'>\nfilename = '/tmp/pytest-of-gcpuser/pytest-278/test_save_RGBA_Tests_images_pi0/temp.dds'\n\n    def _save(im, fp, filename):\n        if im.mode != \"RGB\":\n>           raise OSError(f\"cannot write mode {im.mode} as DDS\")\n\u001b[1m\u001b[31mE           OSError: cannot write mode RGBA as DDS\u001b[0m\n\n\u001b[1m\u001b[31msrc/PIL/DdsImagePlugin.py\u001b[0m:207: OSError\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity_dxt1\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity_dxt3\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity_dxt5\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5_typeless.dds-Tests/images/bc5_unorm.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5_unorm.dds-Tests/images/bc5_unorm.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5_snorm.dds-Tests/images/bc5s.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc5[Tests/images/bc5s.dds-Tests/images/bc5s.dds]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc7\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_bc7_unorm_srgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_r8g8b8a8\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dx10_r8g8b8a8_unorm_srgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_unimplemented_dxgi_format\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_uncompressed_rgb\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest__accept_true\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest__accept_false\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_short_header\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_short_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_dxt5_colorblock_alpha_issue_4142\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_unimplemented_pixel_format\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save_unsupported_mode\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[RGB-Tests/images/hopper.png]\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[RGBA-Tests/images/pil123rgba.png]\u001b[0m - OSError: cannot write mode RGBA as DDS\n\u001b[31m========================= \u001b[31m\u001b[1m1 failed\u001b[0m, \u001b[32m21 passed\u001b[0m\u001b[31m in 0.20s\u001b[0m\u001b[31m =========================\u001b[0m\n",
    "old_commit_res_stderr": ""
}
Tests/test_file_dds.py src/PIL/DdsImagePlugin.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Unable to Save RGBA Images as DDS Format

**Description:**
When attempting to save an image with RGBA mode to the DDS format, an `OSError` is raised, indicating that the mode is unsupported. This issue prevents users from saving images with transparency in the DDS format.

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

# Open an RGBA image
with Image.open("Tests/images/pil123rgba.png") as im:
    # Attempt to save as DDS
    im.save("output.dds")
```

**Expected Behavior:**
The image with RGBA mode should be successfully saved in the DDS format without any errors, preserving the alpha channel for transparency.

**Actual Behavior:**
An `OSError` is raised with the message:
```
OSError: cannot write mode RGBA as DDS
```
This error occurs because the DDS plugin does not recognize the RGBA mode as a valid format for saving.

[/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/DdsImagePlugin.py
"""
A Pillow loader for .dds files (S3TC-compressed aka DXTC)
Jerome Leclanche <jerome@leclan.ch>

Documentation:
  https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt

The contents of this file are hereby released in the public domain (CC0)
Full text of the CC0 license:
  https://creativecommons.org/publicdomain/zero/1.0/
"""

import struct
from io import BytesIO

from . import Image, ImageFile
from ._binary import o32le as o32

# Magic ("DDS ")
DDS_MAGIC = 0x20534444

# DDS flags
DDSD_CAPS = 0x1
DDSD_HEIGHT = 0x2
DDSD_WIDTH = 0x4
DDSD_PITCH = 0x8
DDSD_PIXELFORMAT = 0x1000
DDSD_MIPMAPCOUNT = 0x20000
DDSD_LINEARSIZE = 0x80000
DDSD_DEPTH = 0x800000

# DDS caps
DDSCAPS_COMPLEX = 0x8
DDSCAPS_TEXTURE = 0x1000
DDSCAPS_MIPMAP = 0x400000

DDSCAPS2_CUBEMAP = 0x200
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000
DDSCAPS2_VOLUME = 0x200000

# Pixel Format
DDPF_ALPHAPIXELS = 0x1
DDPF_ALPHA = 0x2
DDPF_FOURCC = 0x4
DDPF_PALETTEINDEXED8 = 0x20
DDPF_RGB = 0x40
DDPF_LUMINANCE = 0x20000


# dds.h

DDS_FOURCC = DDPF_FOURCC
DDS_RGB = DDPF_RGB
DDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS
DDS_LUMINANCE = DDPF_LUMINANCE
DDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS
DDS_ALPHA = DDPF_ALPHA
DDS_PAL8 = DDPF_PALETTEINDEXED8

DDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
DDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT
DDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH
DDS_HEADER_FLAGS_PITCH = DDSD_PITCH
DDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE

DDS_HEIGHT = DDSD_HEIGHT
DDS_WIDTH = DDSD_WIDTH

DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE
DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX

DDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
DDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
DDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
DDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
DDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ


# DXT1
DXT1_FOURCC = 0x31545844

# DXT3
DXT3_FOURCC = 0x33545844

# DXT5
DXT5_FOURCC = 0x35545844


# dxgiformat.h

DXGI_FORMAT_R8G8B8A8_TYPELESS = 27
DXGI_FORMAT_R8G8B8A8_UNORM = 28
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29
DXGI_FORMAT_BC5_TYPELESS = 82
DXGI_FORMAT_BC5_UNORM = 83
DXGI_FORMAT_BC5_SNORM = 84
DXGI_FORMAT_BC7_TYPELESS = 97
DXGI_FORMAT_BC7_UNORM = 98
DXGI_FORMAT_BC7_UNORM_SRGB = 99


class DdsImageFile(ImageFile.ImageFile):
    format = "DDS"
    format_description = "DirectDraw Surface"

    def _open(self):
        magic, header_size = struct.unpack("<II", self.fp.read(8))
        if header_size != 124:
            raise OSError(f"Unsupported header size {repr(header_size)}")
        header_bytes = self.fp.read(header_size - 4)
        if len(header_bytes) != 120:
            raise OSError(f"Incomplete header: {len(header_bytes)} bytes")
        header = BytesIO(header_bytes)

        flags, height, width = struct.unpack("<3I", header.read(12))
        self._size = (width, height)
        self.mode = "RGBA"

        pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
        struct.unpack("<11I", header.read(44))  # reserved

        # pixel format
        pfsize, pfflags = struct.unpack("<2I", header.read(8))
        fourcc = header.read(4)
        (bitcount,) = struct.unpack("<I", header.read(4))
        masks = struct.unpack("<4I", header.read(16))
        if pfflags & DDPF_RGB:
            # Texture contains uncompressed RGB data
            masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
            rawmode = ""
            if bitcount == 32:
                rawmode += masks[0xFF000000]
            else:
                self.mode = "RGB"
            rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]

            self.tile = [("raw", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]
        else:
            data_start = header_size + 4
            n = 0
            if fourcc == b"DXT1":
                self.pixel_format = "DXT1"
                n = 1
            elif fourcc == b"DXT3":
                self.pixel_format = "DXT3"
                n = 2
            elif fourcc == b"DXT5":
                self.pixel_format = "DXT5"
                n = 3
            elif fourcc == b"BC5S":
                self.pixel_format = "BC5S"
                n = 5
                self.mode = "RGB"
            elif fourcc == b"DX10":
                data_start += 20
                # ignoring flags which pertain to volume textures and cubemaps
                (dxgi_format,) = struct.unpack("<I", self.fp.read(4))
                self.fp.read(16)
                if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):
                    self.pixel_format = "BC5"
                    n = 5
                    self.mode = "RGB"
                elif dxgi_format == DXGI_FORMAT_BC5_SNORM:
                    self.pixel_format = "BC5S"
                    n = 5
                    self.mode = "RGB"
                elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
                    self.pixel_format = "BC7"
                    n = 7
                elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:
                    self.pixel_format = "BC7"
                    self.info["gamma"] = 1 / 2.2
                    n = 7
                elif dxgi_format in (
                    DXGI_FORMAT_R8G8B8A8_TYPELESS,
                    DXGI_FORMAT_R8G8B8A8_UNORM,
                    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
                ):
                    self.tile = [("raw", (0, 0) + self.size, 0, ("RGBA", 0, 1))]
                    if dxgi_format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
                        self.info["gamma"] = 1 / 2.2
                    return
                else:
                    raise NotImplementedError(
                        f"Unimplemented DXGI format {dxgi_format}"
                    )
            else:
                raise NotImplementedError(f"Unimplemented pixel format {repr(fourcc)}")

            self.tile = [
                ("bcn", (0, 0) + self.size, data_start, (n, self.pixel_format))
            ]

    def load_seek(self, pos):
        pass


def _save(im, fp, filename):
    if im.mode != "RGB":
        raise OSError(f"cannot write mode {im.mode} as DDS")

    fp.write(
        o32(DDS_MAGIC)
        + o32(124)  # header size
        + o32(
            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT
        )  # flags
        + o32(im.height)
        + o32(im.width)
        + o32((im.width * 24 + 7) // 8)  # pitch
        + o32(0)  # depth
        + o32(0)  # mipmaps
        + o32(0) * 11  # reserved
        + o32(32)  # pfsize
        + o32(DDPF_RGB)  # pfflags
        + o32(0)  # fourcc
        + o32(24)  # bitcount
        + o32(0xFF0000)  # rbitmask
        + o32(0xFF00)  # gbitmask
        + o32(0xFF)  # bbitmask
        + o32(0)  # abitmask
        + o32(DDSCAPS_TEXTURE)  # dwCaps
        + o32(0)  # dwCaps2
        + o32(0)  # dwCaps3
        + o32(0)  # dwCaps4
        + o32(0)  # dwReserved2
    )
    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])


def _accept(prefix):
    return prefix[:4] == b"DDS "


Image.register_open(DdsImageFile.format, DdsImageFile, _accept)
Image.register_save(DdsImageFile.format, _save)
Image.register_extension(DdsImageFile.format, ".dds")

```
--- 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:** Unable to Save RGBA Images as DDS Format

**Description:**
When attempting to save an image with RGBA mode to the DDS format, an `OSError` is raised, indicating that the mode is unsupported. This issue prevents users from saving images with transparency in the DDS format.

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

# Open an RGBA image
with Image.open("Tests/images/pil123rgba.png") as im:
    # Attempt to save as DDS
    im.save("output.dds")
```

**Expected Behavior:**
The image with RGBA mode should be successfully saved in the DDS format without any errors, preserving the alpha channel for transparency.

**Actual Behavior:**
An `OSError` is raised with the message:
```
OSError: cannot write mode RGBA as DDS
```
This error occurs because the DDS plugin does not recognize the RGBA mode as a valid format for saving.

[/ISSUE]
{
    "\u001b[1mtest_sanity_dxt1\u001b[0m": "PASSED",
    "\u001b[1mtest_sanity_dxt3\u001b[0m": "PASSED",
    "\u001b[1mtest_sanity_dxt5\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_bc5[Tests/images/bc5_typeless.dds-Tests/images/bc5_unorm.dds]\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_bc5[Tests/images/bc5_unorm.dds-Tests/images/bc5_unorm.dds]\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_bc5[Tests/images/bc5_snorm.dds-Tests/images/bc5s.dds]\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_bc5[Tests/images/bc5s.dds-Tests/images/bc5s.dds]\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_bc7\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_bc7_unorm_srgb\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_r8g8b8a8\u001b[0m": "PASSED",
    "\u001b[1mtest_dx10_r8g8b8a8_unorm_srgb\u001b[0m": "PASSED",
    "\u001b[1mtest_unimplemented_dxgi_format\u001b[0m": "PASSED",
    "\u001b[1mtest_uncompressed_rgb\u001b[0m": "PASSED",
    "\u001b[1mtest__accept_true\u001b[0m": "PASSED",
    "\u001b[1mtest__accept_false\u001b[0m": "PASSED",
    "\u001b[1mtest_short_header\u001b[0m": "PASSED",
    "\u001b[1mtest_short_file\u001b[0m": "PASSED",
    "\u001b[1mtest_dxt5_colorblock_alpha_issue_4142\u001b[0m": "PASSED",
    "\u001b[1mtest_unimplemented_pixel_format\u001b[0m": "PASSED",
    "\u001b[1mtest_save_unsupported_mode\u001b[0m": "PASSED",
    "\u001b[1mtest_save[RGB-Tests/images/hopper.png]\u001b[0m": "PASSED",
    "\u001b[1mtest_save[RGBA-Tests/images/pil123rgba.png]\u001b[0m": "PASSED"
}
diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py
index e8a41c045..260924fca 100644
--- a/src/PIL/DdsImagePlugin.py
+++ b/src/PIL/DdsImagePlugin.py
@@ -203,7 +203,7 @@ class DdsImageFile(ImageFile.ImageFile):
 
 
 def _save(im, fp, filename):
-    if im.mode != "RGB":
+    if im.mode not in ("RGB", "RGBA"):
         raise OSError(f"cannot write mode {im.mode} as DDS")
 
     fp.write(
@@ -214,24 +214,27 @@ def _save(im, fp, filename):
         )  # flags
         + o32(im.height)
         + o32(im.width)
-        + o32((im.width * 24 + 7) // 8)  # pitch
+        + o32((im.width * (32 if im.mode == "RGBA" else 24) + 7) // 8)  # pitch
         + o32(0)  # depth
         + o32(0)  # mipmaps
         + o32(0) * 11  # reserved
         + o32(32)  # pfsize
-        + o32(DDPF_RGB)  # pfflags
+        + o32(DDS_RGBA if im.mode == "RGBA" else DDPF_RGB)  # pfflags
         + o32(0)  # fourcc
-        + o32(24)  # bitcount
+        + o32(32 if im.mode == "RGBA" else 24)  # bitcount
         + o32(0xFF0000)  # rbitmask
         + o32(0xFF00)  # gbitmask
         + o32(0xFF)  # bbitmask
-        + o32(0)  # abitmask
+        + o32(0xFF000000 if im.mode == "RGBA" else 0)  # abitmask
         + o32(DDSCAPS_TEXTURE)  # dwCaps
         + o32(0)  # dwCaps2
         + o32(0)  # dwCaps3
         + o32(0)  # dwCaps4
         + o32(0)  # dwReserved2
     )
+    if im.mode == "RGBA":
+        r, g, b, a = im.split()
+        im = Image.merge("RGBA", (a, r, g, b))
     ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])
 
 
 

{"src/PIL/DdsImagePlugin.py": "\"\"\"\nA Pillow loader for .dds files (S3TC-compressed aka DXTC)\nJerome Leclanche <jerome@leclan.ch>\n\nDocumentation:\n  https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt\n\nThe contents of this file are hereby released in the public domain (CC0)\nFull text of the CC0 license:\n  https://creativecommons.org/publicdomain/zero/1.0/\n\"\"\"\n\nimport struct\nfrom io import BytesIO\n\nfrom . import Image, ImageFile\nfrom ._binary import o32le as o32\n\n# Magic (\"DDS \")\nDDS_MAGIC = 0x20534444\n\n# DDS flags\nDDSD_CAPS = 0x1\nDDSD_HEIGHT = 0x2\nDDSD_WIDTH = 0x4\nDDSD_PITCH = 0x8\nDDSD_PIXELFORMAT = 0x1000\nDDSD_MIPMAPCOUNT = 0x20000\nDDSD_LINEARSIZE = 0x80000\nDDSD_DEPTH = 0x800000\n\n# DDS caps\nDDSCAPS_COMPLEX = 0x8\nDDSCAPS_TEXTURE = 0x1000\nDDSCAPS_MIPMAP = 0x400000\n\nDDSCAPS2_CUBEMAP = 0x200\nDDSCAPS2_CUBEMAP_POSITIVEX = 0x400\nDDSCAPS2_CUBEMAP_NEGATIVEX = 0x800\nDDSCAPS2_CUBEMAP_POSITIVEY = 0x1000\nDDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000\nDDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000\nDDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000\nDDSCAPS2_VOLUME = 0x200000\n\n# Pixel Format\nDDPF_ALPHAPIXELS = 0x1\nDDPF_ALPHA = 0x2\nDDPF_FOURCC = 0x4\nDDPF_PALETTEINDEXED8 = 0x20\nDDPF_RGB = 0x40\nDDPF_LUMINANCE = 0x20000\n\n\n# dds.h\n\nDDS_FOURCC = DDPF_FOURCC\nDDS_RGB = DDPF_RGB\nDDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS\nDDS_LUMINANCE = DDPF_LUMINANCE\nDDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS\nDDS_ALPHA = DDPF_ALPHA\nDDS_PAL8 = DDPF_PALETTEINDEXED8\n\nDDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT\nDDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT\nDDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH\nDDS_HEADER_FLAGS_PITCH = DDSD_PITCH\nDDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE\n\nDDS_HEIGHT = DDSD_HEIGHT\nDDS_WIDTH = DDSD_WIDTH\n\nDDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE\nDDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\nDDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX\n\nDDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\nDDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\nDDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\nDDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\nDDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\nDDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n\n# DXT1\nDXT1_FOURCC = 0x31545844\n\n# DXT3\nDXT3_FOURCC = 0x33545844\n\n# DXT5\nDXT5_FOURCC = 0x35545844\n\n\n# dxgiformat.h\n\nDXGI_FORMAT_R8G8B8A8_TYPELESS = 27\nDXGI_FORMAT_R8G8B8A8_UNORM = 28\nDXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29\nDXGI_FORMAT_BC5_TYPELESS = 82\nDXGI_FORMAT_BC5_UNORM = 83\nDXGI_FORMAT_BC5_SNORM = 84\nDXGI_FORMAT_BC7_TYPELESS = 97\nDXGI_FORMAT_BC7_UNORM = 98\nDXGI_FORMAT_BC7_UNORM_SRGB = 99\n\n\nclass DdsImageFile(ImageFile.ImageFile):\n    format = \"DDS\"\n    format_description = \"DirectDraw Surface\"\n\n    def _open(self):\n        magic, header_size = struct.unpack(\"<II\", self.fp.read(8))\n        if header_size != 124:\n            raise OSError(f\"Unsupported header size {repr(header_size)}\")\n        header_bytes = self.fp.read(header_size - 4)\n        if len(header_bytes) != 120:\n            raise OSError(f\"Incomplete header: {len(header_bytes)} bytes\")\n        header = BytesIO(header_bytes)\n\n        flags, height, width = struct.unpack(\"<3I\", header.read(12))\n        self._size = (width, height)\n        self.mode = \"RGBA\"\n\n        pitch, depth, mipmaps = struct.unpack(\"<3I\", header.read(12))\n        struct.unpack(\"<11I\", header.read(44))  # reserved\n\n        # pixel format\n        pfsize, pfflags = struct.unpack(\"<2I\", header.read(8))\n        fourcc = header.read(4)\n        (bitcount,) = struct.unpack(\"<I\", header.read(4))\n        masks = struct.unpack(\"<4I\", header.read(16))\n        if pfflags & DDPF_RGB:\n            # Texture contains uncompressed RGB data\n            masks = {mask: [\"R\", \"G\", \"B\", \"A\"][i] for i, mask in enumerate(masks)}\n            rawmode = \"\"\n            if bitcount == 32:\n                rawmode += masks[0xFF000000]\n            else:\n                self.mode = \"RGB\"\n            rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]\n\n            self.tile = [(\"raw\", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]\n        else:\n            data_start = header_size + 4\n            n = 0\n            if fourcc == b\"DXT1\":\n                self.pixel_format = \"DXT1\"\n                n = 1\n            elif fourcc == b\"DXT3\":\n                self.pixel_format = \"DXT3\"\n                n = 2\n            elif fourcc == b\"DXT5\":\n                self.pixel_format = \"DXT5\"\n                n = 3\n            elif fourcc == b\"BC5S\":\n                self.pixel_format = \"BC5S\"\n                n = 5\n                self.mode = \"RGB\"\n            elif fourcc == b\"DX10\":\n                data_start += 20\n                # ignoring flags which pertain to volume textures and cubemaps\n                (dxgi_format,) = struct.unpack(\"<I\", self.fp.read(4))\n                self.fp.read(16)\n                if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):\n                    self.pixel_format = \"BC5\"\n                    n = 5\n                    self.mode = \"RGB\"\n                elif dxgi_format == DXGI_FORMAT_BC5_SNORM:\n                    self.pixel_format = \"BC5S\"\n                    n = 5\n                    self.mode = \"RGB\"\n                elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):\n                    self.pixel_format = \"BC7\"\n                    n = 7\n                elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:\n                    self.pixel_format = \"BC7\"\n                    self.info[\"gamma\"] = 1 / 2.2\n                    n = 7\n                elif dxgi_format in (\n                    DXGI_FORMAT_R8G8B8A8_TYPELESS,\n                    DXGI_FORMAT_R8G8B8A8_UNORM,\n                    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,\n                ):\n                    self.tile = [(\"raw\", (0, 0) + self.size, 0, (\"RGBA\", 0, 1))]\n                    if dxgi_format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n                        self.info[\"gamma\"] = 1 / 2.2\n                    return\n                else:\n                    raise NotImplementedError(\n                        f\"Unimplemented DXGI format {dxgi_format}\"\n                    )\n            else:\n                raise NotImplementedError(f\"Unimplemented pixel format {repr(fourcc)}\")\n\n            self.tile = [\n                (\"bcn\", (0, 0) + self.size, data_start, (n, self.pixel_format))\n            ]\n\n    def load_seek(self, pos):\n        pass\n\n\ndef _save(im, fp, filename):\n    if im.mode != \"RGB\":\n        raise OSError(f\"cannot write mode {im.mode} as DDS\")\n\n    fp.write(\n        o32(DDS_MAGIC)\n        + o32(124)  # header size\n        + o32(\n            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT\n        )  # flags\n        + o32(im.height)\n        + o32(im.width)\n        + o32((im.width * 24 + 7) // 8)  # pitch\n        + o32(0)  # depth\n        + o32(0)  # mipmaps\n        + o32(0) * 11  # reserved\n        + o32(32)  # pfsize\n        + o32(DDPF_RGB)  # pfflags\n        + o32(0)  # fourcc\n        + o32(24)  # bitcount\n        + o32(0xFF0000)  # rbitmask\n        + o32(0xFF00)  # gbitmask\n        + o32(0xFF)  # bbitmask\n        + o32(0)  # abitmask\n        + o32(DDSCAPS_TEXTURE)  # dwCaps\n        + o32(0)  # dwCaps2\n        + o32(0)  # dwCaps3\n        + o32(0)  # dwCaps4\n        + o32(0)  # dwReserved2\n    )\n    ImageFile._save(im, fp, [(\"raw\", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])\n\n\ndef _accept(prefix):\n    return prefix[:4] == b\"DDS \"\n\n\nImage.register_open(DdsImageFile.format, DdsImageFile, _accept)\nImage.register_save(DdsImageFile.format, _save)\nImage.register_extension(DdsImageFile.format, \".dds\")\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:** Unable to Save RGBA Images as DDS Format

**Description:**
When attempting to save an image with RGBA mode to the DDS format, an `OSError` is raised, indicating that the mode is unsupported. This issue prevents users from saving images with transparency in the DDS format.

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

# Open an RGBA image
with Image.open("Tests/images/pil123rgba.png") as im:
    # Attempt to save as DDS
    im.save("output.dds")
```

**Expected Behavior:**
The image with RGBA mode should be successfully saved in the DDS format without any errors, preserving the alpha channel for transparency.

**Actual Behavior:**
An `OSError` is raised with the message:
```
OSError: cannot write mode RGBA as DDS
```
This error occurs because the DDS plugin does not recognize the RGBA mode as a valid format for saving.

[/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/DdsImagePlugin.py
"""
A Pillow loader for .dds files (S3TC-compressed aka DXTC)
Jerome Leclanche <jerome@leclan.ch>

Documentation:
  https://web.archive.org/web/20170802060935/http://oss.sgi.com/projects/ogl-sample/registry/EXT/texture_compression_s3tc.txt

The contents of this file are hereby released in the public domain (CC0)
Full text of the CC0 license:
  https://creativecommons.org/publicdomain/zero/1.0/
"""

import struct
from io import BytesIO

from . import Image, ImageFile
from ._binary import o32le as o32

# Magic ("DDS ")
DDS_MAGIC = 0x20534444

# DDS flags
DDSD_CAPS = 0x1
DDSD_HEIGHT = 0x2
DDSD_WIDTH = 0x4
DDSD_PITCH = 0x8
DDSD_PIXELFORMAT = 0x1000
DDSD_MIPMAPCOUNT = 0x20000
DDSD_LINEARSIZE = 0x80000
DDSD_DEPTH = 0x800000

# DDS caps
DDSCAPS_COMPLEX = 0x8
DDSCAPS_TEXTURE = 0x1000
DDSCAPS_MIPMAP = 0x400000

DDSCAPS2_CUBEMAP = 0x200
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000
DDSCAPS2_VOLUME = 0x200000

# Pixel Format
DDPF_ALPHAPIXELS = 0x1
DDPF_ALPHA = 0x2
DDPF_FOURCC = 0x4
DDPF_PALETTEINDEXED8 = 0x20
DDPF_RGB = 0x40
DDPF_LUMINANCE = 0x20000


# dds.h

DDS_FOURCC = DDPF_FOURCC
DDS_RGB = DDPF_RGB
DDS_RGBA = DDPF_RGB | DDPF_ALPHAPIXELS
DDS_LUMINANCE = DDPF_LUMINANCE
DDS_LUMINANCEA = DDPF_LUMINANCE | DDPF_ALPHAPIXELS
DDS_ALPHA = DDPF_ALPHA
DDS_PAL8 = DDPF_PALETTEINDEXED8

DDS_HEADER_FLAGS_TEXTURE = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
DDS_HEADER_FLAGS_MIPMAP = DDSD_MIPMAPCOUNT
DDS_HEADER_FLAGS_VOLUME = DDSD_DEPTH
DDS_HEADER_FLAGS_PITCH = DDSD_PITCH
DDS_HEADER_FLAGS_LINEARSIZE = DDSD_LINEARSIZE

DDS_HEIGHT = DDSD_HEIGHT
DDS_WIDTH = DDSD_WIDTH

DDS_SURFACE_FLAGS_TEXTURE = DDSCAPS_TEXTURE
DDS_SURFACE_FLAGS_MIPMAP = DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
DDS_SURFACE_FLAGS_CUBEMAP = DDSCAPS_COMPLEX

DDS_CUBEMAP_POSITIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
DDS_CUBEMAP_NEGATIVEX = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
DDS_CUBEMAP_POSITIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
DDS_CUBEMAP_NEGATIVEY = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
DDS_CUBEMAP_POSITIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
DDS_CUBEMAP_NEGATIVEZ = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ


# DXT1
DXT1_FOURCC = 0x31545844

# DXT3
DXT3_FOURCC = 0x33545844

# DXT5
DXT5_FOURCC = 0x35545844


# dxgiformat.h

DXGI_FORMAT_R8G8B8A8_TYPELESS = 27
DXGI_FORMAT_R8G8B8A8_UNORM = 28
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29
DXGI_FORMAT_BC5_TYPELESS = 82
DXGI_FORMAT_BC5_UNORM = 83
DXGI_FORMAT_BC5_SNORM = 84
DXGI_FORMAT_BC7_TYPELESS = 97
DXGI_FORMAT_BC7_UNORM = 98
DXGI_FORMAT_BC7_UNORM_SRGB = 99


class DdsImageFile(ImageFile.ImageFile):
    format = "DDS"
    format_description = "DirectDraw Surface"

    def _open(self):
        magic, header_size = struct.unpack("<II", self.fp.read(8))
        if header_size != 124:
            raise OSError(f"Unsupported header size {repr(header_size)}")
        header_bytes = self.fp.read(header_size - 4)
        if len(header_bytes) != 120:
            raise OSError(f"Incomplete header: {len(header_bytes)} bytes")
        header = BytesIO(header_bytes)

        flags, height, width = struct.unpack("<3I", header.read(12))
        self._size = (width, height)
        self.mode = "RGBA"

        pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
        struct.unpack("<11I", header.read(44))  # reserved

        # pixel format
        pfsize, pfflags = struct.unpack("<2I", header.read(8))
        fourcc = header.read(4)
        (bitcount,) = struct.unpack("<I", header.read(4))
        masks = struct.unpack("<4I", header.read(16))
        if pfflags & DDPF_RGB:
            # Texture contains uncompressed RGB data
            masks = {mask: ["R", "G", "B", "A"][i] for i, mask in enumerate(masks)}
            rawmode = ""
            if bitcount == 32:
                rawmode += masks[0xFF000000]
            else:
                self.mode = "RGB"
            rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]

            self.tile = [("raw", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]
        else:
            data_start = header_size + 4
            n = 0
            if fourcc == b"DXT1":
                self.pixel_format = "DXT1"
                n = 1
            elif fourcc == b"DXT3":
                self.pixel_format = "DXT3"
                n = 2
            elif fourcc == b"DXT5":
                self.pixel_format = "DXT5"
                n = 3
            elif fourcc == b"BC5S":
                self.pixel_format = "BC5S"
                n = 5
                self.mode = "RGB"
            elif fourcc == b"DX10":
                data_start += 20
                # ignoring flags which pertain to volume textures and cubemaps
                (dxgi_format,) = struct.unpack("<I", self.fp.read(4))
                self.fp.read(16)
                if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):
                    self.pixel_format = "BC5"
                    n = 5
                    self.mode = "RGB"
                elif dxgi_format == DXGI_FORMAT_BC5_SNORM:
                    self.pixel_format = "BC5S"
                    n = 5
                    self.mode = "RGB"
                elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
                    self.pixel_format = "BC7"
                    n = 7
                elif dxgi_format == DXGI_FORMAT_BC7_UNORM_SRGB:
                    self.pixel_format = "BC7"
                    self.info["gamma"] = 1 / 2.2
                    n = 7
                elif dxgi_format in (
                    DXGI_FORMAT_R8G8B8A8_TYPELESS,
                    DXGI_FORMAT_R8G8B8A8_UNORM,
                    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
                ):
                    self.tile = [("raw", (0, 0) + self.size, 0, ("RGBA", 0, 1))]
                    if dxgi_format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
                        self.info["gamma"] = 1 / 2.2
                    return
                else:
                    raise NotImplementedError(
                        f"Unimplemented DXGI format {dxgi_format}"
                    )
            else:
                raise NotImplementedError(f"Unimplemented pixel format {repr(fourcc)}")

            self.tile = [
                ("bcn", (0, 0) + self.size, data_start, (n, self.pixel_format))
            ]

    def load_seek(self, pos):
        pass


def _save(im, fp, filename):
    if im.mode != "RGB":
        raise OSError(f"cannot write mode {im.mode} as DDS")

    fp.write(
        o32(DDS_MAGIC)
        + o32(124)  # header size
        + o32(
            DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT
        )  # flags
        + o32(im.height)
        + o32(im.width)
        + o32((im.width * 24 + 7) // 8)  # pitch
        + o32(0)  # depth
        + o32(0)  # mipmaps
        + o32(0) * 11  # reserved
        + o32(32)  # pfsize
        + o32(DDPF_RGB)  # pfflags
        + o32(0)  # fourcc
        + o32(24)  # bitcount
        + o32(0xFF0000)  # rbitmask
        + o32(0xFF00)  # gbitmask
        + o32(0xFF)  # bbitmask
        + o32(0)  # abitmask
        + o32(DDSCAPS_TEXTURE)  # dwCaps
        + o32(0)  # dwCaps2
        + o32(0)  # dwCaps3
        + o32(0)  # dwCaps4
        + o32(0)  # dwReserved2
    )
    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (im.mode[::-1], 0, 1))])


def _accept(prefix):
    return prefix[:4] == b"DDS "


Image.register_open(DdsImageFile.format, DdsImageFile, _accept)
Image.register_save(DdsImageFile.format, _save)
Image.register_extension(DdsImageFile.format, ".dds")

```
--- 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