mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-04 04:20:10 +03:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
f3a195ee73
commit
77b7a4f82c
|
@ -38,28 +38,22 @@
|
||||||
#
|
#
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
from __future__ import annotations
|
||||||
from __future__ import division, print_function
|
|
||||||
|
|
||||||
from PIL import Image, ImageFile
|
|
||||||
from PIL import ImagePalette
|
|
||||||
from PIL import _binary
|
|
||||||
from PIL import TiffTags
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
from fractions import Fraction
|
|
||||||
from numbers import Number, Rational
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
from fractions import Fraction
|
||||||
|
from numbers import Number, Rational
|
||||||
|
|
||||||
|
from PIL import Image, ImageFile, ImagePalette, TiffTags, _binary
|
||||||
|
|
||||||
from .TiffTags import TYPES
|
from .TiffTags import TYPES
|
||||||
|
|
||||||
|
|
||||||
__version__ = "1.3.5"
|
__version__ = "1.3.5"
|
||||||
DEBUG = False # Needs to be merged with the new logging approach.
|
DEBUG = False # Needs to be merged with the new logging approach.
|
||||||
|
|
||||||
|
@ -145,7 +139,6 @@ OPEN_INFO = {
|
||||||
(MM, 1, (1,), 1, (1,), ()): ("1", "1"),
|
(MM, 1, (1,), 1, (1,), ()): ("1", "1"),
|
||||||
(II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
|
(II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
|
||||||
(MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
|
(MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
|
||||||
|
|
||||||
(II, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
|
(II, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
|
||||||
(MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
|
(MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
|
||||||
(II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
|
(II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
|
||||||
|
@ -154,7 +147,6 @@ OPEN_INFO = {
|
||||||
(MM, 1, (1,), 1, (2,), ()): ("L", "L;2"),
|
(MM, 1, (1,), 1, (2,), ()): ("L", "L;2"),
|
||||||
(II, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
|
(II, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
|
||||||
(MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
|
(MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
|
||||||
|
|
||||||
(II, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
|
(II, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
|
||||||
(MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
|
(MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
|
||||||
(II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
|
(II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
|
||||||
|
@ -163,7 +155,6 @@ OPEN_INFO = {
|
||||||
(MM, 1, (1,), 1, (4,), ()): ("L", "L;4"),
|
(MM, 1, (1,), 1, (4,), ()): ("L", "L;4"),
|
||||||
(II, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
|
(II, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
|
||||||
(MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
|
(MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
|
||||||
|
|
||||||
(II, 0, (1,), 1, (8,), ()): ("L", "L;I"),
|
(II, 0, (1,), 1, (8,), ()): ("L", "L;I"),
|
||||||
(MM, 0, (1,), 1, (8,), ()): ("L", "L;I"),
|
(MM, 0, (1,), 1, (8,), ()): ("L", "L;I"),
|
||||||
(II, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
|
(II, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
|
||||||
|
@ -172,18 +163,48 @@ OPEN_INFO = {
|
||||||
(MM, 1, (1,), 1, (8,), ()): ("L", "L"),
|
(MM, 1, (1,), 1, (8,), ()): ("L", "L"),
|
||||||
(II, 1, (1,), 2, (8,), ()): ("L", "L;R"),
|
(II, 1, (1,), 2, (8,), ()): ("L", "L;R"),
|
||||||
(MM, 1, (1,), 2, (8,), ()): ("L", "L;R"),
|
(MM, 1, (1,), 2, (8,), ()): ("L", "L;R"),
|
||||||
|
|
||||||
(II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"),
|
(II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"),
|
||||||
|
|
||||||
(II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"),
|
(II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"),
|
||||||
(II, 1, (1,), 1, (16, 16), (0,)): ("I;16", "I;16"),
|
(II, 1, (1,), 1, (16, 16), (0,)): ("I;16", "I;16"),
|
||||||
(II, 1, (1,), 1, (16,16,16), (0,0,)): ("I;16", "I;16"),
|
(
|
||||||
(II, 1, (1,), 1, (16,16,16,16), (0,0,0,)): ("I;16", "I;16"),
|
II,
|
||||||
(II, 1, (1,), 1, (16,16,16,16,16), (0,0,0,0,)): ("I;16", "I;16"),
|
1,
|
||||||
|
(1,),
|
||||||
|
1,
|
||||||
|
(16, 16, 16),
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
): ("I;16", "I;16"),
|
||||||
|
(
|
||||||
|
II,
|
||||||
|
1,
|
||||||
|
(1,),
|
||||||
|
1,
|
||||||
|
(16, 16, 16, 16),
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
): ("I;16", "I;16"),
|
||||||
|
(
|
||||||
|
II,
|
||||||
|
1,
|
||||||
|
(1,),
|
||||||
|
1,
|
||||||
|
(16, 16, 16, 16, 16),
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
): ("I;16", "I;16"),
|
||||||
(MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"),
|
(MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"),
|
||||||
(II, 1, (2,), 1, (16,), ()): ("I;16S", "I;16S"),
|
(II, 1, (2,), 1, (16,), ()): ("I;16S", "I;16S"),
|
||||||
(MM, 1, (2,), 1, (16,), ()): ("I;16BS", "I;16BS"),
|
(MM, 1, (2,), 1, (16,), ()): ("I;16BS", "I;16BS"),
|
||||||
|
|
||||||
(II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
|
(II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
|
||||||
(MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
|
(MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
|
||||||
(II, 1, (1,), 1, (32,), ()): ("I", "I;32N"),
|
(II, 1, (1,), 1, (32,), ()): ("I", "I;32N"),
|
||||||
|
@ -191,10 +212,8 @@ OPEN_INFO = {
|
||||||
(MM, 1, (2,), 1, (32,), ()): ("I;32BS", "I;32BS"),
|
(MM, 1, (2,), 1, (32,), ()): ("I;32BS", "I;32BS"),
|
||||||
(II, 1, (3,), 1, (32,), ()): ("F", "F;32F"),
|
(II, 1, (3,), 1, (32,), ()): ("F", "F;32F"),
|
||||||
(MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"),
|
(MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"),
|
||||||
|
|
||||||
(II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
|
(II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
|
||||||
(MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
|
(MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
|
||||||
|
|
||||||
(II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
(II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
||||||
(MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
(MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
||||||
(II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
|
(II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
|
||||||
|
@ -209,7 +228,6 @@ OPEN_INFO = {
|
||||||
(MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
|
(MM, 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
|
||||||
(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
|
||||||
|
|
||||||
(II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
|
(II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
|
||||||
(MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
|
(MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
|
||||||
(II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
|
(II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
|
||||||
|
@ -228,13 +246,10 @@ OPEN_INFO = {
|
||||||
(MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
|
(MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
|
||||||
(II, 3, (1,), 2, (8,), ()): ("P", "P;R"),
|
(II, 3, (1,), 2, (8,), ()): ("P", "P;R"),
|
||||||
(MM, 3, (1,), 2, (8,), ()): ("P", "P;R"),
|
(MM, 3, (1,), 2, (8,), ()): ("P", "P;R"),
|
||||||
|
|
||||||
(II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
|
(II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
|
||||||
(MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
|
(MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
|
||||||
|
|
||||||
(II, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
|
(II, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
|
||||||
(MM, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
|
(MM, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
|
||||||
|
|
||||||
(II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
|
(II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
|
||||||
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
|
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
|
||||||
}
|
}
|
||||||
|
@ -251,6 +266,7 @@ def _limit_rational(val, max_val):
|
||||||
n_d = IFDRational(1 / val if inv else val).limit_rational(max_val)
|
n_d = IFDRational(1 / val if inv else val).limit_rational(max_val)
|
||||||
return n_d[::-1] if inv else n_d
|
return n_d[::-1] if inv else n_d
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Wrapper for TIFF IFDs.
|
# Wrapper for TIFF IFDs.
|
||||||
|
|
||||||
|
@ -270,7 +286,7 @@ class IFDRational(Rational):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ('_numerator', '_denominator', '_val')
|
__slots__ = ("_numerator", "_denominator", "_val")
|
||||||
|
|
||||||
def __init__(self, value, denominator=1):
|
def __init__(self, value, denominator=1):
|
||||||
"""
|
"""
|
||||||
|
@ -294,7 +310,7 @@ class IFDRational(Rational):
|
||||||
return
|
return
|
||||||
|
|
||||||
if denominator == 0:
|
if denominator == 0:
|
||||||
self._val = float('nan')
|
self._val = float("nan")
|
||||||
return
|
return
|
||||||
|
|
||||||
elif denominator == 1:
|
elif denominator == 1:
|
||||||
|
@ -339,6 +355,7 @@ class IFDRational(Rational):
|
||||||
def _delegate(op):
|
def _delegate(op):
|
||||||
def delegate(self, *args):
|
def delegate(self, *args):
|
||||||
return getattr(self._val, op)(*args)
|
return getattr(self._val, op)(*args)
|
||||||
|
|
||||||
return delegate
|
return delegate
|
||||||
|
|
||||||
""" a = ['add','radd', 'sub', 'rsub','div', 'rdiv', 'mul', 'rmul',
|
""" a = ['add','radd', 'sub', 'rsub','div', 'rdiv', 'mul', 'rmul',
|
||||||
|
@ -349,34 +366,34 @@ class IFDRational(Rational):
|
||||||
print "\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a)
|
print "\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__add__ = _delegate('__add__')
|
__add__ = _delegate("__add__")
|
||||||
__radd__ = _delegate('__radd__')
|
__radd__ = _delegate("__radd__")
|
||||||
__sub__ = _delegate('__sub__')
|
__sub__ = _delegate("__sub__")
|
||||||
__rsub__ = _delegate('__rsub__')
|
__rsub__ = _delegate("__rsub__")
|
||||||
__div__ = _delegate('__div__')
|
__div__ = _delegate("__div__")
|
||||||
__rdiv__ = _delegate('__rdiv__')
|
__rdiv__ = _delegate("__rdiv__")
|
||||||
__mul__ = _delegate('__mul__')
|
__mul__ = _delegate("__mul__")
|
||||||
__rmul__ = _delegate('__rmul__')
|
__rmul__ = _delegate("__rmul__")
|
||||||
__truediv__ = _delegate('__truediv__')
|
__truediv__ = _delegate("__truediv__")
|
||||||
__rtruediv__ = _delegate('__rtruediv__')
|
__rtruediv__ = _delegate("__rtruediv__")
|
||||||
__floordiv__ = _delegate('__floordiv__')
|
__floordiv__ = _delegate("__floordiv__")
|
||||||
__rfloordiv__ = _delegate('__rfloordiv__')
|
__rfloordiv__ = _delegate("__rfloordiv__")
|
||||||
__mod__ = _delegate('__mod__')
|
__mod__ = _delegate("__mod__")
|
||||||
__rmod__ = _delegate('__rmod__')
|
__rmod__ = _delegate("__rmod__")
|
||||||
__pow__ = _delegate('__pow__')
|
__pow__ = _delegate("__pow__")
|
||||||
__rpow__ = _delegate('__rpow__')
|
__rpow__ = _delegate("__rpow__")
|
||||||
__pos__ = _delegate('__pos__')
|
__pos__ = _delegate("__pos__")
|
||||||
__neg__ = _delegate('__neg__')
|
__neg__ = _delegate("__neg__")
|
||||||
__abs__ = _delegate('__abs__')
|
__abs__ = _delegate("__abs__")
|
||||||
__trunc__ = _delegate('__trunc__')
|
__trunc__ = _delegate("__trunc__")
|
||||||
__lt__ = _delegate('__lt__')
|
__lt__ = _delegate("__lt__")
|
||||||
__gt__ = _delegate('__gt__')
|
__gt__ = _delegate("__gt__")
|
||||||
__le__ = _delegate('__le__')
|
__le__ = _delegate("__le__")
|
||||||
__ge__ = _delegate('__ge__')
|
__ge__ = _delegate("__ge__")
|
||||||
__nonzero__ = _delegate('__nonzero__')
|
__nonzero__ = _delegate("__nonzero__")
|
||||||
__ceil__ = _delegate('__ceil__')
|
__ceil__ = _delegate("__ceil__")
|
||||||
__floor__ = _delegate('__floor__')
|
__floor__ = _delegate("__floor__")
|
||||||
__round__ = _delegate('__round__')
|
__round__ = _delegate("__round__")
|
||||||
|
|
||||||
|
|
||||||
class ImageFileDirectory_v2(collections.MutableMapping):
|
class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
@ -409,6 +426,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
|
||||||
.. versionadded:: 3.0.0
|
.. versionadded:: 3.0.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Documentation:
|
Documentation:
|
||||||
|
|
||||||
|
@ -453,7 +471,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("not a TIFF IFD")
|
raise SyntaxError("not a TIFF IFD")
|
||||||
self.reset()
|
self.reset()
|
||||||
self.next, = self._unpack("L", ifh[4:])
|
(self.next,) = self._unpack("L", ifh[4:])
|
||||||
self._legacy_api = False
|
self._legacy_api = False
|
||||||
|
|
||||||
prefix = property(lambda self: self._prefix)
|
prefix = property(lambda self: self._prefix)
|
||||||
|
@ -480,8 +498,10 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
|
||||||
.. deprecated:: 3.0.0
|
.. deprecated:: 3.0.0
|
||||||
"""
|
"""
|
||||||
warnings.warn("as_dict() is deprecated. " +
|
warnings.warn(
|
||||||
"Please use dict(ifd) instead.", DeprecationWarning)
|
"as_dict() is deprecated. " + "Please use dict(ifd) instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
return dict(self)
|
return dict(self)
|
||||||
|
|
||||||
def named(self):
|
def named(self):
|
||||||
|
@ -490,8 +510,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
|
||||||
Returns the complete tag dictionary, with named tags where possible.
|
Returns the complete tag dictionary, with named tags where possible.
|
||||||
"""
|
"""
|
||||||
return dict((TiffTags.lookup(code).name, value)
|
return dict((TiffTags.lookup(code).name, value) for code, value in self.items())
|
||||||
for code, value in self.items())
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(set(self._tagdata) | set(self._tags_v2))
|
return len(set(self._tagdata) | set(self._tags_v2))
|
||||||
|
@ -504,13 +523,14 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
self[tag] = handler(self, data, self.legacy_api) # check type
|
self[tag] = handler(self, data, self.legacy_api) # check type
|
||||||
val = self._tags_v2[tag]
|
val = self._tags_v2[tag]
|
||||||
if self.legacy_api and not isinstance(val, (tuple, bytes)):
|
if self.legacy_api and not isinstance(val, (tuple, bytes)):
|
||||||
val = val,
|
val = (val,)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def __contains__(self, tag):
|
def __contains__(self, tag):
|
||||||
return tag in self._tags_v2 or tag in self._tagdata
|
return tag in self._tags_v2 or tag in self._tagdata
|
||||||
|
|
||||||
if bytes is str:
|
if bytes is str:
|
||||||
|
|
||||||
def has_key(self, tag):
|
def has_key(self, tag):
|
||||||
return tag in self
|
return tag in self
|
||||||
|
|
||||||
|
@ -520,7 +540,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
def _setitem(self, tag, value, legacy_api):
|
def _setitem(self, tag, value, legacy_api):
|
||||||
basetypes = (Number, bytes, str)
|
basetypes = (Number, bytes, str)
|
||||||
if bytes is str:
|
if bytes is str:
|
||||||
basetypes += unicode,
|
basetypes += (unicode,)
|
||||||
|
|
||||||
info = TiffTags.lookup(tag)
|
info = TiffTags.lookup(tag)
|
||||||
values = [value] if isinstance(value, basetypes) else value
|
values = [value] if isinstance(value, basetypes) else value
|
||||||
|
@ -548,8 +568,10 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
self.tagtype[tag] = 2
|
self.tagtype[tag] = 2
|
||||||
|
|
||||||
if self.tagtype[tag] == 7 and bytes is not str:
|
if self.tagtype[tag] == 7 and bytes is not str:
|
||||||
values = [value.encode("ascii", 'replace') if isinstance(value, str) else value
|
values = [
|
||||||
for value in values]
|
value.encode("ascii", "replace") if isinstance(value, str) else value
|
||||||
|
for value in values
|
||||||
|
]
|
||||||
|
|
||||||
values = tuple(info.cvt_enum(value) for value in values)
|
values = tuple(info.cvt_enum(value) for value in values)
|
||||||
|
|
||||||
|
@ -557,8 +579,8 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
|
||||||
if info.length == 1:
|
if info.length == 1:
|
||||||
if legacy_api and self.tagtype[tag] in [5, 10]:
|
if legacy_api and self.tagtype[tag] in [5, 10]:
|
||||||
values = values,
|
values = (values,)
|
||||||
dest[tag], = values
|
(dest[tag],) = values
|
||||||
else:
|
else:
|
||||||
dest[tag] = values
|
dest[tag] = values
|
||||||
|
|
||||||
|
@ -579,37 +601,52 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
def _register_loader(idx, size):
|
def _register_loader(idx, size):
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
from PIL.TiffTags import TYPES
|
from PIL.TiffTags import TYPES
|
||||||
|
|
||||||
if func.__name__.startswith("load_"):
|
if func.__name__.startswith("load_"):
|
||||||
TYPES[idx] = func.__name__[5:].replace("_", " ")
|
TYPES[idx] = func.__name__[5:].replace("_", " ")
|
||||||
_load_dispatch[idx] = size, func
|
_load_dispatch[idx] = size, func
|
||||||
return func
|
return func
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def _register_writer(idx):
|
def _register_writer(idx):
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
_write_dispatch[idx] = func
|
_write_dispatch[idx] = func
|
||||||
return func
|
return func
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def _register_basic(idx_fmt_name):
|
def _register_basic(idx_fmt_name):
|
||||||
from PIL.TiffTags import TYPES
|
from PIL.TiffTags import TYPES
|
||||||
|
|
||||||
idx, fmt, name = idx_fmt_name
|
idx, fmt, name = idx_fmt_name
|
||||||
TYPES[idx] = name
|
TYPES[idx] = name
|
||||||
size = struct.calcsize("=" + fmt)
|
size = struct.calcsize("=" + fmt)
|
||||||
_load_dispatch[idx] = size, lambda self, data, legacy_api=True: (
|
_load_dispatch[idx] = size, lambda self, data, legacy_api=True: (
|
||||||
self._unpack("{0}{1}".format(len(data) // size, fmt), data))
|
self._unpack(f"{len(data) // size}{fmt}", data)
|
||||||
|
)
|
||||||
_write_dispatch[idx] = lambda self, *values: (
|
_write_dispatch[idx] = lambda self, *values: (
|
||||||
b"".join(self._pack(fmt, value) for value in values))
|
b"".join(self._pack(fmt, value) for value in values)
|
||||||
|
)
|
||||||
|
|
||||||
list(map(_register_basic,
|
list(
|
||||||
[(3, "H", "short"), (4, "L", "long"),
|
map(
|
||||||
(6, "b", "signed byte"), (8, "h", "signed short"),
|
_register_basic,
|
||||||
(9, "l", "signed long"), (11, "f", "float"), (12, "d", "double")]))
|
[
|
||||||
|
(3, "H", "short"),
|
||||||
|
(4, "L", "long"),
|
||||||
|
(6, "b", "signed byte"),
|
||||||
|
(8, "h", "signed short"),
|
||||||
|
(9, "l", "signed long"),
|
||||||
|
(11, "f", "float"),
|
||||||
|
(12, "d", "double"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@_register_loader(1, 1) # Basic type, except for the legacy API.
|
@_register_loader(1, 1) # Basic type, except for the legacy API.
|
||||||
def load_byte(self, data, legacy_api=True):
|
def load_byte(self, data, legacy_api=True):
|
||||||
return (data if legacy_api else
|
return data if legacy_api else tuple(map(ord, data) if bytes is str else data)
|
||||||
tuple(map(ord, data) if bytes is str else data))
|
|
||||||
|
|
||||||
@_register_writer(1) # Basic type, except for the legacy API.
|
@_register_writer(1) # Basic type, except for the legacy API.
|
||||||
def write_byte(self, data):
|
def write_byte(self, data):
|
||||||
|
@ -625,20 +662,20 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
def write_string(self, value):
|
def write_string(self, value):
|
||||||
# remerge of https://github.com/python-pillow/Pillow/pull/1416
|
# remerge of https://github.com/python-pillow/Pillow/pull/1416
|
||||||
if sys.version_info[0] == 2:
|
if sys.version_info[0] == 2:
|
||||||
value = value.decode('ascii', 'replace')
|
value = value.decode("ascii", "replace")
|
||||||
return b"" + value.encode('ascii', 'replace') + b"\0"
|
return b"" + value.encode("ascii", "replace") + b"\0"
|
||||||
|
|
||||||
@_register_loader(5, 8)
|
@_register_loader(5, 8)
|
||||||
def load_rational(self, data, legacy_api=True):
|
def load_rational(self, data, legacy_api=True):
|
||||||
vals = self._unpack("{0}L".format(len(data) // 4), data)
|
vals = self._unpack(f"{len(data) // 4}L", data)
|
||||||
combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b)
|
combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b)
|
||||||
return tuple(combine(num, denom)
|
return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
|
||||||
for num, denom in zip(vals[::2], vals[1::2]))
|
|
||||||
|
|
||||||
@_register_writer(5)
|
@_register_writer(5)
|
||||||
def write_rational(self, *values):
|
def write_rational(self, *values):
|
||||||
return b"".join(self._pack("2L", *_limit_rational(frac, 2 ** 31))
|
return b"".join(
|
||||||
for frac in values)
|
self._pack("2L", *_limit_rational(frac, 2**31)) for frac in values
|
||||||
|
)
|
||||||
|
|
||||||
@_register_loader(7, 1)
|
@_register_loader(7, 1)
|
||||||
def load_undefined(self, data, legacy_api=True):
|
def load_undefined(self, data, legacy_api=True):
|
||||||
|
@ -650,22 +687,23 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
|
||||||
@_register_loader(10, 8)
|
@_register_loader(10, 8)
|
||||||
def load_signed_rational(self, data, legacy_api=True):
|
def load_signed_rational(self, data, legacy_api=True):
|
||||||
vals = self._unpack("{0}l".format(len(data) // 4), data)
|
vals = self._unpack(f"{len(data) // 4}l", data)
|
||||||
combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b)
|
combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b)
|
||||||
return tuple(combine(num, denom)
|
return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
|
||||||
for num, denom in zip(vals[::2], vals[1::2]))
|
|
||||||
|
|
||||||
@_register_writer(10)
|
@_register_writer(10)
|
||||||
def write_signed_rational(self, *values):
|
def write_signed_rational(self, *values):
|
||||||
return b"".join(self._pack("2L", *_limit_rational(frac, 2 ** 30))
|
return b"".join(
|
||||||
for frac in values)
|
self._pack("2L", *_limit_rational(frac, 2**30)) for frac in values
|
||||||
|
)
|
||||||
|
|
||||||
def _ensure_read(self, fp, size):
|
def _ensure_read(self, fp, size):
|
||||||
ret = fp.read(size)
|
ret = fp.read(size)
|
||||||
if len(ret) != size:
|
if len(ret) != size:
|
||||||
raise IOError("Corrupt EXIF data. " +
|
raise OSError(
|
||||||
"Expecting to read %d bytes but only got %d. " %
|
"Corrupt EXIF data. "
|
||||||
(size, len(ret)))
|
+ "Expecting to read %d bytes but only got %d. " % (size, len(ret))
|
||||||
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def load(self, fp):
|
def load(self, fp):
|
||||||
|
@ -679,8 +717,10 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
tagname = TiffTags.lookup(tag).name
|
tagname = TiffTags.lookup(tag).name
|
||||||
typname = TYPES.get(typ, "unknown")
|
typname = TYPES.get(typ, "unknown")
|
||||||
print("tag: %s (%d) - type: %s (%d)" %
|
print(
|
||||||
(tagname, tag, typname, typ), end=" ")
|
"tag: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ),
|
||||||
|
end=" ",
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
unit_size, handler = self._load_dispatch[typ]
|
unit_size, handler = self._load_dispatch[typ]
|
||||||
|
@ -691,10 +731,12 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
size = count * unit_size
|
size = count * unit_size
|
||||||
if size > 4:
|
if size > 4:
|
||||||
here = fp.tell()
|
here = fp.tell()
|
||||||
offset, = self._unpack("L", data)
|
(offset,) = self._unpack("L", data)
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("Tag Location: %s - Data Location: %s" %
|
print(
|
||||||
(here, offset), end=" ")
|
"Tag Location: %s - Data Location: %s" % (here, offset),
|
||||||
|
end=" ",
|
||||||
|
)
|
||||||
fp.seek(offset)
|
fp.seek(offset)
|
||||||
data = ImageFile._safe_read(fp, size)
|
data = ImageFile._safe_read(fp, size)
|
||||||
fp.seek(here)
|
fp.seek(here)
|
||||||
|
@ -702,9 +744,11 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
data = data[:size]
|
data = data[:size]
|
||||||
|
|
||||||
if len(data) != size:
|
if len(data) != size:
|
||||||
warnings.warn("Possibly corrupt EXIF data. "
|
warnings.warn(
|
||||||
|
"Possibly corrupt EXIF data. "
|
||||||
"Expecting to read %d bytes but only got %d. "
|
"Expecting to read %d bytes but only got %d. "
|
||||||
"Skipping tag %s" % (size, len(data), tag))
|
"Skipping tag %s" % (size, len(data), tag)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._tagdata[tag] = data
|
self._tagdata[tag] = data
|
||||||
|
@ -716,8 +760,8 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
else:
|
else:
|
||||||
print("- value:", self[tag])
|
print("- value:", self[tag])
|
||||||
|
|
||||||
self.next, = self._unpack("L", self._ensure_read(fp, 4))
|
(self.next,) = self._unpack("L", self._ensure_read(fp, 4))
|
||||||
except IOError as msg:
|
except OSError as msg:
|
||||||
warnings.warn(str(msg))
|
warnings.warn(str(msg))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -747,8 +791,10 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
tagname = TiffTags.lookup(tag).name
|
tagname = TiffTags.lookup(tag).name
|
||||||
typname = TYPES.get(typ, "unknown")
|
typname = TYPES.get(typ, "unknown")
|
||||||
print("save: %s (%d) - type: %s (%d)" %
|
print(
|
||||||
(tagname, tag, typname, typ), end=" ")
|
"save: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ),
|
||||||
|
end=" ",
|
||||||
|
)
|
||||||
if len(data) >= 16:
|
if len(data) >= 16:
|
||||||
print("- value: <table: %d bytes>" % len(data))
|
print("- value: <table: %d bytes>" % len(data))
|
||||||
else:
|
else:
|
||||||
|
@ -767,8 +813,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
if stripoffsets is not None:
|
if stripoffsets is not None:
|
||||||
tag, typ, count, value, data = entries[stripoffsets]
|
tag, typ, count, value, data = entries[stripoffsets]
|
||||||
if data:
|
if data:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError("multistrip support not yet implemented")
|
||||||
"multistrip support not yet implemented")
|
|
||||||
value = self._pack("L", self._unpack("L", value)[0] + offset)
|
value = self._pack("L", self._unpack("L", value)[0] + offset)
|
||||||
entries[stripoffsets] = tag, typ, count, value, data
|
entries[stripoffsets] = tag, typ, count, value, data
|
||||||
|
|
||||||
|
@ -789,6 +834,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
|
|
||||||
return offset
|
return offset
|
||||||
|
|
||||||
|
|
||||||
ImageFileDirectory_v2._load_dispatch = _load_dispatch
|
ImageFileDirectory_v2._load_dispatch = _load_dispatch
|
||||||
ImageFileDirectory_v2._write_dispatch = _write_dispatch
|
ImageFileDirectory_v2._write_dispatch = _write_dispatch
|
||||||
for idx, name in TYPES.items():
|
for idx, name in TYPES.items():
|
||||||
|
@ -817,6 +863,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
||||||
|
|
||||||
.. deprecated:: 3.0.0
|
.. deprecated:: 3.0.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
ImageFileDirectory_v2.__init__(self, *args, **kwargs)
|
ImageFileDirectory_v2.__init__(self, *args, **kwargs)
|
||||||
self._legacy_api = True
|
self._legacy_api = True
|
||||||
|
@ -881,7 +928,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
||||||
self._setitem(tag, handler(self, data, legacy), legacy)
|
self._setitem(tag, handler(self, data, legacy), legacy)
|
||||||
val = self._tags_v1[tag]
|
val = self._tags_v1[tag]
|
||||||
if not isinstance(val, (tuple, bytes)):
|
if not isinstance(val, (tuple, bytes)):
|
||||||
val = val,
|
val = (val,)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
@ -892,6 +939,7 @@ ImageFileDirectory = ImageFileDirectory_v1
|
||||||
##
|
##
|
||||||
# Image plugin for TIFF files.
|
# Image plugin for TIFF files.
|
||||||
|
|
||||||
|
|
||||||
class TiffImageFile(ImageFile.ImageFile):
|
class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
format = "TIFF"
|
format = "TIFF"
|
||||||
|
@ -966,9 +1014,11 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
if not self.__next:
|
if not self.__next:
|
||||||
raise EOFError("no more images in TIFF file")
|
raise EOFError("no more images in TIFF file")
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("Seeking to frame %s, on frame %s, "
|
print(
|
||||||
"__next %s, location: %s" %
|
"Seeking to frame %s, on frame %s, "
|
||||||
(frame, self.__frame, self.__next, self.fp.tell()))
|
"__next %s, location: %s"
|
||||||
|
% (frame, self.__frame, self.__next, self.fp.tell())
|
||||||
|
)
|
||||||
# reset python3 buffered io handle in case fp
|
# reset python3 buffered io handle in case fp
|
||||||
# was passed to libtiff, invalidating the buffer
|
# was passed to libtiff, invalidating the buffer
|
||||||
self.fp.tell()
|
self.fp.tell()
|
||||||
|
@ -1004,7 +1054,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
if JPEGTABLES in self.tag_v2:
|
if JPEGTABLES in self.tag_v2:
|
||||||
# Hack to handle abbreviated JPEG headers
|
# Hack to handle abbreviated JPEG headers
|
||||||
# FIXME This will fail with more than one value
|
# FIXME This will fail with more than one value
|
||||||
self.tile_prefix, = self.tag_v2[JPEGTABLES]
|
(self.tile_prefix,) = self.tag_v2[JPEGTABLES]
|
||||||
elif compression == "packbits":
|
elif compression == "packbits":
|
||||||
args = rawmode
|
args = rawmode
|
||||||
elif compression == "tiff_lzw":
|
elif compression == "tiff_lzw":
|
||||||
|
@ -1014,7 +1064,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.decoderconfig = (self.tag_v2[PREDICTOR],)
|
self.decoderconfig = (self.tag_v2[PREDICTOR],)
|
||||||
|
|
||||||
if ICCPROFILE in self.tag_v2:
|
if ICCPROFILE in self.tag_v2:
|
||||||
self.info['icc_profile'] = self.tag_v2[ICCPROFILE]
|
self.info["icc_profile"] = self.tag_v2[ICCPROFILE]
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
@ -1030,25 +1080,24 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
pixel = Image.Image.load(self)
|
pixel = Image.Image.load(self)
|
||||||
|
|
||||||
if self.tile is None:
|
if self.tile is None:
|
||||||
raise IOError("cannot load this image")
|
raise OSError("cannot load this image")
|
||||||
if not self.tile:
|
if not self.tile:
|
||||||
return pixel
|
return pixel
|
||||||
|
|
||||||
self.load_prepare()
|
self.load_prepare()
|
||||||
|
|
||||||
if not len(self.tile) == 1:
|
if not len(self.tile) == 1:
|
||||||
raise IOError("Not exactly one tile")
|
raise OSError("Not exactly one tile")
|
||||||
|
|
||||||
# (self._compression, (extents tuple),
|
# (self._compression, (extents tuple),
|
||||||
# 0, (rawmode, self._compression, fp))
|
# 0, (rawmode, self._compression, fp))
|
||||||
extents = self.tile[0][1]
|
extents = self.tile[0][1]
|
||||||
args = self.tile[0][3] + (self.tag_v2.offset,)
|
args = self.tile[0][3] + (self.tag_v2.offset,)
|
||||||
decoder = Image._getdecoder(self.mode, 'libtiff', args,
|
decoder = Image._getdecoder(self.mode, "libtiff", args, self.decoderconfig)
|
||||||
self.decoderconfig)
|
|
||||||
try:
|
try:
|
||||||
decoder.setimage(self.im, extents)
|
decoder.setimage(self.im, extents)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise IOError("Couldn't set the image")
|
raise OSError("Couldn't set the image")
|
||||||
|
|
||||||
if hasattr(self.fp, "getvalue"):
|
if hasattr(self.fp, "getvalue"):
|
||||||
# We've got a stringio like thing passed in. Yay for all in memory.
|
# We've got a stringio like thing passed in. Yay for all in memory.
|
||||||
|
@ -1080,13 +1129,13 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.tile = []
|
self.tile = []
|
||||||
self.readonly = 0
|
self.readonly = 0
|
||||||
# libtiff closed the fp in a, we need to close self.fp, if possible
|
# libtiff closed the fp in a, we need to close self.fp, if possible
|
||||||
if hasattr(self.fp, 'close'):
|
if hasattr(self.fp, "close"):
|
||||||
if not self.__next:
|
if not self.__next:
|
||||||
self.fp.close()
|
self.fp.close()
|
||||||
self.fp = None # might be shared
|
self.fp = None # might be shared
|
||||||
|
|
||||||
if err < 0:
|
if err < 0:
|
||||||
raise IOError(err)
|
raise OSError(err)
|
||||||
|
|
||||||
self.load_end()
|
self.load_end()
|
||||||
|
|
||||||
|
@ -1096,7 +1145,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
"Setup this image object based on current tags"
|
"Setup this image object based on current tags"
|
||||||
|
|
||||||
if 0xBC01 in self.tag_v2:
|
if 0xBC01 in self.tag_v2:
|
||||||
raise IOError("Windows Media Photo files not yet supported")
|
raise OSError("Windows Media Photo files not yet supported")
|
||||||
|
|
||||||
# extract relevant tags
|
# extract relevant tags
|
||||||
self._compression = COMPRESSION_INFO[self.tag_v2.get(COMPRESSION, 1)]
|
self._compression = COMPRESSION_INFO[self.tag_v2.get(COMPRESSION, 1)]
|
||||||
|
@ -1134,9 +1183,12 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# mode: check photometric interpretation and bits per pixel
|
# mode: check photometric interpretation and bits per pixel
|
||||||
key = (
|
key = (
|
||||||
self.tag_v2.prefix, photo, format, fillorder,
|
self.tag_v2.prefix,
|
||||||
|
photo,
|
||||||
|
format,
|
||||||
|
fillorder,
|
||||||
self.tag_v2.get(BITSPERSAMPLE, (1,)),
|
self.tag_v2.get(BITSPERSAMPLE, (1,)),
|
||||||
self.tag_v2.get(EXTRASAMPLES, ())
|
self.tag_v2.get(EXTRASAMPLES, ()),
|
||||||
)
|
)
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("format key:", key)
|
print("format key:", key)
|
||||||
|
@ -1174,14 +1226,18 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
offsets = self.tag_v2[STRIPOFFSETS]
|
offsets = self.tag_v2[STRIPOFFSETS]
|
||||||
h = self.tag_v2.get(ROWSPERSTRIP, ysize)
|
h = self.tag_v2.get(ROWSPERSTRIP, ysize)
|
||||||
w = self.size[0]
|
w = self.size[0]
|
||||||
if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3",
|
if READ_LIBTIFF or self._compression in [
|
||||||
"group4", "tiff_jpeg",
|
"tiff_ccitt",
|
||||||
|
"group3",
|
||||||
|
"group4",
|
||||||
|
"tiff_jpeg",
|
||||||
"tiff_adobe_deflate",
|
"tiff_adobe_deflate",
|
||||||
"tiff_thunderscan",
|
"tiff_thunderscan",
|
||||||
"tiff_deflate",
|
"tiff_deflate",
|
||||||
"tiff_sgilog",
|
"tiff_sgilog",
|
||||||
"tiff_sgilog24",
|
"tiff_sgilog24",
|
||||||
"tiff_raw_16"]:
|
"tiff_raw_16",
|
||||||
|
]:
|
||||||
# if DEBUG:
|
# if DEBUG:
|
||||||
# print "Activating g4 compression for whole file"
|
# print "Activating g4 compression for whole file"
|
||||||
|
|
||||||
|
@ -1201,14 +1257,13 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# libtiff closes the file descriptor, so pass in a dup.
|
# libtiff closes the file descriptor, so pass in a dup.
|
||||||
try:
|
try:
|
||||||
fp = hasattr(self.fp, "fileno") and \
|
fp = hasattr(self.fp, "fileno") and os.dup(self.fp.fileno())
|
||||||
os.dup(self.fp.fileno())
|
|
||||||
# flush the file descriptor, prevents error on pypy 2.4+
|
# flush the file descriptor, prevents error on pypy 2.4+
|
||||||
# should also eliminate the need for fp.tell for py3
|
# should also eliminate the need for fp.tell for py3
|
||||||
# in _seek
|
# in _seek
|
||||||
if hasattr(self.fp, "flush"):
|
if hasattr(self.fp, "flush"):
|
||||||
self.fp.flush()
|
self.fp.flush()
|
||||||
except IOError:
|
except OSError:
|
||||||
# io.BytesIO have a fileno, but returns an IOError if
|
# io.BytesIO have a fileno, but returns an IOError if
|
||||||
# it doesn't use a file descriptor.
|
# it doesn't use a file descriptor.
|
||||||
fp = False
|
fp = False
|
||||||
|
@ -1219,9 +1274,12 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
# https://github.com/python-pillow/Pillow/issues/279
|
# https://github.com/python-pillow/Pillow/issues/279
|
||||||
if fillorder == 2:
|
if fillorder == 2:
|
||||||
key = (
|
key = (
|
||||||
self.tag_v2.prefix, photo, format, 1,
|
self.tag_v2.prefix,
|
||||||
|
photo,
|
||||||
|
format,
|
||||||
|
1,
|
||||||
self.tag_v2.get(BITSPERSAMPLE, (1,)),
|
self.tag_v2.get(BITSPERSAMPLE, (1,)),
|
||||||
self.tag_v2.get(EXTRASAMPLES, ())
|
self.tag_v2.get(EXTRASAMPLES, ()),
|
||||||
)
|
)
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("format key:", key)
|
print("format key:", key)
|
||||||
|
@ -1233,25 +1291,26 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
# we're expecting image byte order. So, if the rawmode
|
# we're expecting image byte order. So, if the rawmode
|
||||||
# contains I;16, we need to convert from native to image
|
# contains I;16, we need to convert from native to image
|
||||||
# byte order.
|
# byte order.
|
||||||
if self.mode in ('I;16B', 'I;16') and 'I;16' in rawmode:
|
if self.mode in ("I;16B", "I;16") and "I;16" in rawmode:
|
||||||
rawmode = 'I;16N'
|
rawmode = "I;16N"
|
||||||
|
|
||||||
# Offset in the tile tuple is 0, we go from 0,0 to
|
# Offset in the tile tuple is 0, we go from 0,0 to
|
||||||
# w,h, and we only do this once -- eds
|
# w,h, and we only do this once -- eds
|
||||||
a = (rawmode, self._compression, fp)
|
a = (rawmode, self._compression, fp)
|
||||||
self.tile.append(
|
self.tile.append((self._compression, (0, 0, w, ysize), 0, a))
|
||||||
(self._compression,
|
|
||||||
(0, 0, w, ysize),
|
|
||||||
0, a))
|
|
||||||
a = None
|
a = None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for i in range(len(offsets)):
|
for i in range(len(offsets)):
|
||||||
a = self._decoder(rawmode, l, i)
|
a = self._decoder(rawmode, l, i)
|
||||||
self.tile.append(
|
self.tile.append(
|
||||||
(self._compression,
|
(
|
||||||
|
self._compression,
|
||||||
(0, min(y, ysize), w, min(y + h, ysize)),
|
(0, min(y, ysize), w, min(y + h, ysize)),
|
||||||
offsets[i], a))
|
offsets[i],
|
||||||
|
a,
|
||||||
|
)
|
||||||
|
)
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("tiles: ", self.tile)
|
print("tiles: ", self.tile)
|
||||||
y = y + h
|
y = y + h
|
||||||
|
@ -1269,10 +1328,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
a = self._decoder(rawmode, l)
|
a = self._decoder(rawmode, l)
|
||||||
# FIXME: this doesn't work if the image size
|
# FIXME: this doesn't work if the image size
|
||||||
# is not a multiple of the tile size...
|
# is not a multiple of the tile size...
|
||||||
self.tile.append(
|
self.tile.append((self._compression, (x, y, x + w, y + h), o, a))
|
||||||
(self._compression,
|
|
||||||
(x, y, x+w, y+h),
|
|
||||||
o, a))
|
|
||||||
x = x + w
|
x = x + w
|
||||||
if x >= self.size[0]:
|
if x >= self.size[0]:
|
||||||
x, y = 0, y + h
|
x, y = 0, y + h
|
||||||
|
@ -1290,6 +1346,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
if self.mode == "P":
|
if self.mode == "P":
|
||||||
palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
|
palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
|
||||||
self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
|
self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Write TIFF files
|
# Write TIFF files
|
||||||
|
@ -1315,7 +1373,6 @@ SAVE_INFO = {
|
||||||
"CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
|
"CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
|
||||||
"YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
|
"YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
|
||||||
"LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
|
"LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
|
||||||
|
|
||||||
"I;32BS": ("I;32BS", MM, 1, 2, (32,), None),
|
"I;32BS": ("I;32BS", MM, 1, 2, (32,), None),
|
||||||
"I;16B": ("I;16B", MM, 1, 1, (16,), None),
|
"I;16B": ("I;16B", MM, 1, 1, (16,), None),
|
||||||
"I;16BS": ("I;16BS", MM, 1, 2, (16,), None),
|
"I;16BS": ("I;16BS", MM, 1, 2, (16,), None),
|
||||||
|
@ -1328,17 +1385,16 @@ def _save(im, fp, filename):
|
||||||
try:
|
try:
|
||||||
rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
|
rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise IOError("cannot write mode %s as TIFF" % im.mode)
|
raise OSError("cannot write mode %s as TIFF" % im.mode)
|
||||||
|
|
||||||
ifd = ImageFileDirectory_v2(prefix=prefix)
|
ifd = ImageFileDirectory_v2(prefix=prefix)
|
||||||
|
|
||||||
compression = im.encoderinfo.get('compression',
|
compression = im.encoderinfo.get("compression", im.info.get("compression", "raw"))
|
||||||
im.info.get('compression', 'raw'))
|
|
||||||
|
|
||||||
libtiff = WRITE_LIBTIFF or compression != 'raw'
|
libtiff = WRITE_LIBTIFF or compression != "raw"
|
||||||
|
|
||||||
# required for color libtiff images
|
# required for color libtiff images
|
||||||
ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)
|
ifd[PLANAR_CONFIGURATION] = getattr(im, "_planar_configuration", 1)
|
||||||
|
|
||||||
ifd[IMAGEWIDTH] = im.size[0]
|
ifd[IMAGEWIDTH] = im.size[0]
|
||||||
ifd[IMAGELENGTH] = im.size[1]
|
ifd[IMAGELENGTH] = im.size[1]
|
||||||
|
@ -1358,10 +1414,16 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
# additions written by Greg Couch, gregc@cgl.ucsf.edu
|
# additions written by Greg Couch, gregc@cgl.ucsf.edu
|
||||||
# inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
|
# inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
|
||||||
if hasattr(im, 'tag_v2'):
|
if hasattr(im, "tag_v2"):
|
||||||
# preserve tags from original TIFF image file
|
# preserve tags from original TIFF image file
|
||||||
for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION,
|
for key in (
|
||||||
IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
|
RESOLUTION_UNIT,
|
||||||
|
X_RESOLUTION,
|
||||||
|
Y_RESOLUTION,
|
||||||
|
IPTC_NAA_CHUNK,
|
||||||
|
PHOTOSHOP_CHUNK,
|
||||||
|
XMP,
|
||||||
|
):
|
||||||
if key in im.tag_v2:
|
if key in im.tag_v2:
|
||||||
ifd[key] = im.tag_v2[key]
|
ifd[key] = im.tag_v2[key]
|
||||||
ifd.tagtype[key] = im.tag_v2.tagtype.get(key, None)
|
ifd.tagtype[key] = im.tag_v2.tagtype.get(key, None)
|
||||||
|
@ -1371,7 +1433,8 @@ def _save(im, fp, filename):
|
||||||
if "icc_profile" in im.info:
|
if "icc_profile" in im.info:
|
||||||
ifd[ICCPROFILE] = im.info["icc_profile"]
|
ifd[ICCPROFILE] = im.info["icc_profile"]
|
||||||
|
|
||||||
for key, name in [(IMAGEDESCRIPTION, "description"),
|
for key, name in [
|
||||||
|
(IMAGEDESCRIPTION, "description"),
|
||||||
(X_RESOLUTION, "resolution"),
|
(X_RESOLUTION, "resolution"),
|
||||||
(Y_RESOLUTION, "resolution"),
|
(Y_RESOLUTION, "resolution"),
|
||||||
(X_RESOLUTION, "x_resolution"),
|
(X_RESOLUTION, "x_resolution"),
|
||||||
|
@ -1380,11 +1443,14 @@ def _save(im, fp, filename):
|
||||||
(SOFTWARE, "software"),
|
(SOFTWARE, "software"),
|
||||||
(DATE_TIME, "date_time"),
|
(DATE_TIME, "date_time"),
|
||||||
(ARTIST, "artist"),
|
(ARTIST, "artist"),
|
||||||
(COPYRIGHT, "copyright")]:
|
(COPYRIGHT, "copyright"),
|
||||||
|
]:
|
||||||
name_with_spaces = name.replace("_", " ")
|
name_with_spaces = name.replace("_", " ")
|
||||||
if "_" in name and name_with_spaces in im.encoderinfo:
|
if "_" in name and name_with_spaces in im.encoderinfo:
|
||||||
warnings.warn("%r is deprecated; use %r instead" %
|
warnings.warn(
|
||||||
(name_with_spaces, name), DeprecationWarning)
|
"%r is deprecated; use %r instead" % (name_with_spaces, name),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
ifd[key] = im.encoderinfo[name.replace("_", " ")]
|
ifd[key] = im.encoderinfo[name.replace("_", " ")]
|
||||||
if name in im.encoderinfo:
|
if name in im.encoderinfo:
|
||||||
ifd[key] = im.encoderinfo[name]
|
ifd[key] = im.encoderinfo[name]
|
||||||
|
@ -1440,11 +1506,11 @@ def _save(im, fp, filename):
|
||||||
# the original file, e.g x,y resolution so that we can
|
# the original file, e.g x,y resolution so that we can
|
||||||
# save(load('')) == original file.
|
# save(load('')) == original file.
|
||||||
legacy_ifd = {}
|
legacy_ifd = {}
|
||||||
if hasattr(im, 'tag'):
|
if hasattr(im, "tag"):
|
||||||
legacy_ifd = im.tag.to_v2()
|
legacy_ifd = im.tag.to_v2()
|
||||||
for tag, value in itertools.chain(ifd.items(),
|
for tag, value in itertools.chain(
|
||||||
getattr(im, 'tag_v2', {}).items(),
|
ifd.items(), getattr(im, "tag_v2", {}).items(), legacy_ifd.items()
|
||||||
legacy_ifd.items()):
|
):
|
||||||
# Libtiff can only process certain core items without adding
|
# Libtiff can only process certain core items without adding
|
||||||
# them to the custom dictionary. It will segfault if it attempts
|
# them to the custom dictionary. It will segfault if it attempts
|
||||||
# to add a custom tag without the dictionary entry
|
# to add a custom tag without the dictionary entry
|
||||||
|
@ -1454,7 +1520,7 @@ def _save(im, fp, filename):
|
||||||
continue
|
continue
|
||||||
if tag not in atts and tag not in blocklist:
|
if tag not in atts and tag not in blocklist:
|
||||||
if isinstance(value, unicode if bytes is str else str):
|
if isinstance(value, unicode if bytes is str else str):
|
||||||
atts[tag] = value.encode('ascii', 'replace') + b"\0"
|
atts[tag] = value.encode("ascii", "replace") + b"\0"
|
||||||
elif isinstance(value, IFDRational):
|
elif isinstance(value, IFDRational):
|
||||||
atts[tag] = float(value)
|
atts[tag] = float(value)
|
||||||
else:
|
else:
|
||||||
|
@ -1467,12 +1533,12 @@ def _save(im, fp, filename):
|
||||||
# we're storing image byte order. So, if the rawmode
|
# we're storing image byte order. So, if the rawmode
|
||||||
# contains I;16, we need to convert from native to image
|
# contains I;16, we need to convert from native to image
|
||||||
# byte order.
|
# byte order.
|
||||||
if im.mode in ('I;16B', 'I;16'):
|
if im.mode in ("I;16B", "I;16"):
|
||||||
rawmode = 'I;16N'
|
rawmode = "I;16N"
|
||||||
|
|
||||||
a = (rawmode, compression, _fp, filename, atts)
|
a = (rawmode, compression, _fp, filename, atts)
|
||||||
# print(im.mode, compression, a, im.encoderconfig)
|
# print(im.mode, compression, a, im.encoderconfig)
|
||||||
e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
|
e = Image._getencoder(im.mode, "libtiff", a, im.encoderconfig)
|
||||||
e.setimage(im.im, (0, 0) + im.size)
|
e.setimage(im.im, (0, 0) + im.size)
|
||||||
while True:
|
while True:
|
||||||
# undone, change to self.decodermaxblock:
|
# undone, change to self.decodermaxblock:
|
||||||
|
@ -1482,20 +1548,21 @@ def _save(im, fp, filename):
|
||||||
if s:
|
if s:
|
||||||
break
|
break
|
||||||
if s < 0:
|
if s < 0:
|
||||||
raise IOError("encoder error %d when writing image file" % s)
|
raise OSError("encoder error %d when writing image file" % s)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
offset = ifd.save(fp)
|
offset = ifd.save(fp)
|
||||||
|
|
||||||
ImageFile._save(im, fp, [
|
ImageFile._save(
|
||||||
("raw", (0, 0)+im.size, offset, (rawmode, stride, 1))
|
im, fp, [("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))]
|
||||||
])
|
)
|
||||||
|
|
||||||
# -- helper for multi-page save --
|
# -- helper for multi-page save --
|
||||||
if "_debug_multipage" in im.encoderinfo:
|
if "_debug_multipage" in im.encoderinfo:
|
||||||
# just to access o32 and o16 (using correct byte order)
|
# just to access o32 and o16 (using correct byte order)
|
||||||
im._debug_multipage = ifd
|
im._debug_multipage = ifd
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# Register
|
# Register
|
||||||
|
|
|
@ -964,7 +964,7 @@ class TestFileTiffW32:
|
||||||
"""Test opening multiband TIFFs and reading all channels."""
|
"""Test opening multiband TIFFs and reading all channels."""
|
||||||
base_value = 4660
|
base_value = 4660
|
||||||
for i in range(2, 6):
|
for i in range(2, 6):
|
||||||
infile = "Tests/images/uint16_{}_{}.tif".format(i, base_value)
|
infile = f"Tests/images/uint16_{i}_{base_value}.tif"
|
||||||
im = Image.open(infile)
|
im = Image.open(infile)
|
||||||
im.load()
|
im.load()
|
||||||
pixel = [base_value + j for j in range(0, i)]
|
pixel = [base_value + j for j in range(0, i)]
|
||||||
|
@ -973,5 +973,6 @@ class TestFileTiffW32:
|
||||||
actual_pixel = [actual_pixel]
|
actual_pixel = [actual_pixel]
|
||||||
self.assertEqual(actual_pixel, pixel)
|
self.assertEqual(actual_pixel, pixel)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user