diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index ae0d430e65a..9cf27b0261b 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -97,7 +97,7 @@ def n_frames(self): current = self.tell() try: while True: - self.seek(self.tell() + 1) + self._seek(self.tell() + 1, False) except EOFError: self._n_frames = self.tell() + 1 self.seek(current) @@ -110,14 +110,16 @@ def is_animated(self): self._is_animated = self._n_frames != 1 else: current = self.tell() - - try: - self.seek(1) + if current: self._is_animated = True - except EOFError: - self._is_animated = False + else: + try: + self._seek(1, False) + self._is_animated = True + except EOFError: + self._is_animated = False - self.seek(current) + self.seek(current) return self._is_animated def seek(self, frame): @@ -135,7 +137,7 @@ def seek(self, frame): self.seek(last_frame) raise EOFError("no more images in GIF file") from e - def _seek(self, frame): + def _seek(self, frame, update_image=True): if frame == 0: # rewind @@ -147,14 +149,11 @@ def _seek(self, frame): self.disposal_method = 0 else: # ensure that the previous frame was loaded - if self.tile: + if self.tile and update_image: self.load() if frame != self.__frame + 1: raise ValueError(f"cannot seek to frame {frame}") - self.__frame = frame - - self.tile = [] self.fp = self.__fp if self.__offset: @@ -164,25 +163,34 @@ def _seek(self, frame): pass self.__offset = 0 - if self.__frame == 1: - self.pyaccess = None - if "transparency" in self.info: - if self.mode == "P": - self.im.putpalettealpha(self.info["transparency"], 0) - self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG) - self.mode = "RGBA" - else: - self.im = self.im.convert_transparent( - "LA", self.info["transparency"] - ) - self.mode = "LA" + s = self.fp.read(1) + if not s or s == b";": + raise EOFError - del self.info["transparency"] - else: - self.mode = "RGB" - self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG) - if self.dispose: - self.im.paste(self.dispose, self.dispose_extent) + self.__frame = frame + + self.tile = [] + + if update_image: + if self.__frame == 1: + self.pyaccess = None + if "transparency" in self.info: + if self.mode == "P": + self.im.putpalettealpha(self.info["transparency"], 0) + self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG) + self.mode = "RGBA" + else: + self.im = self.im.convert_transparent( + "LA", self.info["transparency"] + ) + self.mode = "LA" + + del self.info["transparency"] + else: + self.mode = "RGB" + self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG) + if self.dispose: + self.im.paste(self.dispose, self.dispose_extent) palette = None @@ -191,7 +199,8 @@ def _seek(self, frame): interlace = None while True: - s = self.fp.read(1) + if not s: + s = self.fp.read(1) if not s or s == b";": break @@ -229,6 +238,7 @@ def _seek(self, frame): else: info["comment"] = block block = self.data() + s = None continue elif s[0] == 255: # @@ -270,6 +280,13 @@ def _seek(self, frame): else: pass # raise OSError, "illegal GIF tag `%x`" % s[0] + s = None + + if interlace is None: + # self.__fp = None + raise EOFError + if not update_image: + return frame_palette = palette or self.global_palette @@ -329,9 +346,6 @@ def _rgb(color): (bits, interlace), ) ] - else: - # self.__fp = None - raise EOFError for k in ["duration", "comment", "extension", "loop"]: if k in info: