mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 18:26:17 +03:00
Provide n_frames attribute to multi-frame formats.
cf #1190, #1192. Tests missing.
This commit is contained in:
parent
9a333c8996
commit
1b80fe5507
|
@ -62,6 +62,10 @@ class DcxImageFile(PcxImageFile):
|
|||
self.__fp = self.fp
|
||||
self.seek(0)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return len(self._offset)
|
||||
|
||||
def seek(self, frame):
|
||||
if frame >= len(self._offset):
|
||||
raise EOFError("attempt to seek outside DCX directory")
|
||||
|
|
|
@ -86,9 +86,10 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
self.palette = ImagePalette.raw("RGB", b"".join(palette))
|
||||
|
||||
# set things up to decode first frame
|
||||
self.frame = -1
|
||||
self.__frame = -1
|
||||
self.__fp = self.fp
|
||||
|
||||
self.__rewind = self.fp.tell()
|
||||
self._n_frames = None
|
||||
self.seek(0)
|
||||
|
||||
def _palette(self, palette, shift):
|
||||
|
@ -109,11 +110,35 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
palette[i] = (r, g, b)
|
||||
i += 1
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
current = self.tell()
|
||||
try:
|
||||
while True:
|
||||
self.seek(self.tell() + 1)
|
||||
except EOFError:
|
||||
self._n_frames = self.tell() + 1
|
||||
self.seek(current)
|
||||
return self._n_frames
|
||||
|
||||
def seek(self, frame):
|
||||
if frame == self.__frame:
|
||||
return
|
||||
if frame < self.__frame:
|
||||
self._seek(0)
|
||||
for f in range(self.__frame + 1, frame + 1):
|
||||
self._seek(f)
|
||||
|
||||
def seek(self, frame):
|
||||
|
||||
if frame != self.frame + 1:
|
||||
if frame == 0:
|
||||
self.__frame = -1
|
||||
self.__fp.seek(self.__rewind)
|
||||
|
||||
if frame != self.__frame + 1:
|
||||
raise ValueError("cannot seek to frame %d" % frame)
|
||||
self.frame = frame
|
||||
self.__frame = frame
|
||||
|
||||
# move to next frame
|
||||
self.fp = self.__fp
|
||||
|
@ -132,7 +157,7 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
|
||||
def tell(self):
|
||||
|
||||
return self.frame
|
||||
return self.__frame
|
||||
|
||||
#
|
||||
# registry
|
||||
|
|
|
@ -87,9 +87,30 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
|
||||
self.__fp = self.fp # FIXME: hack
|
||||
self.__rewind = self.fp.tell()
|
||||
self.seek(0) # get ready to read first frame
|
||||
self._n_frames = None
|
||||
self._seek(0) # get ready to read first frame
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
current = self.tell()
|
||||
try:
|
||||
while True:
|
||||
self.seek(self.tell() + 1)
|
||||
except EOFError:
|
||||
self._n_frames = self.tell() + 1
|
||||
self.seek(current)
|
||||
return self._n_frames
|
||||
|
||||
def seek(self, frame):
|
||||
if frame == self.__frame:
|
||||
return
|
||||
if frame < self.__frame:
|
||||
self._seek(0)
|
||||
for f in range(self.__frame + 1, frame + 1):
|
||||
self._seek(f)
|
||||
|
||||
def _seek(self, frame):
|
||||
|
||||
if frame == 0:
|
||||
# rewind
|
||||
|
|
|
@ -260,6 +260,10 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
self.tile = [("raw", (0, 0)+self.size, offs,
|
||||
(self.rawmode, 0, -1))]
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return self.info[FRAMES]
|
||||
|
||||
def seek(self, frame):
|
||||
|
||||
if frame < 0 or frame >= self.info[FRAMES]:
|
||||
|
|
|
@ -71,6 +71,10 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
|
|||
|
||||
self.seek(0)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return len(self.images)
|
||||
|
||||
def seek(self, frame):
|
||||
|
||||
try:
|
||||
|
|
|
@ -62,6 +62,10 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
|
|||
def load_seek(self, pos):
|
||||
self.__fp.seek(pos)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return self.__framecount
|
||||
|
||||
def seek(self, frame):
|
||||
if frame < 0 or frame >= self.__framecount:
|
||||
raise EOFError("no more images in MPO file")
|
||||
|
|
|
@ -132,6 +132,10 @@ class PsdImageFile(ImageFile.ImageFile):
|
|||
self._fp = self.fp
|
||||
self.frame = 0
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return len(self.layers)
|
||||
|
||||
def seek(self, layer):
|
||||
# seek to given layer (1..max)
|
||||
if layer == self.frame:
|
||||
|
|
|
@ -127,12 +127,12 @@ class SpiderImageFile(ImageFile.ImageFile):
|
|||
if self.istack == 0 and self.imgnumber == 0:
|
||||
# stk=0, img=0: a regular 2D image
|
||||
offset = hdrlen
|
||||
self.nimages = 1
|
||||
self._nimages = 1
|
||||
elif self.istack > 0 and self.imgnumber == 0:
|
||||
# stk>0, img=0: Opening the stack for the first time
|
||||
self.imgbytes = int(h[12]) * int(h[2]) * 4
|
||||
self.hdrlen = hdrlen
|
||||
self.nimages = int(h[26])
|
||||
self._nimages = int(h[26])
|
||||
# Point to the first image in the stack
|
||||
offset = hdrlen * 2
|
||||
self.imgnumber = 1
|
||||
|
@ -154,6 +154,10 @@ class SpiderImageFile(ImageFile.ImageFile):
|
|||
(self.rawmode, 0, 1))]
|
||||
self.__fp = self.fp # FIXME: hack
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
return self._nimages
|
||||
|
||||
# 1st image index is zero (although SPIDER imgnumber starts at 1)
|
||||
def tell(self):
|
||||
if self.imgnumber < 1:
|
||||
|
@ -164,7 +168,7 @@ class SpiderImageFile(ImageFile.ImageFile):
|
|||
def seek(self, frame):
|
||||
if self.istack == 0:
|
||||
return
|
||||
if frame >= self.nimages:
|
||||
if frame >= self._nimages:
|
||||
raise EOFError("attempt to seek past end of file")
|
||||
self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
|
||||
self.fp = self.__fp
|
||||
|
|
|
@ -648,6 +648,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
self.__first = self.__next = self.ifd.i32(ifh, 4)
|
||||
self.__frame = -1
|
||||
self.__fp = self.fp
|
||||
self._frame_pos = []
|
||||
self._n_frames = None
|
||||
|
||||
if Image.DEBUG:
|
||||
print("*** TiffImageFile._open ***")
|
||||
|
@ -657,10 +659,22 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# and load the first frame
|
||||
self._seek(0)
|
||||
|
||||
@property
|
||||
def n_frames(self):
|
||||
if self._n_frames is None:
|
||||
current = self.tell()
|
||||
try:
|
||||
while True:
|
||||
self._seek(self.tell() + 1)
|
||||
except EOFError:
|
||||
self._n_frames = self.tell() + 1
|
||||
self.seek(current)
|
||||
return self._n_frames
|
||||
|
||||
def seek(self, frame):
|
||||
"Select a given frame as current image"
|
||||
if frame < 0:
|
||||
frame = 0
|
||||
raise ValueError("invalid seek")
|
||||
self._seek(frame)
|
||||
# Create a new core image object on second and
|
||||
# subsequent frames in the image. Image may be
|
||||
|
@ -668,17 +682,9 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
Image._decompression_bomb_check(self.size)
|
||||
self.im = Image.core.new(self.mode, self.size)
|
||||
|
||||
def tell(self):
|
||||
"Return the current frame number"
|
||||
return self._tell()
|
||||
|
||||
def _seek(self, frame):
|
||||
self.fp = self.__fp
|
||||
if frame < self.__frame:
|
||||
# rewind file
|
||||
self.__frame = -1
|
||||
self.__next = self.__first
|
||||
while self.__frame < frame:
|
||||
while len(self._frame_pos) <= frame:
|
||||
if not self.__next:
|
||||
raise EOFError("no more images in TIFF file")
|
||||
if Image.DEBUG:
|
||||
|
@ -688,14 +694,19 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# was passed to libtiff, invalidating the buffer
|
||||
self.fp.tell()
|
||||
self.fp.seek(self.__next)
|
||||
self._frame_pos.append(self.__next)
|
||||
if Image.DEBUG:
|
||||
print("Loading tags, location: %s" % self.fp.tell())
|
||||
self.tag.load(self.fp)
|
||||
self.__next = self.tag.next
|
||||
self.__frame += 1
|
||||
self.fp.seek(self._frame_pos[frame])
|
||||
self.tag.load(self.fp)
|
||||
self.__frame = frame
|
||||
self._setup()
|
||||
|
||||
def _tell(self):
|
||||
def tell(self):
|
||||
"Return the current frame number"
|
||||
return self.__frame
|
||||
|
||||
def _decoder(self, rawmode, layer, tile=None):
|
||||
|
|
Loading…
Reference in New Issue
Block a user