aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Pillow/py2/PIL/FliImagePlugin.py
blob: 82015e2fc17dc3e1f6ab3dda44425f360d3dd0d3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#
# The Python Imaging Library.
# $Id$
#
# FLI/FLC file handling.
#
# History:
#       95-09-01 fl     Created
#       97-01-03 fl     Fixed parser, setup decoder tile
#       98-07-15 fl     Renamed offset attribute to avoid name clash
#
# Copyright (c) Secret Labs AB 1997-98.
# Copyright (c) Fredrik Lundh 1995-97.
#
# See the README file for information on usage and redistribution.
#


from . import Image, ImageFile, ImagePalette
from ._binary import i8, i16le as i16, i32le as i32, o8

# __version__ is deprecated and will be removed in a future version. Use
# PIL.__version__ instead.
__version__ = "0.2"


#
# decoder


def _accept(prefix):
    return len(prefix) >= 6 and i16(prefix[4:6]) in [0xAF11, 0xAF12]


##
# Image plugin for the FLI/FLC animation format.  Use the <b>seek</b>
# method to load individual frames.


class FliImageFile(ImageFile.ImageFile):

    format = "FLI"
    format_description = "Autodesk FLI/FLC Animation"
    _close_exclusive_fp_after_loading = False

    def _open(self):

        # HEAD
        s = self.fp.read(128)
        magic = i16(s[4:6])
        if not (
            magic in [0xAF11, 0xAF12]
            and i16(s[14:16]) in [0, 3]  # flags
            and s[20:22] == b"\x00\x00"  # reserved
        ):
            raise SyntaxError("not an FLI/FLC file")

        # frames
        self.__framecount = i16(s[6:8])

        # image characteristics
        self.mode = "P"
        self._size = i16(s[8:10]), i16(s[10:12])

        # animation speed
        duration = i32(s[16:20])
        if magic == 0xAF11:
            duration = (duration * 1000) // 70
        self.info["duration"] = duration

        # look for palette
        palette = [(a, a, a) for a in range(256)]

        s = self.fp.read(16)

        self.__offset = 128

        if i16(s[4:6]) == 0xF100:
            # prefix chunk; ignore it
            self.__offset = self.__offset + i32(s)
            s = self.fp.read(16)

        if i16(s[4:6]) == 0xF1FA:
            # look for palette chunk
            s = self.fp.read(6)
            if i16(s[4:6]) == 11:
                self._palette(palette, 2)
            elif i16(s[4:6]) == 4:
                self._palette(palette, 0)

        palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette]
        self.palette = ImagePalette.raw("RGB", b"".join(palette))

        # set things up to decode first frame
        self.__frame = -1
        self.__fp = self.fp
        self.__rewind = self.fp.tell()
        self.seek(0)

    def _palette(self, palette, shift):
        # load palette

        i = 0
        for e in range(i16(self.fp.read(2))):
            s = self.fp.read(2)
            i = i + i8(s[0])
            n = i8(s[1])
            if n == 0:
                n = 256
            s = self.fp.read(n * 3)
            for n in range(0, len(s), 3):
                r = i8(s[n]) << shift
                g = i8(s[n + 1]) << shift
                b = i8(s[n + 2]) << shift
                palette[i] = (r, g, b)
                i += 1

    @property
    def n_frames(self):
        return self.__framecount

    @property
    def is_animated(self):
        return self.__framecount > 1

    def seek(self, frame):
        if not self._seek_check(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:
            self.__frame = -1
            self.__fp.seek(self.__rewind)
            self.__offset = 128
        else:
            # ensure that the previous frame was loaded
            self.load()

        if frame != self.__frame + 1:
            raise ValueError("cannot seek to frame %d" % frame)
        self.__frame = frame

        # move to next frame
        self.fp = self.__fp
        self.fp.seek(self.__offset)

        s = self.fp.read(4)
        if not s:
            raise EOFError

        framesize = i32(s)

        self.decodermaxblock = framesize
        self.tile = [("fli", (0, 0) + self.size, self.__offset, None)]

        self.__offset += framesize

    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


#
# registry

Image.register_open(FliImageFile.format, FliImageFile, _accept)

Image.register_extensions(FliImageFile.format, [".fli", ".flc"])