This commit is contained in:
hugovk 2014-07-28 19:00:06 +03:00
parent 659b8c2f6f
commit 70528dd539

View File

@ -49,7 +49,8 @@ from PIL import _binary
from PIL._util import isStringType
import warnings
import array, sys
import array
import sys
import collections
import itertools
import os
@ -58,8 +59,8 @@ import os
READ_LIBTIFF = False
WRITE_LIBTIFF = False
II = b"II" # little-endian (intel-style)
MM = b"MM" # big-endian (motorola-style)
II = b"II" # little-endian (Intel style)
MM = b"MM" # big-endian (Motorola style)
i8 = _binary.i8
o8 = _binary.o8
@ -164,7 +165,7 @@ OPEN_INFO = {
(II, 2, 1, 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"),
(II, 2, 1, 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
(II, 2, 1, 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
(II, 2, 1, 1, (8,8,8,8), (999,)): ("RGBA", "RGBA"), # corel draw 10
(II, 2, 1, 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
(II, 3, 1, 1, (1,), ()): ("P", "P;1"),
(II, 3, 1, 2, (1,), ()): ("P", "P;1R"),
(II, 3, 1, 1, (2,), ()): ("P", "P;2"),
@ -196,7 +197,7 @@ OPEN_INFO = {
(MM, 2, 1, 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"),
(MM, 2, 1, 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
(MM, 2, 1, 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
(MM, 2, 1, 1, (8,8,8,8), (999,)): ("RGBA", "RGBA"), # corel draw 10
(MM, 2, 1, 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
(MM, 3, 1, 1, (1,), ()): ("P", "P;1"),
(MM, 3, 1, 2, (1,), ()): ("P", "P;1R"),
(MM, 3, 1, 1, (2,), ()): ("P", "P;2"),
@ -214,9 +215,11 @@ OPEN_INFO = {
PREFIXES = [b"MM\000\052", b"II\052\000", b"II\xBC\000"]
def _accept(prefix):
return prefix[:4] in PREFIXES
##
# Wrapper for TIFF IFDs.
@ -287,7 +290,9 @@ class ImageFileDirectory(collections.MutableMapping):
return dict(self.items())
def named(self):
"""Returns the complete tag dictionary, with named tags where posible."""
"""
Returns the complete tag dictionary, with named tags where posible.
"""
from PIL import TiffTags
result = {}
for tag_code, value in self.items():
@ -295,7 +300,6 @@ class ImageFileDirectory(collections.MutableMapping):
result[tag_name] = value
return result
# dictionary API
def __len__(self):
@ -449,14 +453,19 @@ class ImageFileDirectory(collections.MutableMapping):
data = ifd[8:8+size]
if len(data) != size:
warnings.warn("Possibly corrupt EXIF data. Expecting to read %d bytes but only got %d. Skipping tag %s" % (size, len(data), tag))
warnings.warn(
"Possibly corrupt EXIF data. "
"Expecting to read %d bytes but only got %d. "
"Skipping tag %s" % (size, len(data), tag))
continue
self.tagdata[tag] = data
self.tagtype[tag] = typ
if Image.DEBUG:
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
if tag in (
COLORMAP, IPTC_NAA_CHUNK,
PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
print("- value: <table: %d bytes>" % size)
else:
print("- value:", self[tag])
@ -541,7 +550,9 @@ class ImageFileDirectory(collections.MutableMapping):
typname = TiffTags.TYPES.get(typ, "unknown")
print("save: %s (%d)" % (tagname, tag), end=' ')
print("- type: %s (%d)" % (typname, typ), end=' ')
if tag in (COLORMAP, IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
if tag in (
COLORMAP, IPTC_NAA_CHUNK,
PHOTOSHOP_CHUNK, ICCPROFILE, XMP):
size = len(data)
print("- value: <table: %d bytes>" % size)
else:
@ -586,6 +597,7 @@ class ImageFileDirectory(collections.MutableMapping):
return offset
##
# Image plugin for TIFF files.
@ -694,9 +706,11 @@ class TiffImageFile(ImageFile.ImageFile):
if not len(self.tile) == 1:
raise IOError("Not exactly one tile")
# (self._compression, (extents tuple), 0, (rawmode, self._compression, fp))
# (self._compression, (extents tuple),
# 0, (rawmode, self._compression, fp))
ignored, extents, ignored_2, args = self.tile[0]
decoder = Image._getdecoder(self.mode, 'libtiff', args, self.decoderconfig)
decoder = Image._getdecoder(
self.mode, 'libtiff', args, self.decoderconfig)
try:
decoder.setimage(self.im, extents)
except ValueError:
@ -706,12 +720,12 @@ class TiffImageFile(ImageFile.ImageFile):
# We've got a stringio like thing passed in. Yay for all in memory.
# The decoder needs the entire file in one shot, so there's not
# a lot we can do here other than give it the entire file.
# unless we could do something like get the address of the underlying
# string for stringio.
# unless we could do something like get the address of the
# underlying string for stringio.
#
# Rearranging for supporting byteio items, since they have a fileno
# that returns an IOError if there's no underlying fp. Easier to deal
# with here by reordering.
# that returns an IOError if there's no underlying fp. Easier to
# dea. with here by reordering.
if Image.DEBUG:
print ("have getvalue. just sending in a string from getvalue")
n, err = decoder.decode(self.fp.getvalue())
@ -720,7 +734,8 @@ class TiffImageFile(ImageFile.ImageFile):
if Image.DEBUG:
print ("have fileno, calling fileno version of the decoder.")
self.fp.seek(0)
n,err = decoder.decode(b"fpfp") # 4 bytes, otherwise the trace might error out
# 4 bytes, otherwise the trace might error out
n, err = decoder.decode(b"fpfp")
else:
# we have something else.
if Image.DEBUG:
@ -728,7 +743,6 @@ class TiffImageFile(ImageFile.ImageFile):
# UNDONE -- so much for that buffer size thing.
n, err = decoder.decode(self.fp.read())
self.tile = []
self.readonly = 0
# libtiff closed the fp in a, we need to close self.fp, if possible
@ -825,13 +839,14 @@ class TiffImageFile(ImageFile.ImageFile):
offsets = self.tag[STRIPOFFSETS]
h = getscalar(ROWSPERSTRIP, ysize)
w = self.size[0]
if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3", "group4",
if READ_LIBTIFF or self._compression in [
"tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]:
## if Image.DEBUG:
## print "Activating g4 compression for whole file"
# if Image.DEBUG:
# print "Activating g4 compression for whole file"
# Decoder expects entire file as one tile.
# There's a buffer size limit in load (64k)
@ -850,7 +865,8 @@ class TiffImageFile(ImageFile.ImageFile):
# libtiff closes the file descriptor, so pass in a dup.
try:
fp = hasattr(self.fp, "fileno") and os.dup(self.fp.fileno())
fp = hasattr(self.fp, "fileno") and \
os.dup(self.fp.fileno())
except IOError:
# io.BytesIO have a fileno, but returns an IOError if
# it doesn't use a file descriptor.
@ -937,10 +953,12 @@ class TiffImageFile(ImageFile.ImageFile):
# --------------------------------------------------------------------
# Write TIFF files
# little endian is default except for image modes with explict big endian byte-order
# little endian is default except for image modes with
# explict big endian byte-order
SAVE_INFO = {
# mode => rawmode, byteorder, photometrics, sampleformat, bitspersample, extra
# mode => rawmode, byteorder, photometrics,
# sampleformat, bitspersample, extra
"1": ("1", II, 1, 1, (1,), None),
"L": ("L", II, 1, 1, (8,), None),
"LA": ("LA", II, 1, 1, (8, 8), 2),
@ -963,6 +981,7 @@ SAVE_INFO = {
"F;32BF": ("F;32BF", MM, 1, 3, (32,), None),
}
def _cvt_res(value):
# convert value to TIFF rational number -- (numerator, denominator)
if isinstance(value, collections.Sequence):
@ -973,6 +992,7 @@ def _cvt_res(value):
value = float(value)
return (int(value * 65536), 65536)
def _save(im, fp, filename):
try:
@ -982,7 +1002,8 @@ def _save(im, fp, filename):
ifd = ImageFileDirectory(prefix)
compression = im.encoderinfo.get('compression',im.info.get('compression','raw'))
compression = im.encoderinfo.get(
'compression', im.info.get('compression', 'raw'))
libtiff = WRITE_LIBTIFF or compression != 'raw'
@ -1010,7 +1031,6 @@ def _save(im, fp, filename):
except:
pass # might not be an IFD, Might not have populated type
# additions written by Greg Couch, gregc@cgl.ucsf.edu
# inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
if hasattr(im, 'tag'):
@ -1078,7 +1098,8 @@ def _save(im, fp, filename):
ifd[ROWSPERSTRIP] = im.size[1]
ifd[STRIPBYTECOUNTS] = stride * im.size[1]
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression,1) # no compression by default
# no compression by default:
ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
if libtiff:
if Image.DEBUG:
@ -1089,23 +1110,27 @@ def _save(im, fp, filename):
fp.seek(0)
_fp = os.dup(fp.fileno())
blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes.
# ICC Profile crashes.
blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE]
atts = {}
# bits per sample is a single short in the tiff directory, not a list.
atts[BITSPERSAMPLE] = bits[0]
# Merge the ones that we have with (optional) more bits from
# the original file, e.g x,y resolution so that we can
# save(load('')) == original file.
for k,v in itertools.chain(ifd.items(), getattr(im, 'ifd', {}).items()):
for k, v in itertools.chain(
ifd.items(), getattr(im, 'ifd', {}).items()):
if k not in atts and k not in blocklist:
if type(v[0]) == tuple and len(v) > 1:
# A tuple of more than one rational tuples
# flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
# flatten to floats,
# following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = [float(elt[0])/float(elt[1]) for elt in v]
continue
if type(v[0]) == tuple and len(v) == 1:
# A tuple of one rational tuples
# flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
# flatten to floats,
# following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = float(v[0][0])/float(v[0][1])
continue
if type(v) == tuple and len(v) > 2:
@ -1115,7 +1140,8 @@ def _save(im, fp, filename):
continue
if type(v) == tuple and len(v) == 2:
# one rational tuple
# flatten to float, following tiffcp.c->cpTag->TIFF_RATIONAL
# flatten to float,
# following tiffcp.c->cpTag->TIFF_RATIONAL
atts[k] = float(v[0])/float(v[1])
continue
if type(v) == tuple and len(v) == 1:
@ -1143,7 +1169,8 @@ def _save(im, fp, filename):
e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
e.setimage(im.im, (0, 0)+im.size)
while True:
l, s, d = e.encode(16*1024) # undone, change to self.decodermaxblock
# undone, change to self.decodermaxblock:
l, s, d = e.encode(16*1024)
if not _fp:
fp.write(d)
if s:
@ -1158,7 +1185,6 @@ def _save(im, fp, filename):
("raw", (0, 0)+im.size, offset, (rawmode, stride, 1))
])
# -- helper for multi-page save --
if "_debug_multipage" in im.encoderinfo:
# just to access o32 and o16 (using correct byte order)