mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 02:36:17 +03:00
commit
bcded33cee
|
@ -16,7 +16,6 @@ trim_trailing_whitespace = true
|
||||||
[*.yml]
|
[*.yml]
|
||||||
# Two-space indentation
|
# Two-space indentation
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
|
||||||
|
|
||||||
# Tab indentation (no size specified)
|
# Tab indentation (no size specified)
|
||||||
[Makefile]
|
[Makefile]
|
||||||
|
|
|
@ -567,7 +567,7 @@ class TestTransformColorLut3D:
|
||||||
assert tuple(lut.size) == tuple(source.size)
|
assert tuple(lut.size) == tuple(source.size)
|
||||||
assert len(lut.table) == len(source.table)
|
assert len(lut.table) == len(source.table)
|
||||||
assert lut.table != source.table
|
assert lut.table != source.table
|
||||||
assert lut.table[0:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
|
assert lut.table[:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
|
||||||
|
|
||||||
def test_3_to_4_channels(self):
|
def test_3_to_4_channels(self):
|
||||||
source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b))
|
source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b))
|
||||||
|
@ -576,7 +576,7 @@ class TestTransformColorLut3D:
|
||||||
assert len(lut.table) != len(source.table)
|
assert len(lut.table) != len(source.table)
|
||||||
assert lut.table != source.table
|
assert lut.table != source.table
|
||||||
# fmt: off
|
# fmt: off
|
||||||
assert lut.table[0:16] == [
|
assert lut.table[:16] == [
|
||||||
0.0, 0.0, 0.0, 1, 0.2**2, 0.0, 0.0, 1,
|
0.0, 0.0, 0.0, 1, 0.2**2, 0.0, 0.0, 1,
|
||||||
0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1]
|
0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
@ -592,7 +592,7 @@ class TestTransformColorLut3D:
|
||||||
assert len(lut.table) != len(source.table)
|
assert len(lut.table) != len(source.table)
|
||||||
assert lut.table != source.table
|
assert lut.table != source.table
|
||||||
# fmt: off
|
# fmt: off
|
||||||
assert lut.table[0:18] == [
|
assert lut.table[:18] == [
|
||||||
1.0, 1.0, 1.0, 0.75, 1.0, 1.0, 0.0, 1.0, 1.0,
|
1.0, 1.0, 1.0, 0.75, 1.0, 1.0, 0.0, 1.0, 1.0,
|
||||||
1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0]
|
1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
@ -606,7 +606,7 @@ class TestTransformColorLut3D:
|
||||||
assert len(lut.table) == len(source.table)
|
assert len(lut.table) == len(source.table)
|
||||||
assert lut.table != source.table
|
assert lut.table != source.table
|
||||||
# fmt: off
|
# fmt: off
|
||||||
assert lut.table[0:16] == [
|
assert lut.table[:16] == [
|
||||||
0.0, 0.0, 0.0, 0.5, 0.2**2, 0.0, 0.0, 0.5,
|
0.0, 0.0, 0.0, 0.5, 0.2**2, 0.0, 0.0, 0.5,
|
||||||
0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5]
|
0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
@ -622,7 +622,7 @@ class TestTransformColorLut3D:
|
||||||
assert len(lut.table) == len(source.table)
|
assert len(lut.table) == len(source.table)
|
||||||
assert lut.table != source.table
|
assert lut.table != source.table
|
||||||
# fmt: off
|
# fmt: off
|
||||||
assert lut.table[0:18] == [
|
assert lut.table[:18] == [
|
||||||
0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.24, 0.0, 0.0,
|
0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.24, 0.0, 0.0,
|
||||||
0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0]
|
0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
@ -639,7 +639,7 @@ class TestTransformColorLut3D:
|
||||||
assert len(lut.table) == len(source.table)
|
assert len(lut.table) == len(source.table)
|
||||||
assert lut.table != source.table
|
assert lut.table != source.table
|
||||||
# fmt: off
|
# fmt: off
|
||||||
assert lut.table[0:16] == [
|
assert lut.table[:16] == [
|
||||||
0.0, 0.0, 0.0, 0.5, 0.25, 0.0, 0.0, 0.5,
|
0.0, 0.0, 0.0, 0.5, 0.25, 0.0, 0.0, 0.5,
|
||||||
0.0, 0.0, 0.0, 0.5, 0.0, 0.16, 0.0, 0.5]
|
0.0, 0.0, 0.0, 0.5, 0.0, 0.16, 0.0, 0.5]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
|
@ -70,12 +70,12 @@ class TestDecompressionBomb:
|
||||||
|
|
||||||
class TestDecompressionCrop:
|
class TestDecompressionCrop:
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup_class(self):
|
def setup_class(cls):
|
||||||
width, height = 128, 128
|
width, height = 128, 128
|
||||||
Image.MAX_IMAGE_PIXELS = height * width * 4 - 1
|
Image.MAX_IMAGE_PIXELS = height * width * 4 - 1
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def teardown_class(self):
|
def teardown_class(cls):
|
||||||
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
|
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
|
||||||
|
|
||||||
def test_enlarge_crop(self):
|
def test_enlarge_crop(self):
|
||||||
|
|
|
@ -170,7 +170,7 @@ class TestImage:
|
||||||
temp_file = str(tmp_path / "temp.jpg")
|
temp_file = str(tmp_path / "temp.jpg")
|
||||||
|
|
||||||
class FP:
|
class FP:
|
||||||
def write(a, b):
|
def write(self, b):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
fp = FP()
|
fp = FP()
|
||||||
|
|
|
@ -27,15 +27,15 @@ def test_sanity():
|
||||||
"HSV",
|
"HSV",
|
||||||
)
|
)
|
||||||
|
|
||||||
for mode in modes:
|
for input_mode in modes:
|
||||||
im = hopper(mode)
|
im = hopper(input_mode)
|
||||||
for mode in modes:
|
for output_mode in modes:
|
||||||
convert(im, mode)
|
convert(im, output_mode)
|
||||||
|
|
||||||
# Check 0
|
# Check 0
|
||||||
im = Image.new(mode, (0, 0))
|
im = Image.new(input_mode, (0, 0))
|
||||||
for mode in modes:
|
for output_mode in modes:
|
||||||
convert(im, mode)
|
convert(im, output_mode)
|
||||||
|
|
||||||
|
|
||||||
def test_default():
|
def test_default():
|
||||||
|
|
|
@ -458,7 +458,7 @@ class TestCoreResampleBox:
|
||||||
def split_range(size, tiles):
|
def split_range(size, tiles):
|
||||||
scale = size / tiles
|
scale = size / tiles
|
||||||
for i in range(tiles):
|
for i in range(tiles):
|
||||||
yield (int(round(scale * i)), int(round(scale * (i + 1))))
|
yield int(round(scale * i)), int(round(scale * (i + 1)))
|
||||||
|
|
||||||
tiled = Image.new(im.mode, dst_size)
|
tiled = Image.new(im.mode, dst_size)
|
||||||
scale = (im.size[0] / tiled.size[0], im.size[1] / tiled.size[1])
|
scale = (im.size[0] / tiled.size[0], im.size[1] / tiled.size[1])
|
||||||
|
|
|
@ -77,9 +77,9 @@ def test_consecutive():
|
||||||
def test_palette_mmap():
|
def test_palette_mmap():
|
||||||
# Using mmap in ImageFile can require to reload the palette.
|
# Using mmap in ImageFile can require to reload the palette.
|
||||||
with Image.open("Tests/images/multipage-mmap.tiff") as im:
|
with Image.open("Tests/images/multipage-mmap.tiff") as im:
|
||||||
color1 = im.getpalette()[0:3]
|
color1 = im.getpalette()[:3]
|
||||||
im.seek(0)
|
im.seek(0)
|
||||||
color2 = im.getpalette()[0:3]
|
color2 = im.getpalette()[:3]
|
||||||
assert color1 == color2
|
assert color1 == color2
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,10 @@ metadata tag numbers, names, and type information.
|
||||||
.. method:: lookup(tag)
|
.. method:: lookup(tag)
|
||||||
|
|
||||||
:param tag: Integer tag number
|
:param tag: Integer tag number
|
||||||
|
:param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in
|
||||||
|
|
||||||
|
.. versionadded:: 8.3.0
|
||||||
|
|
||||||
:returns: Taginfo namedtuple, From the :py:data:`~PIL.TiffTags.TAGS_V2` info if possible,
|
:returns: Taginfo namedtuple, From the :py:data:`~PIL.TiffTags.TAGS_V2` info if possible,
|
||||||
otherwise just populating the value and name from :py:data:`~PIL.TiffTags.TAGS`.
|
otherwise just populating the value and name from :py:data:`~PIL.TiffTags.TAGS`.
|
||||||
If the tag is not recognized, "unknown" is returned for the name
|
If the tag is not recognized, "unknown" is returned for the name
|
||||||
|
@ -42,6 +46,16 @@ metadata tag numbers, names, and type information.
|
||||||
|
|
||||||
.. versionadded:: 3.0.0
|
.. versionadded:: 3.0.0
|
||||||
|
|
||||||
|
.. py:data:: PIL.TiffTags.TAGS_V2_GROUPS
|
||||||
|
:type: dict
|
||||||
|
|
||||||
|
:py:data:`~PIL.TiffTags.TAGS_V2` is one dimensional and
|
||||||
|
doesn't account for the fact that tags actually exist in
|
||||||
|
`different groups <https://exiftool.org/TagNames/EXIF.html>`_.
|
||||||
|
This dictionary is used when the tag in question is part of a group.
|
||||||
|
|
||||||
|
.. versionadded:: 8.3.0
|
||||||
|
|
||||||
.. py:data:: PIL.TiffTags.TAGS
|
.. py:data:: PIL.TiffTags.TAGS
|
||||||
:type: dict
|
:type: dict
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ def testimage():
|
||||||
|
|
||||||
>>> from PIL import Image, ImageDraw, ImageFilter, ImageMath
|
>>> from PIL import Image, ImageDraw, ImageFilter, ImageMath
|
||||||
>>> im = Image.new("1", (128, 128)) # monochrome
|
>>> im = Image.new("1", (128, 128)) # monochrome
|
||||||
>>> def _info(im): return (im.format, im.mode, im.size)
|
>>> def _info(im): return im.format, im.mode, im.size
|
||||||
>>> _info(im)
|
>>> _info(im)
|
||||||
(None, '1', (128, 128))
|
(None, '1', (128, 128))
|
||||||
>>> _info(Image.new("L", (128, 128))) # grayscale (luminance)
|
>>> _info(Image.new("L", (128, 128))) # grayscale (luminance)
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -269,7 +269,7 @@ def _pkg_config(name):
|
||||||
.strip()
|
.strip()
|
||||||
.replace("-I", "")
|
.replace("-I", "")
|
||||||
)
|
)
|
||||||
return (libs, cflags)
|
return libs, cflags
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ def __getattr__(name):
|
||||||
|
|
||||||
|
|
||||||
def unpack_565(i):
|
def unpack_565(i):
|
||||||
return (((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3)
|
return ((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3
|
||||||
|
|
||||||
|
|
||||||
def decode_dxt1(data, alpha=False):
|
def decode_dxt1(data, alpha=False):
|
||||||
|
|
|
@ -76,10 +76,8 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
read, seek = self.fp.read, self.fp.seek
|
read, seek = self.fp.read, self.fp.seek
|
||||||
if header:
|
if header:
|
||||||
seek(header)
|
seek(header)
|
||||||
file_info = {}
|
|
||||||
# read bmp header size @offset 14 (this is part of the header size)
|
# read bmp header size @offset 14 (this is part of the header size)
|
||||||
file_info["header_size"] = i32(read(4))
|
file_info = {"header_size": i32(read(4)), "direction": -1}
|
||||||
file_info["direction"] = -1
|
|
||||||
|
|
||||||
# -------------------- If requested, read header at a specific position
|
# -------------------- If requested, read header at a specific position
|
||||||
# read the rest of the bmp header, without its size
|
# read the rest of the bmp header, without its size
|
||||||
|
|
|
@ -325,7 +325,7 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("not an EPS file")
|
raise SyntaxError("not an EPS file")
|
||||||
|
|
||||||
return (length, offset)
|
return length, offset
|
||||||
|
|
||||||
def load(self, scale=1, transparency=False):
|
def load(self, scale=1, transparency=False):
|
||||||
# Load EPS via Ghostscript
|
# Load EPS via Ghostscript
|
||||||
|
|
|
@ -22,7 +22,7 @@ from ._binary import i32le as i32
|
||||||
# we map from colour field tuples to (mode, rawmode) descriptors
|
# we map from colour field tuples to (mode, rawmode) descriptors
|
||||||
MODES = {
|
MODES = {
|
||||||
# opacity
|
# opacity
|
||||||
(0x00007FFE): ("A", "L"),
|
(0x00007FFE,): ("A", "L"),
|
||||||
# monochrome
|
# monochrome
|
||||||
(0x00010000,): ("L", "L"),
|
(0x00010000,): ("L", "L"),
|
||||||
(0x00018000, 0x00017FFE): ("RGBA", "LA"),
|
(0x00018000, 0x00017FFE): ("RGBA", "LA"),
|
||||||
|
@ -162,7 +162,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
||||||
"raw",
|
"raw",
|
||||||
(x, y, x + xtile, y + ytile),
|
(x, y, x + xtile, y + ytile),
|
||||||
i32(s, i) + 28,
|
i32(s, i) + 28,
|
||||||
(self.rawmode),
|
(self.rawmode,),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ class FtexImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
if format == Format.DXT1:
|
if format == Format.DXT1:
|
||||||
self.mode = "RGBA"
|
self.mode = "RGBA"
|
||||||
self.tile = [("bcn", (0, 0) + self.size, 0, (1))]
|
self.tile = [("bcn", (0, 0) + self.size, 0, 1)]
|
||||||
elif format == Format.UNCOMPRESSED:
|
elif format == Format.UNCOMPRESSED:
|
||||||
self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]
|
self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -80,7 +80,7 @@ def open(fp, mode="r"):
|
||||||
"""
|
"""
|
||||||
Load texture from a GD image file.
|
Load texture from a GD image file.
|
||||||
|
|
||||||
:param filename: GD file name, or an opened file handle.
|
:param fp: GD file name, or an opened file handle.
|
||||||
:param mode: Optional mode. In this version, if the mode argument
|
:param mode: Optional mode. In this version, if the mode argument
|
||||||
is given, it must be "r".
|
is given, it must be "r".
|
||||||
:returns: An image instance.
|
:returns: An image instance.
|
||||||
|
|
|
@ -990,8 +990,6 @@ def getheader(im, palette=None, info=None):
|
||||||
return header, used_palette_colors
|
return header, used_palette_colors
|
||||||
|
|
||||||
|
|
||||||
# To specify duration, add the time in milliseconds to getdata(),
|
|
||||||
# e.g. getdata(im_frame, duration=1000)
|
|
||||||
def getdata(im, offset=(0, 0), **params):
|
def getdata(im, offset=(0, 0), **params):
|
||||||
"""
|
"""
|
||||||
Legacy Method
|
Legacy Method
|
||||||
|
@ -1000,10 +998,13 @@ def getdata(im, offset=(0, 0), **params):
|
||||||
The first string is a local image header, the rest contains
|
The first string is a local image header, the rest contains
|
||||||
encoded image data.
|
encoded image data.
|
||||||
|
|
||||||
|
To specify duration, add the time in milliseconds,
|
||||||
|
e.g. ``getdata(im_frame, duration=1000)``
|
||||||
|
|
||||||
:param im: Image object
|
:param im: Image object
|
||||||
:param offset: Tuple of (x, y) pixels. Defaults to (0, 0)
|
:param offset: Tuple of (x, y) pixels. Defaults to (0, 0)
|
||||||
:param \\**params: E.g. duration or other encoder info parameters
|
:param \\**params: e.g. duration or other encoder info parameters
|
||||||
:returns: List of Bytes containing gif encoded frame data
|
:returns: List of bytes containing GIF encoded frame data
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ def register_handler(handler):
|
||||||
|
|
||||||
|
|
||||||
def _accept(prefix):
|
def _accept(prefix):
|
||||||
return prefix[0:4] == b"GRIB" and prefix[7] == 1
|
return prefix[:4] == b"GRIB" and prefix[7] == 1
|
||||||
|
|
||||||
|
|
||||||
class GribStubImageFile(ImageFile.StubImageFile):
|
class GribStubImageFile(ImageFile.StubImageFile):
|
||||||
|
|
|
@ -210,7 +210,7 @@ class ImImageFile(ImageFile.ImageFile):
|
||||||
self.mode = self.info[MODE]
|
self.mode = self.info[MODE]
|
||||||
|
|
||||||
# Skip forward to start of image data
|
# Skip forward to start of image data
|
||||||
while s and s[0:1] != b"\x1A":
|
while s and s[:1] != b"\x1A":
|
||||||
s = self.fp.read(1)
|
s = self.fp.read(1)
|
||||||
if not s:
|
if not s:
|
||||||
raise SyntaxError("File truncated")
|
raise SyntaxError("File truncated")
|
||||||
|
|
|
@ -2546,7 +2546,7 @@ class Image:
|
||||||
h = box[3] - box[1]
|
h = box[3] - box[1]
|
||||||
|
|
||||||
if method == Transform.AFFINE:
|
if method == Transform.AFFINE:
|
||||||
data = data[0:6]
|
data = data[:6]
|
||||||
|
|
||||||
elif method == Transform.EXTENT:
|
elif method == Transform.EXTENT:
|
||||||
# convert extent to an affine transform
|
# convert extent to an affine transform
|
||||||
|
@ -2557,12 +2557,12 @@ class Image:
|
||||||
data = (xs, 0, x0, 0, ys, y0)
|
data = (xs, 0, x0, 0, ys, y0)
|
||||||
|
|
||||||
elif method == Transform.PERSPECTIVE:
|
elif method == Transform.PERSPECTIVE:
|
||||||
data = data[0:8]
|
data = data[:8]
|
||||||
|
|
||||||
elif method == Transform.QUAD:
|
elif method == Transform.QUAD:
|
||||||
# quadrilateral warp. data specifies the four corners
|
# quadrilateral warp. data specifies the four corners
|
||||||
# given as NW, SW, SE, and NE.
|
# given as NW, SW, SE, and NE.
|
||||||
nw = data[0:2]
|
nw = data[:2]
|
||||||
sw = data[2:4]
|
sw = data[2:4]
|
||||||
se = data[4:6]
|
se = data[4:6]
|
||||||
ne = data[6:8]
|
ne = data[6:8]
|
||||||
|
@ -2956,12 +2956,11 @@ _fromarray_typemap = {
|
||||||
((1, 1, 2), "|u1"): ("LA", "LA"),
|
((1, 1, 2), "|u1"): ("LA", "LA"),
|
||||||
((1, 1, 3), "|u1"): ("RGB", "RGB"),
|
((1, 1, 3), "|u1"): ("RGB", "RGB"),
|
||||||
((1, 1, 4), "|u1"): ("RGBA", "RGBA"),
|
((1, 1, 4), "|u1"): ("RGBA", "RGBA"),
|
||||||
|
# shortcuts:
|
||||||
|
((1, 1), _ENDIAN + "i4"): ("I", "I"),
|
||||||
|
((1, 1), _ENDIAN + "f4"): ("F", "F"),
|
||||||
}
|
}
|
||||||
|
|
||||||
# shortcuts
|
|
||||||
_fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I")
|
|
||||||
_fromarray_typemap[((1, 1), _ENDIAN + "f4")] = ("F", "F")
|
|
||||||
|
|
||||||
|
|
||||||
def _decompression_bomb_check(size):
|
def _decompression_bomb_check(size):
|
||||||
if MAX_IMAGE_PIXELS is None:
|
if MAX_IMAGE_PIXELS is None:
|
||||||
|
|
|
@ -316,6 +316,7 @@ def offset(image, xoffset, yoffset=None):
|
||||||
distances. Data wraps around the edges. If ``yoffset`` is omitted, it
|
distances. Data wraps around the edges. If ``yoffset`` is omitted, it
|
||||||
is assumed to be equal to ``xoffset``.
|
is assumed to be equal to ``xoffset``.
|
||||||
|
|
||||||
|
:param image: Input image.
|
||||||
:param xoffset: The horizontal distance.
|
:param xoffset: The horizontal distance.
|
||||||
:param yoffset: The vertical distance. If omitted, both
|
:param yoffset: The vertical distance. If omitted, both
|
||||||
distances are set to the same value.
|
distances are set to the same value.
|
||||||
|
|
|
@ -150,7 +150,7 @@ FLAGS = {
|
||||||
"SOFTPROOFING": 16384, # Do softproofing
|
"SOFTPROOFING": 16384, # Do softproofing
|
||||||
"PRESERVEBLACK": 32768, # Black preservation
|
"PRESERVEBLACK": 32768, # Black preservation
|
||||||
"NODEFAULTRESOURCEDEF": 16777216, # CRD special
|
"NODEFAULTRESOURCEDEF": 16777216, # CRD special
|
||||||
"GRIDPOINTS": lambda n: ((n) & 0xFF) << 16, # Gridpoints
|
"GRIDPOINTS": lambda n: (n & 0xFF) << 16, # Gridpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
_MAX_FLAG = 0
|
_MAX_FLAG = 0
|
||||||
|
@ -1014,4 +1014,4 @@ def versions():
|
||||||
(pyCMS) Fetches versions.
|
(pyCMS) Fetches versions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return (VERSION, core.littlecms_version, sys.version.split()[0], Image.__version__)
|
return VERSION, core.littlecms_version, sys.version.split()[0], Image.__version__
|
||||||
|
|
|
@ -45,7 +45,7 @@ def getrgb(color):
|
||||||
|
|
||||||
# check for known string formats
|
# check for known string formats
|
||||||
if re.match("#[a-f0-9]{3}$", color):
|
if re.match("#[a-f0-9]{3}$", color):
|
||||||
return (int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16))
|
return int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16)
|
||||||
|
|
||||||
if re.match("#[a-f0-9]{4}$", color):
|
if re.match("#[a-f0-9]{4}$", color):
|
||||||
return (
|
return (
|
||||||
|
@ -56,7 +56,7 @@ def getrgb(color):
|
||||||
)
|
)
|
||||||
|
|
||||||
if re.match("#[a-f0-9]{6}$", color):
|
if re.match("#[a-f0-9]{6}$", color):
|
||||||
return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
|
return int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)
|
||||||
|
|
||||||
if re.match("#[a-f0-9]{8}$", color):
|
if re.match("#[a-f0-9]{8}$", color):
|
||||||
return (
|
return (
|
||||||
|
@ -68,7 +68,7 @@ def getrgb(color):
|
||||||
|
|
||||||
m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
|
m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
|
||||||
if m:
|
if m:
|
||||||
return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
return int(m.group(1)), int(m.group(2)), int(m.group(3))
|
||||||
|
|
||||||
m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
|
m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
|
||||||
if m:
|
if m:
|
||||||
|
@ -114,25 +114,26 @@ def getrgb(color):
|
||||||
|
|
||||||
m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
|
m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
|
||||||
if m:
|
if m:
|
||||||
return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)))
|
return int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))
|
||||||
raise ValueError(f"unknown color specifier: {repr(color)}")
|
raise ValueError(f"unknown color specifier: {repr(color)}")
|
||||||
|
|
||||||
|
|
||||||
def getcolor(color, mode):
|
def getcolor(color, mode):
|
||||||
"""
|
"""
|
||||||
Same as :py:func:`~PIL.ImageColor.getrgb`, but converts the RGB value to a
|
Same as :py:func:`~PIL.ImageColor.getrgb`, but converts the RGB value to a
|
||||||
greyscale value if the mode is not color or a palette image. If the string
|
greyscale value if ``mode`` is not color or a palette image. If the string
|
||||||
cannot be parsed, this function raises a :py:exc:`ValueError` exception.
|
cannot be parsed, this function raises a :py:exc:`ValueError` exception.
|
||||||
|
|
||||||
.. versionadded:: 1.1.4
|
.. versionadded:: 1.1.4
|
||||||
|
|
||||||
:param color: A color string
|
:param color: A color string
|
||||||
|
:param mode: Convert result to this mode
|
||||||
:return: ``(graylevel[, alpha]) or (red, green, blue[, alpha])``
|
:return: ``(graylevel[, alpha]) or (red, green, blue[, alpha])``
|
||||||
"""
|
"""
|
||||||
# same as getrgb, but converts the result to the given mode
|
# same as getrgb, but converts the result to the given mode
|
||||||
color, alpha = getrgb(color), 255
|
color, alpha = getrgb(color), 255
|
||||||
if len(color) == 4:
|
if len(color) == 4:
|
||||||
color, alpha = color[0:3], color[3]
|
color, alpha = color[:3], color[3]
|
||||||
|
|
||||||
if Image.getmodebase(mode) == "L":
|
if Image.getmodebase(mode) == "L":
|
||||||
r, g, b = color
|
r, g, b = color
|
||||||
|
@ -140,7 +141,7 @@ def getcolor(color, mode):
|
||||||
# scaled to 24 bits to match the convert's implementation.
|
# scaled to 24 bits to match the convert's implementation.
|
||||||
color = (r * 19595 + g * 38470 + b * 7471 + 0x8000) >> 16
|
color = (r * 19595 + g * 38470 + b * 7471 + 0x8000) >> 16
|
||||||
if mode[-1] == "A":
|
if mode[-1] == "A":
|
||||||
return (color, alpha)
|
return color, alpha
|
||||||
else:
|
else:
|
||||||
if mode[-1] == "A":
|
if mode[-1] == "A":
|
||||||
return color + (alpha,)
|
return color + (alpha,)
|
||||||
|
|
|
@ -571,7 +571,7 @@ class PyCodecState:
|
||||||
self.yoff = 0
|
self.yoff = 0
|
||||||
|
|
||||||
def extents(self):
|
def extents(self):
|
||||||
return (self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize)
|
return self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize
|
||||||
|
|
||||||
|
|
||||||
class PyCodec:
|
class PyCodec:
|
||||||
|
@ -681,7 +681,7 @@ class PyDecoder(PyCodec):
|
||||||
|
|
||||||
if not rawmode:
|
if not rawmode:
|
||||||
rawmode = self.mode
|
rawmode = self.mode
|
||||||
d = Image._getdecoder(self.mode, "raw", (rawmode))
|
d = Image._getdecoder(self.mode, "raw", rawmode)
|
||||||
d.setimage(self.im, self.state.extents())
|
d.setimage(self.im, self.state.extents())
|
||||||
s = d.decode(data)
|
s = d.decode(data)
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ _UNSPECIFIED = object()
|
||||||
|
|
||||||
|
|
||||||
class ImageFont:
|
class ImageFont:
|
||||||
"PIL font wrapper"
|
"""PIL font wrapper"""
|
||||||
|
|
||||||
def _load_pilfont(self, filename):
|
def _load_pilfont(self, filename):
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ class ImageFont:
|
||||||
|
|
||||||
|
|
||||||
class FreeTypeFont:
|
class FreeTypeFont:
|
||||||
"FreeType font wrapper (requires _imagingft service)"
|
"""FreeType font wrapper (requires _imagingft service)"""
|
||||||
|
|
||||||
def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None):
|
def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None):
|
||||||
# FIXME: use service provider instead
|
# FIXME: use service provider instead
|
||||||
|
@ -774,7 +774,7 @@ class FreeTypeFont:
|
||||||
|
|
||||||
|
|
||||||
class TransposedFont:
|
class TransposedFont:
|
||||||
"Wrapper for writing rotated or mirrored text"
|
"""Wrapper for writing rotated or mirrored text"""
|
||||||
|
|
||||||
def __init__(self, font, orientation=None):
|
def __init__(self, font, orientation=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -119,13 +119,13 @@ class LutBuilder:
|
||||||
# mirror
|
# mirror
|
||||||
if "M" in options:
|
if "M" in options:
|
||||||
n = len(patterns)
|
n = len(patterns)
|
||||||
for pattern, res in patterns[0:n]:
|
for pattern, res in patterns[:n]:
|
||||||
patterns.append((self._string_permute(pattern, MIRROR_MATRIX), res))
|
patterns.append((self._string_permute(pattern, MIRROR_MATRIX), res))
|
||||||
|
|
||||||
# negate
|
# negate
|
||||||
if "N" in options:
|
if "N" in options:
|
||||||
n = len(patterns)
|
n = len(patterns)
|
||||||
for pattern, res in patterns[0:n]:
|
for pattern, res in patterns[:n]:
|
||||||
# Swap 0 and 1
|
# Swap 0 and 1
|
||||||
pattern = pattern.replace("0", "Z").replace("1", "0").replace("Z", "1")
|
pattern = pattern.replace("0", "Z").replace("1", "0").replace("Z", "1")
|
||||||
res = 1 - int(res)
|
res = 1 - int(res)
|
||||||
|
|
|
@ -184,6 +184,8 @@ class PhotoImage:
|
||||||
:param im: A PIL image. The size must match the target region. If the
|
:param im: A PIL image. The size must match the target region. If the
|
||||||
mode does not match, the image is converted to the mode of
|
mode does not match, the image is converted to the mode of
|
||||||
the bitmap image.
|
the bitmap image.
|
||||||
|
:param box: Deprecated. This parameter will be removed in Pillow 10
|
||||||
|
(2023-07-01).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if box is not None:
|
if box is not None:
|
||||||
|
|
|
@ -124,7 +124,7 @@ def _parse_codestream(fp):
|
||||||
else:
|
else:
|
||||||
mode = None
|
mode = None
|
||||||
|
|
||||||
return (size, mode)
|
return size, mode
|
||||||
|
|
||||||
|
|
||||||
def _res_to_dpi(num, denom, exp):
|
def _res_to_dpi(num, denom, exp):
|
||||||
|
@ -191,7 +191,7 @@ def _parse_jp2_header(fp):
|
||||||
if size is None or mode is None:
|
if size is None or mode is None:
|
||||||
raise SyntaxError("Malformed JP2 header")
|
raise SyntaxError("Malformed JP2 header")
|
||||||
|
|
||||||
return (size, mode, mimetype, dpi)
|
return size, mode, mimetype, dpi
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -331,7 +331,7 @@ MARKER = {
|
||||||
|
|
||||||
def _accept(prefix):
|
def _accept(prefix):
|
||||||
# Magic number was taken from https://en.wikipedia.org/wiki/JPEG
|
# Magic number was taken from https://en.wikipedia.org/wiki/JPEG
|
||||||
return prefix[0:3] == b"\xFF\xD8\xFF"
|
return prefix[:3] == b"\xFF\xD8\xFF"
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -445,7 +445,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
self.decoderconfig = (scale, 0)
|
self.decoderconfig = (scale, 0)
|
||||||
|
|
||||||
box = (0, 0, original_size[0] / scale, original_size[1] / scale)
|
box = (0, 0, original_size[0] / scale, original_size[1] / scale)
|
||||||
return (self.mode, box)
|
return self.mode, box
|
||||||
|
|
||||||
def load_djpeg(self):
|
def load_djpeg(self):
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class PaletteFile:
|
||||||
|
|
||||||
if not s:
|
if not s:
|
||||||
break
|
break
|
||||||
if s[0:1] == b"#":
|
if s[:1] == b"#":
|
||||||
continue
|
continue
|
||||||
if len(s) > 100:
|
if len(s) > 100:
|
||||||
raise SyntaxError("bad palette file")
|
raise SyntaxError("bad palette file")
|
||||||
|
|
|
@ -590,7 +590,7 @@ class PdfParser:
|
||||||
whitespace_mandatory
|
whitespace_mandatory
|
||||||
+ rb"trailer"
|
+ rb"trailer"
|
||||||
+ whitespace_optional
|
+ whitespace_optional
|
||||||
+ rb"\<\<(.*\>\>)"
|
+ rb"<<(.*>>)"
|
||||||
+ newline
|
+ newline
|
||||||
+ rb"startxref"
|
+ rb"startxref"
|
||||||
+ newline
|
+ newline
|
||||||
|
@ -605,7 +605,7 @@ class PdfParser:
|
||||||
whitespace_optional
|
whitespace_optional
|
||||||
+ rb"trailer"
|
+ rb"trailer"
|
||||||
+ whitespace_optional
|
+ whitespace_optional
|
||||||
+ rb"\<\<(.*?\>\>)"
|
+ rb"<<(.*?>>)"
|
||||||
+ newline
|
+ newline
|
||||||
+ rb"startxref"
|
+ rb"startxref"
|
||||||
+ newline
|
+ newline
|
||||||
|
@ -659,8 +659,8 @@ class PdfParser:
|
||||||
+ delimiter_or_ws
|
+ delimiter_or_ws
|
||||||
+ rb")"
|
+ rb")"
|
||||||
)
|
)
|
||||||
re_dict_start = re.compile(whitespace_optional + rb"\<\<")
|
re_dict_start = re.compile(whitespace_optional + rb"<<")
|
||||||
re_dict_end = re.compile(whitespace_optional + rb"\>\>" + whitespace_optional)
|
re_dict_end = re.compile(whitespace_optional + rb">>" + whitespace_optional)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def interpret_trailer(cls, trailer_data):
|
def interpret_trailer(cls, trailer_data):
|
||||||
|
@ -719,7 +719,7 @@ class PdfParser:
|
||||||
re_array_start = re.compile(whitespace_optional + rb"\[")
|
re_array_start = re.compile(whitespace_optional + rb"\[")
|
||||||
re_array_end = re.compile(whitespace_optional + rb"]")
|
re_array_end = re.compile(whitespace_optional + rb"]")
|
||||||
re_string_hex = re.compile(
|
re_string_hex = re.compile(
|
||||||
whitespace_optional + rb"\<(" + whitespace_or_hex + rb"*)\>"
|
whitespace_optional + rb"<(" + whitespace_or_hex + rb"*)>"
|
||||||
)
|
)
|
||||||
re_string_lit = re.compile(whitespace_optional + rb"\(")
|
re_string_lit = re.compile(whitespace_optional + rb"\(")
|
||||||
re_indirect_reference = re.compile(
|
re_indirect_reference = re.compile(
|
||||||
|
|
|
@ -178,7 +178,7 @@ def _layerinfo(fp, ct_bytes):
|
||||||
if ct_bytes < (abs(ct) * 20):
|
if ct_bytes < (abs(ct) * 20):
|
||||||
raise SyntaxError("Layer block too short for number of layers requested")
|
raise SyntaxError("Layer block too short for number of layers requested")
|
||||||
|
|
||||||
for i in range(abs(ct)):
|
for _ in range(abs(ct)):
|
||||||
|
|
||||||
# bounding box
|
# bounding box
|
||||||
y0 = i32(read(4))
|
y0 = i32(read(4))
|
||||||
|
@ -193,7 +193,7 @@ def _layerinfo(fp, ct_bytes):
|
||||||
if len(types) > 4:
|
if len(types) > 4:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for i in types:
|
for _ in types:
|
||||||
type = i16(read(2))
|
type = i16(read(2))
|
||||||
|
|
||||||
if type == 65535:
|
if type == 65535:
|
||||||
|
|
|
@ -135,7 +135,7 @@ class _PyAccess32_2(PyAccess):
|
||||||
|
|
||||||
def get_pixel(self, x, y):
|
def get_pixel(self, x, y):
|
||||||
pixel = self.pixels[y][x]
|
pixel = self.pixels[y][x]
|
||||||
return (pixel.r, pixel.a)
|
return pixel.r, pixel.a
|
||||||
|
|
||||||
def set_pixel(self, x, y, color):
|
def set_pixel(self, x, y, color):
|
||||||
pixel = self.pixels[y][x]
|
pixel = self.pixels[y][x]
|
||||||
|
@ -152,7 +152,7 @@ class _PyAccess32_3(PyAccess):
|
||||||
|
|
||||||
def get_pixel(self, x, y):
|
def get_pixel(self, x, y):
|
||||||
pixel = self.pixels[y][x]
|
pixel = self.pixels[y][x]
|
||||||
return (pixel.r, pixel.g, pixel.b)
|
return pixel.r, pixel.g, pixel.b
|
||||||
|
|
||||||
def set_pixel(self, x, y, color):
|
def set_pixel(self, x, y, color):
|
||||||
pixel = self.pixels[y][x]
|
pixel = self.pixels[y][x]
|
||||||
|
@ -171,7 +171,7 @@ class _PyAccess32_4(PyAccess):
|
||||||
|
|
||||||
def get_pixel(self, x, y):
|
def get_pixel(self, x, y):
|
||||||
pixel = self.pixels[y][x]
|
pixel = self.pixels[y][x]
|
||||||
return (pixel.r, pixel.g, pixel.b, pixel.a)
|
return pixel.r, pixel.g, pixel.b, pixel.a
|
||||||
|
|
||||||
def set_pixel(self, x, y, color):
|
def set_pixel(self, x, y, color):
|
||||||
pixel = self.pixels[y][x]
|
pixel = self.pixels[y][x]
|
||||||
|
|
|
@ -338,12 +338,12 @@ class IFDRational(Rational):
|
||||||
self._val = Fraction(value, denominator)
|
self._val = Fraction(value, denominator)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def numerator(a):
|
def numerator(self):
|
||||||
return a._numerator
|
return self._numerator
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def denominator(a):
|
def denominator(self):
|
||||||
return a._denominator
|
return self._denominator
|
||||||
|
|
||||||
def limit_rational(self, max_denominator):
|
def limit_rational(self, max_denominator):
|
||||||
"""
|
"""
|
||||||
|
@ -353,10 +353,10 @@ class IFDRational(Rational):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.denominator == 0:
|
if self.denominator == 0:
|
||||||
return (self.numerator, self.denominator)
|
return self.numerator, self.denominator
|
||||||
|
|
||||||
f = self._val.limit_denominator(max_denominator)
|
f = self._val.limit_denominator(max_denominator)
|
||||||
return (f.numerator, f.denominator)
|
return f.numerator, f.denominator
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(float(self._val))
|
return str(float(self._val))
|
||||||
|
@ -1748,9 +1748,8 @@ def _save(im, fp, filename):
|
||||||
SUBIFD,
|
SUBIFD,
|
||||||
]
|
]
|
||||||
|
|
||||||
atts = {}
|
|
||||||
# bits per sample is a single short in the tiff directory, not a list.
|
# bits per sample is a single short in the tiff directory, not a list.
|
||||||
atts[BITSPERSAMPLE] = bits[0]
|
atts = {BITSPERSAMPLE: bits[0]}
|
||||||
# Merge the ones that we have with (optional) more bits from
|
# Merge the ones that we have with (optional) more bits from
|
||||||
# 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.
|
||||||
|
|
|
@ -36,8 +36,12 @@ class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
|
||||||
def lookup(tag, group=None):
|
def lookup(tag, group=None):
|
||||||
"""
|
"""
|
||||||
:param tag: Integer tag number
|
:param tag: Integer tag number
|
||||||
:returns: Taginfo namedtuple, From the TAGS_V2 info if possible,
|
:param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in
|
||||||
otherwise just populating the value and name from TAGS.
|
|
||||||
|
.. versionadded:: 8.3.0
|
||||||
|
|
||||||
|
:returns: Taginfo namedtuple, From the ``TAGS_V2`` info if possible,
|
||||||
|
otherwise just populating the value and name from ``TAGS``.
|
||||||
If the tag is not recognized, "unknown" is returned for the name
|
If the tag is not recognized, "unknown" is returned for the name
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -222,11 +222,10 @@ def _save_all(im, fp, filename):
|
||||||
if (
|
if (
|
||||||
not isinstance(background, (list, tuple))
|
not isinstance(background, (list, tuple))
|
||||||
or len(background) != 4
|
or len(background) != 4
|
||||||
or not all(v >= 0 and v < 256 for v in background)
|
or not all(0 <= v < 256 for v in background)
|
||||||
):
|
):
|
||||||
raise OSError(
|
raise OSError(
|
||||||
"Background color is not an RGBA tuple clamped to (0-255): %s"
|
f"Background color is not an RGBA tuple clamped to (0-255): {background}"
|
||||||
% str(background)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Convert to packed uint
|
# Convert to packed uint
|
||||||
|
|
|
@ -31,7 +31,7 @@ xbm_head = re.compile(
|
||||||
b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
|
b"#define[ \t]+[^_]*_x_hot[ \t]+(?P<xhot>[0-9]+)[\r\n]+"
|
||||||
b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
|
b"#define[ \t]+[^_]*_y_hot[ \t]+(?P<yhot>[0-9]+)[\r\n]+"
|
||||||
b")?"
|
b")?"
|
||||||
b"[\\000-\\377]*_bits\\[\\]"
|
rb"[\000-\377]*_bits\[]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ class XpmImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
palette = [b"\0\0\0"] * 256
|
palette = [b"\0\0\0"] * 256
|
||||||
|
|
||||||
for i in range(pal):
|
for _ in range(pal):
|
||||||
|
|
||||||
s = self.fp.readline()
|
s = self.fp.readline()
|
||||||
if s[-2:] == b"\r\n":
|
if s[-2:] == b"\r\n":
|
||||||
|
@ -83,7 +83,7 @@ class XpmImageFile(ImageFile.ImageFile):
|
||||||
rgb = s[i + 1]
|
rgb = s[i + 1]
|
||||||
if rgb == b"None":
|
if rgb == b"None":
|
||||||
self.info["transparency"] = c
|
self.info["transparency"] = c
|
||||||
elif rgb[0:1] == b"#":
|
elif rgb[:1] == b"#":
|
||||||
# FIXME: handle colour names (see ImagePalette.py)
|
# FIXME: handle colour names (see ImagePalette.py)
|
||||||
rgb = int(rgb[1:], 16)
|
rgb = int(rgb[1:], 16)
|
||||||
palette[c] = (
|
palette[c] = (
|
||||||
|
|
Loading…
Reference in New Issue
Block a user