~ubuntu-branches/ubuntu/saucy/python-imaging/saucy-proposed

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-03-20 16:44:01 UTC
  • mfrom: (2.1.13 experimental)
  • Revision ID: package-import@ubuntu.com-20130320164401-ptf6m0ttg4zw72az
Tags: 1.1.7+2.0.0-1
Pillow 2.0.0 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# The Python Imaging Library.
3
 
# $Id$
4
 
#
5
 
# TIFF file handling
6
 
#
7
 
# TIFF is a flexible, if somewhat aged, image file format originally
8
 
# defined by Aldus.  Although TIFF supports a wide variety of pixel
9
 
# layouts and compression methods, the name doesn't really stand for
10
 
# "thousands of incompatible file formats," it just feels that way.
11
 
#
12
 
# To read TIFF data from a stream, the stream must be seekable.  For
13
 
# progressive decoding, make sure to use TIFF files where the tag
14
 
# directory is placed first in the file.
15
 
#
16
 
# History:
17
 
# 1995-09-01 fl   Created
18
 
# 1996-05-04 fl   Handle JPEGTABLES tag
19
 
# 1996-05-18 fl   Fixed COLORMAP support
20
 
# 1997-01-05 fl   Fixed PREDICTOR support
21
 
# 1997-08-27 fl   Added support for rational tags (from Perry Stoll)
22
 
# 1998-01-10 fl   Fixed seek/tell (from Jan Blom)
23
 
# 1998-07-15 fl   Use private names for internal variables
24
 
# 1999-06-13 fl   Rewritten for PIL 1.0 (1.0)
25
 
# 2000-10-11 fl   Additional fixes for Python 2.0 (1.1)
26
 
# 2001-04-17 fl   Fixed rewind support (seek to frame 0) (1.2)
27
 
# 2001-05-12 fl   Added write support for more tags (from Greg Couch) (1.3)
28
 
# 2001-12-18 fl   Added workaround for broken Matrox library
29
 
# 2002-01-18 fl   Don't mess up if photometric tag is missing (D. Alan Stewart)
30
 
# 2003-05-19 fl   Check FILLORDER tag
31
 
# 2003-09-26 fl   Added RGBa support
32
 
# 2004-02-24 fl   Added DPI support; fixed rational write support
33
 
# 2005-02-07 fl   Added workaround for broken Corel Draw 10 files
34
 
# 2006-01-09 fl   Added support for float/double tags (from Russell Nelson)
35
 
#
36
 
# Copyright (c) 1997-2006 by Secret Labs AB.  All rights reserved.
37
 
# Copyright (c) 1995-1997 by Fredrik Lundh
38
 
#
39
 
# See the README file for information on usage and redistribution.
40
 
#
41
 
 
42
 
__version__ = "1.3.5"
43
 
 
44
 
import Image, ImageFile
45
 
import ImagePalette
46
 
 
47
 
import array, string, sys
48
 
 
49
 
II = "II" # little-endian (intel-style)
50
 
MM = "MM" # big-endian (motorola-style)
51
 
 
52
 
try:
53
 
    if sys.byteorder == "little":
54
 
        native_prefix = II
55
 
    else:
56
 
        native_prefix = MM
57
 
except AttributeError:
58
 
    if ord(array.array("i",[1]).tostring()[0]):
59
 
        native_prefix = II
60
 
    else:
61
 
        native_prefix = MM
62
 
 
63
 
#
64
 
# --------------------------------------------------------------------
65
 
# Read TIFF files
66
 
 
67
 
def il16(c,o=0):
68
 
    return ord(c[o]) + (ord(c[o+1])<<8)
69
 
def il32(c,o=0):
70
 
    return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24)
71
 
def ol16(i):
72
 
    return chr(i&255) + chr(i>>8&255)
73
 
def ol32(i):
74
 
    return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
75
 
 
76
 
def ib16(c,o=0):
77
 
    return ord(c[o+1]) + (ord(c[o])<<8)
78
 
def ib32(c,o=0):
79
 
    return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
80
 
def ob16(i):
81
 
    return chr(i>>8&255) + chr(i&255)
82
 
def ob32(i):
83
 
    return chr(i>>24&255) + chr(i>>16&255) + chr(i>>8&255) + chr(i&255)
84
 
 
85
 
# a few tag names, just to make the code below a bit more readable
86
 
IMAGEWIDTH = 256
87
 
IMAGELENGTH = 257
88
 
BITSPERSAMPLE = 258
89
 
COMPRESSION = 259
90
 
PHOTOMETRIC_INTERPRETATION = 262
91
 
FILLORDER = 266
92
 
IMAGEDESCRIPTION = 270
93
 
STRIPOFFSETS = 273
94
 
SAMPLESPERPIXEL = 277
95
 
ROWSPERSTRIP = 278
96
 
STRIPBYTECOUNTS = 279
97
 
X_RESOLUTION = 282
98
 
Y_RESOLUTION = 283
99
 
PLANAR_CONFIGURATION = 284
100
 
RESOLUTION_UNIT = 296
101
 
SOFTWARE = 305
102
 
DATE_TIME = 306
103
 
ARTIST = 315
104
 
PREDICTOR = 317
105
 
COLORMAP = 320
106
 
TILEOFFSETS = 324
107
 
EXTRASAMPLES = 338
108
 
SAMPLEFORMAT = 339
109
 
JPEGTABLES = 347
110
 
COPYRIGHT = 33432
111
 
IPTC_NAA_CHUNK = 33723 # newsphoto properties
112
 
PHOTOSHOP_CHUNK = 34377 # photoshop properties
113
 
ICCPROFILE = 34675
114
 
EXIFIFD = 34665
115
 
XMP = 700
116
 
 
117
 
COMPRESSION_INFO = {
118
 
    # Compression => pil compression name
119
 
    1: "raw",
120
 
    2: "tiff_ccitt",
121
 
    3: "group3",
122
 
    4: "group4",
123
 
    5: "tiff_lzw",
124
 
    6: "tiff_jpeg", # obsolete
125
 
    7: "jpeg",
126
 
    32771: "tiff_raw_16", # 16-bit padding
127
 
    32773: "packbits"
128
 
}
129
 
 
130
 
OPEN_INFO = {
131
 
    # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
132
 
    #  ExtraSamples) => mode, rawmode
133
 
    (II, 0, 1, 1, (1,), ()): ("1", "1;I"),
134
 
    (II, 0, 1, 2, (1,), ()): ("1", "1;IR"),
135
 
    (II, 0, 1, 1, (8,), ()): ("L", "L;I"),
136
 
    (II, 0, 1, 2, (8,), ()): ("L", "L;IR"),
137
 
    (II, 1, 1, 1, (1,), ()): ("1", "1"),
138
 
    (II, 1, 1, 2, (1,), ()): ("1", "1;R"),
139
 
    (II, 1, 1, 1, (8,), ()): ("L", "L"),
140
 
    (II, 1, 1, 1, (8,8), (2,)): ("LA", "LA"),
141
 
    (II, 1, 1, 2, (8,), ()): ("L", "L;R"),
142
 
    (II, 1, 1, 1, (16,), ()): ("I;16", "I;16"),
143
 
    (II, 1, 2, 1, (16,), ()): ("I;16S", "I;16S"),
144
 
    (II, 1, 2, 1, (32,), ()): ("I", "I;32S"),
145
 
    (II, 1, 3, 1, (32,), ()): ("F", "F;32F"),
146
 
    (II, 2, 1, 1, (8,8,8), ()): ("RGB", "RGB"),
147
 
    (II, 2, 1, 2, (8,8,8), ()): ("RGB", "RGB;R"),
148
 
    (II, 2, 1, 1, (8,8,8,8), (0,)): ("RGBX", "RGBX"),
149
 
    (II, 2, 1, 1, (8,8,8,8), (1,)): ("RGBA", "RGBa"),
150
 
    (II, 2, 1, 1, (8,8,8,8), (2,)): ("RGBA", "RGBA"),
151
 
    (II, 2, 1, 1, (8,8,8,8), (999,)): ("RGBA", "RGBA"), # corel draw 10
152
 
    (II, 3, 1, 1, (1,), ()): ("P", "P;1"),
153
 
    (II, 3, 1, 2, (1,), ()): ("P", "P;1R"),
154
 
    (II, 3, 1, 1, (2,), ()): ("P", "P;2"),
155
 
    (II, 3, 1, 2, (2,), ()): ("P", "P;2R"),
156
 
    (II, 3, 1, 1, (4,), ()): ("P", "P;4"),
157
 
    (II, 3, 1, 2, (4,), ()): ("P", "P;4R"),
158
 
    (II, 3, 1, 1, (8,), ()): ("P", "P"),
159
 
    (II, 3, 1, 1, (8,8), (2,)): ("PA", "PA"),
160
 
    (II, 3, 1, 2, (8,), ()): ("P", "P;R"),
161
 
    (II, 5, 1, 1, (8,8,8,8), ()): ("CMYK", "CMYK"),
162
 
    (II, 6, 1, 1, (8,8,8), ()): ("YCbCr", "YCbCr"),
163
 
    (II, 8, 1, 1, (8,8,8), ()): ("LAB", "LAB"),
164
 
 
165
 
    (MM, 0, 1, 1, (1,), ()): ("1", "1;I"),
166
 
    (MM, 0, 1, 2, (1,), ()): ("1", "1;IR"),
167
 
    (MM, 0, 1, 1, (8,), ()): ("L", "L;I"),
168
 
    (MM, 0, 1, 2, (8,), ()): ("L", "L;IR"),
169
 
    (MM, 1, 1, 1, (1,), ()): ("1", "1"),
170
 
    (MM, 1, 1, 2, (1,), ()): ("1", "1;R"),
171
 
    (MM, 1, 1, 1, (8,), ()): ("L", "L"),
172
 
    (MM, 1, 1, 1, (8,8), (2,)): ("LA", "LA"),
173
 
    (MM, 1, 1, 2, (8,), ()): ("L", "L;R"),
174
 
    (MM, 1, 1, 1, (16,), ()): ("I;16B", "I;16B"),
175
 
    (MM, 1, 2, 1, (16,), ()): ("I;16BS", "I;16BS"),
176
 
    (MM, 1, 2, 1, (32,), ()): ("I;32BS", "I;32BS"),
177
 
    (MM, 1, 3, 1, (32,), ()): ("F;32BF", "F;32BF"),
178
 
    (MM, 2, 1, 1, (8,8,8), ()): ("RGB", "RGB"),
179
 
    (MM, 2, 1, 2, (8,8,8), ()): ("RGB", "RGB;R"),
180
 
    (MM, 2, 1, 1, (8,8,8,8), (0,)): ("RGBX", "RGBX"),
181
 
    (MM, 2, 1, 1, (8,8,8,8), (1,)): ("RGBA", "RGBa"),
182
 
    (MM, 2, 1, 1, (8,8,8,8), (2,)): ("RGBA", "RGBA"),
183
 
    (MM, 2, 1, 1, (8,8,8,8), (999,)): ("RGBA", "RGBA"), # corel draw 10
184
 
    (MM, 3, 1, 1, (1,), ()): ("P", "P;1"),
185
 
    (MM, 3, 1, 2, (1,), ()): ("P", "P;1R"),
186
 
    (MM, 3, 1, 1, (2,), ()): ("P", "P;2"),
187
 
    (MM, 3, 1, 2, (2,), ()): ("P", "P;2R"),
188
 
    (MM, 3, 1, 1, (4,), ()): ("P", "P;4"),
189
 
    (MM, 3, 1, 2, (4,), ()): ("P", "P;4R"),
190
 
    (MM, 3, 1, 1, (8,), ()): ("P", "P"),
191
 
    (MM, 3, 1, 1, (8,8), (2,)): ("PA", "PA"),
192
 
    (MM, 3, 1, 2, (8,), ()): ("P", "P;R"),
193
 
    (MM, 5, 1, 1, (8,8,8,8), ()): ("CMYK", "CMYK"),
194
 
    (MM, 6, 1, 1, (8,8,8), ()): ("YCbCr", "YCbCr"),
195
 
    (MM, 8, 1, 1, (8,8,8), ()): ("LAB", "LAB"),
196
 
 
197
 
}
198
 
 
199
 
PREFIXES = ["MM\000\052", "II\052\000", "II\xBC\000"]
200
 
 
201
 
def _accept(prefix):
202
 
    return prefix[:4] in PREFIXES
203
 
 
204
 
##
205
 
# Wrapper for TIFF IFDs.
206
 
 
207
 
class ImageFileDirectory:
208
 
 
209
 
    # represents a TIFF tag directory.  to speed things up,
210
 
    # we don't decode tags unless they're asked for.
211
 
 
212
 
    def __init__(self, prefix):
213
 
        self.prefix = prefix[:2]
214
 
        if self.prefix == MM:
215
 
            self.i16, self.i32 = ib16, ib32
216
 
            self.o16, self.o32 = ob16, ob32
217
 
        elif self.prefix == II:
218
 
            self.i16, self.i32 = il16, il32
219
 
            self.o16, self.o32 = ol16, ol32
220
 
        else:
221
 
            raise SyntaxError("not a TIFF IFD")
222
 
        self.reset()
223
 
 
224
 
    def reset(self):
225
 
        self.tags = {}
226
 
        self.tagdata = {}
227
 
        self.tagtype = {} # added 2008-06-05 by Florian Hoech
228
 
        self.next = None
229
 
 
230
 
    # dictionary API (sort of)
231
 
 
232
 
    def keys(self):
233
 
        return self.tagdata.keys() + self.tags.keys()
234
 
 
235
 
    def items(self):
236
 
        items = self.tags.items()
237
 
        for tag in self.tagdata.keys():
238
 
            items.append((tag, self[tag]))
239
 
        return items
240
 
 
241
 
    def __len__(self):
242
 
        return len(self.tagdata) + len(self.tags)
243
 
 
244
 
    def __getitem__(self, tag):
245
 
        try:
246
 
            return self.tags[tag]
247
 
        except KeyError:
248
 
            type, data = self.tagdata[tag] # unpack on the fly
249
 
            size, handler = self.load_dispatch[type]
250
 
            self.tags[tag] = data = handler(self, data)
251
 
            del self.tagdata[tag]
252
 
            return data
253
 
 
254
 
    def get(self, tag, default=None):
255
 
        try:
256
 
            return self[tag]
257
 
        except KeyError:
258
 
            return default
259
 
 
260
 
    def getscalar(self, tag, default=None):
261
 
        try:
262
 
            value = self[tag]
263
 
            if len(value) != 1:
264
 
                if tag == SAMPLEFORMAT:
265
 
                    # work around broken (?) matrox library
266
 
                    # (from Ted Wright, via Bob Klimek)
267
 
                    raise KeyError # use default
268
 
                raise ValueError, "not a scalar"
269
 
            return value[0]
270
 
        except KeyError:
271
 
            if default is None:
272
 
                raise
273
 
            return default
274
 
 
275
 
    def has_key(self, tag):
276
 
        return self.tags.has_key(tag) or self.tagdata.has_key(tag)
277
 
 
278
 
    def __setitem__(self, tag, value):
279
 
        if type(value) is not type(()):
280
 
            value = (value,)
281
 
        self.tags[tag] = value
282
 
 
283
 
    # load primitives
284
 
 
285
 
    load_dispatch = {}
286
 
 
287
 
    def load_byte(self, data):
288
 
        l = []
289
 
        for i in range(len(data)):
290
 
            l.append(ord(data[i]))
291
 
        return tuple(l)
292
 
    load_dispatch[1] = (1, load_byte)
293
 
 
294
 
    def load_string(self, data):
295
 
        if data[-1:] == '\0':
296
 
            data = data[:-1]
297
 
        return data
298
 
    load_dispatch[2] = (1, load_string)
299
 
 
300
 
    def load_short(self, data):
301
 
        l = []
302
 
        for i in range(0, len(data), 2):
303
 
            l.append(self.i16(data, i))
304
 
        return tuple(l)
305
 
    load_dispatch[3] = (2, load_short)
306
 
 
307
 
    def load_long(self, data):
308
 
        l = []
309
 
        for i in range(0, len(data), 4):
310
 
            l.append(self.i32(data, i))
311
 
        return tuple(l)
312
 
    load_dispatch[4] = (4, load_long)
313
 
 
314
 
    def load_rational(self, data):
315
 
        l = []
316
 
        for i in range(0, len(data), 8):
317
 
            l.append((self.i32(data, i), self.i32(data, i+4)))
318
 
        return tuple(l)
319
 
    load_dispatch[5] = (8, load_rational)
320
 
 
321
 
    def load_float(self, data):
322
 
        a = array.array("f", data)
323
 
        if self.prefix != native_prefix:
324
 
            a.byteswap()
325
 
        return tuple(a)
326
 
    load_dispatch[11] = (4, load_float)
327
 
 
328
 
    def load_double(self, data):
329
 
        a = array.array("d", data)
330
 
        if self.prefix != native_prefix:
331
 
            a.byteswap()
332
 
        return tuple(a)
333
 
    load_dispatch[12] = (8, load_double)
334
 
 
335
 
    def load_undefined(self, data):
336
 
        # Untyped data
337
 
        return data
338
 
    load_dispatch[7] = (1, load_undefined)
339
 
 
340
 
    def load(self, fp):
341
 
        # load tag dictionary
342
 
 
343
 
        self.reset()
344
 
 
345
 
        i16 = self.i16
346
 
        i32 = self.i32
347
 
 
348
 
        for i in range(i16(fp.read(2))):
349
 
 
350
 
            ifd = fp.read(12)
351
 
 
352
 
            tag, typ = i16(ifd), i16(ifd, 2)
353
 
 
354
 
            if Image.DEBUG:
355
 
                import TiffTags
356
 
                tagname = TiffTags.TAGS.get(tag, "unknown")
357
 
                typname = TiffTags.TYPES.get(typ, "unknown")
358
 
                print "tag: %s (%d)" % (tagname, tag),
359
 
                print "- type: %s (%d)" % (typname, typ),
360
 
 
361
 
            try:
362
 
                dispatch = self.load_dispatch[typ]
363
 
            except KeyError:
364
 
                if Image.DEBUG:
365
 
                    print "- unsupported type", typ
366
 
                continue # ignore unsupported type
367
 
 
368
 
            size, handler = dispatch
369
 
 
370
 
            size = size * i32(ifd, 4)
371
 
 
372
 
            # Get and expand tag value
373
 
            if size > 4:
374
 
                here = fp.tell()
375
 
                fp.seek(i32(ifd, 8))
376
 
                data = ImageFile._safe_read(fp, size)
377
 
                fp.seek(here)
378
 
            else:
379
 
                data = ifd[8:8+size]
380
 
 
381
 
            if len(data) != size:
382
 
                raise IOError, "not enough data"
383
 
 
384
 
            self.tagdata[tag] = typ, data
385
 
            self.tagtype[tag] = typ
386
 
 
387
 
            if Image.DEBUG:
388
 
                if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
389
 
                    print "- value: <table: %d bytes>" % size
390
 
                else:
391
 
                    print "- value:", self[tag]
392
 
 
393
 
        self.next = i32(fp.read(4))
394
 
 
395
 
    # save primitives
396
 
 
397
 
    def save(self, fp):
398
 
 
399
 
        o16 = self.o16
400
 
        o32 = self.o32
401
 
 
402
 
        fp.write(o16(len(self.tags)))
403
 
 
404
 
        # always write in ascending tag order
405
 
        tags = self.tags.items()
406
 
        tags.sort()
407
 
 
408
 
        directory = []
409
 
        append = directory.append
410
 
 
411
 
        offset = fp.tell() + len(self.tags) * 12 + 4
412
 
 
413
 
        stripoffsets = None
414
 
 
415
 
        # pass 1: convert tags to binary format
416
 
        for tag, value in tags:
417
 
 
418
 
            typ = None
419
 
 
420
 
            if self.tagtype.has_key(tag):
421
 
                typ = self.tagtype[tag]
422
 
 
423
 
            if typ == 1:
424
 
                # byte data
425
 
                data = value = string.join(map(chr, value), "")
426
 
            elif typ == 7:
427
 
                # untyped data
428
 
                data = value = string.join(value, "")
429
 
            elif type(value[0]) is type(""):
430
 
                # string data
431
 
                typ = 2
432
 
                data = value = string.join(value, "\0") + "\0"
433
 
            else:
434
 
                # integer data
435
 
                if tag == STRIPOFFSETS:
436
 
                    stripoffsets = len(directory)
437
 
                    typ = 4 # to avoid catch-22
438
 
                elif tag in (X_RESOLUTION, Y_RESOLUTION):
439
 
                    # identify rational data fields
440
 
                    typ = 5
441
 
                elif not typ:
442
 
                    typ = 3
443
 
                    for v in value:
444
 
                        if v >= 65536:
445
 
                            typ = 4
446
 
                if typ == 3:
447
 
                    data = string.join(map(o16, value), "")
448
 
                else:
449
 
                    data = string.join(map(o32, value), "")
450
 
 
451
 
            if Image.DEBUG:
452
 
                import TiffTags
453
 
                tagname = TiffTags.TAGS.get(tag, "unknown")
454
 
                typname = TiffTags.TYPES.get(typ, "unknown")
455
 
                print "save: %s (%d)" % (tagname, tag),
456
 
                print "- type: %s (%d)" % (typname, typ),
457
 
                if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
458
 
                    size = len(data)
459
 
                    print "- value: <table: %d bytes>" % size
460
 
                else:
461
 
                    print "- value:", value
462
 
 
463
 
            # figure out if data fits into the directory
464
 
            if len(data) == 4:
465
 
                append((tag, typ, len(value), data, ""))
466
 
            elif len(data) < 4:
467
 
                append((tag, typ, len(value), data + (4-len(data))*"\0", ""))
468
 
            else:
469
 
                count = len(value)
470
 
                if typ == 5:
471
 
                    count = count / 2        # adjust for rational data field
472
 
                append((tag, typ, count, o32(offset), data))
473
 
                offset = offset + len(data)
474
 
                if offset & 1:
475
 
                    offset = offset + 1 # word padding
476
 
 
477
 
        # update strip offset data to point beyond auxiliary data
478
 
        if stripoffsets is not None:
479
 
            tag, typ, count, value, data = directory[stripoffsets]
480
 
            assert not data, "multistrip support not yet implemented"
481
 
            value = o32(self.i32(value) + offset)
482
 
            directory[stripoffsets] = tag, typ, count, value, data
483
 
 
484
 
        # pass 2: write directory to file
485
 
        for tag, typ, count, value, data in directory:
486
 
            if Image.DEBUG > 1:
487
 
                print tag, typ, count, repr(value), repr(data)
488
 
            fp.write(o16(tag) + o16(typ) + o32(count) + value)
489
 
 
490
 
        # -- overwrite here for multi-page --
491
 
        fp.write("\0\0\0\0") # end of directory
492
 
 
493
 
        # pass 3: write auxiliary data to file
494
 
        for tag, typ, count, value, data in directory:
495
 
            fp.write(data)
496
 
            if len(data) & 1:
497
 
                fp.write("\0")
498
 
 
499
 
        return offset
500
 
 
501
 
##
502
 
# Image plugin for TIFF files.
503
 
 
504
 
class TiffImageFile(ImageFile.ImageFile):
505
 
 
506
 
    format = "TIFF"
507
 
    format_description = "Adobe TIFF"
508
 
 
509
 
    def _open(self):
510
 
        "Open the first image in a TIFF file"
511
 
 
512
 
        # Header
513
 
        ifh = self.fp.read(8)
514
 
 
515
 
        if ifh[:4] not in PREFIXES:
516
 
            raise SyntaxError, "not a TIFF file"
517
 
 
518
 
        # image file directory (tag dictionary)
519
 
        self.tag = self.ifd = ImageFileDirectory(ifh[:2])
520
 
 
521
 
        # setup frame pointers
522
 
        self.__first = self.__next = self.ifd.i32(ifh, 4)
523
 
        self.__frame = -1
524
 
        self.__fp = self.fp
525
 
 
526
 
        # and load the first frame
527
 
        self._seek(0)
528
 
 
529
 
    def seek(self, frame):
530
 
        "Select a given frame as current image"
531
 
 
532
 
        if frame < 0:
533
 
            frame = 0
534
 
        self._seek(frame)
535
 
 
536
 
    def tell(self):
537
 
        "Return the current frame number"
538
 
 
539
 
        return self._tell()
540
 
 
541
 
    def _seek(self, frame):
542
 
 
543
 
        self.fp = self.__fp
544
 
        if frame < self.__frame:
545
 
            # rewind file
546
 
            self.__frame = -1
547
 
            self.__next = self.__first
548
 
        while self.__frame < frame:
549
 
            if not self.__next:
550
 
                raise EOFError, "no more images in TIFF file"
551
 
            self.fp.seek(self.__next)
552
 
            self.tag.load(self.fp)
553
 
            self.__next = self.tag.next
554
 
            self.__frame = self.__frame + 1
555
 
        self._setup()
556
 
 
557
 
    def _tell(self):
558
 
 
559
 
        return self.__frame
560
 
 
561
 
    def _decoder(self, rawmode, layer):
562
 
        "Setup decoder contexts"
563
 
 
564
 
        args = None
565
 
        if rawmode == "RGB" and self._planar_configuration == 2:
566
 
            rawmode = rawmode[layer]
567
 
        compression = self._compression
568
 
        if compression == "raw":
569
 
            args = (rawmode, 0, 1)
570
 
        elif compression == "jpeg":
571
 
            args = rawmode, ""
572
 
            if self.tag.has_key(JPEGTABLES):
573
 
                # Hack to handle abbreviated JPEG headers
574
 
                self.tile_prefix = self.tag[JPEGTABLES]
575
 
        elif compression == "packbits":
576
 
            args = rawmode
577
 
        elif compression == "tiff_lzw":
578
 
            args = rawmode
579
 
            if self.tag.has_key(317):
580
 
                # Section 14: Differencing Predictor
581
 
                self.decoderconfig = (self.tag[PREDICTOR][0],)
582
 
 
583
 
        if self.tag.has_key(ICCPROFILE):
584
 
            self.info['icc_profile'] = self.tag[ICCPROFILE]
585
 
 
586
 
        return args
587
 
 
588
 
    def _setup(self):
589
 
        "Setup this image object based on current tags"
590
 
 
591
 
        if self.tag.has_key(0xBC01):
592
 
            raise IOError, "Windows Media Photo files not yet supported"
593
 
 
594
 
        getscalar = self.tag.getscalar
595
 
 
596
 
        # extract relevant tags
597
 
        self._compression = COMPRESSION_INFO[getscalar(COMPRESSION, 1)]
598
 
        self._planar_configuration = getscalar(PLANAR_CONFIGURATION, 1)
599
 
 
600
 
        # photometric is a required tag, but not everyone is reading
601
 
        # the specification
602
 
        photo = getscalar(PHOTOMETRIC_INTERPRETATION, 0)
603
 
 
604
 
        fillorder = getscalar(FILLORDER, 1)
605
 
 
606
 
        if Image.DEBUG:
607
 
            print "*** Summary ***"
608
 
            print "- compression:", self._compression
609
 
            print "- photometric_interpretation:", photo
610
 
            print "- planar_configuration:", self._planar_configuration
611
 
            print "- fill_order:", fillorder
612
 
 
613
 
        # size
614
 
        xsize = getscalar(IMAGEWIDTH)
615
 
        ysize = getscalar(IMAGELENGTH)
616
 
        self.size = xsize, ysize
617
 
 
618
 
        if Image.DEBUG:
619
 
            print "- size:", self.size
620
 
 
621
 
        format = getscalar(SAMPLEFORMAT, 1)
622
 
 
623
 
        # mode: check photometric interpretation and bits per pixel
624
 
        key = (
625
 
            self.tag.prefix, photo, format, fillorder,
626
 
            self.tag.get(BITSPERSAMPLE, (1,)),
627
 
            self.tag.get(EXTRASAMPLES, ())
628
 
            )
629
 
        if Image.DEBUG:
630
 
            print "format key:", key
631
 
        try:
632
 
            self.mode, rawmode = OPEN_INFO[key]
633
 
        except KeyError:
634
 
            if Image.DEBUG:
635
 
                print "- unsupported format"
636
 
            raise SyntaxError, "unknown pixel mode"
637
 
 
638
 
        if Image.DEBUG:
639
 
            print "- raw mode:", rawmode
640
 
            print "- pil mode:", self.mode
641
 
 
642
 
        self.info["compression"] = self._compression
643
 
 
644
 
        xres = getscalar(X_RESOLUTION, (1, 1))
645
 
        yres = getscalar(Y_RESOLUTION, (1, 1))
646
 
 
647
 
        if xres and yres:
648
 
            xres = xres[0] / (xres[1] or 1)
649
 
            yres = yres[0] / (yres[1] or 1)
650
 
            resunit = getscalar(RESOLUTION_UNIT, 1)
651
 
            if resunit == 2: # dots per inch
652
 
                self.info["dpi"] = xres, yres
653
 
            elif resunit == 3: # dots per centimeter. convert to dpi
654
 
                self.info["dpi"] = xres * 2.54, yres * 2.54
655
 
            else: # No absolute unit of measurement
656
 
                self.info["resolution"] = xres, yres
657
 
 
658
 
        # build tile descriptors
659
 
        x = y = l = 0
660
 
        self.tile = []
661
 
        if self.tag.has_key(STRIPOFFSETS):
662
 
            # striped image
663
 
            h = getscalar(ROWSPERSTRIP, ysize)
664
 
            w = self.size[0]
665
 
            a = None
666
 
            for o in self.tag[STRIPOFFSETS]:
667
 
                if not a:
668
 
                    a = self._decoder(rawmode, l)
669
 
                self.tile.append(
670
 
                    (self._compression,
671
 
                    (0, min(y, ysize), w, min(y+h, ysize)),
672
 
                    o, a))
673
 
                y = y + h
674
 
                if y >= self.size[1]:
675
 
                    x = y = 0
676
 
                    l = l + 1
677
 
                    a = None
678
 
        elif self.tag.has_key(TILEOFFSETS):
679
 
            # tiled image
680
 
            w = getscalar(322)
681
 
            h = getscalar(323)
682
 
            a = None
683
 
            for o in self.tag[TILEOFFSETS]:
684
 
                if not a:
685
 
                    a = self._decoder(rawmode, l)
686
 
                # FIXME: this doesn't work if the image size
687
 
                # is not a multiple of the tile size...
688
 
                self.tile.append(
689
 
                    (self._compression,
690
 
                    (x, y, x+w, y+h),
691
 
                    o, a))
692
 
                x = x + w
693
 
                if x >= self.size[0]:
694
 
                    x, y = 0, y + h
695
 
                    if y >= self.size[1]:
696
 
                        x = y = 0
697
 
                        l = l + 1
698
 
                        a = None
699
 
        else:
700
 
            if Image.DEBUG:
701
 
                print "- unsupported data organization"
702
 
            raise SyntaxError("unknown data organization")
703
 
 
704
 
        # fixup palette descriptor
705
 
 
706
 
        if self.mode == "P":
707
 
            palette = map(lambda a: chr(a / 256), self.tag[COLORMAP])
708
 
            self.palette = ImagePalette.raw("RGB;L", string.join(palette, ""))
709
 
#
710
 
# --------------------------------------------------------------------
711
 
# Write TIFF files
712
 
 
713
 
# little endian is default except for image modes with explict big endian byte-order
714
 
 
715
 
SAVE_INFO = {
716
 
    # mode => rawmode, byteorder, photometrics, sampleformat, bitspersample, extra
717
 
    "1": ("1", II, 1, 1, (1,), None),
718
 
    "L": ("L", II, 1, 1, (8,), None),
719
 
    "LA": ("LA", II, 1, 1, (8,8), 2),
720
 
    "P": ("P", II, 3, 1, (8,), None),
721
 
    "PA": ("PA", II, 3, 1, (8,8), 2),
722
 
    "I": ("I;32S", II, 1, 2, (32,), None),
723
 
    "I;16": ("I;16", II, 1, 1, (16,), None),
724
 
    "I;16S": ("I;16S", II, 1, 2, (16,), None),
725
 
    "F": ("F;32F", II, 1, 3, (32,), None),
726
 
    "RGB": ("RGB", II, 2, 1, (8,8,8), None),
727
 
    "RGBX": ("RGBX", II, 2, 1, (8,8,8,8), 0),
728
 
    "RGBA": ("RGBA", II, 2, 1, (8,8,8,8), 2),
729
 
    "CMYK": ("CMYK", II, 5, 1, (8,8,8,8), None),
730
 
    "YCbCr": ("YCbCr", II, 6, 1, (8,8,8), None),
731
 
    "LAB": ("LAB", II, 8, 1, (8,8,8), None),
732
 
 
733
 
    "I;32BS": ("I;32BS", MM, 1, 2, (32,), None),
734
 
    "I;16B": ("I;16B", MM, 1, 1, (16,), None),
735
 
    "I;16BS": ("I;16BS", MM, 1, 2, (16,), None),
736
 
    "F;32BF": ("F;32BF", MM, 1, 3, (32,), None),
737
 
}
738
 
 
739
 
def _cvt_res(value):
740
 
    # convert value to TIFF rational number -- (numerator, denominator)
741
 
    if type(value) in (type([]), type(())):
742
 
        assert(len(value) % 2 == 0)
743
 
        return value
744
 
    if type(value) == type(1):
745
 
        return (value, 1)
746
 
    value = float(value)
747
 
    return (int(value * 65536), 65536)
748
 
 
749
 
def _save(im, fp, filename):
750
 
 
751
 
    try:
752
 
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
753
 
    except KeyError:
754
 
        raise IOError, "cannot write mode %s as TIFF" % im.mode
755
 
 
756
 
    ifd = ImageFileDirectory(prefix)
757
 
 
758
 
    # -- multi-page -- skip TIFF header on subsequent pages
759
 
    if fp.tell() == 0:
760
 
        # tiff header (write via IFD to get everything right)
761
 
        # PIL always starts the first IFD at offset 8
762
 
        fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))
763
 
 
764
 
    ifd[IMAGEWIDTH] = im.size[0]
765
 
    ifd[IMAGELENGTH] = im.size[1]
766
 
 
767
 
    # additions written by Greg Couch, gregc@cgl.ucsf.edu
768
 
    # inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
769
 
    if hasattr(im, 'tag'):
770
 
        # preserve tags from original TIFF image file
771
 
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION):
772
 
            if im.tag.tagdata.has_key(key):
773
 
                ifd[key] = im.tag.tagdata.get(key)
774
 
        # preserve some more tags from original TIFF image file
775
 
        # -- 2008-06-06 Florian Hoech
776
 
        ifd.tagtype = im.tag.tagtype
777
 
        for key in (IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
778
 
            if im.tag.has_key(key):
779
 
                ifd[key] = im.tag[key]
780
 
        # preserve ICC profile (should also work when saving other formats
781
 
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
782
 
        if im.info.has_key("icc_profile"):
783
 
            ifd[ICCPROFILE] = im.info["icc_profile"]
784
 
    if im.encoderinfo.has_key("description"):
785
 
        ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
786
 
    if im.encoderinfo.has_key("resolution"):
787
 
        ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
788
 
                                = _cvt_res(im.encoderinfo["resolution"])
789
 
    if im.encoderinfo.has_key("x resolution"):
790
 
        ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
791
 
    if im.encoderinfo.has_key("y resolution"):
792
 
        ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
793
 
    if im.encoderinfo.has_key("resolution unit"):
794
 
        unit = im.encoderinfo["resolution unit"]
795
 
        if unit == "inch":
796
 
            ifd[RESOLUTION_UNIT] = 2
797
 
        elif unit == "cm" or unit == "centimeter":
798
 
            ifd[RESOLUTION_UNIT] = 3
799
 
        else:
800
 
            ifd[RESOLUTION_UNIT] = 1
801
 
    if im.encoderinfo.has_key("software"):
802
 
        ifd[SOFTWARE] = im.encoderinfo["software"]
803
 
    if im.encoderinfo.has_key("date time"):
804
 
        ifd[DATE_TIME] = im.encoderinfo["date time"]
805
 
    if im.encoderinfo.has_key("artist"):
806
 
        ifd[ARTIST] = im.encoderinfo["artist"]
807
 
    if im.encoderinfo.has_key("copyright"):
808
 
        ifd[COPYRIGHT] = im.encoderinfo["copyright"]
809
 
 
810
 
    dpi = im.encoderinfo.get("dpi")
811
 
    if dpi:
812
 
        ifd[RESOLUTION_UNIT] = 2
813
 
        ifd[X_RESOLUTION] = _cvt_res(dpi[0])
814
 
        ifd[Y_RESOLUTION] = _cvt_res(dpi[1])
815
 
 
816
 
    if bits != (1,):
817
 
        ifd[BITSPERSAMPLE] = bits
818
 
        if len(bits) != 1:
819
 
            ifd[SAMPLESPERPIXEL] = len(bits)
820
 
    if extra is not None:
821
 
        ifd[EXTRASAMPLES] = extra
822
 
    if format != 1:
823
 
        ifd[SAMPLEFORMAT] = format
824
 
 
825
 
    ifd[PHOTOMETRIC_INTERPRETATION] = photo
826
 
 
827
 
    if im.mode == "P":
828
 
        lut = im.im.getpalette("RGB", "RGB;L")
829
 
        ifd[COLORMAP] = tuple(map(lambda v: ord(v) * 256, lut))
830
 
 
831
 
    # data orientation
832
 
    stride = len(bits) * ((im.size[0]*bits[0]+7)/8)
833
 
    ifd[ROWSPERSTRIP] = im.size[1]
834
 
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
835
 
    ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
836
 
    ifd[COMPRESSION] = 1 # no compression
837
 
 
838
 
    offset = ifd.save(fp)
839
 
 
840
 
    ImageFile._save(im, fp, [
841
 
        ("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
842
 
        ])
843
 
 
844
 
 
845
 
    # -- helper for multi-page save --
846
 
    if im.encoderinfo.has_key("_debug_multipage"):
847
 
        #just to access o32 and o16 (using correct byte order)
848
 
        im._debug_multipage = ifd
849
 
 
850
 
#
851
 
# --------------------------------------------------------------------
852
 
# Register
853
 
 
854
 
Image.register_open("TIFF", TiffImageFile, _accept)
855
 
Image.register_save("TIFF", _save)
856
 
 
857
 
Image.register_extension("TIFF", ".tif")
858
 
Image.register_extension("TIFF", ".tiff")
859
 
 
860
 
Image.register_mime("TIFF", "image/tiff")