1
# Patched version to fix dpi problem, see the python image-sig mailing list:
2
# http://www.mail-archive.com/image-sig@python.org/msg01572.html
3
# Two patches: see line 580 & 732
5
# The Python Imaging Library (PIL) is
7
# Copyright (c) 1997-2006 by Secret Labs AB
8
# Copyright (c) 1995-2006 by Fredrik Lundh
10
# By obtaining, using, and/or copying this software and/or its associated
11
# documentation, you agree that you have read, understood, and will comply with
12
# the following terms and conditions:
14
# Permission to use, copy, modify, and distribute this software and its
15
# associated documentation for any purpose and without fee is hereby granted,
16
# provided that the above copyright notice appears in all copies, and that both
17
# that copyright notice and this permission notice appear in supporting
18
# documentation, and that the name of Secret Labs AB or the author not be used
19
# in advertising or publicity pertaining to distribution of the software
20
# without specific, written prior permission.
22
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
23
# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
24
# IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
25
# INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
26
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
27
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28
# PERFORMANCE OF THIS SOFTWARE.
30
# http://www.pythonware.com/products/pil/license.htm
32
# The Python Imaging Library.
33
# $Id: TiffImagePlugin.py 2803 2006-07-31 19:18:57Z fredrik $
37
# TIFF is a flexible, if somewhat aged, image file format originally
38
# defined by Aldus. Although TIFF supports a wide variety of pixel
39
# layouts and compression methods, the name doesn't really stand for
40
# "thousands of incompatible file formats," it just feels that way.
42
# To read TIFF data from a stream, the stream must be seekable. For
43
# progressive decoding, make sure to use TIFF files where the tag
44
# directory is placed first in the file.
47
# 1995-09-01 fl Created
48
# 1996-05-04 fl Handle JPEGTABLES tag
49
# 1996-05-18 fl Fixed COLORMAP support
50
# 1997-01-05 fl Fixed PREDICTOR support
51
# 1997-08-27 fl Added support for rational tags (from Perry Stoll)
52
# 1998-01-10 fl Fixed seek/tell (from Jan Blom)
53
# 1998-07-15 fl Use private names for internal variables
54
# 1999-06-13 fl Rewritten for PIL 1.0 (1.0)
55
# 2000-10-11 fl Additional fixes for Python 2.0 (1.1)
56
# 2001-04-17 fl Fixed rewind support (seek to frame 0) (1.2)
57
# 2001-05-12 fl Added write support for more tags (from Greg Couch) (1.3)
58
# 2001-12-18 fl Added workaround for broken Matrox library
59
# 2002-01-18 fl Don't mess up if photometric tag is missing (D. Alan Stewart)
60
# 2003-05-19 fl Check FILLORDER tag
61
# 2003-09-26 fl Added RGBa support
62
# 2004-02-24 fl Added DPI support; fixed rational write support
63
# 2005-02-07 fl Added workaround for broken Corel Draw 10 files
64
# 2006-01-09 fl Added support for float/double tags (from Russell Nelson)
66
# Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved.
67
# Copyright (c) 1995-1997 by Fredrik Lundh
69
# See the README file for information on usage and redistribution.
74
import Image, ImageFile
77
import array, string, sys
80
if sys.byteorder == "little":
84
except AttributeError:
85
if ord(array.array("i",[1]).tostring()[0]):
91
# --------------------------------------------------------------------
95
return ord(c[o]) + (ord(c[o+1])<<8)
97
return ord(c[o]) + (ord(c[o+1])<<8) + (ord(c[o+2])<<16) + (ord(c[o+3])<<24)
99
return chr(i&255) + chr(i>>8&255)
101
return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
104
return ord(c[o+1]) + (ord(c[o])<<8)
106
return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
108
# a few tag names, just to make the code below a bit more readable
113
PHOTOMETRIC_INTERPRETATION = 262
115
IMAGEDESCRIPTION = 270
117
SAMPLESPERPIXEL = 277
119
STRIPBYTECOUNTS = 279
122
PLANAR_CONFIGURATION = 284
123
RESOLUTION_UNIT = 296
133
IPTC_NAA_CHUNK = 33723 # newsphoto properties
134
PHOTOSHOP_CHUNK = 34377 # photoshop properties
137
# Compression => pil compression name
143
6: "tiff_jpeg", # obsolete
145
32771: "tiff_raw_16", # 16-bit padding
150
# (PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
151
# ExtraSamples) => mode, rawmode
152
(0, 1, 1, (1,), ()): ("1", "1;I"),
153
(0, 1, 2, (1,), ()): ("1", "1;IR"),
154
(0, 1, 1, (8,), ()): ("L", "L;I"),
155
(0, 1, 2, (8,), ()): ("L", "L;IR"),
156
(1, 1, 1, (1,), ()): ("1", "1"),
157
(1, 1, 2, (1,), ()): ("1", "1;R"),
158
(1, 1, 1, (8,), ()): ("L", "L"),
159
(1, 1, 1, (8,8), (2,)): ("LA", "LA"),
160
(1, 1, 2, (8,), ()): ("L", "L;R"),
161
(1, 1, 1, (16,), ()): ("I;16", "I;16"),
162
(1, 2, 1, (16,), ()): ("I;16S", "I;16S"),
163
(1, 2, 1, (32,), ()): ("I", "I;32S"),
164
(1, 3, 1, (32,), ()): ("F", "F;32F"),
165
(2, 1, 1, (8,8,8), ()): ("RGB", "RGB"),
166
(2, 1, 2, (8,8,8), ()): ("RGB", "RGB;R"),
167
(2, 1, 1, (8,8,8,8), (0,)): ("RGBX", "RGBX"),
168
(2, 1, 1, (8,8,8,8), (1,)): ("RGBA", "RGBa"),
169
(2, 1, 1, (8,8,8,8), (2,)): ("RGBA", "RGBA"),
170
(2, 1, 1, (8,8,8,8), (999,)): ("RGBA", "RGBA"), # corel draw 10
171
(3, 1, 1, (1,), ()): ("P", "P;1"),
172
(3, 1, 2, (1,), ()): ("P", "P;1R"),
173
(3, 1, 1, (2,), ()): ("P", "P;2"),
174
(3, 1, 2, (2,), ()): ("P", "P;2R"),
175
(3, 1, 1, (4,), ()): ("P", "P;4"),
176
(3, 1, 2, (4,), ()): ("P", "P;4R"),
177
(3, 1, 1, (8,), ()): ("P", "P"),
178
(3, 1, 1, (8,8), (2,)): ("PA", "PA"),
179
(3, 1, 2, (8,), ()): ("P", "P;R"),
180
(5, 1, 1, (8,8,8,8), ()): ("CMYK", "CMYK"),
181
(6, 1, 1, (8,8,8), ()): ("YCbCr", "YCbCr"),
182
(8, 1, 1, (8,8,8), ()): ("LAB", "LAB"),
185
PREFIXES = ["MM\000\052", "II\052\000", "II\xBC\000"]
188
return prefix[:4] in PREFIXES
191
# Wrapper for TIFF IFDs.
193
class ImageFileDirectory:
195
# represents a TIFF tag directory. to speed things up,
196
# we don't decode tags unless they're asked for.
198
def __init__(self, prefix="II"):
199
self.prefix = prefix[:2]
200
if self.prefix == "MM":
201
self.i16, self.i32 = ib16, ib32
202
# FIXME: save doesn't yet support big-endian mode...
203
elif self.prefix == "II":
204
self.i16, self.i32 = il16, il32
205
self.o16, self.o32 = ol16, ol32
207
raise SyntaxError("not a TIFF IFD")
215
# dictionary API (sort of)
218
return self.tagdata.keys() + self.tags.keys()
221
items = self.tags.items()
222
for tag in self.tagdata.keys():
223
items.append((tag, self[tag]))
227
return len(self.tagdata) + len(self.tags)
229
def __getitem__(self, tag):
231
return self.tags[tag]
233
type, data = self.tagdata[tag] # unpack on the fly
234
size, handler = self.load_dispatch[type]
235
self.tags[tag] = data = handler(self, data)
236
del self.tagdata[tag]
239
def get(self, tag, default=None):
245
def getscalar(self, tag, default=None):
249
if tag == SAMPLEFORMAT:
250
# work around broken (?) matrox library
251
# (from Ted Wright, via Bob Klimek)
252
raise KeyError # use default
253
raise ValueError, "not a scalar"
260
def has_key(self, tag):
261
return self.tags.has_key(tag) or self.tagdata.has_key(tag)
263
def __setitem__(self, tag, value):
264
if type(value) is not type(()):
266
self.tags[tag] = value
272
def load_byte(self, data):
274
for i in range(len(data)):
275
l.append(ord(data[i]))
277
load_dispatch[1] = (1, load_byte)
279
def load_string(self, data):
280
if data[-1:] == '\0':
283
load_dispatch[2] = (1, load_string)
285
def load_short(self, data):
287
for i in range(0, len(data), 2):
288
l.append(self.i16(data, i))
290
load_dispatch[3] = (2, load_short)
292
def load_long(self, data):
294
for i in range(0, len(data), 4):
295
l.append(self.i32(data, i))
297
load_dispatch[4] = (4, load_long)
299
def load_rational(self, data):
301
for i in range(0, len(data), 8):
302
l.append((self.i32(data, i), self.i32(data, i+4)))
304
load_dispatch[5] = (8, load_rational)
306
def load_float(self, data):
307
a = array.array("f", data)
308
if self.prefix != byteorder:
311
load_dispatch[11] = (4, load_float)
313
def load_double(self, data):
314
a = array.array("d", data)
315
if self.prefix != byteorder:
318
load_dispatch[12] = (8, load_double)
320
def load_undefined(self, data):
323
load_dispatch[7] = (1, load_undefined)
326
# load tag dictionary
333
for i in range(i16(fp.read(2))):
337
tag, typ = i16(ifd), i16(ifd, 2)
341
tagname = TiffTags.TAGS.get(tag, "unknown")
342
typname = TiffTags.TYPES.get(typ, "unknown")
343
print "tag: %s (%d)" % (tagname, tag),
344
print "- type: %s (%d)" % (typname, typ),
347
dispatch = self.load_dispatch[typ]
350
print "- unsupported type", typ
351
continue # ignore unsupported type
353
size, handler = dispatch
355
size = size * i32(ifd, 4)
357
# Get and expand tag value
361
data = ImageFile._safe_read(fp, size)
366
if len(data) != size:
367
raise IOError, "not enough data"
369
self.tagdata[tag] = typ, data
372
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK):
373
print "- value: <table: %d bytes>" % size
375
print "- value:", self[tag]
377
self.next = i32(fp.read(4))
386
fp.write(o16(len(self.tags)))
388
# always write in ascending tag order
389
tags = self.tags.items()
393
append = directory.append
395
offset = fp.tell() + len(self.tags) * 12 + 4
399
# pass 1: convert tags to binary format
400
for tag, value in tags:
404
tagname = TiffTags.TAGS.get(tag, "unknown")
405
print "save: %s (%d)" % (tagname, tag),
406
print "- value:", value
408
if type(value[0]) is type(""):
411
data = value = string.join(value, "\0") + "\0"
415
if tag == STRIPOFFSETS:
416
stripoffsets = len(directory)
417
typ = 4 # to avoid catch-22
418
elif tag in (X_RESOLUTION, Y_RESOLUTION):
419
# identify rational data fields
427
data = string.join(map(o16, value), "")
429
data = string.join(map(o32, value), "")
431
# figure out if data fits into the directory
433
append((tag, typ, len(value), data, ""))
435
append((tag, typ, len(value), data + (4-len(data))*"\0", ""))
439
count = count / 2 # adjust for rational data field
440
append((tag, typ, count, o32(offset), data))
441
offset = offset + len(data)
443
offset = offset + 1 # word padding
445
# update strip offset data to point beyond auxiliary data
446
if stripoffsets is not None:
447
tag, typ, count, value, data = directory[stripoffsets]
448
assert not data, "multistrip support not yet implemented"
449
value = o32(self.i32(value) + offset)
450
directory[stripoffsets] = tag, typ, count, value, data
452
# pass 2: write directory to file
453
for tag, typ, count, value, data in directory:
455
print tag, typ, count, repr(value), repr(data)
456
fp.write(o16(tag) + o16(typ) + o32(count) + value)
457
fp.write("\0\0\0\0") # end of directory
459
# pass 3: write auxiliary data to file
460
for tag, typ, count, value, data in directory:
468
# Image plugin for TIFF files.
470
class TiffImageFile(ImageFile.ImageFile):
473
format_description = "Adobe TIFF"
476
"Open the first image in a TIFF file"
479
ifh = self.fp.read(8)
481
if ifh[:4] not in PREFIXES:
482
raise SyntaxError, "not a TIFF file"
484
# image file directory (tag dictionary)
485
self.tag = self.ifd = ImageFileDirectory(ifh[:2])
487
# setup frame pointers
488
self.__first = self.__next = self.ifd.i32(ifh, 4)
492
# and load the first frame
495
def seek(self, frame):
496
"Select a given frame as current image"
503
"Return the current frame number"
507
def _seek(self, frame):
510
if frame < self.__frame:
513
self.__next = self.__first
514
while self.__frame < frame:
516
raise EOFError, "no more images in TIFF file"
517
self.fp.seek(self.__next)
518
self.tag.load(self.fp)
519
self.__next = self.tag.next
520
self.__frame = self.__frame + 1
527
def _decoder(self, rawmode, layer):
528
"Setup decoder contexts"
531
if rawmode == "RGB" and self._planar_configuration == 2:
532
rawmode = rawmode[layer]
533
compression = self._compression
534
if compression == "raw":
535
args = (rawmode, 0, 1)
536
elif compression == "jpeg":
538
if self.tag.has_key(JPEGTABLES):
539
# Hack to handle abbreviated JPEG headers
540
self.tile_prefix = self.tag[JPEGTABLES]
541
elif compression == "packbits":
543
elif compression == "tiff_lzw":
545
if self.tag.has_key(317):
546
# Section 14: Differencing Predictor
547
self.decoderconfig = (self.tag[PREDICTOR][0],)
552
"Setup this image object based on current tags"
554
if self.tag.has_key(0xBC01):
555
raise IOError, "Windows Media Photo files not yet supported"
557
getscalar = self.tag.getscalar
559
# extract relevant tags
560
self._compression = COMPRESSION_INFO[getscalar(COMPRESSION, 1)]
561
self._planar_configuration = getscalar(PLANAR_CONFIGURATION, 1)
563
# photometric is a required tag, but not everyone is reading
565
photo = getscalar(PHOTOMETRIC_INTERPRETATION, 0)
567
fillorder = getscalar(FILLORDER, 1)
570
print "*** Summary ***"
571
print "- compression:", self._compression
572
print "- photometric_interpretation:", photo
573
print "- planar_configuration:", self._planar_configuration
574
print "- fill_order:", fillorder
577
xsize = getscalar(IMAGEWIDTH)
578
ysize = getscalar(IMAGELENGTH)
579
self.size = xsize, ysize
582
print "- size:", self.size
584
format = getscalar(SAMPLEFORMAT, 1)
586
# mode: check photometric interpretation and bits per pixel
588
photo, format, fillorder,
589
self.tag.get(BITSPERSAMPLE, (1,)),
590
self.tag.get(EXTRASAMPLES, ())
593
print "format key:", key
595
self.mode, rawmode = OPEN_INFO[key]
598
print "- unsupported format"
599
raise SyntaxError, "unknown pixel mode"
602
print "- raw mode:", rawmode
603
print "- pil mode:", self.mode
605
self.info["compression"] = self._compression
608
xres = getscalar(X_RESOLUTION, (1, 1))
609
yres = getscalar(Y_RESOLUTION, (1, 1))
612
xres = xres[0] / (xres[1] or 1)
613
yres = yres[0] / (yres[1] or 1)
614
resunit = getscalar(RESOLUTION_UNIT, 1)
615
if resunit == 2: # Inches
616
self.info["dpi"] = xres, yres
617
elif resunit == 3: # Centimeters
618
self.info["dpi"] = xres * 2.54, yres * 2.54
619
else: # No absolute unit of measurement.
620
self.info["resolution"] = xres, yres
623
# build tile descriptors
626
if self.tag.has_key(STRIPOFFSETS):
628
h = getscalar(ROWSPERSTRIP, ysize)
631
for o in self.tag[STRIPOFFSETS]:
633
a = self._decoder(rawmode, l)
636
(0, min(y, ysize), w, min(y+h, ysize)),
639
if y >= self.size[1]:
643
elif self.tag.has_key(324):
648
for o in self.tag[324]:
650
a = self._decoder(rawmode, l)
651
# FIXME: this doesn't work if the image size
652
# is not a multiple of the tile size...
658
if x >= self.size[0]:
660
if y >= self.size[1]:
666
print "- unsupported data organization"
667
raise SyntaxError("unknown data organization")
669
# fixup palette descriptor
671
palette = map(lambda a: chr(a / 256), self.tag[COLORMAP])
672
self.palette = ImagePalette.raw("RGB;L", string.join(palette, ""))
675
# --------------------------------------------------------------------
678
# little endian is default
681
# mode => rawmode, photometrics, sampleformat, bitspersample, extra
682
"1": ("1", 1, 1, (1,), None),
683
"L": ("L", 1, 1, (8,), None),
684
"LA": ("LA", 1, 1, (8,8), 2),
685
"P": ("P", 3, 1, (8,), None),
686
"PA": ("PA", 3, 1, (8,8), 2),
687
"I": ("I;32S", 1, 2, (32,), None),
688
"I;16": ("I;16", 1, 1, (16,), None),
689
"I;16S": ("I;16S", 1, 2, (16,), None),
690
"F": ("F;32F", 1, 3, (32,), None),
691
"RGB": ("RGB", 2, 1, (8,8,8), None),
692
"RGBX": ("RGBX", 2, 1, (8,8,8,8), 0),
693
"RGBA": ("RGBA", 2, 1, (8,8,8,8), 2),
694
"CMYK": ("CMYK", 5, 1, (8,8,8,8), None),
695
"YCbCr": ("YCbCr", 6, 1, (8,8,8), None),
696
"LAB": ("LAB", 8, 1, (8,8,8), None),
700
# convert value to TIFF rational number -- (numerator, denominator)
701
if type(value) in (type([]), type(())):
702
assert(len(value) % 2 == 0)
704
if type(value) == type(1):
707
return (int(value * 65536), 65536)
709
def _save(im, fp, filename):
712
rawmode, photo, format, bits, extra = SAVE_INFO[im.mode]
714
raise IOError, "cannot write mode %s as TIFF" % im.mode
716
ifd = ImageFileDirectory()
718
# tiff header (write via IFD to get everything right)
719
fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))
721
ifd[IMAGEWIDTH] = im.size[0]
722
ifd[IMAGELENGTH] = im.size[1]
724
# additions written by Greg Couch, gregc@cgl.ucsf.edu
725
# inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
726
if hasattr(im, 'tag'):
727
# preserve tags from original TIFF image file
728
for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION):
729
if im.tag.tagdata.has_key(key):
730
ifd[key] = im.tag.tagdata.get(key)
731
if im.encoderinfo.has_key("description"):
732
ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
733
if im.encoderinfo.has_key("resolution"):
734
ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
735
= _cvt_res(im.encoderinfo["resolution"])
736
if im.encoderinfo.has_key("x resolution"):
737
ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
738
if im.encoderinfo.has_key("y resolution"):
739
ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
740
if im.encoderinfo.has_key("resolution unit"):
741
unit = im.encoderinfo["resolution unit"]
743
ifd[RESOLUTION_UNIT] = 2
744
elif unit == "cm" or unit == "centimeter":
745
ifd[RESOLUTION_UNIT] = 3
747
ifd[RESOLUTION_UNIT] = 1
748
if im.encoderinfo.has_key("software"):
749
ifd[SOFTWARE] = im.encoderinfo["software"]
750
if im.encoderinfo.has_key("date time"):
751
ifd[DATE_TIME] = im.encoderinfo["date time"]
752
if im.encoderinfo.has_key("artist"):
753
ifd[ARTIST] = im.encoderinfo["artist"]
754
if im.encoderinfo.has_key("copyright"):
755
ifd[COPYRIGHT] = im.encoderinfo["copyright"]
757
dpi = im.encoderinfo.get("dpi")
760
ifd[RESOLUTION_UNIT] = 2
762
ifd[X_RESOLUTION] = _cvt_res(dpi[0])
763
ifd[Y_RESOLUTION] = _cvt_res(dpi[1])
766
ifd[BITSPERSAMPLE] = bits
768
ifd[SAMPLESPERPIXEL] = len(bits)
769
if extra is not None:
770
ifd[EXTRASAMPLES] = extra
772
ifd[SAMPLEFORMAT] = format
774
ifd[PHOTOMETRIC_INTERPRETATION] = photo
777
lut = im.im.getpalette("RGB", "RGB;L")
778
ifd[COLORMAP] = tuple(map(lambda v: ord(v) * 256, lut))
781
stride = len(bits) * ((im.size[0]*bits[0]+7)/8)
782
ifd[ROWSPERSTRIP] = im.size[1]
783
ifd[STRIPBYTECOUNTS] = stride * im.size[1]
784
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
785
ifd[COMPRESSION] = 1 # no compression
787
offset = ifd.save(fp)
789
ImageFile._save(im, fp, [
790
("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
794
# --------------------------------------------------------------------
797
Image.register_open("TIFF", TiffImageFile, _accept)
798
Image.register_save("TIFF", _save)
800
Image.register_extension("TIFF", ".tif")
801
Image.register_extension("TIFF", ".tiff")
803
Image.register_mime("TIFF", "image/tiff")