{
    "file_diffs": [
        {
            "old_file_content": "from __future__ import annotations\n\nfrom pathlib import Path\nfrom typing import IO\n\nimport pytest\n\nfrom PIL import Image, ImageFile, WmfImagePlugin\n\nfrom .helper import assert_image_similar_tofile, hopper\n\n\ndef test_load_raw() -> None:\n    # Test basic EMF open and rendering\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            # Currently, support for WMF/EMF is Windows-only\n            im.load()\n            # Compare to reference rendering\n            assert_image_similar_tofile(im, \"Tests/images/drawing_emf_ref.png\", 0)\n\n    # Test basic WMF open and rendering\n    with Image.open(\"Tests/images/drawing.wmf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            # Currently, support for WMF/EMF is Windows-only\n            im.load()\n            # Compare to reference rendering\n            assert_image_similar_tofile(im, \"Tests/images/drawing_wmf_ref.png\", 2.0)\n\n\ndef test_load() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            assert im.load()[0, 0] == (255, 255, 255)\n\n\ndef test_register_handler(tmp_path: Path) -> None:\n    class TestHandler(ImageFile.StubHandler):\n        methodCalled = False\n\n        def load(self, im: ImageFile.StubImageFile) -> Image.Image:\n            return Image.new(\"RGB\", (1, 1))\n\n        def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:\n            self.methodCalled = True\n\n    handler = TestHandler()\n    original_handler = WmfImagePlugin._handler\n    WmfImagePlugin.register_handler(handler)\n\n    im = hopper()\n    tmpfile = str(tmp_path / \"temp.wmf\")\n    im.save(tmpfile)\n    assert handler.methodCalled\n\n    # Restore the state before this test\n    WmfImagePlugin.register_handler(original_handler)\n\n\ndef test_load_float_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        assert im.info[\"dpi\"] == 1423.7668161434979\n\n\ndef test_load_set_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.wmf\") as im:\n        assert im.size == (82, 82)\n\n        if hasattr(Image.core, \"drawwmf\"):\n            im.load(144)\n            assert im.size == (164, 164)\n\n            assert_image_similar_tofile(im, \"Tests/images/drawing_wmf_ref_144.png\", 2.1)\n\n\n@pytest.mark.parametrize(\"ext\", (\".wmf\", \".emf\"))\ndef test_save(ext: str, tmp_path: Path) -> None:\n    im = hopper()\n\n    tmpfile = str(tmp_path / (\"temp\" + ext))\n    with pytest.raises(OSError):\n        im.save(tmpfile)\n",
            "new_file_content": "from __future__ import annotations\n\nfrom io import BytesIO\nfrom pathlib import Path\nfrom typing import IO\n\nimport pytest\n\nfrom PIL import Image, ImageFile, WmfImagePlugin\n\nfrom .helper import assert_image_similar_tofile, hopper\n\n\ndef test_load_raw() -> None:\n    # Test basic EMF open and rendering\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            # Currently, support for WMF/EMF is Windows-only\n            im.load()\n            # Compare to reference rendering\n            assert_image_similar_tofile(im, \"Tests/images/drawing_emf_ref.png\", 0)\n\n    # Test basic WMF open and rendering\n    with Image.open(\"Tests/images/drawing.wmf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            # Currently, support for WMF/EMF is Windows-only\n            im.load()\n            # Compare to reference rendering\n            assert_image_similar_tofile(im, \"Tests/images/drawing_wmf_ref.png\", 2.0)\n\n\ndef test_load() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            assert im.load()[0, 0] == (255, 255, 255)\n\n\ndef test_register_handler(tmp_path: Path) -> None:\n    class TestHandler(ImageFile.StubHandler):\n        methodCalled = False\n\n        def load(self, im: ImageFile.StubImageFile) -> Image.Image:\n            return Image.new(\"RGB\", (1, 1))\n\n        def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:\n            self.methodCalled = True\n\n    handler = TestHandler()\n    original_handler = WmfImagePlugin._handler\n    WmfImagePlugin.register_handler(handler)\n\n    im = hopper()\n    tmpfile = str(tmp_path / \"temp.wmf\")\n    im.save(tmpfile)\n    assert handler.methodCalled\n\n    # Restore the state before this test\n    WmfImagePlugin.register_handler(original_handler)\n\n\ndef test_load_float_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        assert im.info[\"dpi\"] == 1423.7668161434979\n\n    with open(\"Tests/images/drawing.emf\", \"rb\") as fp:\n        data = fp.read()\n    b = BytesIO(data[:8] + b\"\\x06\\xFA\" + data[10:])\n    with Image.open(b) as im:\n        assert im.info[\"dpi\"][0] == 2540\n\n\ndef test_load_set_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.wmf\") as im:\n        assert im.size == (82, 82)\n\n        if hasattr(Image.core, \"drawwmf\"):\n            im.load(144)\n            assert im.size == (164, 164)\n\n            assert_image_similar_tofile(im, \"Tests/images/drawing_wmf_ref_144.png\", 2.1)\n\n\n@pytest.mark.parametrize(\"ext\", (\".wmf\", \".emf\"))\ndef test_save(ext: str, tmp_path: Path) -> None:\n    im = hopper()\n\n    tmpfile = str(tmp_path / (\"temp\" + ext))\n    with pytest.raises(OSError):\n        im.save(tmpfile)\n",
            "header": {
                "file": {
                    "path": "Tests/test_file_wmf.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "79e707263",
                "new_commit_hash": "424640d7b",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_file_wmf.py"
            },
            "plus_file": {
                "path": "b/Tests/test_file_wmf.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1,
                            "length": 5
                        },
                        "new_range": {
                            "start": 1,
                            "length": 6
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "from __future__ import annotations",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "from io import BytesIO",
                                "type": "added"
                            },
                            {
                                "content": "from pathlib import Path",
                                "type": "context"
                            },
                            {
                                "content": "from typing import IO",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "Tests/test_file_wmf.py",
                            "type": "statement",
                            "name": "",
                            "content": "from io import BytesIO",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 3,
                            "end_lineno": 3,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 61,
                            "length": 6
                        },
                        "new_range": {
                            "start": 62,
                            "length": 12
                        },
                        "section": "def test_load_float_dpi() -> None:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    with Image.open(\"Tests/images/drawing.emf\") as im:",
                                "type": "context"
                            },
                            {
                                "content": "        assert im.info[\"dpi\"] == 1423.7668161434979",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    with open(\"Tests/images/drawing.emf\", \"rb\") as fp:",
                                "type": "added"
                            },
                            {
                                "content": "        data = fp.read()",
                                "type": "added"
                            },
                            {
                                "content": "    b = BytesIO(data[:8] + b\"\\x06\\xFA\" + data[10:])",
                                "type": "added"
                            },
                            {
                                "content": "    with Image.open(b) as im:",
                                "type": "added"
                            },
                            {
                                "content": "        assert im.info[\"dpi\"][0] == 2540",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_load_set_dpi() -> None:",
                                "type": "context"
                            },
                            {
                                "content": "    with Image.open(\"Tests/images/drawing.wmf\") as im:",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_file_wmf.py",
                            "type": "function",
                            "name": "test_load_float_dpi",
                            "content": "def test_load_float_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        assert im.info[\"dpi\"] == 1423.7668161434979\n\n    with open(\"Tests/images/drawing.emf\", \"rb\") as fp:\n        data = fp.read()\n    b = BytesIO(data[:8] + b\"\\x06\\xFA\" + data[10:])\n    with Image.open(b) as im:\n        assert im.info[\"dpi\"][0] == 2540",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 61,
                            "end_lineno": 69,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#\n# The Python Imaging Library\n# $Id$\n#\n# WMF stub codec\n#\n# history:\n# 1996-12-14 fl   Created\n# 2004-02-22 fl   Turned into a stub driver\n# 2004-02-23 fl   Added EMF support\n#\n# Copyright (c) Secret Labs AB 1997-2004.  All rights reserved.\n# Copyright (c) Fredrik Lundh 1996.\n#\n# See the README file for information on usage and redistribution.\n#\n# WMF/EMF reference documentation:\n# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf\n# http://wvware.sourceforge.net/caolan/index.html\n# http://wvware.sourceforge.net/caolan/ora-wmf.html\nfrom __future__ import annotations\n\nfrom typing import IO\n\nfrom . import Image, ImageFile\nfrom ._binary import i16le as word\nfrom ._binary import si16le as short\nfrom ._binary import si32le as _long\n\n_handler = None\n\n\ndef register_handler(handler: ImageFile.StubHandler | None) -> None:\n    \"\"\"\n    Install application-specific WMF image handler.\n\n    :param handler: Handler object.\n    \"\"\"\n    global _handler\n    _handler = handler\n\n\nif hasattr(Image.core, \"drawwmf\"):\n    # install default handler (windows only)\n\n    class WmfHandler(ImageFile.StubHandler):\n        def open(self, im: ImageFile.StubImageFile) -> None:\n            im._mode = \"RGB\"\n            self.bbox = im.info[\"wmf_bbox\"]\n\n        def load(self, im: ImageFile.StubImageFile) -> Image.Image:\n            im.fp.seek(0)  # rewind\n            return Image.frombytes(\n                \"RGB\",\n                im.size,\n                Image.core.drawwmf(im.fp.read(), im.size, self.bbox),\n                \"raw\",\n                \"BGR\",\n                (im.size[0] * 3 + 3) & -4,\n                -1,\n            )\n\n    register_handler(WmfHandler())\n\n#\n# --------------------------------------------------------------------\n# Read WMF file\n\n\ndef _accept(prefix: bytes) -> bool:\n    return (\n        prefix[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\" or prefix[:4] == b\"\\x01\\x00\\x00\\x00\"\n    )\n\n\n##\n# Image plugin for Windows metafiles.\n\n\nclass WmfStubImageFile(ImageFile.StubImageFile):\n    format = \"WMF\"\n    format_description = \"Windows Metafile\"\n\n    def _open(self) -> None:\n        self._inch = None\n\n        # check placable header\n        s = self.fp.read(80)\n\n        if s[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\":\n            # placeable windows metafile\n\n            # get units per inch\n            self._inch = word(s, 14)\n\n            # get bounding box\n            x0 = short(s, 6)\n            y0 = short(s, 8)\n            x1 = short(s, 10)\n            y1 = short(s, 12)\n\n            # normalize size to 72 dots per inch\n            self.info[\"dpi\"] = 72\n            size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            # sanity check (standard metafile header)\n            if s[22:26] != b\"\\x01\\x00\\t\\x00\":\n                msg = \"Unsupported WMF file format\"\n                raise SyntaxError(msg)\n\n        elif s[:4] == b\"\\x01\\x00\\x00\\x00\" and s[40:44] == b\" EMF\":\n            # enhanced metafile\n\n            # get bounding box\n            x0 = _long(s, 8)\n            y0 = _long(s, 12)\n            x1 = _long(s, 16)\n            y1 = _long(s, 20)\n\n            # get frame (in 0.01 millimeter units)\n            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)\n\n            size = x1 - x0, y1 - y0\n\n            # calculate dots per inch from bbox and frame\n            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])\n            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            if xdpi == ydpi:\n                self.info[\"dpi\"] = xdpi\n            else:\n                self.info[\"dpi\"] = xdpi, ydpi\n\n        else:\n            msg = \"Unsupported file format\"\n            raise SyntaxError(msg)\n\n        self._mode = \"RGB\"\n        self._size = size\n\n        loader = self._load()\n        if loader:\n            loader.open(self)\n\n    def _load(self) -> ImageFile.StubHandler | None:\n        return _handler\n\n    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:\n        if dpi is not None and self._inch is not None:\n            self.info[\"dpi\"] = dpi\n            x0, y0, x1, y1 = self.info[\"wmf_bbox\"]\n            self._size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n        return super().load()\n\n\ndef _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:\n    if _handler is None or not hasattr(_handler, \"save\"):\n        msg = \"WMF save handler not installed\"\n        raise OSError(msg)\n    _handler.save(im, fp, filename)\n\n\n#\n# --------------------------------------------------------------------\n# Registry stuff\n\n\nImage.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)\nImage.register_save(WmfStubImageFile.format, _save)\n\nImage.register_extensions(WmfStubImageFile.format, [\".wmf\", \".emf\"])\n",
            "new_file_content": "#\n# The Python Imaging Library\n# $Id$\n#\n# WMF stub codec\n#\n# history:\n# 1996-12-14 fl   Created\n# 2004-02-22 fl   Turned into a stub driver\n# 2004-02-23 fl   Added EMF support\n#\n# Copyright (c) Secret Labs AB 1997-2004.  All rights reserved.\n# Copyright (c) Fredrik Lundh 1996.\n#\n# See the README file for information on usage and redistribution.\n#\n# WMF/EMF reference documentation:\n# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf\n# http://wvware.sourceforge.net/caolan/index.html\n# http://wvware.sourceforge.net/caolan/ora-wmf.html\nfrom __future__ import annotations\n\nfrom typing import IO\n\nfrom . import Image, ImageFile\nfrom ._binary import i16le as word\nfrom ._binary import si16le as short\nfrom ._binary import si32le as _long\n\n_handler = None\n\n\ndef register_handler(handler: ImageFile.StubHandler | None) -> None:\n    \"\"\"\n    Install application-specific WMF image handler.\n\n    :param handler: Handler object.\n    \"\"\"\n    global _handler\n    _handler = handler\n\n\nif hasattr(Image.core, \"drawwmf\"):\n    # install default handler (windows only)\n\n    class WmfHandler(ImageFile.StubHandler):\n        def open(self, im: ImageFile.StubImageFile) -> None:\n            im._mode = \"RGB\"\n            self.bbox = im.info[\"wmf_bbox\"]\n\n        def load(self, im: ImageFile.StubImageFile) -> Image.Image:\n            im.fp.seek(0)  # rewind\n            return Image.frombytes(\n                \"RGB\",\n                im.size,\n                Image.core.drawwmf(im.fp.read(), im.size, self.bbox),\n                \"raw\",\n                \"BGR\",\n                (im.size[0] * 3 + 3) & -4,\n                -1,\n            )\n\n    register_handler(WmfHandler())\n\n#\n# --------------------------------------------------------------------\n# Read WMF file\n\n\ndef _accept(prefix: bytes) -> bool:\n    return (\n        prefix[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\" or prefix[:4] == b\"\\x01\\x00\\x00\\x00\"\n    )\n\n\n##\n# Image plugin for Windows metafiles.\n\n\nclass WmfStubImageFile(ImageFile.StubImageFile):\n    format = \"WMF\"\n    format_description = \"Windows Metafile\"\n\n    def _open(self) -> None:\n        self._inch = None\n\n        # check placable header\n        s = self.fp.read(80)\n\n        if s[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\":\n            # placeable windows metafile\n\n            # get units per inch\n            self._inch = word(s, 14)\n\n            # get bounding box\n            x0 = short(s, 6)\n            y0 = short(s, 8)\n            x1 = short(s, 10)\n            y1 = short(s, 12)\n\n            # normalize size to 72 dots per inch\n            self.info[\"dpi\"] = 72\n            size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            # sanity check (standard metafile header)\n            if s[22:26] != b\"\\x01\\x00\\t\\x00\":\n                msg = \"Unsupported WMF file format\"\n                raise SyntaxError(msg)\n\n        elif s[:4] == b\"\\x01\\x00\\x00\\x00\" and s[40:44] == b\" EMF\":\n            # enhanced metafile\n\n            # get bounding box\n            x0 = _long(s, 8)\n            y0 = _long(s, 12)\n            x1 = _long(s, 16)\n            y1 = _long(s, 20)\n\n            # get frame (in 0.01 millimeter units)\n            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)\n\n            size = x1 - x0, y1 - y0\n\n            # calculate dots per inch from bbox and frame\n            xdpi = 2540.0 * (x1 - x0) / (frame[2] - frame[0])\n            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            if xdpi == ydpi:\n                self.info[\"dpi\"] = xdpi\n            else:\n                self.info[\"dpi\"] = xdpi, ydpi\n\n        else:\n            msg = \"Unsupported file format\"\n            raise SyntaxError(msg)\n\n        self._mode = \"RGB\"\n        self._size = size\n\n        loader = self._load()\n        if loader:\n            loader.open(self)\n\n    def _load(self) -> ImageFile.StubHandler | None:\n        return _handler\n\n    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:\n        if dpi is not None and self._inch is not None:\n            self.info[\"dpi\"] = dpi\n            x0, y0, x1, y1 = self.info[\"wmf_bbox\"]\n            self._size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n        return super().load()\n\n\ndef _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:\n    if _handler is None or not hasattr(_handler, \"save\"):\n        msg = \"WMF save handler not installed\"\n        raise OSError(msg)\n    _handler.save(im, fp, filename)\n\n\n#\n# --------------------------------------------------------------------\n# Registry stuff\n\n\nImage.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)\nImage.register_save(WmfStubImageFile.format, _save)\n\nImage.register_extensions(WmfStubImageFile.format, [\".wmf\", \".emf\"])\n",
            "header": {
                "file": {
                    "path": "src/PIL/WmfImagePlugin.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "68f8a74f5",
                "new_commit_hash": "cad6c98d5",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/WmfImagePlugin.py"
            },
            "plus_file": {
                "path": "b/src/PIL/WmfImagePlugin.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 128,
                            "length": 7
                        },
                        "new_range": {
                            "start": 128,
                            "length": 7
                        },
                        "section": "class WmfStubImageFile(ImageFile.StubImageFile):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            size = x1 - x0, y1 - y0",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "            # calculate dots per inch from bbox and frame",
                                "type": "context"
                            },
                            {
                                "content": "            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])",
                                "type": "deleted"
                            },
                            {
                                "content": "            xdpi = 2540.0 * (x1 - x0) / (frame[2] - frame[0])",
                                "type": "added"
                            },
                            {
                                "content": "            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "            self.info[\"wmf_bbox\"] = x0, y0, x1, y1",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/WmfImagePlugin.py",
                            "type": "class",
                            "name": "WmfStubImageFile",
                            "content": "class WmfStubImageFile(ImageFile.StubImageFile):\n    format = \"WMF\"\n    format_description = \"Windows Metafile\"\n\n    def _open(self) -> None:\n        self._inch = None\n\n        # check placable header\n        s = self.fp.read(80)\n\n        if s[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\":\n            # placeable windows metafile\n\n            # get units per inch\n            self._inch = word(s, 14)\n\n            # get bounding box\n            x0 = short(s, 6)\n            y0 = short(s, 8)\n            x1 = short(s, 10)\n            y1 = short(s, 12)\n\n            # normalize size to 72 dots per inch\n            self.info[\"dpi\"] = 72\n            size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            # sanity check (standard metafile header)\n            if s[22:26] != b\"\\x01\\x00\\t\\x00\":\n                msg = \"Unsupported WMF file format\"\n                raise SyntaxError(msg)\n\n        elif s[:4] == b\"\\x01\\x00\\x00\\x00\" and s[40:44] == b\" EMF\":\n            # enhanced metafile\n\n            # get bounding box\n            x0 = _long(s, 8)\n            y0 = _long(s, 12)\n            x1 = _long(s, 16)\n            y1 = _long(s, 20)\n\n            # get frame (in 0.01 millimeter units)\n            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)\n\n            size = x1 - x0, y1 - y0\n\n            # calculate dots per inch from bbox and frame\n            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])\n            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            if xdpi == ydpi:\n                self.info[\"dpi\"] = xdpi\n            else:\n                self.info[\"dpi\"] = xdpi, ydpi\n\n        else:\n            msg = \"Unsupported file format\"\n            raise SyntaxError(msg)\n\n        self._mode = \"RGB\"\n        self._size = size\n\n        loader = self._load()\n        if loader:\n            loader.open(self)\n\n    def _load(self) -> ImageFile.StubHandler | None:\n        return _handler\n\n    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:\n        if dpi is not None and self._inch is not None:\n            self.info[\"dpi\"] = dpi\n            x0, y0, x1, y1 = self.info[\"wmf_bbox\"]\n            self._size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n        return super().load()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 80,
                            "end_lineno": 163,
                            "parent": null
                        },
                        {
                            "file_name": "src/PIL/WmfImagePlugin.py",
                            "type": "method",
                            "name": "WmfStubImageFile._open",
                            "content": "class WmfStubImageFile(ImageFile.StubImageFile):\n    format = \"WMF\"\n    format_description = \"Windows Metafile\"\n\n    def _open(self) -> None:\n        self._inch = None\n\n        # check placable header\n        s = self.fp.read(80)\n\n        if s[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\":\n            # placeable windows metafile\n\n            # get units per inch\n            self._inch = word(s, 14)\n\n            # get bounding box\n            x0 = short(s, 6)\n            y0 = short(s, 8)\n            x1 = short(s, 10)\n            y1 = short(s, 12)\n\n            # normalize size to 72 dots per inch\n            self.info[\"dpi\"] = 72\n            size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            # sanity check (standard metafile header)\n            if s[22:26] != b\"\\x01\\x00\\t\\x00\":\n                msg = \"Unsupported WMF file format\"\n                raise SyntaxError(msg)\n\n        elif s[:4] == b\"\\x01\\x00\\x00\\x00\" and s[40:44] == b\" EMF\":\n            # enhanced metafile\n\n            # get bounding box\n            x0 = _long(s, 8)\n            y0 = _long(s, 12)\n            x1 = _long(s, 16)\n            y1 = _long(s, 20)\n\n            # get frame (in 0.01 millimeter units)\n            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)\n\n            size = x1 - x0, y1 - y0\n\n            # calculate dots per inch from bbox and frame\n            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])\n            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            if xdpi == ydpi:\n                self.info[\"dpi\"] = xdpi\n            else:\n                self.info[\"dpi\"] = xdpi, ydpi\n\n        else:\n            msg = \"Unsupported file format\"\n            raise SyntaxError(msg)\n\n        self._mode = \"RGB\"\n        self._size = size\n\n        loader = self._load()\n        if loader:\n            loader.open(self)\n\n    def _load(self) -> ImageFile.StubHandler | None:\n        return _handler\n\n    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:\n        if dpi is not None and self._inch is not None:\n            self.info[\"dpi\"] = dpi\n            x0, y0, x1, y1 = self.info[\"wmf_bbox\"]\n            self._size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n        return super().load()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 84,
                            "end_lineno": 150,
                            "parent": {
                                "file_name": "src/PIL/WmfImagePlugin.py",
                                "type": "class",
                                "name": "WmfStubImageFile",
                                "content": "class WmfStubImageFile(ImageFile.StubImageFile):\n    format = \"WMF\"\n    format_description = \"Windows Metafile\"\n\n    def _open(self) -> None:\n        self._inch = None\n\n        # check placable header\n        s = self.fp.read(80)\n\n        if s[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\":\n            # placeable windows metafile\n\n            # get units per inch\n            self._inch = word(s, 14)\n\n            # get bounding box\n            x0 = short(s, 6)\n            y0 = short(s, 8)\n            x1 = short(s, 10)\n            y1 = short(s, 12)\n\n            # normalize size to 72 dots per inch\n            self.info[\"dpi\"] = 72\n            size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            # sanity check (standard metafile header)\n            if s[22:26] != b\"\\x01\\x00\\t\\x00\":\n                msg = \"Unsupported WMF file format\"\n                raise SyntaxError(msg)\n\n        elif s[:4] == b\"\\x01\\x00\\x00\\x00\" and s[40:44] == b\" EMF\":\n            # enhanced metafile\n\n            # get bounding box\n            x0 = _long(s, 8)\n            y0 = _long(s, 12)\n            x1 = _long(s, 16)\n            y1 = _long(s, 20)\n\n            # get frame (in 0.01 millimeter units)\n            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)\n\n            size = x1 - x0, y1 - y0\n\n            # calculate dots per inch from bbox and frame\n            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])\n            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            if xdpi == ydpi:\n                self.info[\"dpi\"] = xdpi\n            else:\n                self.info[\"dpi\"] = xdpi, ydpi\n\n        else:\n            msg = \"Unsupported file format\"\n            raise SyntaxError(msg)\n\n        self._mode = \"RGB\"\n        self._size = size\n\n        loader = self._load()\n        if loader:\n            loader.open(self)\n\n    def _load(self) -> ImageFile.StubHandler | None:\n        return _handler\n\n    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:\n        if dpi is not None and self._inch is not None:\n            self.info[\"dpi\"] = dpi\n            x0, y0, x1, y1 = self.info[\"wmf_bbox\"]\n            self._size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n        return super().load()",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 80,
                                "end_lineno": 163,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "55579084cd57461517dfe77d7804dfa24219a9f6^",
    "new_commit_hash": "55579084cd57461517dfe77d7804dfa24219a9f6",
    "commit_message": "Corrected EMF DPI",
    "commit_date": "2024-10-19T20:40:13+11:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "55579084cd57461517dfe77d7804dfa24219a9f6",
    "test_file_codes": [
        "from __future__ import annotations\n\nfrom io import BytesIO\nfrom pathlib import Path\nfrom typing import IO\n\nimport pytest\n\nfrom PIL import Image, ImageFile, WmfImagePlugin\n\nfrom .helper import assert_image_similar_tofile, hopper\n\n\ndef test_load_raw() -> None:\n    # Test basic EMF open and rendering\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            # Currently, support for WMF/EMF is Windows-only\n            im.load()\n            # Compare to reference rendering\n            assert_image_similar_tofile(im, \"Tests/images/drawing_emf_ref.png\", 0)\n\n    # Test basic WMF open and rendering\n    with Image.open(\"Tests/images/drawing.wmf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            # Currently, support for WMF/EMF is Windows-only\n            im.load()\n            # Compare to reference rendering\n            assert_image_similar_tofile(im, \"Tests/images/drawing_wmf_ref.png\", 2.0)\n\n\ndef test_load() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        if hasattr(Image.core, \"drawwmf\"):\n            assert im.load()[0, 0] == (255, 255, 255)\n\n\ndef test_register_handler(tmp_path: Path) -> None:\n    class TestHandler(ImageFile.StubHandler):\n        methodCalled = False\n\n        def load(self, im: ImageFile.StubImageFile) -> Image.Image:\n            return Image.new(\"RGB\", (1, 1))\n\n        def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:\n            self.methodCalled = True\n\n    handler = TestHandler()\n    original_handler = WmfImagePlugin._handler\n    WmfImagePlugin.register_handler(handler)\n\n    im = hopper()\n    tmpfile = str(tmp_path / \"temp.wmf\")\n    im.save(tmpfile)\n    assert handler.methodCalled\n\n    # Restore the state before this test\n    WmfImagePlugin.register_handler(original_handler)\n\n\ndef test_load_float_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.emf\") as im:\n        assert im.info[\"dpi\"] == 1423.7668161434979\n\n    with open(\"Tests/images/drawing.emf\", \"rb\") as fp:\n        data = fp.read()\n    b = BytesIO(data[:8] + b\"\\x06\\xFA\" + data[10:])\n    with Image.open(b) as im:\n        assert im.info[\"dpi\"][0] == 2540\n\n\ndef test_load_set_dpi() -> None:\n    with Image.open(\"Tests/images/drawing.wmf\") as im:\n        assert im.size == (82, 82)\n\n        if hasattr(Image.core, \"drawwmf\"):\n            im.load(144)\n            assert im.size == (164, 164)\n\n            assert_image_similar_tofile(im, \"Tests/images/drawing_wmf_ref_144.png\", 2.1)\n\n\n@pytest.mark.parametrize(\"ext\", (\".wmf\", \".emf\"))\ndef test_save(ext: str, tmp_path: Path) -> None:\n    im = hopper()\n\n    tmpfile = str(tmp_path / (\"temp\" + ext))\n    with pytest.raises(OSError):\n        im.save(tmpfile)\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": "warning: `VIRTUAL_ENV=/home/gcpuser/r2e-edits-internal/.venv` does not match the project environment path `.venv` and will be ignored\nUsing CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 12 packages in 20ms\nInstalled 12 packages in 70ms\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 1.18s\nPrepared 1 package in 33.46s\nInstalled 1 package in 1ms\n + pillow==11.1.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_55579084cd57461517dfe77d7804dfa24219a9f6)\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_55579084cd57461517dfe77d7804dfa24219a9f6\nconfigfile: pyproject.toml\nplugins: cov-6.0.0\ncollected 7 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                                              [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_load_raw\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_register_handler\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load_float_dpi\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load_set_dpi\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[.wmf]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[.emf]\u001b[0m\n\u001b[32m============================== \u001b[32m\u001b[1m7 passed\u001b[0m\u001b[32m in 0.12s\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_55579084cd57461517dfe77d7804dfa24219a9f6\nconfigfile: pyproject.toml\nplugins: cov-6.0.0\ncollected 7 items\n\nr2e_tests/test_1.py \u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31m                                              [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m_____________________________ test_load_float_dpi ______________________________\u001b[0m\n\n    def test_load_float_dpi() -> None:\n        with Image.open(\"Tests/images/drawing.emf\") as im:\n            assert im.info[\"dpi\"] == 1423.7668161434979\n    \n        with open(\"Tests/images/drawing.emf\", \"rb\") as fp:\n            data = fp.read()\n        b = BytesIO(data[:8] + b\"\\x06\\xFA\" + data[10:])\n        with Image.open(b) as im:\n>           assert im.info[\"dpi\"][0] == 2540\n\u001b[1m\u001b[31mE           TypeError: 'float' object is not subscriptable\u001b[0m\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:69: TypeError\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load_raw\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_register_handler\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load_set_dpi\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[.wmf]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save[.emf]\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_load_float_dpi\u001b[0m - TypeError: 'float' object is not subscriptable\n\u001b[31m========================= \u001b[31m\u001b[1m1 failed\u001b[0m, \u001b[32m6 passed\u001b[0m\u001b[31m in 0.07s\u001b[0m\u001b[31m ==========================\u001b[0m\n",
    "old_commit_res_stderr": ""
}
Tests/test_file_wmf.py src/PIL/WmfImagePlugin.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** DPI Information for EMF Images Returns Float Instead of Tuple, Causing Subscript Errors

**Description:**
When loading EMF images and manipulating their data, accessing the DPI information as a tuple results in a `TypeError` because the DPI is returned as a float instead of a tuple.

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

with Image.open("Tests/images/drawing.emf") as im:
    dpi = im.info["dpi"]

with open("Tests/images/drawing.emf", "rb") as fp:
    data = fp.read()
b = BytesIO(data[:8] + b"\x06\xFA" + data[10:])
with Image.open(b) as im:
    xdpi = im.info["dpi"][0]  # Raises TypeError
```

**Expected Behavior:**
The DPI information should be a tuple containing both horizontal and vertical DPI values, allowing access via indexing (e.g., `dpi[0]` for horizontal DPI).

**Actual Behavior:**
The DPI information is a single float, making it unindexable and causing a `TypeError` when attempting to access `dpi[0]`.
[/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/WmfImagePlugin.py
#
# The Python Imaging Library
# $Id$
#
# WMF stub codec
#
# history:
# 1996-12-14 fl   Created
# 2004-02-22 fl   Turned into a stub driver
# 2004-02-23 fl   Added EMF support
#
# Copyright (c) Secret Labs AB 1997-2004.  All rights reserved.
# Copyright (c) Fredrik Lundh 1996.
#
# See the README file for information on usage and redistribution.
#
# WMF/EMF reference documentation:
# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf
# http://wvware.sourceforge.net/caolan/index.html
# http://wvware.sourceforge.net/caolan/ora-wmf.html
from __future__ import annotations

from typing import IO

from . import Image, ImageFile
from ._binary import i16le as word
from ._binary import si16le as short
from ._binary import si32le as _long

_handler = None


def register_handler(handler: ImageFile.StubHandler | None) -> None:
    """
    Install application-specific WMF image handler.

    :param handler: Handler object.
    """
    global _handler
    _handler = handler


if hasattr(Image.core, "drawwmf"):
    # install default handler (windows only)

    class WmfHandler(ImageFile.StubHandler):
        def open(self, im: ImageFile.StubImageFile) -> None:
            im._mode = "RGB"
            self.bbox = im.info["wmf_bbox"]

        def load(self, im: ImageFile.StubImageFile) -> Image.Image:
            im.fp.seek(0)  # rewind
            return Image.frombytes(
                "RGB",
                im.size,
                Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
                "raw",
                "BGR",
                (im.size[0] * 3 + 3) & -4,
                -1,
            )

    register_handler(WmfHandler())

#
# --------------------------------------------------------------------
# Read WMF file


def _accept(prefix: bytes) -> bool:
    return (
        prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or prefix[:4] == b"\x01\x00\x00\x00"
    )


##
# Image plugin for Windows metafiles.


class WmfStubImageFile(ImageFile.StubImageFile):
    format = "WMF"
    format_description = "Windows Metafile"

    def _open(self) -> None:
        self._inch = None

        # check placable header
        s = self.fp.read(80)

        if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
            # placeable windows metafile

            # get units per inch
            self._inch = word(s, 14)

            # get bounding box
            x0 = short(s, 6)
            y0 = short(s, 8)
            x1 = short(s, 10)
            y1 = short(s, 12)

            # normalize size to 72 dots per inch
            self.info["dpi"] = 72
            size = (
                (x1 - x0) * self.info["dpi"] // self._inch,
                (y1 - y0) * self.info["dpi"] // self._inch,
            )

            self.info["wmf_bbox"] = x0, y0, x1, y1

            # sanity check (standard metafile header)
            if s[22:26] != b"\x01\x00\t\x00":
                msg = "Unsupported WMF file format"
                raise SyntaxError(msg)

        elif s[:4] == b"\x01\x00\x00\x00" and s[40:44] == b" EMF":
            # enhanced metafile

            # get bounding box
            x0 = _long(s, 8)
            y0 = _long(s, 12)
            x1 = _long(s, 16)
            y1 = _long(s, 20)

            # get frame (in 0.01 millimeter units)
            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)

            size = x1 - x0, y1 - y0

            # calculate dots per inch from bbox and frame
            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])
            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])

            self.info["wmf_bbox"] = x0, y0, x1, y1

            if xdpi == ydpi:
                self.info["dpi"] = xdpi
            else:
                self.info["dpi"] = xdpi, ydpi

        else:
            msg = "Unsupported file format"
            raise SyntaxError(msg)

        self._mode = "RGB"
        self._size = size

        loader = self._load()
        if loader:
            loader.open(self)

    def _load(self) -> ImageFile.StubHandler | None:
        return _handler

    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:
        if dpi is not None and self._inch is not None:
            self.info["dpi"] = dpi
            x0, y0, x1, y1 = self.info["wmf_bbox"]
            self._size = (
                (x1 - x0) * self.info["dpi"] // self._inch,
                (y1 - y0) * self.info["dpi"] // self._inch,
            )
        return super().load()


def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
    if _handler is None or not hasattr(_handler, "save"):
        msg = "WMF save handler not installed"
        raise OSError(msg)
    _handler.save(im, fp, filename)


#
# --------------------------------------------------------------------
# Registry stuff


Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)
Image.register_save(WmfStubImageFile.format, _save)

Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"])

```
--- 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:** DPI Information for EMF Images Returns Float Instead of Tuple, Causing Subscript Errors

**Description:**
When loading EMF images and manipulating their data, accessing the DPI information as a tuple results in a `TypeError` because the DPI is returned as a float instead of a tuple.

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

with Image.open("Tests/images/drawing.emf") as im:
    dpi = im.info["dpi"]

with open("Tests/images/drawing.emf", "rb") as fp:
    data = fp.read()
b = BytesIO(data[:8] + b"\x06\xFA" + data[10:])
with Image.open(b) as im:
    xdpi = im.info["dpi"][0]  # Raises TypeError
```

**Expected Behavior:**
The DPI information should be a tuple containing both horizontal and vertical DPI values, allowing access via indexing (e.g., `dpi[0]` for horizontal DPI).

**Actual Behavior:**
The DPI information is a single float, making it unindexable and causing a `TypeError` when attempting to access `dpi[0]`.
[/ISSUE]
{
    "\u001b[1mtest_load_raw\u001b[0m": "PASSED",
    "\u001b[1mtest_load\u001b[0m": "PASSED",
    "\u001b[1mtest_register_handler\u001b[0m": "PASSED",
    "\u001b[1mtest_load_float_dpi\u001b[0m": "PASSED",
    "\u001b[1mtest_load_set_dpi\u001b[0m": "PASSED",
    "\u001b[1mtest_save[.wmf]\u001b[0m": "PASSED",
    "\u001b[1mtest_save[.emf]\u001b[0m": "PASSED"
}
diff --git a/src/PIL/WmfImagePlugin.py b/src/PIL/WmfImagePlugin.py
index 68f8a74f5..cad6c98d5 100644
--- a/src/PIL/WmfImagePlugin.py
+++ b/src/PIL/WmfImagePlugin.py
@@ -128,7 +128,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
             size = x1 - x0, y1 - y0
 
             # calculate dots per inch from bbox and frame
-            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])
+            xdpi = 2540.0 * (x1 - x0) / (frame[2] - frame[0])
             ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])
 
             self.info["wmf_bbox"] = x0, y0, x1, y1
 

{"src/PIL/WmfImagePlugin.py": "#\n# The Python Imaging Library\n# $Id$\n#\n# WMF stub codec\n#\n# history:\n# 1996-12-14 fl   Created\n# 2004-02-22 fl   Turned into a stub driver\n# 2004-02-23 fl   Added EMF support\n#\n# Copyright (c) Secret Labs AB 1997-2004.  All rights reserved.\n# Copyright (c) Fredrik Lundh 1996.\n#\n# See the README file for information on usage and redistribution.\n#\n# WMF/EMF reference documentation:\n# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf\n# http://wvware.sourceforge.net/caolan/index.html\n# http://wvware.sourceforge.net/caolan/ora-wmf.html\nfrom __future__ import annotations\n\nfrom typing import IO\n\nfrom . import Image, ImageFile\nfrom ._binary import i16le as word\nfrom ._binary import si16le as short\nfrom ._binary import si32le as _long\n\n_handler = None\n\n\ndef register_handler(handler: ImageFile.StubHandler | None) -> None:\n    \"\"\"\n    Install application-specific WMF image handler.\n\n    :param handler: Handler object.\n    \"\"\"\n    global _handler\n    _handler = handler\n\n\nif hasattr(Image.core, \"drawwmf\"):\n    # install default handler (windows only)\n\n    class WmfHandler(ImageFile.StubHandler):\n        def open(self, im: ImageFile.StubImageFile) -> None:\n            im._mode = \"RGB\"\n            self.bbox = im.info[\"wmf_bbox\"]\n\n        def load(self, im: ImageFile.StubImageFile) -> Image.Image:\n            im.fp.seek(0)  # rewind\n            return Image.frombytes(\n                \"RGB\",\n                im.size,\n                Image.core.drawwmf(im.fp.read(), im.size, self.bbox),\n                \"raw\",\n                \"BGR\",\n                (im.size[0] * 3 + 3) & -4,\n                -1,\n            )\n\n    register_handler(WmfHandler())\n\n#\n# --------------------------------------------------------------------\n# Read WMF file\n\n\ndef _accept(prefix: bytes) -> bool:\n    return (\n        prefix[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\" or prefix[:4] == b\"\\x01\\x00\\x00\\x00\"\n    )\n\n\n##\n# Image plugin for Windows metafiles.\n\n\nclass WmfStubImageFile(ImageFile.StubImageFile):\n    format = \"WMF\"\n    format_description = \"Windows Metafile\"\n\n    def _open(self) -> None:\n        self._inch = None\n\n        # check placable header\n        s = self.fp.read(80)\n\n        if s[:6] == b\"\\xd7\\xcd\\xc6\\x9a\\x00\\x00\":\n            # placeable windows metafile\n\n            # get units per inch\n            self._inch = word(s, 14)\n\n            # get bounding box\n            x0 = short(s, 6)\n            y0 = short(s, 8)\n            x1 = short(s, 10)\n            y1 = short(s, 12)\n\n            # normalize size to 72 dots per inch\n            self.info[\"dpi\"] = 72\n            size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            # sanity check (standard metafile header)\n            if s[22:26] != b\"\\x01\\x00\\t\\x00\":\n                msg = \"Unsupported WMF file format\"\n                raise SyntaxError(msg)\n\n        elif s[:4] == b\"\\x01\\x00\\x00\\x00\" and s[40:44] == b\" EMF\":\n            # enhanced metafile\n\n            # get bounding box\n            x0 = _long(s, 8)\n            y0 = _long(s, 12)\n            x1 = _long(s, 16)\n            y1 = _long(s, 20)\n\n            # get frame (in 0.01 millimeter units)\n            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)\n\n            size = x1 - x0, y1 - y0\n\n            # calculate dots per inch from bbox and frame\n            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])\n            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])\n\n            self.info[\"wmf_bbox\"] = x0, y0, x1, y1\n\n            if xdpi == ydpi:\n                self.info[\"dpi\"] = xdpi\n            else:\n                self.info[\"dpi\"] = xdpi, ydpi\n\n        else:\n            msg = \"Unsupported file format\"\n            raise SyntaxError(msg)\n\n        self._mode = \"RGB\"\n        self._size = size\n\n        loader = self._load()\n        if loader:\n            loader.open(self)\n\n    def _load(self) -> ImageFile.StubHandler | None:\n        return _handler\n\n    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:\n        if dpi is not None and self._inch is not None:\n            self.info[\"dpi\"] = dpi\n            x0, y0, x1, y1 = self.info[\"wmf_bbox\"]\n            self._size = (\n                (x1 - x0) * self.info[\"dpi\"] // self._inch,\n                (y1 - y0) * self.info[\"dpi\"] // self._inch,\n            )\n        return super().load()\n\n\ndef _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:\n    if _handler is None or not hasattr(_handler, \"save\"):\n        msg = \"WMF save handler not installed\"\n        raise OSError(msg)\n    _handler.save(im, fp, filename)\n\n\n#\n# --------------------------------------------------------------------\n# Registry stuff\n\n\nImage.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)\nImage.register_save(WmfStubImageFile.format, _save)\n\nImage.register_extensions(WmfStubImageFile.format, [\".wmf\", \".emf\"])\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:** DPI Information for EMF Images Returns Float Instead of Tuple, Causing Subscript Errors

**Description:**
When loading EMF images and manipulating their data, accessing the DPI information as a tuple results in a `TypeError` because the DPI is returned as a float instead of a tuple.

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

with Image.open("Tests/images/drawing.emf") as im:
    dpi = im.info["dpi"]

with open("Tests/images/drawing.emf", "rb") as fp:
    data = fp.read()
b = BytesIO(data[:8] + b"\x06\xFA" + data[10:])
with Image.open(b) as im:
    xdpi = im.info["dpi"][0]  # Raises TypeError
```

**Expected Behavior:**
The DPI information should be a tuple containing both horizontal and vertical DPI values, allowing access via indexing (e.g., `dpi[0]` for horizontal DPI).

**Actual Behavior:**
The DPI information is a single float, making it unindexable and causing a `TypeError` when attempting to access `dpi[0]`.
[/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/WmfImagePlugin.py
#
# The Python Imaging Library
# $Id$
#
# WMF stub codec
#
# history:
# 1996-12-14 fl   Created
# 2004-02-22 fl   Turned into a stub driver
# 2004-02-23 fl   Added EMF support
#
# Copyright (c) Secret Labs AB 1997-2004.  All rights reserved.
# Copyright (c) Fredrik Lundh 1996.
#
# See the README file for information on usage and redistribution.
#
# WMF/EMF reference documentation:
# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf
# http://wvware.sourceforge.net/caolan/index.html
# http://wvware.sourceforge.net/caolan/ora-wmf.html
from __future__ import annotations

from typing import IO

from . import Image, ImageFile
from ._binary import i16le as word
from ._binary import si16le as short
from ._binary import si32le as _long

_handler = None


def register_handler(handler: ImageFile.StubHandler | None) -> None:
    """
    Install application-specific WMF image handler.

    :param handler: Handler object.
    """
    global _handler
    _handler = handler


if hasattr(Image.core, "drawwmf"):
    # install default handler (windows only)

    class WmfHandler(ImageFile.StubHandler):
        def open(self, im: ImageFile.StubImageFile) -> None:
            im._mode = "RGB"
            self.bbox = im.info["wmf_bbox"]

        def load(self, im: ImageFile.StubImageFile) -> Image.Image:
            im.fp.seek(0)  # rewind
            return Image.frombytes(
                "RGB",
                im.size,
                Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
                "raw",
                "BGR",
                (im.size[0] * 3 + 3) & -4,
                -1,
            )

    register_handler(WmfHandler())

#
# --------------------------------------------------------------------
# Read WMF file


def _accept(prefix: bytes) -> bool:
    return (
        prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or prefix[:4] == b"\x01\x00\x00\x00"
    )


##
# Image plugin for Windows metafiles.


class WmfStubImageFile(ImageFile.StubImageFile):
    format = "WMF"
    format_description = "Windows Metafile"

    def _open(self) -> None:
        self._inch = None

        # check placable header
        s = self.fp.read(80)

        if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
            # placeable windows metafile

            # get units per inch
            self._inch = word(s, 14)

            # get bounding box
            x0 = short(s, 6)
            y0 = short(s, 8)
            x1 = short(s, 10)
            y1 = short(s, 12)

            # normalize size to 72 dots per inch
            self.info["dpi"] = 72
            size = (
                (x1 - x0) * self.info["dpi"] // self._inch,
                (y1 - y0) * self.info["dpi"] // self._inch,
            )

            self.info["wmf_bbox"] = x0, y0, x1, y1

            # sanity check (standard metafile header)
            if s[22:26] != b"\x01\x00\t\x00":
                msg = "Unsupported WMF file format"
                raise SyntaxError(msg)

        elif s[:4] == b"\x01\x00\x00\x00" and s[40:44] == b" EMF":
            # enhanced metafile

            # get bounding box
            x0 = _long(s, 8)
            y0 = _long(s, 12)
            x1 = _long(s, 16)
            y1 = _long(s, 20)

            # get frame (in 0.01 millimeter units)
            frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)

            size = x1 - x0, y1 - y0

            # calculate dots per inch from bbox and frame
            xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0])
            ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1])

            self.info["wmf_bbox"] = x0, y0, x1, y1

            if xdpi == ydpi:
                self.info["dpi"] = xdpi
            else:
                self.info["dpi"] = xdpi, ydpi

        else:
            msg = "Unsupported file format"
            raise SyntaxError(msg)

        self._mode = "RGB"
        self._size = size

        loader = self._load()
        if loader:
            loader.open(self)

    def _load(self) -> ImageFile.StubHandler | None:
        return _handler

    def load(self, dpi: int | None = None) -> Image.core.PixelAccess | None:
        if dpi is not None and self._inch is not None:
            self.info["dpi"] = dpi
            x0, y0, x1, y1 = self.info["wmf_bbox"]
            self._size = (
                (x1 - x0) * self.info["dpi"] // self._inch,
                (y1 - y0) * self.info["dpi"] // self._inch,
            )
        return super().load()


def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
    if _handler is None or not hasattr(_handler, "save"):
        msg = "WMF save handler not installed"
        raise OSError(msg)
    _handler.save(im, fp, filename)


#
# --------------------------------------------------------------------
# Registry stuff


Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)
Image.register_save(WmfStubImageFile.format, _save)

Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"])

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