{
    "file_diffs": [
        {
            "old_file_content": "import warnings\nfrom io import BytesIO\n\nimport pytest\n\nfrom PIL import Image\n\nfrom .helper import assert_image_similar, is_pypy, skip_unless_feature\n\ntest_files = [\"Tests/images/sugarshack.mpo\", \"Tests/images/frozenpond.mpo\"]\n\npytestmark = skip_unless_feature(\"jpg\")\n\n\ndef frame_roundtrip(im, **options):\n    # Note that for now, there is no MPO saving functionality\n    out = BytesIO()\n    im.save(out, \"MPO\", **options)\n    test_bytes = out.tell()\n    out.seek(0)\n    im = Image.open(out)\n    im.bytes = test_bytes  # for testing only\n    return im\n\n\ndef test_sanity():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            im.load()\n            assert im.mode == \"RGB\"\n            assert im.size == (640, 480)\n            assert im.format == \"MPO\"\n\n\n@pytest.mark.skipif(is_pypy(), reason=\"Requires CPython\")\ndef test_unclosed_file():\n    def open():\n        im = Image.open(test_files[0])\n        im.load()\n\n    pytest.warns(ResourceWarning, open)\n\n\ndef test_closed_file():\n    with warnings.catch_warnings():\n        im = Image.open(test_files[0])\n        im.load()\n        im.close()\n\n\ndef test_context_manager():\n    with warnings.catch_warnings():\n        with Image.open(test_files[0]) as im:\n            im.load()\n\n\ndef test_app():\n    for test_file in test_files:\n        # Test APP/COM reader (@PIL135)\n        with Image.open(test_file) as im:\n            assert im.applist[0][0] == \"APP1\"\n            assert im.applist[1][0] == \"APP2\"\n            assert (\n                im.applist[1][1][:16]\n                == b\"MPF\\x00MM\\x00*\\x00\\x00\\x00\\x08\\x00\\x03\\xb0\\x00\"\n            )\n            assert len(im.applist) == 2\n\n\ndef test_exif():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            info = im._getexif()\n            assert info[272] == \"Nintendo 3DS\"\n            assert info[296] == 2\n            assert info[34665] == 188\n\n\ndef test_frame_size():\n    # This image has been hexedited to contain a different size\n    # in the EXIF data of the second frame\n    with Image.open(\"Tests/images/sugarshack_frame_size.mpo\") as im:\n        assert im.size == (640, 480)\n\n        im.seek(1)\n        assert im.size == (680, 480)\n\n\ndef test_ignore_frame_size():\n    # Ignore the different size of the second frame\n    # since this is not a \"Large Thumbnail\" image\n    with Image.open(\"Tests/images/ignore_frame_size.mpo\") as im:\n        assert im.size == (64, 64)\n\n        im.seek(1)\n        assert (\n            im.mpinfo[0xB002][1][\"Attribute\"][\"MPType\"]\n            == \"Multi-Frame Image: (Disparity)\"\n        )\n        assert im.size == (64, 64)\n\n\ndef test_parallax():\n    # Nintendo\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        exif = im.getexif()\n        assert exif.get_ifd(0x927C)[0x1101][\"Parallax\"] == -44.798187255859375\n\n    # Fujifilm\n    with Image.open(\"Tests/images/fujifilm.mpo\") as im:\n        im.seek(1)\n        exif = im.getexif()\n        assert exif.get_ifd(0x927C)[0xB211] == -3.125\n\n\ndef test_mp():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            mpinfo = im._getmp()\n            assert mpinfo[45056] == b\"0100\"\n            assert mpinfo[45057] == 2\n\n\ndef test_mp_offset():\n    # This image has been manually hexedited to have an IFD offset of 10\n    # in APP2 data, in contrast to normal 8\n    with Image.open(\"Tests/images/sugarshack_ifd_offset.mpo\") as im:\n        mpinfo = im._getmp()\n        assert mpinfo[45056] == b\"0100\"\n        assert mpinfo[45057] == 2\n\n\ndef test_mp_no_data():\n    # This image has been manually hexedited to have the second frame\n    # beyond the end of the file\n    with Image.open(\"Tests/images/sugarshack_no_data.mpo\") as im:\n        with pytest.raises(ValueError):\n            im.seek(1)\n\n\ndef test_mp_attribute():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            mpinfo = im._getmp()\n        frameNumber = 0\n        for mpentry in mpinfo[0xB002]:\n            mpattr = mpentry[\"Attribute\"]\n            if frameNumber:\n                assert not mpattr[\"RepresentativeImageFlag\"]\n            else:\n                assert mpattr[\"RepresentativeImageFlag\"]\n            assert not mpattr[\"DependentParentImageFlag\"]\n            assert not mpattr[\"DependentChildImageFlag\"]\n            assert mpattr[\"ImageDataFormat\"] == \"JPEG\"\n            assert mpattr[\"MPType\"] == \"Multi-Frame Image: (Disparity)\"\n            assert mpattr[\"Reserved\"] == 0\n            frameNumber += 1\n\n\ndef test_seek():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            # prior to first image raises an error, both blatant and borderline\n            with pytest.raises(EOFError):\n                im.seek(-1)\n            with pytest.raises(EOFError):\n                im.seek(-523)\n            # after the final image raises an error,\n            # both blatant and borderline\n            with pytest.raises(EOFError):\n                im.seek(2)\n            with pytest.raises(EOFError):\n                im.seek(523)\n            # bad calls shouldn't change the frame\n            assert im.tell() == 0\n            # this one will work\n            im.seek(1)\n            assert im.tell() == 1\n            # and this one, too\n            im.seek(0)\n            assert im.tell() == 0\n\n\ndef test_n_frames():\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        assert im.n_frames == 2\n        assert im.is_animated\n\n\ndef test_eoferror():\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        n_frames = im.n_frames\n\n        # Test seeking past the last frame\n        with pytest.raises(EOFError):\n            im.seek(n_frames)\n        assert im.tell() < n_frames\n\n        # Test that seeking to the last frame does not raise an error\n        im.seek(n_frames - 1)\n\n\ndef test_image_grab():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            im0 = im.tobytes()\n            im.seek(1)\n            assert im.tell() == 1\n            im1 = im.tobytes()\n            im.seek(0)\n            assert im.tell() == 0\n            im02 = im.tobytes()\n            assert im0 == im02\n            assert im0 != im1\n\n\ndef test_save():\n    # Note that only individual frames can be saved at present\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            jpg0 = frame_roundtrip(im)\n            assert_image_similar(im, jpg0, 30)\n            im.seek(1)\n            assert im.tell() == 1\n            jpg1 = frame_roundtrip(im)\n            assert_image_similar(im, jpg1, 30)\n",
            "new_file_content": "import warnings\nfrom io import BytesIO\n\nimport pytest\n\nfrom PIL import Image\n\nfrom .helper import assert_image_similar, is_pypy, skip_unless_feature\n\ntest_files = [\"Tests/images/sugarshack.mpo\", \"Tests/images/frozenpond.mpo\"]\n\npytestmark = skip_unless_feature(\"jpg\")\n\n\ndef frame_roundtrip(im, **options):\n    # Note that for now, there is no MPO saving functionality\n    out = BytesIO()\n    im.save(out, \"MPO\", **options)\n    test_bytes = out.tell()\n    out.seek(0)\n    im = Image.open(out)\n    im.bytes = test_bytes  # for testing only\n    return im\n\n\ndef test_sanity():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            im.load()\n            assert im.mode == \"RGB\"\n            assert im.size == (640, 480)\n            assert im.format == \"MPO\"\n\n\n@pytest.mark.skipif(is_pypy(), reason=\"Requires CPython\")\ndef test_unclosed_file():\n    def open():\n        im = Image.open(test_files[0])\n        im.load()\n\n    pytest.warns(ResourceWarning, open)\n\n\ndef test_closed_file():\n    with warnings.catch_warnings():\n        im = Image.open(test_files[0])\n        im.load()\n        im.close()\n\n\ndef test_context_manager():\n    with warnings.catch_warnings():\n        with Image.open(test_files[0]) as im:\n            im.load()\n\n\ndef test_app():\n    for test_file in test_files:\n        # Test APP/COM reader (@PIL135)\n        with Image.open(test_file) as im:\n            assert im.applist[0][0] == \"APP1\"\n            assert im.applist[1][0] == \"APP2\"\n            assert (\n                im.applist[1][1][:16]\n                == b\"MPF\\x00MM\\x00*\\x00\\x00\\x00\\x08\\x00\\x03\\xb0\\x00\"\n            )\n            assert len(im.applist) == 2\n\n\ndef test_exif():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            info = im._getexif()\n            assert info[272] == \"Nintendo 3DS\"\n            assert info[296] == 2\n            assert info[34665] == 188\n\n\ndef test_frame_size():\n    # This image has been hexedited to contain a different size\n    # in the EXIF data of the second frame\n    with Image.open(\"Tests/images/sugarshack_frame_size.mpo\") as im:\n        assert im.size == (640, 480)\n\n        im.seek(1)\n        assert im.size == (680, 480)\n\n        im.seek(0)\n        assert im.size == (640, 480)\n\n\ndef test_ignore_frame_size():\n    # Ignore the different size of the second frame\n    # since this is not a \"Large Thumbnail\" image\n    with Image.open(\"Tests/images/ignore_frame_size.mpo\") as im:\n        assert im.size == (64, 64)\n\n        im.seek(1)\n        assert (\n            im.mpinfo[0xB002][1][\"Attribute\"][\"MPType\"]\n            == \"Multi-Frame Image: (Disparity)\"\n        )\n        assert im.size == (64, 64)\n\n\ndef test_parallax():\n    # Nintendo\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        exif = im.getexif()\n        assert exif.get_ifd(0x927C)[0x1101][\"Parallax\"] == -44.798187255859375\n\n    # Fujifilm\n    with Image.open(\"Tests/images/fujifilm.mpo\") as im:\n        im.seek(1)\n        exif = im.getexif()\n        assert exif.get_ifd(0x927C)[0xB211] == -3.125\n\n\ndef test_mp():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            mpinfo = im._getmp()\n            assert mpinfo[45056] == b\"0100\"\n            assert mpinfo[45057] == 2\n\n\ndef test_mp_offset():\n    # This image has been manually hexedited to have an IFD offset of 10\n    # in APP2 data, in contrast to normal 8\n    with Image.open(\"Tests/images/sugarshack_ifd_offset.mpo\") as im:\n        mpinfo = im._getmp()\n        assert mpinfo[45056] == b\"0100\"\n        assert mpinfo[45057] == 2\n\n\ndef test_mp_no_data():\n    # This image has been manually hexedited to have the second frame\n    # beyond the end of the file\n    with Image.open(\"Tests/images/sugarshack_no_data.mpo\") as im:\n        with pytest.raises(ValueError):\n            im.seek(1)\n\n\ndef test_mp_attribute():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            mpinfo = im._getmp()\n        frameNumber = 0\n        for mpentry in mpinfo[0xB002]:\n            mpattr = mpentry[\"Attribute\"]\n            if frameNumber:\n                assert not mpattr[\"RepresentativeImageFlag\"]\n            else:\n                assert mpattr[\"RepresentativeImageFlag\"]\n            assert not mpattr[\"DependentParentImageFlag\"]\n            assert not mpattr[\"DependentChildImageFlag\"]\n            assert mpattr[\"ImageDataFormat\"] == \"JPEG\"\n            assert mpattr[\"MPType\"] == \"Multi-Frame Image: (Disparity)\"\n            assert mpattr[\"Reserved\"] == 0\n            frameNumber += 1\n\n\ndef test_seek():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            # prior to first image raises an error, both blatant and borderline\n            with pytest.raises(EOFError):\n                im.seek(-1)\n            with pytest.raises(EOFError):\n                im.seek(-523)\n            # after the final image raises an error,\n            # both blatant and borderline\n            with pytest.raises(EOFError):\n                im.seek(2)\n            with pytest.raises(EOFError):\n                im.seek(523)\n            # bad calls shouldn't change the frame\n            assert im.tell() == 0\n            # this one will work\n            im.seek(1)\n            assert im.tell() == 1\n            # and this one, too\n            im.seek(0)\n            assert im.tell() == 0\n\n\ndef test_n_frames():\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        assert im.n_frames == 2\n        assert im.is_animated\n\n\ndef test_eoferror():\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        n_frames = im.n_frames\n\n        # Test seeking past the last frame\n        with pytest.raises(EOFError):\n            im.seek(n_frames)\n        assert im.tell() < n_frames\n\n        # Test that seeking to the last frame does not raise an error\n        im.seek(n_frames - 1)\n\n\ndef test_image_grab():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            im0 = im.tobytes()\n            im.seek(1)\n            assert im.tell() == 1\n            im1 = im.tobytes()\n            im.seek(0)\n            assert im.tell() == 0\n            im02 = im.tobytes()\n            assert im0 == im02\n            assert im0 != im1\n\n\ndef test_save():\n    # Note that only individual frames can be saved at present\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            jpg0 = frame_roundtrip(im)\n            assert_image_similar(im, jpg0, 30)\n            im.seek(1)\n            assert im.tell() == 1\n            jpg1 = frame_roundtrip(im)\n            assert_image_similar(im, jpg1, 30)\n",
            "header": {
                "file": {
                    "path": "Tests/test_file_mpo.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "0e59e4d56",
                "new_commit_hash": "0fa3b6382",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_file_mpo.py"
            },
            "plus_file": {
                "path": "b/Tests/test_file_mpo.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 85,
                            "length": 6
                        },
                        "new_range": {
                            "start": 85,
                            "length": 9
                        },
                        "section": "def test_frame_size():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        im.seek(1)",
                                "type": "context"
                            },
                            {
                                "content": "        assert im.size == (680, 480)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        im.seek(0)",
                                "type": "added"
                            },
                            {
                                "content": "        assert im.size == (640, 480)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_ignore_frame_size():",
                                "type": "context"
                            },
                            {
                                "content": "    # Ignore the different size of the second frame",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_file_mpo.py",
                            "type": "function",
                            "name": "test_frame_size",
                            "content": "def test_frame_size():\n    # This image has been hexedited to contain a different size\n    # in the EXIF data of the second frame\n    with Image.open(\"Tests/images/sugarshack_frame_size.mpo\") as im:\n        assert im.size == (640, 480)\n\n        im.seek(1)\n        assert im.size == (680, 480)\n\n        im.seek(0)\n        assert im.size == (640, 480)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 79,
                            "end_lineno": 89,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# MPO file handling\n#\n# See \"Multi-Picture Format\" (CIPA DC-007-Translation 2009, Standard of the\n# Camera & Imaging Products Association)\n#\n# The multi-picture object combines multiple JPEG images (with a modified EXIF\n# data format) into a single file. While it can theoretically be used much like\n# a GIF animation, it is commonly used to represent 3D photographs and is (as\n# of this writing) the most commonly used format by 3D cameras.\n#\n# History:\n# 2014-03-13 Feneric   Created\n#\n# See the README file for information on usage and redistribution.\n#\n\nfrom . import Image, ImageFile, JpegImagePlugin\nfrom ._binary import i16be as i16\n\n# def _accept(prefix):\n#     return JpegImagePlugin._accept(prefix)\n\n\ndef _save(im, fp, filename):\n    # Note that we can only save the current frame at present\n    return JpegImagePlugin._save(im, fp, filename)\n\n\n##\n# Image plugin for MPO images.\n\n\nclass MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance\n\n\n# ---------------------------------------------------------------------\n# Registry stuff\n\n# Note that since MPO shares a factory with JPEG, we do not need to do a\n# separate registration for it here.\n# Image.register_open(MpoImageFile.format,\n#                     JpegImagePlugin.jpeg_factory, _accept)\nImage.register_save(MpoImageFile.format, _save)\n\nImage.register_extension(MpoImageFile.format, \".mpo\")\n\nImage.register_mime(MpoImageFile.format, \"image/mpo\")\n",
            "new_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# MPO file handling\n#\n# See \"Multi-Picture Format\" (CIPA DC-007-Translation 2009, Standard of the\n# Camera & Imaging Products Association)\n#\n# The multi-picture object combines multiple JPEG images (with a modified EXIF\n# data format) into a single file. While it can theoretically be used much like\n# a GIF animation, it is commonly used to represent 3D photographs and is (as\n# of this writing) the most commonly used format by 3D cameras.\n#\n# History:\n# 2014-03-13 Feneric   Created\n#\n# See the README file for information on usage and redistribution.\n#\n\nfrom . import Image, ImageFile, JpegImagePlugin\nfrom ._binary import i16be as i16\n\n# def _accept(prefix):\n#     return JpegImagePlugin._accept(prefix)\n\n\ndef _save(im, fp, filename):\n    # Note that we can only save the current frame at present\n    return JpegImagePlugin._save(im, fp, filename)\n\n\n##\n# Image plugin for MPO images.\n\n\nclass MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance\n\n\n# ---------------------------------------------------------------------\n# Registry stuff\n\n# Note that since MPO shares a factory with JPEG, we do not need to do a\n# separate registration for it here.\n# Image.register_open(MpoImageFile.format,\n#                     JpegImagePlugin.jpeg_factory, _accept)\nImage.register_save(MpoImageFile.format, _save)\n\nImage.register_extension(MpoImageFile.format, \".mpo\")\n\nImage.register_mime(MpoImageFile.format, \"image/mpo\")\n",
            "header": {
                "file": {
                    "path": "src/PIL/MpoImagePlugin.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "7ccf27c42",
                "new_commit_hash": "88c1bfcc5",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/MpoImagePlugin.py"
            },
            "plus_file": {
                "path": "b/src/PIL/MpoImagePlugin.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 46,
                            "length": 6
                        },
                        "new_range": {
                            "start": 46,
                            "length": 7
                        },
                        "section": "class MpoImageFile(JpegImagePlugin.JpegImageFile):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self._after_jpeg_open()",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def _after_jpeg_open(self, mpheader=None):",
                                "type": "context"
                            },
                            {
                                "content": "        self._initial_size = self.size",
                                "type": "added"
                            },
                            {
                                "content": "        self.mpinfo = mpheader if mpheader is not None else self._getmp()",
                                "type": "context"
                            },
                            {
                                "content": "        self.n_frames = self.mpinfo[0xB001]",
                                "type": "context"
                            },
                            {
                                "content": "        self.__mpoffsets = [",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/MpoImagePlugin.py",
                            "type": "method",
                            "name": "MpoImageFile._after_jpeg_open",
                            "content": "class MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 48,
                            "end_lineno": 66,
                            "parent": {
                                "file_name": "src/PIL/MpoImagePlugin.py",
                                "type": "class",
                                "name": "MpoImageFile",
                                "content": "class MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 37,
                                "end_lineno": 123,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "src/PIL/MpoImagePlugin.py",
                            "type": "class",
                            "name": "MpoImageFile",
                            "content": "class MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 37,
                            "end_lineno": 123,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 77,
                            "length": 6
                        },
                        "new_range": {
                            "start": 78,
                            "length": 7
                        },
                        "section": "class MpoImageFile(JpegImagePlugin.JpegImageFile):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        segment = self.fp.read(2)",
                                "type": "context"
                            },
                            {
                                "content": "        if not segment:",
                                "type": "context"
                            },
                            {
                                "content": "            raise ValueError(\"No data found for frame\")",
                                "type": "context"
                            },
                            {
                                "content": "        self._size = self._initial_size",
                                "type": "added"
                            },
                            {
                                "content": "        if i16(segment) == 0xFFE1:  # APP1",
                                "type": "context"
                            },
                            {
                                "content": "            n = i16(self.fp.read(2)) - 2",
                                "type": "context"
                            },
                            {
                                "content": "            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/MpoImagePlugin.py",
                            "type": "method",
                            "name": "MpoImageFile.seek",
                            "content": "class MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 71,
                            "end_lineno": 95,
                            "parent": {
                                "file_name": "src/PIL/MpoImagePlugin.py",
                                "type": "class",
                                "name": "MpoImageFile",
                                "content": "class MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 37,
                                "end_lineno": 123,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "src/PIL/MpoImagePlugin.py",
                            "type": "class",
                            "name": "MpoImageFile",
                            "content": "class MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self._initial_size = self.size\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        self._size = self._initial_size\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 37,
                            "end_lineno": 123,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "235500179764e173f0a519e454a537676adcf8a6^",
    "new_commit_hash": "235500179764e173f0a519e454a537676adcf8a6",
    "commit_message": "Merge pull request #6101 from radarhere/mpo\n\nReset size when seeking away from \"Large Thumbnail\" MPO frame",
    "commit_date": "2022-03-02T08:08:20+02:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "235500179764e173f0a519e454a537676adcf8a6",
    "test_file_codes": [
        "import warnings\nfrom io import BytesIO\n\nimport pytest\n\nfrom PIL import Image\n\nfrom .helper import assert_image_similar, is_pypy, skip_unless_feature\n\ntest_files = [\"Tests/images/sugarshack.mpo\", \"Tests/images/frozenpond.mpo\"]\n\npytestmark = skip_unless_feature(\"jpg\")\n\n\ndef frame_roundtrip(im, **options):\n    # Note that for now, there is no MPO saving functionality\n    out = BytesIO()\n    im.save(out, \"MPO\", **options)\n    test_bytes = out.tell()\n    out.seek(0)\n    im = Image.open(out)\n    im.bytes = test_bytes  # for testing only\n    return im\n\n\ndef test_sanity():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            im.load()\n            assert im.mode == \"RGB\"\n            assert im.size == (640, 480)\n            assert im.format == \"MPO\"\n\n\n@pytest.mark.skipif(is_pypy(), reason=\"Requires CPython\")\ndef test_unclosed_file():\n    def open():\n        im = Image.open(test_files[0])\n        im.load()\n\n    pytest.warns(ResourceWarning, open)\n\n\ndef test_closed_file():\n    with warnings.catch_warnings():\n        im = Image.open(test_files[0])\n        im.load()\n        im.close()\n\n\ndef test_context_manager():\n    with warnings.catch_warnings():\n        with Image.open(test_files[0]) as im:\n            im.load()\n\n\ndef test_app():\n    for test_file in test_files:\n        # Test APP/COM reader (@PIL135)\n        with Image.open(test_file) as im:\n            assert im.applist[0][0] == \"APP1\"\n            assert im.applist[1][0] == \"APP2\"\n            assert (\n                im.applist[1][1][:16]\n                == b\"MPF\\x00MM\\x00*\\x00\\x00\\x00\\x08\\x00\\x03\\xb0\\x00\"\n            )\n            assert len(im.applist) == 2\n\n\ndef test_exif():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            info = im._getexif()\n            assert info[272] == \"Nintendo 3DS\"\n            assert info[296] == 2\n            assert info[34665] == 188\n\n\ndef test_frame_size():\n    # This image has been hexedited to contain a different size\n    # in the EXIF data of the second frame\n    with Image.open(\"Tests/images/sugarshack_frame_size.mpo\") as im:\n        assert im.size == (640, 480)\n\n        im.seek(1)\n        assert im.size == (680, 480)\n\n        im.seek(0)\n        assert im.size == (640, 480)\n\n\ndef test_ignore_frame_size():\n    # Ignore the different size of the second frame\n    # since this is not a \"Large Thumbnail\" image\n    with Image.open(\"Tests/images/ignore_frame_size.mpo\") as im:\n        assert im.size == (64, 64)\n\n        im.seek(1)\n        assert (\n            im.mpinfo[0xB002][1][\"Attribute\"][\"MPType\"]\n            == \"Multi-Frame Image: (Disparity)\"\n        )\n        assert im.size == (64, 64)\n\n\ndef test_parallax():\n    # Nintendo\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        exif = im.getexif()\n        assert exif.get_ifd(0x927C)[0x1101][\"Parallax\"] == -44.798187255859375\n\n    # Fujifilm\n    with Image.open(\"Tests/images/fujifilm.mpo\") as im:\n        im.seek(1)\n        exif = im.getexif()\n        assert exif.get_ifd(0x927C)[0xB211] == -3.125\n\n\ndef test_mp():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            mpinfo = im._getmp()\n            assert mpinfo[45056] == b\"0100\"\n            assert mpinfo[45057] == 2\n\n\ndef test_mp_offset():\n    # This image has been manually hexedited to have an IFD offset of 10\n    # in APP2 data, in contrast to normal 8\n    with Image.open(\"Tests/images/sugarshack_ifd_offset.mpo\") as im:\n        mpinfo = im._getmp()\n        assert mpinfo[45056] == b\"0100\"\n        assert mpinfo[45057] == 2\n\n\ndef test_mp_no_data():\n    # This image has been manually hexedited to have the second frame\n    # beyond the end of the file\n    with Image.open(\"Tests/images/sugarshack_no_data.mpo\") as im:\n        with pytest.raises(ValueError):\n            im.seek(1)\n\n\ndef test_mp_attribute():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            mpinfo = im._getmp()\n        frameNumber = 0\n        for mpentry in mpinfo[0xB002]:\n            mpattr = mpentry[\"Attribute\"]\n            if frameNumber:\n                assert not mpattr[\"RepresentativeImageFlag\"]\n            else:\n                assert mpattr[\"RepresentativeImageFlag\"]\n            assert not mpattr[\"DependentParentImageFlag\"]\n            assert not mpattr[\"DependentChildImageFlag\"]\n            assert mpattr[\"ImageDataFormat\"] == \"JPEG\"\n            assert mpattr[\"MPType\"] == \"Multi-Frame Image: (Disparity)\"\n            assert mpattr[\"Reserved\"] == 0\n            frameNumber += 1\n\n\ndef test_seek():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            # prior to first image raises an error, both blatant and borderline\n            with pytest.raises(EOFError):\n                im.seek(-1)\n            with pytest.raises(EOFError):\n                im.seek(-523)\n            # after the final image raises an error,\n            # both blatant and borderline\n            with pytest.raises(EOFError):\n                im.seek(2)\n            with pytest.raises(EOFError):\n                im.seek(523)\n            # bad calls shouldn't change the frame\n            assert im.tell() == 0\n            # this one will work\n            im.seek(1)\n            assert im.tell() == 1\n            # and this one, too\n            im.seek(0)\n            assert im.tell() == 0\n\n\ndef test_n_frames():\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        assert im.n_frames == 2\n        assert im.is_animated\n\n\ndef test_eoferror():\n    with Image.open(\"Tests/images/sugarshack.mpo\") as im:\n        n_frames = im.n_frames\n\n        # Test seeking past the last frame\n        with pytest.raises(EOFError):\n            im.seek(n_frames)\n        assert im.tell() < n_frames\n\n        # Test that seeking to the last frame does not raise an error\n        im.seek(n_frames - 1)\n\n\ndef test_image_grab():\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            im0 = im.tobytes()\n            im.seek(1)\n            assert im.tell() == 1\n            im1 = im.tobytes()\n            im.seek(0)\n            assert im.tell() == 0\n            im02 = im.tobytes()\n            assert im0 == im02\n            assert im0 != im1\n\n\ndef test_save():\n    # Note that only individual frames can be saved at present\n    for test_file in test_files:\n        with Image.open(test_file) as im:\n            assert im.tell() == 0\n            jpg0 = frame_roundtrip(im)\n            assert_image_similar(im, jpg0, 30)\n            im.seek(1)\n            assert im.tell() == 1\n            jpg1 = frame_roundtrip(im)\n            assert_image_similar(im, jpg1, 30)\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 15ms\nInstalled 12 packages in 135ms\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 664ms\nPrepared 1 package in 32.72s\nInstalled 1 package in 0.93ms\n + pillow==9.1.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_235500179764e173f0a519e454a537676adcf8a6)\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_235500179764e173f0a519e454a537676adcf8a6\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 18 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                                   [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\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_unclosed_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_closed_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_context_manager\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_app\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_exif\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_frame_size\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_ignore_frame_size\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_parallax\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp_offset\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp_no_data\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp_attribute\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_seek\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_n_frames\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_eoferror\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_image_grab\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save\u001b[0m\n\u001b[32m============================== \u001b[32m\u001b[1m18 passed\u001b[0m\u001b[32m in 0.29s\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_235500179764e173f0a519e454a537676adcf8a6\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 18 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[31mF\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[31m                                   [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m_______________________________ test_frame_size ________________________________\u001b[0m\n\n    def test_frame_size():\n        # This image has been hexedited to contain a different size\n        # in the EXIF data of the second frame\n        with Image.open(\"Tests/images/sugarshack_frame_size.mpo\") as im:\n            assert im.size == (640, 480)\n    \n            im.seek(1)\n            assert im.size == (680, 480)\n    \n            im.seek(0)\n>           assert im.size == (640, 480)\n\u001b[1m\u001b[31mE           assert (680, 480) == (640, 480)\u001b[0m\n\u001b[1m\u001b[31mE             \u001b[0m\n\u001b[1m\u001b[31mE             At index 0 diff: 680 != 640\u001b[0m\n\u001b[1m\u001b[31mE             Use -v to get more diff\u001b[0m\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:89: AssertionError\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\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_unclosed_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_closed_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_context_manager\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_app\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_exif\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_ignore_frame_size\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_parallax\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp_offset\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp_no_data\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_mp_attribute\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_seek\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_n_frames\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_eoferror\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_image_grab\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_save\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_frame_size\u001b[0m - assert (680, 480) == (640, 480)\n\u001b[31m========================= \u001b[31m\u001b[1m1 failed\u001b[0m, \u001b[32m17 passed\u001b[0m\u001b[31m in 0.17s\u001b[0m\u001b[31m =========================\u001b[0m\n",
    "old_commit_res_stderr": ""
}
Tests/test_file_mpo.py src/PIL/MpoImagePlugin.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title**: Image Size Not Reset When Seeking Back to "Large Thumbnail" MPO Frame

**Description**:
When handling MPO images with multiple frames, seeking back to the "Large Thumbnail" frame does not correctly reset the image size to its original dimensions. Instead, the size of the previously accessed frame persists, causing inconsistencies in image rendering.

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

with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
    # Initial frame size should be (640, 480)
    print(im.size)  # Outputs: (640, 480)
    
    im.seek(1)
    print(im.size)  # Outputs: (680, 480)
    
    im.seek(0)
    print(im.size)  # Expected: (640, 480), but outputs: (680, 480)
```

**Expected Behavior**:
After seeking back to the "Large Thumbnail" frame, the image size should reset to the original dimensions of (640, 480).

**Actual Behavior**:
The image size remains at (680, 480), which is the size of the second frame, instead of reverting to (640, 480).

[/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/MpoImagePlugin.py
#
# The Python Imaging Library.
# $Id$
#
# MPO file handling
#
# See "Multi-Picture Format" (CIPA DC-007-Translation 2009, Standard of the
# Camera & Imaging Products Association)
#
# The multi-picture object combines multiple JPEG images (with a modified EXIF
# data format) into a single file. While it can theoretically be used much like
# a GIF animation, it is commonly used to represent 3D photographs and is (as
# of this writing) the most commonly used format by 3D cameras.
#
# History:
# 2014-03-13 Feneric   Created
#
# See the README file for information on usage and redistribution.
#

from . import Image, ImageFile, JpegImagePlugin
from ._binary import i16be as i16

# def _accept(prefix):
#     return JpegImagePlugin._accept(prefix)


def _save(im, fp, filename):
    # Note that we can only save the current frame at present
    return JpegImagePlugin._save(im, fp, filename)


##
# Image plugin for MPO images.


class MpoImageFile(JpegImagePlugin.JpegImageFile):

    format = "MPO"
    format_description = "MPO (CIPA DC-007)"
    _close_exclusive_fp_after_loading = False

    def _open(self):
        self.fp.seek(0)  # prep the fp in order to pass the JPEG test
        JpegImagePlugin.JpegImageFile._open(self)
        self._after_jpeg_open()

    def _after_jpeg_open(self, mpheader=None):
        self.mpinfo = mpheader if mpheader is not None else self._getmp()
        self.n_frames = self.mpinfo[0xB001]
        self.__mpoffsets = [
            mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002]
        ]
        self.__mpoffsets[0] = 0
        # Note that the following assertion will only be invalid if something
        # gets broken within JpegImagePlugin.
        assert self.n_frames == len(self.__mpoffsets)
        del self.info["mpoffset"]  # no longer needed
        self.is_animated = self.n_frames > 1
        self.__fp = self.fp  # FIXME: hack
        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame
        self.__frame = 0
        self.offset = 0
        # for now we can only handle reading and individual frame extraction
        self.readonly = 1

    def load_seek(self, pos):
        self.__fp.seek(pos)

    def seek(self, frame):
        if not self._seek_check(frame):
            return
        self.fp = self.__fp
        self.offset = self.__mpoffsets[frame]

        self.fp.seek(self.offset + 2)  # skip SOI marker
        segment = self.fp.read(2)
        if not segment:
            raise ValueError("No data found for frame")
        if i16(segment) == 0xFFE1:  # APP1
            n = i16(self.fp.read(2)) - 2
            self.info["exif"] = ImageFile._safe_read(self.fp, n)

            mptype = self.mpinfo[0xB002][frame]["Attribute"]["MPType"]
            if mptype.startswith("Large Thumbnail"):
                exif = self.getexif().get_ifd(0x8769)
                if 40962 in exif and 40963 in exif:
                    self._size = (exif[40962], exif[40963])
        elif "exif" in self.info:
            del self.info["exif"]

        self.tile = [("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))]
        self.__frame = frame

    def tell(self):
        return self.__frame

    def _close__fp(self):
        try:
            if self.__fp != self.fp:
                self.__fp.close()
        except AttributeError:
            pass
        finally:
            self.__fp = None

    @staticmethod
    def adopt(jpeg_instance, mpheader=None):
        """
        Transform the instance of JpegImageFile into
        an instance of MpoImageFile.
        After the call, the JpegImageFile is extended
        to be an MpoImageFile.

        This is essentially useful when opening a JPEG
        file that reveals itself as an MPO, to avoid
        double call to _open.
        """
        jpeg_instance.__class__ = MpoImageFile
        jpeg_instance._after_jpeg_open(mpheader)
        return jpeg_instance


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

# Note that since MPO shares a factory with JPEG, we do not need to do a
# separate registration for it here.
# Image.register_open(MpoImageFile.format,
#                     JpegImagePlugin.jpeg_factory, _accept)
Image.register_save(MpoImageFile.format, _save)

Image.register_extension(MpoImageFile.format, ".mpo")

Image.register_mime(MpoImageFile.format, "image/mpo")

```
--- 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**: Image Size Not Reset When Seeking Back to "Large Thumbnail" MPO Frame

**Description**:
When handling MPO images with multiple frames, seeking back to the "Large Thumbnail" frame does not correctly reset the image size to its original dimensions. Instead, the size of the previously accessed frame persists, causing inconsistencies in image rendering.

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

with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
    # Initial frame size should be (640, 480)
    print(im.size)  # Outputs: (640, 480)
    
    im.seek(1)
    print(im.size)  # Outputs: (680, 480)
    
    im.seek(0)
    print(im.size)  # Expected: (640, 480), but outputs: (680, 480)
```

**Expected Behavior**:
After seeking back to the "Large Thumbnail" frame, the image size should reset to the original dimensions of (640, 480).

**Actual Behavior**:
The image size remains at (680, 480), which is the size of the second frame, instead of reverting to (640, 480).

[/ISSUE]
{
    "\u001b[1mtest_sanity\u001b[0m": "PASSED",
    "\u001b[1mtest_unclosed_file\u001b[0m": "PASSED",
    "\u001b[1mtest_closed_file\u001b[0m": "PASSED",
    "\u001b[1mtest_context_manager\u001b[0m": "PASSED",
    "\u001b[1mtest_app\u001b[0m": "PASSED",
    "\u001b[1mtest_exif\u001b[0m": "PASSED",
    "\u001b[1mtest_frame_size\u001b[0m": "PASSED",
    "\u001b[1mtest_ignore_frame_size\u001b[0m": "PASSED",
    "\u001b[1mtest_parallax\u001b[0m": "PASSED",
    "\u001b[1mtest_mp\u001b[0m": "PASSED",
    "\u001b[1mtest_mp_offset\u001b[0m": "PASSED",
    "\u001b[1mtest_mp_no_data\u001b[0m": "PASSED",
    "\u001b[1mtest_mp_attribute\u001b[0m": "PASSED",
    "\u001b[1mtest_seek\u001b[0m": "PASSED",
    "\u001b[1mtest_n_frames\u001b[0m": "PASSED",
    "\u001b[1mtest_eoferror\u001b[0m": "PASSED",
    "\u001b[1mtest_image_grab\u001b[0m": "PASSED",
    "\u001b[1mtest_save\u001b[0m": "PASSED"
}
diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py
index 7ccf27c42..88c1bfcc5 100644
--- a/src/PIL/MpoImagePlugin.py
+++ b/src/PIL/MpoImagePlugin.py
@@ -46,6 +46,7 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
         self._after_jpeg_open()
 
     def _after_jpeg_open(self, mpheader=None):
+        self._initial_size = self.size
         self.mpinfo = mpheader if mpheader is not None else self._getmp()
         self.n_frames = self.mpinfo[0xB001]
         self.__mpoffsets = [
@@ -77,6 +78,7 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
         segment = self.fp.read(2)
         if not segment:
             raise ValueError("No data found for frame")
+        self._size = self._initial_size
         if i16(segment) == 0xFFE1:  # APP1
             n = i16(self.fp.read(2)) - 2
             self.info["exif"] = ImageFile._safe_read(self.fp, n)
 

{"src/PIL/MpoImagePlugin.py": "#\n# The Python Imaging Library.\n# $Id$\n#\n# MPO file handling\n#\n# See \"Multi-Picture Format\" (CIPA DC-007-Translation 2009, Standard of the\n# Camera & Imaging Products Association)\n#\n# The multi-picture object combines multiple JPEG images (with a modified EXIF\n# data format) into a single file. While it can theoretically be used much like\n# a GIF animation, it is commonly used to represent 3D photographs and is (as\n# of this writing) the most commonly used format by 3D cameras.\n#\n# History:\n# 2014-03-13 Feneric   Created\n#\n# See the README file for information on usage and redistribution.\n#\n\nfrom . import Image, ImageFile, JpegImagePlugin\nfrom ._binary import i16be as i16\n\n# def _accept(prefix):\n#     return JpegImagePlugin._accept(prefix)\n\n\ndef _save(im, fp, filename):\n    # Note that we can only save the current frame at present\n    return JpegImagePlugin._save(im, fp, filename)\n\n\n##\n# Image plugin for MPO images.\n\n\nclass MpoImageFile(JpegImagePlugin.JpegImageFile):\n\n    format = \"MPO\"\n    format_description = \"MPO (CIPA DC-007)\"\n    _close_exclusive_fp_after_loading = False\n\n    def _open(self):\n        self.fp.seek(0)  # prep the fp in order to pass the JPEG test\n        JpegImagePlugin.JpegImageFile._open(self)\n        self._after_jpeg_open()\n\n    def _after_jpeg_open(self, mpheader=None):\n        self.mpinfo = mpheader if mpheader is not None else self._getmp()\n        self.n_frames = self.mpinfo[0xB001]\n        self.__mpoffsets = [\n            mpent[\"DataOffset\"] + self.info[\"mpoffset\"] for mpent in self.mpinfo[0xB002]\n        ]\n        self.__mpoffsets[0] = 0\n        # Note that the following assertion will only be invalid if something\n        # gets broken within JpegImagePlugin.\n        assert self.n_frames == len(self.__mpoffsets)\n        del self.info[\"mpoffset\"]  # no longer needed\n        self.is_animated = self.n_frames > 1\n        self.__fp = self.fp  # FIXME: hack\n        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame\n        self.__frame = 0\n        self.offset = 0\n        # for now we can only handle reading and individual frame extraction\n        self.readonly = 1\n\n    def load_seek(self, pos):\n        self.__fp.seek(pos)\n\n    def seek(self, frame):\n        if not self._seek_check(frame):\n            return\n        self.fp = self.__fp\n        self.offset = self.__mpoffsets[frame]\n\n        self.fp.seek(self.offset + 2)  # skip SOI marker\n        segment = self.fp.read(2)\n        if not segment:\n            raise ValueError(\"No data found for frame\")\n        if i16(segment) == 0xFFE1:  # APP1\n            n = i16(self.fp.read(2)) - 2\n            self.info[\"exif\"] = ImageFile._safe_read(self.fp, n)\n\n            mptype = self.mpinfo[0xB002][frame][\"Attribute\"][\"MPType\"]\n            if mptype.startswith(\"Large Thumbnail\"):\n                exif = self.getexif().get_ifd(0x8769)\n                if 40962 in exif and 40963 in exif:\n                    self._size = (exif[40962], exif[40963])\n        elif \"exif\" in self.info:\n            del self.info[\"exif\"]\n\n        self.tile = [(\"jpeg\", (0, 0) + self.size, self.offset, (self.mode, \"\"))]\n        self.__frame = frame\n\n    def tell(self):\n        return self.__frame\n\n    def _close__fp(self):\n        try:\n            if self.__fp != self.fp:\n                self.__fp.close()\n        except AttributeError:\n            pass\n        finally:\n            self.__fp = None\n\n    @staticmethod\n    def adopt(jpeg_instance, mpheader=None):\n        \"\"\"\n        Transform the instance of JpegImageFile into\n        an instance of MpoImageFile.\n        After the call, the JpegImageFile is extended\n        to be an MpoImageFile.\n\n        This is essentially useful when opening a JPEG\n        file that reveals itself as an MPO, to avoid\n        double call to _open.\n        \"\"\"\n        jpeg_instance.__class__ = MpoImageFile\n        jpeg_instance._after_jpeg_open(mpheader)\n        return jpeg_instance\n\n\n# ---------------------------------------------------------------------\n# Registry stuff\n\n# Note that since MPO shares a factory with JPEG, we do not need to do a\n# separate registration for it here.\n# Image.register_open(MpoImageFile.format,\n#                     JpegImagePlugin.jpeg_factory, _accept)\nImage.register_save(MpoImageFile.format, _save)\n\nImage.register_extension(MpoImageFile.format, \".mpo\")\n\nImage.register_mime(MpoImageFile.format, \"image/mpo\")\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**: Image Size Not Reset When Seeking Back to "Large Thumbnail" MPO Frame

**Description**:
When handling MPO images with multiple frames, seeking back to the "Large Thumbnail" frame does not correctly reset the image size to its original dimensions. Instead, the size of the previously accessed frame persists, causing inconsistencies in image rendering.

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

with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
    # Initial frame size should be (640, 480)
    print(im.size)  # Outputs: (640, 480)
    
    im.seek(1)
    print(im.size)  # Outputs: (680, 480)
    
    im.seek(0)
    print(im.size)  # Expected: (640, 480), but outputs: (680, 480)
```

**Expected Behavior**:
After seeking back to the "Large Thumbnail" frame, the image size should reset to the original dimensions of (640, 480).

**Actual Behavior**:
The image size remains at (680, 480), which is the size of the second frame, instead of reverting to (640, 480).

[/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/MpoImagePlugin.py
#
# The Python Imaging Library.
# $Id$
#
# MPO file handling
#
# See "Multi-Picture Format" (CIPA DC-007-Translation 2009, Standard of the
# Camera & Imaging Products Association)
#
# The multi-picture object combines multiple JPEG images (with a modified EXIF
# data format) into a single file. While it can theoretically be used much like
# a GIF animation, it is commonly used to represent 3D photographs and is (as
# of this writing) the most commonly used format by 3D cameras.
#
# History:
# 2014-03-13 Feneric   Created
#
# See the README file for information on usage and redistribution.
#

from . import Image, ImageFile, JpegImagePlugin
from ._binary import i16be as i16

# def _accept(prefix):
#     return JpegImagePlugin._accept(prefix)


def _save(im, fp, filename):
    # Note that we can only save the current frame at present
    return JpegImagePlugin._save(im, fp, filename)


##
# Image plugin for MPO images.


class MpoImageFile(JpegImagePlugin.JpegImageFile):

    format = "MPO"
    format_description = "MPO (CIPA DC-007)"
    _close_exclusive_fp_after_loading = False

    def _open(self):
        self.fp.seek(0)  # prep the fp in order to pass the JPEG test
        JpegImagePlugin.JpegImageFile._open(self)
        self._after_jpeg_open()

    def _after_jpeg_open(self, mpheader=None):
        self.mpinfo = mpheader if mpheader is not None else self._getmp()
        self.n_frames = self.mpinfo[0xB001]
        self.__mpoffsets = [
            mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002]
        ]
        self.__mpoffsets[0] = 0
        # Note that the following assertion will only be invalid if something
        # gets broken within JpegImagePlugin.
        assert self.n_frames == len(self.__mpoffsets)
        del self.info["mpoffset"]  # no longer needed
        self.is_animated = self.n_frames > 1
        self.__fp = self.fp  # FIXME: hack
        self.__fp.seek(self.__mpoffsets[0])  # get ready to read first frame
        self.__frame = 0
        self.offset = 0
        # for now we can only handle reading and individual frame extraction
        self.readonly = 1

    def load_seek(self, pos):
        self.__fp.seek(pos)

    def seek(self, frame):
        if not self._seek_check(frame):
            return
        self.fp = self.__fp
        self.offset = self.__mpoffsets[frame]

        self.fp.seek(self.offset + 2)  # skip SOI marker
        segment = self.fp.read(2)
        if not segment:
            raise ValueError("No data found for frame")
        if i16(segment) == 0xFFE1:  # APP1
            n = i16(self.fp.read(2)) - 2
            self.info["exif"] = ImageFile._safe_read(self.fp, n)

            mptype = self.mpinfo[0xB002][frame]["Attribute"]["MPType"]
            if mptype.startswith("Large Thumbnail"):
                exif = self.getexif().get_ifd(0x8769)
                if 40962 in exif and 40963 in exif:
                    self._size = (exif[40962], exif[40963])
        elif "exif" in self.info:
            del self.info["exif"]

        self.tile = [("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))]
        self.__frame = frame

    def tell(self):
        return self.__frame

    def _close__fp(self):
        try:
            if self.__fp != self.fp:
                self.__fp.close()
        except AttributeError:
            pass
        finally:
            self.__fp = None

    @staticmethod
    def adopt(jpeg_instance, mpheader=None):
        """
        Transform the instance of JpegImageFile into
        an instance of MpoImageFile.
        After the call, the JpegImageFile is extended
        to be an MpoImageFile.

        This is essentially useful when opening a JPEG
        file that reveals itself as an MPO, to avoid
        double call to _open.
        """
        jpeg_instance.__class__ = MpoImageFile
        jpeg_instance._after_jpeg_open(mpheader)
        return jpeg_instance


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

# Note that since MPO shares a factory with JPEG, we do not need to do a
# separate registration for it here.
# Image.register_open(MpoImageFile.format,
#                     JpegImagePlugin.jpeg_factory, _accept)
Image.register_save(MpoImageFile.format, _save)

Image.register_extension(MpoImageFile.format, ".mpo")

Image.register_mime(MpoImageFile.format, "image/mpo")

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