2
# The Python Imaging Library.
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.
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.
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)
36
# Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved.
37
# Copyright (c) 1995-1997 by Fredrik Lundh
39
# See the README file for information on usage and redistribution.
44
import Image, ImageFile
47
import array, string, sys
49
II = "II" # little-endian (intel-style)
50
MM = "MM" # big-endian (motorola-style)
53
if sys.byteorder == "little":
57
except AttributeError:
58
if ord(array.array("i",[1]).tostring()[0]):
64
# --------------------------------------------------------------------
68
return ord(c[o]) + (ord(c[o+1])<<8)
70
return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24)
72
return chr(i&255) + chr(i>>8&255)
74
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
77
return ord(c[o+1]) + (ord(c[o])<<8)
79
return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
81
return chr(i>>8&255) + chr(i&255)
83
return chr(i>>24&255) + chr(i>>16&255) + chr(i>>8&255) + chr(i&255)
85
# a few tag names, just to make the code below a bit more readable
90
PHOTOMETRIC_INTERPRETATION = 262
92
IMAGEDESCRIPTION = 270
99
PLANAR_CONFIGURATION = 284
100
RESOLUTION_UNIT = 296
111
IPTC_NAA_CHUNK = 33723 # newsphoto properties
112
PHOTOSHOP_CHUNK = 34377 # photoshop properties
118
# Compression => pil compression name
124
6: "tiff_jpeg", # obsolete
126
32771: "tiff_raw_16", # 16-bit padding
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"),
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"),
199
PREFIXES = ["MM\000\052", "II\052\000", "II\xBC\000"]
202
return prefix[:4] in PREFIXES
205
# Wrapper for TIFF IFDs.
207
class ImageFileDirectory:
209
# represents a TIFF tag directory. to speed things up,
210
# we don't decode tags unless they're asked for.
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
221
raise SyntaxError("not a TIFF IFD")
227
self.tagtype = {} # added 2008-06-05 by Florian Hoech
230
# dictionary API (sort of)
233
return self.tagdata.keys() + self.tags.keys()
236
items = self.tags.items()
237
for tag in self.tagdata.keys():
238
items.append((tag, self[tag]))
242
return len(self.tagdata) + len(self.tags)
244
def __getitem__(self, tag):
246
return self.tags[tag]
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]
254
def get(self, tag, default=None):
260
def getscalar(self, tag, default=None):
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"
275
def has_key(self, tag):
276
return self.tags.has_key(tag) or self.tagdata.has_key(tag)
278
def __setitem__(self, tag, value):
279
if type(value) is not type(()):
281
self.tags[tag] = value
287
def load_byte(self, data):
289
for i in range(len(data)):
290
l.append(ord(data[i]))
292
load_dispatch[1] = (1, load_byte)
294
def load_string(self, data):
295
if data[-1:] == '\0':
298
load_dispatch[2] = (1, load_string)
300
def load_short(self, data):
302
for i in range(0, len(data), 2):
303
l.append(self.i16(data, i))
305
load_dispatch[3] = (2, load_short)
307
def load_long(self, data):
309
for i in range(0, len(data), 4):
310
l.append(self.i32(data, i))
312
load_dispatch[4] = (4, load_long)
314
def load_rational(self, data):
316
for i in range(0, len(data), 8):
317
l.append((self.i32(data, i), self.i32(data, i+4)))
319
load_dispatch[5] = (8, load_rational)
321
def load_float(self, data):
322
a = array.array("f", data)
323
if self.prefix != native_prefix:
326
load_dispatch[11] = (4, load_float)
328
def load_double(self, data):
329
a = array.array("d", data)
330
if self.prefix != native_prefix:
333
load_dispatch[12] = (8, load_double)
335
def load_undefined(self, data):
338
load_dispatch[7] = (1, load_undefined)
341
# load tag dictionary
348
for i in range(i16(fp.read(2))):
352
tag, typ = i16(ifd), i16(ifd, 2)
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),
362
dispatch = self.load_dispatch[typ]
365
print "- unsupported type", typ
366
continue # ignore unsupported type
368
size, handler = dispatch
370
size = size * i32(ifd, 4)
372
# Get and expand tag value
376
data = ImageFile._safe_read(fp, size)
381
if len(data) != size:
382
raise IOError, "not enough data"
384
self.tagdata[tag] = typ, data
385
self.tagtype[tag] = typ
388
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
389
print "- value: <table: %d bytes>" % size
391
print "- value:", self[tag]
393
self.next = i32(fp.read(4))
402
fp.write(o16(len(self.tags)))
404
# always write in ascending tag order
405
tags = self.tags.items()
409
append = directory.append
411
offset = fp.tell() + len(self.tags) * 12 + 4
415
# pass 1: convert tags to binary format
416
for tag, value in tags:
420
if self.tagtype.has_key(tag):
421
typ = self.tagtype[tag]
425
data = value = string.join(map(chr, value), "")
428
data = value = string.join(value, "")
429
elif type(value[0]) is type(""):
432
data = value = string.join(value, "\0") + "\0"
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
447
data = string.join(map(o16, value), "")
449
data = string.join(map(o32, value), "")
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):
459
print "- value: <table: %d bytes>" % size
461
print "- value:", value
463
# figure out if data fits into the directory
465
append((tag, typ, len(value), data, ""))
467
append((tag, typ, len(value), data + (4-len(data))*"\0", ""))
471
count = count / 2 # adjust for rational data field
472
append((tag, typ, count, o32(offset), data))
473
offset = offset + len(data)
475
offset = offset + 1 # word padding
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
484
# pass 2: write directory to file
485
for tag, typ, count, value, data in directory:
487
print tag, typ, count, repr(value), repr(data)
488
fp.write(o16(tag) + o16(typ) + o32(count) + value)
490
# -- overwrite here for multi-page --
491
fp.write("\0\0\0\0") # end of directory
493
# pass 3: write auxiliary data to file
494
for tag, typ, count, value, data in directory:
502
# Image plugin for TIFF files.
504
class TiffImageFile(ImageFile.ImageFile):
507
format_description = "Adobe TIFF"
510
"Open the first image in a TIFF file"
513
ifh = self.fp.read(8)
515
if ifh[:4] not in PREFIXES:
516
raise SyntaxError, "not a TIFF file"
518
# image file directory (tag dictionary)
519
self.tag = self.ifd = ImageFileDirectory(ifh[:2])
521
# setup frame pointers
522
self.__first = self.__next = self.ifd.i32(ifh, 4)
526
# and load the first frame
529
def seek(self, frame):
530
"Select a given frame as current image"
537
"Return the current frame number"
541
def _seek(self, frame):
544
if frame < self.__frame:
547
self.__next = self.__first
548
while self.__frame < frame:
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
561
def _decoder(self, rawmode, layer):
562
"Setup decoder contexts"
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":
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":
577
elif compression == "tiff_lzw":
579
if self.tag.has_key(317):
580
# Section 14: Differencing Predictor
581
self.decoderconfig = (self.tag[PREDICTOR][0],)
583
if self.tag.has_key(ICCPROFILE):
584
self.info['icc_profile'] = self.tag[ICCPROFILE]
589
"Setup this image object based on current tags"
591
if self.tag.has_key(0xBC01):
592
raise IOError, "Windows Media Photo files not yet supported"
594
getscalar = self.tag.getscalar
596
# extract relevant tags
597
self._compression = COMPRESSION_INFO[getscalar(COMPRESSION, 1)]
598
self._planar_configuration = getscalar(PLANAR_CONFIGURATION, 1)
600
# photometric is a required tag, but not everyone is reading
602
photo = getscalar(PHOTOMETRIC_INTERPRETATION, 0)
604
fillorder = getscalar(FILLORDER, 1)
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
614
xsize = getscalar(IMAGEWIDTH)
615
ysize = getscalar(IMAGELENGTH)
616
self.size = xsize, ysize
619
print "- size:", self.size
621
format = getscalar(SAMPLEFORMAT, 1)
623
# mode: check photometric interpretation and bits per pixel
625
self.tag.prefix, photo, format, fillorder,
626
self.tag.get(BITSPERSAMPLE, (1,)),
627
self.tag.get(EXTRASAMPLES, ())
630
print "format key:", key
632
self.mode, rawmode = OPEN_INFO[key]
635
print "- unsupported format"
636
raise SyntaxError, "unknown pixel mode"
639
print "- raw mode:", rawmode
640
print "- pil mode:", self.mode
642
self.info["compression"] = self._compression
644
xres = getscalar(X_RESOLUTION, (1, 1))
645
yres = getscalar(Y_RESOLUTION, (1, 1))
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
658
# build tile descriptors
661
if self.tag.has_key(STRIPOFFSETS):
663
h = getscalar(ROWSPERSTRIP, ysize)
666
for o in self.tag[STRIPOFFSETS]:
668
a = self._decoder(rawmode, l)
671
(0, min(y, ysize), w, min(y+h, ysize)),
674
if y >= self.size[1]:
678
elif self.tag.has_key(TILEOFFSETS):
683
for o in self.tag[TILEOFFSETS]:
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...
693
if x >= self.size[0]:
695
if y >= self.size[1]:
701
print "- unsupported data organization"
702
raise SyntaxError("unknown data organization")
704
# fixup palette descriptor
707
palette = map(lambda a: chr(a / 256), self.tag[COLORMAP])
708
self.palette = ImagePalette.raw("RGB;L", string.join(palette, ""))
710
# --------------------------------------------------------------------
713
# little endian is default except for image modes with explict big endian byte-order
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),
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),
740
# convert value to TIFF rational number -- (numerator, denominator)
741
if type(value) in (type([]), type(())):
742
assert(len(value) % 2 == 0)
744
if type(value) == type(1):
747
return (int(value * 65536), 65536)
749
def _save(im, fp, filename):
752
rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
754
raise IOError, "cannot write mode %s as TIFF" % im.mode
756
ifd = ImageFileDirectory(prefix)
758
# -- multi-page -- skip TIFF header on subsequent pages
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))
764
ifd[IMAGEWIDTH] = im.size[0]
765
ifd[IMAGELENGTH] = im.size[1]
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"]
796
ifd[RESOLUTION_UNIT] = 2
797
elif unit == "cm" or unit == "centimeter":
798
ifd[RESOLUTION_UNIT] = 3
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"]
810
dpi = im.encoderinfo.get("dpi")
812
ifd[RESOLUTION_UNIT] = 2
813
ifd[X_RESOLUTION] = _cvt_res(dpi[0])
814
ifd[Y_RESOLUTION] = _cvt_res(dpi[1])
817
ifd[BITSPERSAMPLE] = bits
819
ifd[SAMPLESPERPIXEL] = len(bits)
820
if extra is not None:
821
ifd[EXTRASAMPLES] = extra
823
ifd[SAMPLEFORMAT] = format
825
ifd[PHOTOMETRIC_INTERPRETATION] = photo
828
lut = im.im.getpalette("RGB", "RGB;L")
829
ifd[COLORMAP] = tuple(map(lambda v: ord(v) * 256, lut))
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
838
offset = ifd.save(fp)
840
ImageFile._save(im, fp, [
841
("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
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
851
# --------------------------------------------------------------------
854
Image.register_open("TIFF", TiffImageFile, _accept)
855
Image.register_save("TIFF", _save)
857
Image.register_extension("TIFF", ".tif")
858
Image.register_extension("TIFF", ".tiff")
860
Image.register_mime("TIFF", "image/tiff")