Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/PIL/FliImagePlugin.py: 15%
85 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1#
2# The Python Imaging Library.
3# $Id$
4#
5# FLI/FLC file handling.
6#
7# History:
8# 95-09-01 fl Created
9# 97-01-03 fl Fixed parser, setup decoder tile
10# 98-07-15 fl Renamed offset attribute to avoid name clash
11#
12# Copyright (c) Secret Labs AB 1997-98.
13# Copyright (c) Fredrik Lundh 1995-97.
14#
15# See the README file for information on usage and redistribution.
16#
19from . import Image, ImageFile, ImagePalette
20from ._binary import i16le as i16
21from ._binary import i32le as i32
22from ._binary import o8
24#
25# decoder
28def _accept(prefix):
29 return (
30 len(prefix) >= 6
31 and i16(prefix, 4) in [0xAF11, 0xAF12]
32 and i16(prefix, 14) in [0, 3] # flags
33 )
36##
37# Image plugin for the FLI/FLC animation format. Use the <b>seek</b>
38# method to load individual frames.
41class FliImageFile(ImageFile.ImageFile):
43 format = "FLI"
44 format_description = "Autodesk FLI/FLC Animation"
45 _close_exclusive_fp_after_loading = False
47 def _open(self):
49 # HEAD
50 s = self.fp.read(128)
51 if not (_accept(s) and s[20:22] == b"\x00\x00"):
52 raise SyntaxError("not an FLI/FLC file")
54 # frames
55 self.n_frames = i16(s, 6)
56 self.is_animated = self.n_frames > 1
58 # image characteristics
59 self.mode = "P"
60 self._size = i16(s, 8), i16(s, 10)
62 # animation speed
63 duration = i32(s, 16)
64 magic = i16(s, 4)
65 if magic == 0xAF11:
66 duration = (duration * 1000) // 70
67 self.info["duration"] = duration
69 # look for palette
70 palette = [(a, a, a) for a in range(256)]
72 s = self.fp.read(16)
74 self.__offset = 128
76 if i16(s, 4) == 0xF100:
77 # prefix chunk; ignore it
78 self.__offset = self.__offset + i32(s)
79 s = self.fp.read(16)
81 if i16(s, 4) == 0xF1FA:
82 # look for palette chunk
83 s = self.fp.read(6)
84 if i16(s, 4) == 11:
85 self._palette(palette, 2)
86 elif i16(s, 4) == 4:
87 self._palette(palette, 0)
89 palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette]
90 self.palette = ImagePalette.raw("RGB", b"".join(palette))
92 # set things up to decode first frame
93 self.__frame = -1
94 self._fp = self.fp
95 self.__rewind = self.fp.tell()
96 self.seek(0)
98 def _palette(self, palette, shift):
99 # load palette
101 i = 0
102 for e in range(i16(self.fp.read(2))):
103 s = self.fp.read(2)
104 i = i + s[0]
105 n = s[1]
106 if n == 0:
107 n = 256
108 s = self.fp.read(n * 3)
109 for n in range(0, len(s), 3):
110 r = s[n] << shift
111 g = s[n + 1] << shift
112 b = s[n + 2] << shift
113 palette[i] = (r, g, b)
114 i += 1
116 def seek(self, frame):
117 if not self._seek_check(frame):
118 return
119 if frame < self.__frame:
120 self._seek(0)
122 for f in range(self.__frame + 1, frame + 1):
123 self._seek(f)
125 def _seek(self, frame):
126 if frame == 0:
127 self.__frame = -1
128 self._fp.seek(self.__rewind)
129 self.__offset = 128
130 else:
131 # ensure that the previous frame was loaded
132 self.load()
134 if frame != self.__frame + 1:
135 raise ValueError(f"cannot seek to frame {frame}")
136 self.__frame = frame
138 # move to next frame
139 self.fp = self._fp
140 self.fp.seek(self.__offset)
142 s = self.fp.read(4)
143 if not s:
144 raise EOFError
146 framesize = i32(s)
148 self.decodermaxblock = framesize
149 self.tile = [("fli", (0, 0) + self.size, self.__offset, None)]
151 self.__offset += framesize
153 def tell(self):
154 return self.__frame
157#
158# registry
160Image.register_open(FliImageFile.format, FliImageFile, _accept)
162Image.register_extensions(FliImageFile.format, [".fli", ".flc"])