~ubuntu-branches/ubuntu/wily/python-imaging/wily

« back to all changes in this revision

Viewing changes to .pc/git-updates.diff/PIL/GifImagePlugin.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-01-31 20:49:20 UTC
  • mfrom: (27.1.1 raring-proposed)
  • Revision ID: package-import@ubuntu.com-20130131204920-b5zshy6vgfvdionl
Tags: 1.1.7+1.7.8-1ubuntu1
Rewrite build dependencies to allow cross builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# The Python Imaging Library.
 
3
# $Id$
 
4
#
 
5
# GIF file handling
 
6
#
 
7
# History:
 
8
# 1995-09-01 fl   Created
 
9
# 1996-12-14 fl   Added interlace support
 
10
# 1996-12-30 fl   Added animation support
 
11
# 1997-01-05 fl   Added write support, fixed local colour map bug
 
12
# 1997-02-23 fl   Make sure to load raster data in getdata()
 
13
# 1997-07-05 fl   Support external decoder (0.4)
 
14
# 1998-07-09 fl   Handle all modes when saving (0.5)
 
15
# 1998-07-15 fl   Renamed offset attribute to avoid name clash
 
16
# 2001-04-16 fl   Added rewind support (seek to frame 0) (0.6)
 
17
# 2001-04-17 fl   Added palette optimization (0.7)
 
18
# 2002-06-06 fl   Added transparency support for save (0.8)
 
19
# 2004-02-24 fl   Disable interlacing for small images
 
20
#
 
21
# Copyright (c) 1997-2004 by Secret Labs AB
 
22
# Copyright (c) 1995-2004 by Fredrik Lundh
 
23
#
 
24
# See the README file for information on usage and redistribution.
 
25
#
 
26
 
 
27
 
 
28
__version__ = "0.9"
 
29
 
 
30
 
 
31
import Image, ImageFile, ImagePalette
 
32
 
 
33
 
 
34
# --------------------------------------------------------------------
 
35
# Helpers
 
36
 
 
37
def i16(c):
 
38
    return ord(c[0]) + (ord(c[1])<<8)
 
39
 
 
40
def o16(i):
 
41
    return chr(i&255) + chr(i>>8&255)
 
42
 
 
43
 
 
44
# --------------------------------------------------------------------
 
45
# Identify/read GIF files
 
46
 
 
47
def _accept(prefix):
 
48
    return prefix[:6] in ["GIF87a", "GIF89a"]
 
49
 
 
50
##
 
51
# Image plugin for GIF images.  This plugin supports both GIF87 and
 
52
# GIF89 images.
 
53
 
 
54
class GifImageFile(ImageFile.ImageFile):
 
55
 
 
56
    format = "GIF"
 
57
    format_description = "Compuserve GIF"
 
58
 
 
59
    global_palette = None
 
60
 
 
61
    def data(self):
 
62
        s = self.fp.read(1)
 
63
        if s and ord(s):
 
64
            return self.fp.read(ord(s))
 
65
        return None
 
66
 
 
67
    def _open(self):
 
68
 
 
69
        # Screen
 
70
        s = self.fp.read(13)
 
71
        if s[:6] not in ["GIF87a", "GIF89a"]:
 
72
            raise SyntaxError, "not a GIF file"
 
73
 
 
74
        self.info["version"] = s[:6]
 
75
 
 
76
        self.size = i16(s[6:]), i16(s[8:])
 
77
 
 
78
        self.tile = []
 
79
 
 
80
        flags = ord(s[10])
 
81
 
 
82
        bits = (flags & 7) + 1
 
83
 
 
84
        if flags & 128:
 
85
            # get global palette
 
86
            self.info["background"] = ord(s[11])
 
87
            # check if palette contains colour indices
 
88
            p = self.fp.read(3<<bits)
 
89
            for i in range(0, len(p), 3):
 
90
                if not (chr(i/3) == p[i] == p[i+1] == p[i+2]):
 
91
                    p = ImagePalette.raw("RGB", p)
 
92
                    self.global_palette = self.palette = p
 
93
                    break
 
94
 
 
95
        self.__fp = self.fp # FIXME: hack
 
96
        self.__rewind = self.fp.tell()
 
97
        self.seek(0) # get ready to read first frame
 
98
 
 
99
    def seek(self, frame):
 
100
 
 
101
        if frame == 0:
 
102
            # rewind
 
103
            self.__offset = 0
 
104
            self.dispose = None
 
105
            self.__frame = -1
 
106
            self.__fp.seek(self.__rewind)
 
107
 
 
108
        if frame != self.__frame + 1:
 
109
            raise ValueError, "cannot seek to frame %d" % frame
 
110
        self.__frame = frame
 
111
 
 
112
        self.tile = []
 
113
 
 
114
        self.fp = self.__fp
 
115
        if self.__offset:
 
116
            # backup to last frame
 
117
            self.fp.seek(self.__offset)
 
118
            while self.data():
 
119
                pass
 
120
            self.__offset = 0
 
121
 
 
122
        if self.dispose:
 
123
            self.im = self.dispose
 
124
            self.dispose = None
 
125
 
 
126
        self.palette = self.global_palette
 
127
 
 
128
        while 1:
 
129
 
 
130
            s = self.fp.read(1)
 
131
            if not s or s == ";":
 
132
                break
 
133
 
 
134
            elif s == "!":
 
135
                #
 
136
                # extensions
 
137
                #
 
138
                s = self.fp.read(1)
 
139
                block = self.data()
 
140
                if ord(s) == 249:
 
141
                    #
 
142
                    # graphic control extension
 
143
                    #
 
144
                    flags = ord(block[0])
 
145
                    if flags & 1:
 
146
                        self.info["transparency"] = ord(block[3])
 
147
                    self.info["duration"] = i16(block[1:3]) * 10
 
148
                    try:
 
149
                        # disposal methods
 
150
                        if flags & 8:
 
151
                            # replace with background colour
 
152
                            self.dispose = Image.core.fill("P", self.size,
 
153
                                self.info["background"])
 
154
                        elif flags & 16:
 
155
                            # replace with previous contents
 
156
                            self.dispose = self.im.copy()
 
157
                    except (AttributeError, KeyError):
 
158
                        pass
 
159
                elif ord(s) == 255:
 
160
                    #
 
161
                    # application extension
 
162
                    #
 
163
                    self.info["extension"] = block, self.fp.tell()
 
164
                    if block[:11] == "NETSCAPE2.0":
 
165
                        block = self.data()
 
166
                        if len(block) >= 3 and ord(block[0]) == 1:
 
167
                            self.info["loop"] = i16(block[1:3])
 
168
                while self.data():
 
169
                    pass
 
170
 
 
171
            elif s == ",":
 
172
                #
 
173
                # local image
 
174
                #
 
175
                s = self.fp.read(9)
 
176
 
 
177
                # extent
 
178
                x0, y0 = i16(s[0:]), i16(s[2:])
 
179
                x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:])
 
180
                flags = ord(s[8])
 
181
 
 
182
                interlace = (flags & 64) != 0
 
183
 
 
184
                if flags & 128:
 
185
                    bits = (flags & 7) + 1
 
186
                    self.palette =\
 
187
                        ImagePalette.raw("RGB", self.fp.read(3<<bits))
 
188
 
 
189
                # image data
 
190
                bits = ord(self.fp.read(1))
 
191
                self.__offset = self.fp.tell()
 
192
                self.tile = [("gif",
 
193
                             (x0, y0, x1, y1),
 
194
                             self.__offset,
 
195
                             (bits, interlace))]
 
196
                break
 
197
 
 
198
            else:
 
199
                pass
 
200
                # raise IOError, "illegal GIF tag `%x`" % ord(s)
 
201
 
 
202
        if not self.tile:
 
203
            # self.__fp = None
 
204
            raise EOFError, "no more images in GIF file"
 
205
 
 
206
        self.mode = "L"
 
207
        if self.palette:
 
208
            self.mode = "P"
 
209
 
 
210
    def tell(self):
 
211
        return self.__frame
 
212
 
 
213
 
 
214
# --------------------------------------------------------------------
 
215
# Write GIF files
 
216
 
 
217
try:
 
218
    import _imaging_gif
 
219
except ImportError:
 
220
    _imaging_gif = None
 
221
 
 
222
RAWMODE = {
 
223
    "1": "L",
 
224
    "L": "L",
 
225
    "P": "P",
 
226
}
 
227
 
 
228
def _save(im, fp, filename):
 
229
 
 
230
    if _imaging_gif:
 
231
        # call external driver
 
232
        try:
 
233
            _imaging_gif.save(im, fp, filename)
 
234
            return
 
235
        except IOError:
 
236
            pass # write uncompressed file
 
237
 
 
238
    try:
 
239
        rawmode = RAWMODE[im.mode]
 
240
        imOut = im
 
241
    except KeyError:
 
242
        # convert on the fly (EXPERIMENTAL -- I'm not sure PIL
 
243
        # should automatically convert images on save...)
 
244
        if Image.getmodebase(im.mode) == "RGB":
 
245
            imOut = im.convert("P")
 
246
            rawmode = "P"
 
247
        else:
 
248
            imOut = im.convert("L")
 
249
            rawmode = "L"
 
250
 
 
251
    # header
 
252
    for s in getheader(imOut, im.encoderinfo):
 
253
        fp.write(s)
 
254
 
 
255
    flags = 0
 
256
 
 
257
    try:
 
258
        interlace = im.encoderinfo["interlace"]
 
259
    except KeyError:
 
260
        interlace = 1
 
261
 
 
262
    # workaround for @PIL153
 
263
    if min(im.size) < 16:
 
264
        interlace = 0
 
265
 
 
266
    if interlace:
 
267
        flags = flags | 64
 
268
 
 
269
    try:
 
270
        transparency = im.encoderinfo["transparency"]
 
271
    except KeyError:
 
272
        pass
 
273
    else:
 
274
        # transparency extension block
 
275
        fp.write("!" +
 
276
                 chr(249) +             # extension intro
 
277
                 chr(4) +               # length
 
278
                 chr(1) +               # transparency info present
 
279
                 o16(0) +               # duration
 
280
                 chr(int(transparency)) # transparency index
 
281
                 + chr(0))
 
282
 
 
283
    # local image header
 
284
    fp.write("," +
 
285
             o16(0) + o16(0) +          # bounding box
 
286
             o16(im.size[0]) +          # size
 
287
             o16(im.size[1]) +
 
288
             chr(flags) +               # flags
 
289
             chr(8))                    # bits
 
290
 
 
291
    imOut.encoderconfig = (8, interlace)
 
292
 
 
293
    ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)])
 
294
 
 
295
    fp.write("\0") # end of image data
 
296
 
 
297
    fp.write(";") # end of file
 
298
 
 
299
    try:
 
300
        fp.flush()
 
301
    except: pass
 
302
 
 
303
def _save_netpbm(im, fp, filename):
 
304
 
 
305
    #
 
306
    # If you need real GIF compression and/or RGB quantization, you
 
307
    # can use the external NETPBM/PBMPLUS utilities.  See comments
 
308
    # below for information on how to enable this.
 
309
 
 
310
    import os
 
311
    file = im._dump()
 
312
    if im.mode != "RGB":
 
313
        os.system("ppmtogif %s >%s" % (file, filename))
 
314
    else:
 
315
        os.system("ppmquant 256 %s | ppmtogif >%s" % (file, filename))
 
316
    try: os.unlink(file)
 
317
    except: pass
 
318
 
 
319
 
 
320
# --------------------------------------------------------------------
 
321
# GIF utilities
 
322
 
 
323
def getheader(im, info=None):
 
324
    """Return a list of strings representing a GIF header"""
 
325
 
 
326
    optimize = info and info.get("optimize", 0)
 
327
 
 
328
    s = [
 
329
        "GIF87a" +              # magic
 
330
        o16(im.size[0]) +       # size
 
331
        o16(im.size[1]) +
 
332
        chr(7 + 128) +          # flags: bits + palette
 
333
        chr(0) +                # background
 
334
        chr(0)                  # reserved/aspect
 
335
    ]
 
336
 
 
337
    if optimize:
 
338
        # minimize color palette
 
339
        i = 0
 
340
        maxcolor = 0
 
341
        for count in im.histogram():
 
342
            if count:
 
343
                maxcolor = i
 
344
            i = i + 1
 
345
    else:
 
346
        maxcolor = 256
 
347
 
 
348
    # global palette
 
349
    if im.mode == "P":
 
350
        # colour palette
 
351
        s.append(im.im.getpalette("RGB")[:maxcolor*3])
 
352
    else:
 
353
        # greyscale
 
354
        for i in range(maxcolor):
 
355
            s.append(chr(i) * 3)
 
356
 
 
357
    return s
 
358
 
 
359
def getdata(im, offset = (0, 0), **params):
 
360
    """Return a list of strings representing this image.
 
361
       The first string is a local image header, the rest contains
 
362
       encoded image data."""
 
363
 
 
364
    class collector:
 
365
        data = []
 
366
        def write(self, data):
 
367
            self.data.append(data)
 
368
 
 
369
    im.load() # make sure raster data is available
 
370
 
 
371
    fp = collector()
 
372
 
 
373
    try:
 
374
        im.encoderinfo = params
 
375
 
 
376
        # local image header
 
377
        fp.write("," +
 
378
                 o16(offset[0]) +       # offset
 
379
                 o16(offset[1]) +
 
380
                 o16(im.size[0]) +      # size
 
381
                 o16(im.size[1]) +
 
382
                 chr(0) +               # flags
 
383
                 chr(8))                # bits
 
384
 
 
385
        ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])])
 
386
 
 
387
        fp.write("\0") # end of image data
 
388
 
 
389
    finally:
 
390
        del im.encoderinfo
 
391
 
 
392
    return fp.data
 
393
 
 
394
 
 
395
# --------------------------------------------------------------------
 
396
# Registry
 
397
 
 
398
Image.register_open(GifImageFile.format, GifImageFile, _accept)
 
399
Image.register_save(GifImageFile.format, _save)
 
400
Image.register_extension(GifImageFile.format, ".gif")
 
401
Image.register_mime(GifImageFile.format, "image/gif")
 
402
 
 
403
#
 
404
# Uncomment the following line if you wish to use NETPBM/PBMPLUS
 
405
# instead of the built-in "uncompressed" GIF encoder
 
406
 
 
407
# Image.register_save(GifImageFile.format, _save_netpbm)