mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-03 05:04:24 +03:00
Merge branch 'main' into null
This commit is contained in:
commit
dc79a09d62
3
.github/workflows/docs.yml
vendored
3
.github/workflows/docs.yml
vendored
|
@ -18,6 +18,9 @@ concurrency:
|
|||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
|
|
2
.github/workflows/test-docker.yml
vendored
2
.github/workflows/test-docker.yml
vendored
|
@ -33,11 +33,11 @@ jobs:
|
|||
# Then run the remainder
|
||||
alpine,
|
||||
amazon-2-amd64,
|
||||
amazon-2023-amd64,
|
||||
arch,
|
||||
centos-7-amd64,
|
||||
centos-stream-8-amd64,
|
||||
centos-stream-9-amd64,
|
||||
debian-10-buster-x86,
|
||||
debian-11-bullseye-x86,
|
||||
fedora-36-amd64,
|
||||
fedora-37-amd64,
|
||||
|
|
27
CHANGES.rst
27
CHANGES.rst
|
@ -5,6 +5,33 @@ Changelog (Pillow)
|
|||
9.5.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Allow libtiff_support_custom_tags to be missing #7020
|
||||
[radarhere]
|
||||
|
||||
- Improved I;16N support #6834
|
||||
[radarhere]
|
||||
|
||||
- Added QOI reading #6852
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Added saving RGBA images as PDFs #6925
|
||||
[radarhere]
|
||||
|
||||
- Do not raise an error if os.environ does not contain PATH #6935
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Close OleFileIO instance when closing or exiting FPX or MIC #7005
|
||||
[radarhere]
|
||||
|
||||
- Added __int__ to IFDRational for Python >= 3.11 #6998
|
||||
[radarhere]
|
||||
|
||||
- Added memoryview support to Dib.frombytes() #6988
|
||||
[radarhere, nulano]
|
||||
|
||||
- Close file pointer copy in the libtiff encoder if still open #6986
|
||||
[fcarron, radarhere]
|
||||
|
||||
- Raise an error if ImageDraw co-ordinates are incorrectly ordered #6978
|
||||
[radarhere]
|
||||
|
||||
|
|
11
Makefile
11
Makefile
|
@ -16,10 +16,16 @@ coverage:
|
|||
python3 -m coverage report
|
||||
|
||||
.PHONY: doc
|
||||
doc:
|
||||
.PHONY: html
|
||||
doc html:
|
||||
python3 -c "import PIL" > /dev/null 2>&1 || python3 -m pip install .
|
||||
$(MAKE) -C docs html
|
||||
|
||||
.PHONY: htmlview
|
||||
htmlview:
|
||||
python3 -c "import PIL" > /dev/null 2>&1 || python3 -m pip install .
|
||||
$(MAKE) -C docs htmlview
|
||||
|
||||
.PHONY: doccheck
|
||||
doccheck:
|
||||
$(MAKE) doc
|
||||
|
@ -38,7 +44,8 @@ help:
|
|||
@echo " coverage run coverage test (in progress)"
|
||||
@echo " doc make HTML docs"
|
||||
@echo " docserve run an HTTP server on the docs directory"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " html make HTML docs"
|
||||
@echo " htmlview open the index page built by the html target in your browser"
|
||||
@echo " inplace make inplace extension"
|
||||
@echo " install make and install"
|
||||
@echo " install-coverage make and install with C coverage"
|
||||
|
|
|
@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
HAS_UPLOADER = False
|
||||
|
||||
if os.environ.get("SHOW_ERRORS", None):
|
||||
if os.environ.get("SHOW_ERRORS"):
|
||||
# local img.show for errors.
|
||||
HAS_UPLOADER = True
|
||||
|
||||
|
@ -271,7 +271,7 @@ def netpbm_available():
|
|||
|
||||
def magick_command():
|
||||
if sys.platform == "win32":
|
||||
magickhome = os.environ.get("MAGICK_HOME", "")
|
||||
magickhome = os.environ.get("MAGICK_HOME")
|
||||
if magickhome:
|
||||
imagemagick = [os.path.join(magickhome, "convert.exe")]
|
||||
graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"]
|
||||
|
|
BIN
Tests/images/hopper.qoi
Normal file
BIN
Tests/images/hopper.qoi
Normal file
Binary file not shown.
BIN
Tests/images/pil123rgba.qoi
Normal file
BIN
Tests/images/pil123rgba.qoi
Normal file
Binary file not shown.
|
@ -56,6 +56,7 @@ def test_handler(tmp_path):
|
|||
|
||||
def load(self, im):
|
||||
self.loaded = True
|
||||
im.fp.close()
|
||||
return Image.new("RGB", (1, 1))
|
||||
|
||||
def save(self, im, fp, filename):
|
||||
|
|
|
@ -60,6 +60,7 @@ def test_stub_deprecated():
|
|||
|
||||
def load(self, im):
|
||||
self.loaded = True
|
||||
im.fp.close()
|
||||
return Image.new("RGB", (1, 1))
|
||||
|
||||
handler = Handler()
|
||||
|
|
|
@ -18,6 +18,16 @@ def test_sanity():
|
|||
assert_image_equal_tofile(im, "Tests/images/input_bw_one_band.png")
|
||||
|
||||
|
||||
def test_close():
|
||||
with Image.open("Tests/images/input_bw_one_band.fpx") as im:
|
||||
pass
|
||||
assert im.ole.fp.closed
|
||||
|
||||
im = Image.open("Tests/images/input_bw_one_band.fpx")
|
||||
im.close()
|
||||
assert im.ole.fp.closed
|
||||
|
||||
|
||||
def test_invalid_file():
|
||||
# Test an invalid OLE file
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
|
|
@ -56,6 +56,7 @@ def test_handler(tmp_path):
|
|||
|
||||
def load(self, im):
|
||||
self.loaded = True
|
||||
im.fp.close()
|
||||
return Image.new("RGB", (1, 1))
|
||||
|
||||
def save(self, im, fp, filename):
|
||||
|
|
|
@ -57,6 +57,7 @@ def test_handler(tmp_path):
|
|||
|
||||
def load(self, im):
|
||||
self.loaded = True
|
||||
im.fp.close()
|
||||
return Image.new("RGB", (1, 1))
|
||||
|
||||
def save(self, im, fp, filename):
|
||||
|
|
|
@ -984,6 +984,36 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
) as im:
|
||||
assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name, mode, size, tile",
|
||||
[
|
||||
(
|
||||
"tiff_wrong_bits_per_sample.tiff",
|
||||
"RGBA",
|
||||
(52, 53),
|
||||
[("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))],
|
||||
),
|
||||
(
|
||||
"tiff_wrong_bits_per_sample_2.tiff",
|
||||
"RGB",
|
||||
(16, 16),
|
||||
[("raw", (0, 0, 16, 16), 8, ("RGB", 0, 1))],
|
||||
),
|
||||
(
|
||||
"tiff_wrong_bits_per_sample_3.tiff",
|
||||
"RGBA",
|
||||
(512, 256),
|
||||
[("libtiff", (0, 0, 512, 256), 0, ("RGBA", "tiff_lzw", False, 48782))],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_wrong_bits_per_sample(self, file_name, mode, size, tile):
|
||||
with Image.open("Tests/images/" + file_name) as im:
|
||||
assert im.mode == mode
|
||||
assert im.size == size
|
||||
assert im.tile == tile
|
||||
im.load()
|
||||
|
||||
def test_no_rows_per_strip(self):
|
||||
# This image does not have a RowsPerStrip TIFF tag
|
||||
infile = "Tests/images/no_rows_per_strip.tif"
|
||||
|
@ -1071,3 +1101,21 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
out = str(tmp_path / "temp.tif")
|
||||
for _ in range(10000):
|
||||
im.save(out, compression="jpeg")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path, sizes",
|
||||
(
|
||||
("Tests/images/hopper.tif", ()),
|
||||
("Tests/images/child_ifd.tiff", (16, 8)),
|
||||
("Tests/images/child_ifd_jpeg.tiff", (20,)),
|
||||
),
|
||||
)
|
||||
def test_get_child_images(self, path, sizes):
|
||||
with Image.open(path) as im:
|
||||
ims = im.get_child_images()
|
||||
|
||||
assert len(ims) == len(sizes)
|
||||
for i, im in enumerate(ims):
|
||||
w = sizes[i]
|
||||
expected = Image.new("RGB", (w, w), "#f00")
|
||||
assert_image_similar(im, expected, 1)
|
||||
|
|
|
@ -51,6 +51,16 @@ def test_seek():
|
|||
assert im.tell() == 0
|
||||
|
||||
|
||||
def test_close():
|
||||
with Image.open(TEST_FILE) as im:
|
||||
pass
|
||||
assert im.ole.fp.closed
|
||||
|
||||
im = Image.open(TEST_FILE)
|
||||
im.close()
|
||||
assert im.ole.fp.closed
|
||||
|
||||
|
||||
def test_invalid_file():
|
||||
# Test an invalid OLE file
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
|
|
@ -8,7 +8,7 @@ import pytest
|
|||
|
||||
from PIL import Image, PdfParser, features
|
||||
|
||||
from .helper import hopper, mark_if_feature_version
|
||||
from .helper import hopper, mark_if_feature_version, skip_unless_feature
|
||||
|
||||
|
||||
def helper_save_as_pdf(tmp_path, mode, **kwargs):
|
||||
|
@ -42,6 +42,11 @@ def test_save(tmp_path, mode):
|
|||
helper_save_as_pdf(tmp_path, mode)
|
||||
|
||||
|
||||
@skip_unless_feature("jpg_2000")
|
||||
def test_save_rgba(tmp_path):
|
||||
helper_save_as_pdf(tmp_path, "RGBA")
|
||||
|
||||
|
||||
def test_monochrome(tmp_path):
|
||||
# Arrange
|
||||
mode = "1"
|
||||
|
|
28
Tests/test_file_qoi.py
Normal file
28
Tests/test_file_qoi.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import pytest
|
||||
|
||||
from PIL import Image, QoiImagePlugin
|
||||
|
||||
from .helper import assert_image_equal_tofile, assert_image_similar_tofile
|
||||
|
||||
|
||||
def test_sanity():
|
||||
with Image.open("Tests/images/hopper.qoi") as im:
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
assert im.format == "QOI"
|
||||
|
||||
assert_image_equal_tofile(im, "Tests/images/hopper.png")
|
||||
|
||||
with Image.open("Tests/images/pil123rgba.qoi") as im:
|
||||
assert im.mode == "RGBA"
|
||||
assert im.size == (162, 150)
|
||||
assert im.format == "QOI"
|
||||
|
||||
assert_image_similar_tofile(im, "Tests/images/pil123rgba.png", 0.03)
|
||||
|
||||
|
||||
def test_invalid_file():
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
with pytest.raises(SyntaxError):
|
||||
QoiImagePlugin.QoiImageFile(invalid_file)
|
|
@ -84,24 +84,6 @@ class TestFileTiff:
|
|||
with Image.open("Tests/images/multipage.tiff") as im:
|
||||
im.load()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path, sizes",
|
||||
(
|
||||
("Tests/images/hopper.tif", ()),
|
||||
("Tests/images/child_ifd.tiff", (16, 8)),
|
||||
("Tests/images/child_ifd_jpeg.tiff", (20,)),
|
||||
),
|
||||
)
|
||||
def test_get_child_images(self, path, sizes):
|
||||
with Image.open(path) as im:
|
||||
ims = im.get_child_images()
|
||||
|
||||
assert len(ims) == len(sizes)
|
||||
for i, im in enumerate(ims):
|
||||
w = sizes[i]
|
||||
expected = Image.new("RGB", (w, w), "#f00")
|
||||
assert_image_similar(im, expected, 1)
|
||||
|
||||
def test_mac_tiff(self):
|
||||
# Read RGBa images from macOS [@PIL136]
|
||||
|
||||
|
@ -118,36 +100,6 @@ class TestFileTiff:
|
|||
with Image.open("Tests/images/hopper_bigtiff.tif") as im:
|
||||
assert_image_equal_tofile(im, "Tests/images/hopper.tif")
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name,mode,size,tile",
|
||||
[
|
||||
(
|
||||
"tiff_wrong_bits_per_sample.tiff",
|
||||
"RGBA",
|
||||
(52, 53),
|
||||
[("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))],
|
||||
),
|
||||
(
|
||||
"tiff_wrong_bits_per_sample_2.tiff",
|
||||
"RGB",
|
||||
(16, 16),
|
||||
[("raw", (0, 0, 16, 16), 8, ("RGB", 0, 1))],
|
||||
),
|
||||
(
|
||||
"tiff_wrong_bits_per_sample_3.tiff",
|
||||
"RGBA",
|
||||
(512, 256),
|
||||
[("libtiff", (0, 0, 512, 256), 0, ("RGBA", "tiff_lzw", False, 48782))],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_wrong_bits_per_sample(self, file_name, mode, size, tile):
|
||||
with Image.open("Tests/images/" + file_name) as im:
|
||||
assert im.mode == mode
|
||||
assert im.size == size
|
||||
assert im.tile == tile
|
||||
im.load()
|
||||
|
||||
def test_set_legacy_api(self):
|
||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
with pytest.raises(Exception) as e:
|
||||
|
|
|
@ -275,15 +275,10 @@ class TestCffi(AccessTest):
|
|||
# self._test_get_access(hopper('PA')) # PA -- how do I make a PA image?
|
||||
self._test_get_access(hopper("F"))
|
||||
|
||||
im = Image.new("I;16", (10, 10), 40000)
|
||||
self._test_get_access(im)
|
||||
im = Image.new("I;16L", (10, 10), 40000)
|
||||
self._test_get_access(im)
|
||||
im = Image.new("I;16B", (10, 10), 40000)
|
||||
self._test_get_access(im)
|
||||
for mode in ("I;16", "I;16L", "I;16B", "I;16N", "I"):
|
||||
im = Image.new(mode, (10, 10), 40000)
|
||||
self._test_get_access(im)
|
||||
|
||||
im = Image.new("I", (10, 10), 40000)
|
||||
self._test_get_access(im)
|
||||
# These don't actually appear to be modes that I can actually make,
|
||||
# as unpack sets them directly into the I mode.
|
||||
# im = Image.new('I;32L', (10, 10), -2**10)
|
||||
|
@ -322,15 +317,10 @@ class TestCffi(AccessTest):
|
|||
# self._test_set_access(i, (128, 128)) #PA -- undone how to make
|
||||
self._test_set_access(hopper("F"), 1024.0)
|
||||
|
||||
im = Image.new("I;16", (10, 10), 40000)
|
||||
self._test_set_access(im, 45000)
|
||||
im = Image.new("I;16L", (10, 10), 40000)
|
||||
self._test_set_access(im, 45000)
|
||||
im = Image.new("I;16B", (10, 10), 40000)
|
||||
self._test_set_access(im, 45000)
|
||||
for mode in ("I;16", "I;16L", "I;16B", "I;16N", "I"):
|
||||
im = Image.new(mode, (10, 10), 40000)
|
||||
self._test_set_access(im, 45000)
|
||||
|
||||
im = Image.new("I", (10, 10), 40000)
|
||||
self._test_set_access(im, 45000)
|
||||
# im = Image.new('I;32L', (10, 10), -(2**10))
|
||||
# self._test_set_access(im, -(2**13)+1)
|
||||
# im = Image.new('I;32B', (10, 10), 2**10)
|
||||
|
|
|
@ -254,17 +254,6 @@ def test_p2pa_palette():
|
|||
assert im_pa.getpalette() == im.getpalette()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
|
||||
def test_rgb_lab(mode):
|
||||
im = Image.new(mode, (1, 1))
|
||||
converted_im = im.convert("LAB")
|
||||
assert converted_im.getpixel((0, 0)) == (0, 128, 128)
|
||||
|
||||
im = Image.new("LAB", (1, 1), (255, 0, 0))
|
||||
converted_im = im.convert(mode)
|
||||
assert converted_im.getpixel((0, 0))[:3] == (0, 255, 255)
|
||||
|
||||
|
||||
def test_matrix_illegal_conversion():
|
||||
# Arrange
|
||||
im = hopper("CMYK")
|
||||
|
|
|
@ -625,3 +625,14 @@ def test_constants_deprecation():
|
|||
for name in enum.__members__:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert getattr(ImageCms, prefix + name) == enum[name]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
|
||||
def test_rgb_lab(mode):
|
||||
im = Image.new(mode, (1, 1))
|
||||
converted_im = im.convert("LAB")
|
||||
assert converted_im.getpixel((0, 0)) == (0, 128, 128)
|
||||
|
||||
im = Image.new("LAB", (1, 1), (255, 0, 0))
|
||||
converted_im = im.convert(mode)
|
||||
assert converted_im.getpixel((0, 0))[:3] == (0, 255, 255)
|
||||
|
|
|
@ -55,8 +55,8 @@ def test_show_without_viewers():
|
|||
viewers = ImageShow._viewers
|
||||
ImageShow._viewers = []
|
||||
|
||||
im = hopper()
|
||||
assert not ImageShow.show(im)
|
||||
with hopper() as im:
|
||||
assert not ImageShow.show(im)
|
||||
|
||||
ImageShow._viewers = viewers
|
||||
|
||||
|
|
|
@ -100,8 +100,11 @@ class TestImageWinDib:
|
|||
# Act
|
||||
# Make one the same as the using tobytes()/frombytes()
|
||||
test_buffer = dib1.tobytes()
|
||||
dib2.frombytes(test_buffer)
|
||||
for datatype in ("bytes", "memoryview"):
|
||||
if datatype == "memoryview":
|
||||
test_buffer = memoryview(test_buffer)
|
||||
dib2.frombytes(test_buffer)
|
||||
|
||||
# Assert
|
||||
# Confirm they're the same
|
||||
assert dib1.tobytes() == dib2.tobytes()
|
||||
# Assert
|
||||
# Confirm they're the same
|
||||
assert dib1.tobytes() == dib2.tobytes()
|
||||
|
|
|
@ -207,6 +207,9 @@ class TestLibPack:
|
|||
0x01000083,
|
||||
)
|
||||
|
||||
def test_I16(self):
|
||||
self.assert_pack("I;16N", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||
|
||||
def test_F_float(self):
|
||||
self.assert_pack("F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34)
|
||||
|
||||
|
@ -761,10 +764,12 @@ class TestLibUnpack:
|
|||
self.assert_unpack("I;16", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||
self.assert_unpack("I;16B", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||
self.assert_unpack("I;16L", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||
self.assert_unpack("I;16N", "I;16N", 2, 0x0201, 0x0403, 0x0605)
|
||||
else:
|
||||
self.assert_unpack("I;16", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||
self.assert_unpack("I;16B", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||
self.assert_unpack("I;16L", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||
self.assert_unpack("I;16N", "I;16N", 2, 0x0102, 0x0304, 0x0506)
|
||||
|
||||
def test_CMYK16(self):
|
||||
self.assert_unpack("CMYK", "CMYK;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16))
|
||||
|
|
|
@ -88,10 +88,7 @@ def test_tobytes():
|
|||
def test_convert():
|
||||
im = original.copy()
|
||||
|
||||
verify(im.convert("I;16"))
|
||||
verify(im.convert("I;16").convert("L"))
|
||||
verify(im.convert("I;16").convert("I"))
|
||||
|
||||
verify(im.convert("I;16B"))
|
||||
verify(im.convert("I;16B").convert("L"))
|
||||
verify(im.convert("I;16B").convert("I"))
|
||||
for mode in ("I;16", "I;16B", "I;16N"):
|
||||
verify(im.convert(mode))
|
||||
verify(im.convert(mode).convert("L"))
|
||||
verify(im.convert(mode).convert("I"))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# install libimagequant
|
||||
|
||||
archive=libimagequant-4.1.0
|
||||
archive=libimagequant-4.1.1
|
||||
|
||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " htmlview to open the index page built by the html target in your browser"
|
||||
@echo " serve to start a local server for viewing docs"
|
||||
@echo " livehtml to start a local server for viewing docs and auto-reload on change"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
|
@ -45,7 +46,7 @@ clean:
|
|||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
install-sphinx:
|
||||
$(PYTHON) -m pip install --quiet furo olefile sphinx sphinx-copybutton sphinx-inline-tabs sphinx-issues sphinx-removed-in sphinxext-opengraph
|
||||
$(PYTHON) -m pip install --quiet furo olefile sphinx sphinx-copybutton sphinx-inline-tabs sphinx-removed-in sphinxext-opengraph
|
||||
|
||||
.PHONY: html
|
||||
html:
|
||||
|
@ -196,6 +197,10 @@ doctest:
|
|||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
.PHONY: htmlview
|
||||
htmlview: html
|
||||
$(PYTHON) -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('$(BUILDDIR)/html/index.html'))"
|
||||
|
||||
.PHONY: livehtml
|
||||
livehtml: html
|
||||
livereload $(BUILDDIR)/html -p 33233
|
||||
|
|
15
docs/conf.py
15
docs/conf.py
|
@ -28,11 +28,11 @@ needs_sphinx = "2.4"
|
|||
# ones.
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.extlinks",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx_copybutton",
|
||||
"sphinx_inline_tabs",
|
||||
"sphinx_issues",
|
||||
"sphinx_removed_in",
|
||||
"sphinxext.opengraph",
|
||||
]
|
||||
|
@ -317,8 +317,17 @@ def setup(app):
|
|||
app.add_css_file("css/dark.css")
|
||||
|
||||
|
||||
# GitHub repo for sphinx-issues
|
||||
issues_github_path = "python-pillow/Pillow"
|
||||
# sphinx.ext.extlinks
|
||||
# This config is a dictionary of external sites,
|
||||
# mapping unique short aliases to a base URL and a prefix.
|
||||
# https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
|
||||
_repo = "https://github.com/python-pillow/Pillow/"
|
||||
extlinks = {
|
||||
"cve": ("https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s", "CVE-%s"),
|
||||
"cwe": ("https://cwe.mitre.org/data/definitions/%s.html", "CWE-%s"),
|
||||
"issue": (_repo + "issues/%s", "#%s"),
|
||||
"pr": (_repo + "pull/%s", "#%s"),
|
||||
}
|
||||
|
||||
# sphinxext.opengraph
|
||||
ogp_image = (
|
||||
|
|
|
@ -261,7 +261,7 @@ FreeType 2.7
|
|||
Support for FreeType 2.7 has been removed.
|
||||
|
||||
We recommend upgrading to at least `FreeType`_ 2.10.4, which fixed a severe
|
||||
vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).
|
||||
vulnerability introduced in FreeType 2.6 (:cve:`2020-15999`).
|
||||
|
||||
.. _FreeType: https://freetype.org/
|
||||
|
||||
|
|
|
@ -1457,8 +1457,13 @@ PDF
|
|||
^^^
|
||||
|
||||
Pillow can write PDF (Acrobat) images. Such images are written as binary PDF 1.4
|
||||
files, using either JPEG or HEX encoding depending on the image mode (and
|
||||
whether JPEG support is available or not).
|
||||
files. Different encoding methods are used, depending on the image mode.
|
||||
|
||||
* 1 mode images are saved using TIFF encoding, or JPEG encoding if libtiff support is
|
||||
unavailable
|
||||
* L, RGB and CMYK mode images use JPEG encoding
|
||||
* P mode images use HEX encoding
|
||||
* RGBA mode images use JPEG2000 encoding
|
||||
|
||||
.. _pdf-saving:
|
||||
|
||||
|
@ -1544,6 +1549,13 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
QOI
|
||||
^^^
|
||||
|
||||
.. versionadded:: 9.5.0
|
||||
|
||||
Pillow identifies and reads images in Quite OK Image format.
|
||||
|
||||
XV Thumbnails
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ Many of Pillow's features require external libraries:
|
|||
|
||||
* **libimagequant** provides improved color quantization
|
||||
|
||||
* Pillow has been tested with libimagequant **2.6-4.1**
|
||||
* Pillow has been tested with libimagequant **2.6-4.1.1**
|
||||
* Libimagequant is licensed GPLv3, which is more restrictive than
|
||||
the Pillow license, therefore we will not be distributing binaries
|
||||
with libimagequant support enabled.
|
||||
|
@ -424,6 +424,8 @@ These platforms are built and tested for every change.
|
|||
+----------------------------------+----------------------------+---------------------+
|
||||
| Amazon Linux 2 | 3.7 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Amazon Linux 2023 | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Arch | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| CentOS 7 | 3.9 | x86-64 |
|
||||
|
@ -432,8 +434,6 @@ These platforms are built and tested for every change.
|
|||
+----------------------------------+----------------------------+---------------------+
|
||||
| CentOS Stream 9 | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Debian 10 Buster | 3.7 | x86 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Debian 11 Bullseye | 3.9 | x86 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Fedora 36 | 3.10 | x86-64 |
|
||||
|
|
|
@ -19,6 +19,7 @@ if "%1" == "help" (
|
|||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. htmlview to open the index page built by the html target in your browser
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
|
@ -44,12 +45,23 @@ if "%1" == "clean" (
|
|||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
set html=false
|
||||
if "%1%" == "html" set html=true
|
||||
if "%1%" == "htmlview" set html=true
|
||||
if "%html%" == "true" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
|
||||
if "%1" == "htmlview" (
|
||||
if EXIST "%BUILDDIR%\html\index.html" (
|
||||
echo.Opening "%BUILDDIR%\html\index.html" in the default web browser...
|
||||
start "" "%BUILDDIR%\html\index.html"
|
||||
)
|
||||
)
|
||||
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
|
|
|
@ -320,8 +320,8 @@ Methods
|
|||
:param xy: Two points to define the bounding box. Sequence of either
|
||||
``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``, where ``x1 >= x0`` and
|
||||
``y1 >= y0``. The bounding box is inclusive of both endpoints.
|
||||
:param outline: Color to use for the outline.
|
||||
:param fill: Color to use for the fill.
|
||||
:param outline: Color to use for the outline.
|
||||
:param width: The line width, in pixels.
|
||||
|
||||
.. versionadded:: 5.3.0
|
||||
|
@ -334,8 +334,8 @@ Methods
|
|||
``[(x0, y0), (x1, y1)]`` or ``[x0, y0, x1, y1]``, where ``x1 >= x0`` and
|
||||
``y1 >= y0``. The bounding box is inclusive of both endpoints.
|
||||
:param radius: Radius of the corners.
|
||||
:param outline: Color to use for the outline.
|
||||
:param fill: Color to use for the fill.
|
||||
:param outline: Color to use for the outline.
|
||||
:param width: The line width, in pixels.
|
||||
:param corners: A tuple of whether to round each corner,
|
||||
``(top_left, top_right, bottom_right, bottom_left)``.
|
||||
|
|
|
@ -10,19 +10,13 @@ distributions.
|
|||
|
||||
- ``python3-dbg`` package for the gdb extensions and python symbols
|
||||
- ``gdb`` and ``valgrind``
|
||||
- Potentially debug symbols for libraries. On ubuntu they're shipped
|
||||
in package-dbgsym packages, from a different repo.
|
||||
- Potentially debug symbols for libraries. On Ubuntu you can follow those
|
||||
instructions to install the corresponding packages: `Debug Symbol Packages <https://wiki.ubuntu.com/Debug%20Symbol%20Packages#Getting_-dbgsym.ddeb_packages>`_
|
||||
|
||||
::
|
||||
Then ``sudo apt-get install libtiff5-dbgsym``
|
||||
|
||||
deb http://ddebs.ubuntu.com focal main restricted universe multiverse
|
||||
deb http://ddebs.ubuntu.com focal-updates main restricted universe multiverse
|
||||
deb http://ddebs.ubuntu.com focal-proposed main restricted universe multiverse
|
||||
|
||||
Then ``sudo apt-get update && sudo apt-get install libtiff5-dbgsym``
|
||||
|
||||
- There's a bug with the dbg package for at least python 3.8 on ubuntu
|
||||
20.04, and you need to add a new link or two to make it autoload when
|
||||
- There's a bug with the ``python3-dbg`` package for at least Python 3.8 on
|
||||
Ubuntu 20.04, and you need to add a new link or two to make it autoload when
|
||||
running python:
|
||||
|
||||
::
|
||||
|
|
|
@ -6,7 +6,7 @@ CVE-2016-0740 -- Buffer overflow in TiffDecode.c
|
|||
------------------------------------------------
|
||||
|
||||
Pillow 3.1.0 and earlier when linked against libtiff >= 4.0.0 on x64
|
||||
may overflow a buffer when reading a specially crafted tiff file (:cve:`CVE-2016-0740`).
|
||||
may overflow a buffer when reading a specially crafted tiff file (:cve:`2016-0740`).
|
||||
|
||||
Specifically, libtiff >= 4.0.0 changed the return type of
|
||||
``TIFFScanlineSize`` from ``int32`` to machine dependent
|
||||
|
@ -24,7 +24,7 @@ CVE-2016-0775 -- Buffer overflow in FliDecode.c
|
|||
-----------------------------------------------
|
||||
|
||||
In all versions of Pillow, dating back at least to the last PIL 1.1.7
|
||||
release, FliDecode.c has a buffer overflow error (:cve:`CVE-2016-0775`).
|
||||
release, FliDecode.c has a buffer overflow error (:cve:`2016-0775`).
|
||||
|
||||
Around line 192:
|
||||
|
||||
|
@ -53,7 +53,7 @@ CVE-2016-2533 -- Buffer overflow in PcdDecode.c
|
|||
-----------------------------------------------
|
||||
|
||||
In all versions of Pillow, dating back at least to the last PIL 1.1.7
|
||||
release, ``PcdDecode.c`` has a buffer overflow error (:cve:`CVE-2016-2533`).
|
||||
release, ``PcdDecode.c`` has a buffer overflow error (:cve:`2016-2533`).
|
||||
|
||||
The ``state.buffer`` for ``PcdDecode.c`` is allocated based on a 3
|
||||
bytes per pixel sizing, where ``PcdDecode.c`` wrote into the buffer
|
||||
|
|
|
@ -7,7 +7,7 @@ CVE-2016-3076 -- Buffer overflow in Jpeg2KEncode.c
|
|||
|
||||
Pillow between 2.5.0 and 3.1.1 may overflow a buffer when writing
|
||||
large Jpeg2000 files, allowing for code execution or other memory
|
||||
corruption (:cve:`CVE-2016-3076`).
|
||||
corruption (:cve:`2016-3076`).
|
||||
|
||||
This occurs specifically in the function ``j2k_encode_entry``, at the line:
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ Security
|
|||
========
|
||||
|
||||
This release catches several buffer overruns, as well as addressing
|
||||
:cve:`CVE-2019-16865`. The CVE is regarding DOS problems, such as consuming large
|
||||
:cve:`2019-16865`. The CVE is regarding DOS problems, such as consuming large
|
||||
amounts of memory, or taking a large amount of time to process an image.
|
||||
|
||||
In RawDecode.c, an error is now thrown if skip is calculated to be less than
|
||||
|
|
|
@ -6,13 +6,13 @@ Security
|
|||
|
||||
This release addresses several security problems.
|
||||
|
||||
:cve:`CVE-2019-19911` is regarding FPX images. If an image reports that it has a large
|
||||
:cve:`2019-19911` is regarding FPX images. If an image reports that it has a large
|
||||
number of bands, a large amount of resources will be used when trying to process the
|
||||
image. This is fixed by limiting the number of bands to those usable by Pillow.
|
||||
|
||||
Buffer overruns were found when processing an SGI (:cve:`CVE-2020-5311`),
|
||||
PCX (:cve:`CVE-2020-5312`) or FLI image (:cve:`CVE-2020-5313`). Checks have been added
|
||||
Buffer overruns were found when processing an SGI (:cve:`2020-5311`),
|
||||
PCX (:cve:`2020-5312`) or FLI image (:cve:`2020-5313`). Checks have been added
|
||||
to prevent this.
|
||||
|
||||
:cve:`CVE-2020-5310`: Overflow checks have been added when calculating the size of a
|
||||
:cve:`2020-5310`: Overflow checks have been added when calculating the size of a
|
||||
memory block to be reallocated in the processing of a TIFF image.
|
||||
|
|
|
@ -72,11 +72,11 @@ Security
|
|||
|
||||
This release includes security fixes.
|
||||
|
||||
* :cve:`CVE-2020-10177` Fix multiple out-of-bounds reads in FLI decoding
|
||||
* :cve:`CVE-2020-10378` Fix bounds overflow in PCX decoding
|
||||
* :cve:`CVE-2020-10379` Fix two buffer overflows in TIFF decoding
|
||||
* :cve:`CVE-2020-10994` Fix bounds overflow in JPEG 2000 decoding
|
||||
* :cve:`CVE-2020-11538` Fix buffer overflow in SGI-RLE decoding
|
||||
* :cve:`2020-10177` Fix multiple out-of-bounds reads in FLI decoding
|
||||
* :cve:`2020-10378` Fix bounds overflow in PCX decoding
|
||||
* :cve:`2020-10379` Fix two buffer overflows in TIFF decoding
|
||||
* :cve:`2020-10994` Fix bounds overflow in JPEG 2000 decoding
|
||||
* :cve:`2020-11538` Fix buffer overflow in SGI-RLE decoding
|
||||
|
||||
Other Changes
|
||||
=============
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Security
|
||||
========
|
||||
|
||||
Update FreeType used in binary wheels to `2.10.4`_ to fix :cve:`CVE-2020-15999`:
|
||||
Update FreeType used in binary wheels to `2.10.4`_ to fix :cve:`2020-15999`:
|
||||
|
||||
- A heap buffer overflow has been found in the handling of embedded PNG bitmaps,
|
||||
introduced in FreeType version 2.6.
|
||||
|
|
|
@ -11,7 +11,7 @@ Support for FreeType 2.7 is deprecated and will be removed in Pillow 9.0.0 (2022
|
|||
when FreeType 2.8 will be the minimum supported.
|
||||
|
||||
We recommend upgrading to at least FreeType `2.10.4`_, which fixed a severe
|
||||
vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).
|
||||
vulnerability introduced in FreeType 2.6 (:cve:`2020-15999`).
|
||||
|
||||
.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/
|
||||
|
||||
|
@ -40,13 +40,13 @@ This release includes security fixes.
|
|||
|
||||
* An out-of-bounds read when saving TIFFs with custom metadata through LibTIFF
|
||||
* An out-of-bounds read when saving a GIF of 1px width
|
||||
* :cve:`CVE-2020-35653` Buffer read overrun in PCX decoding
|
||||
* :cve:`2020-35653` Buffer read overrun in PCX decoding
|
||||
|
||||
The PCX image decoder used the reported image stride to calculate the row buffer,
|
||||
rather than calculating it from the image size. This issue dates back to the PIL fork.
|
||||
Thanks to Google's `OSS-Fuzz`_ project for finding this.
|
||||
|
||||
* :cve:`CVE-2020-35654` Fix TIFF out-of-bounds write error
|
||||
* :cve:`2020-35654` Fix TIFF out-of-bounds write error
|
||||
|
||||
Out-of-bounds write in ``TiffDecode.c`` when reading corrupt YCbCr files in some
|
||||
LibTIFF versions (4.1.0/Ubuntu 20.04, but not 4.0.9/Ubuntu 18.04). In some cases
|
||||
|
@ -55,7 +55,7 @@ an out-of-bounds write in ``TiffDecode.c``. This potentially affects Pillow vers
|
|||
from 6.0.0 to 8.0.1, depending on the version of LibTIFF. This was reported through
|
||||
`Tidelift`_.
|
||||
|
||||
* :cve:`CVE-2020-35655` Fix for SGI Decode buffer overrun
|
||||
* :cve:`2020-35655` Fix for SGI Decode buffer overrun
|
||||
|
||||
4 byte read overflow in ``SgiRleDecode.c``, where the code was not correctly checking the
|
||||
offsets and length tables. Independently reported through `Tidelift`_ and Google's
|
||||
|
|
|
@ -4,19 +4,19 @@
|
|||
Security
|
||||
========
|
||||
|
||||
:cve:`CVE-2021-25289`: The previous fix for :cve:`CVE-2020-35654` was insufficient
|
||||
:cve:`2021-25289`: The previous fix for :cve:`2020-35654` was insufficient
|
||||
due to incorrect error checking in ``TiffDecode.c``.
|
||||
|
||||
:cve:`CVE-2021-25290`: In ``TiffDecode.c``, there is a negative-offset ``memcpy``
|
||||
:cve:`2021-25290`: In ``TiffDecode.c``, there is a negative-offset ``memcpy``
|
||||
with an invalid size.
|
||||
|
||||
:cve:`CVE-2021-25291`: In ``TiffDecode.c``, invalid tile boundaries could lead to
|
||||
:cve:`2021-25291`: In ``TiffDecode.c``, invalid tile boundaries could lead to
|
||||
an out-of-bounds read in ``TIFFReadRGBATile``.
|
||||
|
||||
:cve:`CVE-2021-25292`: The PDF parser has a catastrophic backtracking regex
|
||||
:cve:`2021-25292`: The PDF parser has a catastrophic backtracking regex
|
||||
that could be used as a DOS attack.
|
||||
|
||||
:cve:`CVE-2021-25293`: There is an out-of-bounds read in ``SgiRleDecode.c``,
|
||||
:cve:`2021-25293`: There is an out-of-bounds read in ``SgiRleDecode.c``,
|
||||
since Pillow 4.3.0.
|
||||
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
Security
|
||||
========
|
||||
|
||||
There is an exhaustion of memory DOS in the BLP (:cve:`CVE-2021-27921`),
|
||||
ICNS (:cve:`CVE-2021-27922`) and ICO (:cve:`CVE-2021-27923`) container formats
|
||||
There is an exhaustion of memory DOS in the BLP (:cve:`2021-27921`),
|
||||
ICNS (:cve:`2021-27922`) and ICO (:cve:`2021-27923`) container formats
|
||||
where Pillow did not properly check the reported size of the contained image.
|
||||
These images could cause arbitrarily large memory allocations. This was reported
|
||||
by Jiayi Lin, Luke Shaffer, Xinran Xie, and Akshay Ajayan of
|
||||
|
|
|
@ -129,15 +129,15 @@ Security
|
|||
|
||||
These were all found with `OSS-Fuzz`_.
|
||||
|
||||
:cve:`CVE-2021-25287`, :cve:`CVE-2021-25288`: Fix OOB read in Jpeg2KDecode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:cve:`2021-25287`, :cve:`2021-25288`: Fix OOB read in Jpeg2KDecode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* For J2k images with multiple bands, it's legal to have different widths for each band,
|
||||
e.g. 1 byte for ``L``, 4 bytes for ``A``.
|
||||
* This dates to Pillow 2.4.0.
|
||||
|
||||
:cve:`CVE-2021-28675`: Fix DOS in PsdImagePlugin
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:cve:`2021-28675`: Fix DOS in PsdImagePlugin
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* :py:class:`.PsdImagePlugin.PsdImageFile` did not sanity check the number of input
|
||||
layers with regard to the size of the data block, this could lead to a
|
||||
|
@ -145,15 +145,15 @@ These were all found with `OSS-Fuzz`_.
|
|||
:py:meth:`~PIL.Image.Image.load`.
|
||||
* This dates to the PIL fork.
|
||||
|
||||
:cve:`CVE-2021-28676`: Fix FLI DOS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:cve:`2021-28676`: Fix FLI DOS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* ``FliDecode.c`` did not properly check that the block advance was non-zero,
|
||||
potentially leading to an infinite loop on load.
|
||||
* This dates to the PIL fork.
|
||||
|
||||
:cve:`CVE-2021-28677`: Fix EPS DOS on _open
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:cve:`2021-28677`: Fix EPS DOS on _open
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* The readline used in EPS has to deal with any combination of ``\r`` and ``\n`` as line
|
||||
endings. It accidentally used a quadratic method of accumulating lines while looking
|
||||
|
@ -162,8 +162,8 @@ These were all found with `OSS-Fuzz`_.
|
|||
open phase, before an image was accepted for opening.
|
||||
* This dates to the PIL fork.
|
||||
|
||||
:cve:`CVE-2021-28678`: Fix BLP DOS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:cve:`2021-28678`: Fix BLP DOS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* ``BlpImagePlugin`` did not properly check that reads after jumping to file offsets
|
||||
returned data. This could lead to a denial-of-service where the decoder could be run a
|
||||
|
|
|
@ -85,7 +85,7 @@ Security
|
|||
Buffer overflow
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This release addresses :cve:`CVE-2021-34552`. PIL since 1.1.4 and Pillow since 1.0
|
||||
This release addresses :cve:`2021-34552`. PIL since 1.1.4 and Pillow since 1.0
|
||||
allowed parameters passed into a convert function to trigger buffer overflow in
|
||||
Convert.c.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Security
|
||||
========
|
||||
|
||||
* :cve:`CVE-2021-23437`: Avoid a potential ReDoS (regular expression denial of service)
|
||||
* :cve:`2021-23437`: Avoid a potential ReDoS (regular expression denial of service)
|
||||
in :py:class:`~PIL.ImageColor`'s :py:meth:`~PIL.ImageColor.getrgb` by raising
|
||||
:py:exc:`ValueError` if the color specifier is too long. Present since Pillow 5.2.0.
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ FreeType 2.7
|
|||
Support for FreeType 2.7 has been removed; FreeType 2.8 is the minimum supported.
|
||||
|
||||
We recommend upgrading to at least `FreeType`_ 2.10.4, which fixed a severe
|
||||
vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).
|
||||
vulnerability introduced in FreeType 2.6 (:cve:`2020-15999`).
|
||||
|
||||
.. _FreeType: https://freetype.org/
|
||||
|
||||
|
@ -119,7 +119,7 @@ Google's `OSS-Fuzz`_ project for finding this issue.
|
|||
Restrict builtins available to ImageMath.eval
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:cve:`CVE-2022-22817`: To limit :py:class:`PIL.ImageMath` to working with images, Pillow
|
||||
:cve:`2022-22817`: To limit :py:class:`PIL.ImageMath` to working with images, Pillow
|
||||
will now restrict the builtins available to :py:meth:`PIL.ImageMath.eval`. This will
|
||||
help prevent problems arising if users evaluate arbitrary expressions, such as
|
||||
``ImageMath.eval("exec(exit())")``.
|
||||
|
@ -127,7 +127,7 @@ help prevent problems arising if users evaluate arbitrary expressions, such as
|
|||
Fixed ImagePath.Path array handling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
:cve:`CVE-2022-22815` (:cwe:`CWE-126`) and :cve:`CVE-2022-22816` (:cwe:`CWE-665`) were
|
||||
:cve:`2022-22815` (:cwe:`126`) and :cve:`2022-22816` (:cwe:`665`) were
|
||||
found when initializing ``ImagePath.Path``.
|
||||
|
||||
.. _OSS-Fuzz: https://github.com/google/oss-fuzz
|
||||
|
|
|
@ -6,12 +6,12 @@ Security
|
|||
|
||||
This release addresses several security problems.
|
||||
|
||||
:cve:`CVE-2022-24303`: If the path to the temporary directory on Linux or macOS
|
||||
:cve:`2022-24303`: If the path to the temporary directory on Linux or macOS
|
||||
contained a space, this would break removal of the temporary image file after
|
||||
``im.show()`` (and related actions), and potentially remove an unrelated file. This
|
||||
has been present since PIL.
|
||||
|
||||
:cve:`CVE-2022-22817`: While Pillow 9.0 restricted top-level builtins available to
|
||||
:cve:`2022-22817`: While Pillow 9.0 restricted top-level builtins available to
|
||||
:py:meth:`PIL.ImageMath.eval`, it did not prevent builtins available to lambda
|
||||
expressions. These are now also restricted.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Security
|
|||
|
||||
This release addresses several security problems.
|
||||
|
||||
:cve:`CVE-2022-30595`: When reading a TGA file with RLE packets that cross scan lines,
|
||||
:cve:`2022-30595`: When reading a TGA file with RLE packets that cross scan lines,
|
||||
Pillow reads the information past the end of the first line without deducting that
|
||||
from the length of the remaining file data. This vulnerability was introduced in Pillow
|
||||
9.1.0, and can cause a heap buffer overflow.
|
||||
|
|
|
@ -28,6 +28,11 @@ TODO
|
|||
API Additions
|
||||
=============
|
||||
|
||||
QOI file format
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Pillow can now read images in Quite OK Image format.
|
||||
|
||||
Added ``dpi`` argument when saving PDFs
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -54,7 +59,14 @@ TODO
|
|||
Other Changes
|
||||
=============
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
Added support for saving PDFs in RGBA mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
TODO
|
||||
Using the JPXDecode filter, PDFs can now be saved in RGBA mode.
|
||||
|
||||
|
||||
Improved I;16N support
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Support has been added for I;16N access, packing and unpacking. Conversion to
|
||||
and from L mode has also been added.
|
||||
|
|
|
@ -48,7 +48,6 @@ docs =
|
|||
sphinx>=2.4
|
||||
sphinx-copybutton
|
||||
sphinx-inline-tabs
|
||||
sphinx-issues>=3.0.1
|
||||
sphinx-removed-in
|
||||
sphinxext-opengraph
|
||||
tests =
|
||||
|
|
8
setup.py
8
setup.py
|
@ -242,7 +242,9 @@ def _find_include_dir(self, dirname, include):
|
|||
return subdir
|
||||
|
||||
|
||||
def _cmd_exists(cmd):
|
||||
def _cmd_exists(cmd: str) -> bool:
|
||||
if "PATH" not in os.environ:
|
||||
return False
|
||||
return any(
|
||||
os.access(os.path.join(path, cmd), os.X_OK)
|
||||
for path in os.environ["PATH"].split(os.pathsep)
|
||||
|
@ -570,9 +572,7 @@ class pil_build_ext(build_ext):
|
|||
):
|
||||
for dirname in _find_library_dirs_ldconfig():
|
||||
_add_directory(library_dirs, dirname)
|
||||
if sys.platform.startswith("linux") and os.environ.get(
|
||||
"ANDROID_ROOT", None
|
||||
):
|
||||
if sys.platform.startswith("linux") and os.environ.get("ANDROID_ROOT"):
|
||||
# termux support for android.
|
||||
# system libraries (zlib) are installed in /system/lib
|
||||
# headers are at $PREFIX/include
|
||||
|
|
|
@ -235,6 +235,14 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
|
||||
return ImageFile.ImageFile.load(self)
|
||||
|
||||
def close(self):
|
||||
self.ole.close()
|
||||
super().close()
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.ole.close()
|
||||
super().__exit__()
|
||||
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
|
|
@ -423,7 +423,6 @@ class ImageDraw:
|
|||
self.draw.draw_rectangle(right, ink, 1)
|
||||
|
||||
def _multiline_check(self, text):
|
||||
"""Draw text."""
|
||||
split_character = "\n" if isinstance(text, str) else b"\n"
|
||||
|
||||
return split_character in text
|
||||
|
@ -464,6 +463,7 @@ class ImageDraw:
|
|||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
"""Draw text."""
|
||||
if self._multiline_check(text):
|
||||
return self.multiline_text(
|
||||
xy,
|
||||
|
|
|
@ -1012,7 +1012,7 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
|||
if windir:
|
||||
dirs.append(os.path.join(windir, "fonts"))
|
||||
elif sys.platform in ("linux", "linux2"):
|
||||
lindirs = os.environ.get("XDG_DATA_DIRS", "")
|
||||
lindirs = os.environ.get("XDG_DATA_DIRS")
|
||||
if not lindirs:
|
||||
# According to the freedesktop spec, XDG_DATA_DIRS should
|
||||
# default to /usr/share
|
||||
|
|
|
@ -89,6 +89,14 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
|
|||
def tell(self):
|
||||
return self.frame
|
||||
|
||||
def close(self):
|
||||
self.ole.close()
|
||||
super().close()
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.ole.close()
|
||||
super().__exit__()
|
||||
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
|
|
@ -173,6 +173,10 @@ def _save(im, fp, filename, save_all=False):
|
|||
filter = "DCTDecode"
|
||||
colorspace = PdfParser.PdfName("DeviceRGB")
|
||||
procset = "ImageC" # color images
|
||||
elif im.mode == "RGBA":
|
||||
filter = "JPXDecode"
|
||||
colorspace = PdfParser.PdfName("DeviceRGB")
|
||||
procset = "ImageC" # color images
|
||||
elif im.mode == "CMYK":
|
||||
filter = "DCTDecode"
|
||||
colorspace = PdfParser.PdfName("DeviceCMYK")
|
||||
|
@ -199,6 +203,8 @@ def _save(im, fp, filename, save_all=False):
|
|||
)
|
||||
elif filter == "DCTDecode":
|
||||
Image.SAVE["JPEG"](im, op, filename)
|
||||
elif filter == "JPXDecode":
|
||||
Image.SAVE["JPEG2000"](im, op, filename)
|
||||
elif filter == "FlateDecode":
|
||||
ImageFile._save(im, op, [("zip", (0, 0) + im.size, 0, im.mode)])
|
||||
elif filter == "RunLengthDecode":
|
||||
|
|
|
@ -320,6 +320,7 @@ mode_map = {
|
|||
"1": _PyAccess8,
|
||||
"L": _PyAccess8,
|
||||
"P": _PyAccess8,
|
||||
"I;16N": _PyAccessI16_N,
|
||||
"LA": _PyAccess32_2,
|
||||
"La": _PyAccess32_2,
|
||||
"PA": _PyAccess32_2,
|
||||
|
|
105
src/PIL/QoiImagePlugin.py
Normal file
105
src/PIL/QoiImagePlugin.py
Normal file
|
@ -0,0 +1,105 @@
|
|||
#
|
||||
# The Python Imaging Library.
|
||||
#
|
||||
# QOI support for PIL
|
||||
#
|
||||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i32be as i32
|
||||
from ._binary import o8
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return prefix[:4] == b"qoif"
|
||||
|
||||
|
||||
class QoiImageFile(ImageFile.ImageFile):
|
||||
format = "QOI"
|
||||
format_description = "Quite OK Image"
|
||||
|
||||
def _open(self):
|
||||
if not _accept(self.fp.read(4)):
|
||||
msg = "not a QOI file"
|
||||
raise SyntaxError(msg)
|
||||
|
||||
self._size = tuple(i32(self.fp.read(4)) for i in range(2))
|
||||
|
||||
channels = self.fp.read(1)[0]
|
||||
self.mode = "RGB" if channels == 3 else "RGBA"
|
||||
|
||||
self.fp.seek(1, os.SEEK_CUR) # colorspace
|
||||
self.tile = [("qoi", (0, 0) + self._size, self.fp.tell(), None)]
|
||||
|
||||
|
||||
class QoiDecoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def _add_to_previous_pixels(self, value):
|
||||
self._previous_pixel = value
|
||||
|
||||
r, g, b, a = value
|
||||
hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64
|
||||
self._previously_seen_pixels[hash_value] = value
|
||||
|
||||
def decode(self, buffer):
|
||||
self._previously_seen_pixels = {}
|
||||
self._previous_pixel = None
|
||||
self._add_to_previous_pixels(b"".join(o8(i) for i in (0, 0, 0, 255)))
|
||||
|
||||
data = bytearray()
|
||||
bands = Image.getmodebands(self.mode)
|
||||
while len(data) < self.state.xsize * self.state.ysize * bands:
|
||||
byte = self.fd.read(1)[0]
|
||||
if byte == 0b11111110: # QOI_OP_RGB
|
||||
value = self.fd.read(3) + o8(255)
|
||||
elif byte == 0b11111111: # QOI_OP_RGBA
|
||||
value = self.fd.read(4)
|
||||
else:
|
||||
op = byte >> 6
|
||||
if op == 0: # QOI_OP_INDEX
|
||||
op_index = byte & 0b00111111
|
||||
value = self._previously_seen_pixels.get(op_index, (0, 0, 0, 0))
|
||||
elif op == 1: # QOI_OP_DIFF
|
||||
value = (
|
||||
(self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2)
|
||||
% 256,
|
||||
(self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2)
|
||||
% 256,
|
||||
(self._previous_pixel[2] + (byte & 0b00000011) - 2) % 256,
|
||||
)
|
||||
value += (self._previous_pixel[3],)
|
||||
elif op == 2: # QOI_OP_LUMA
|
||||
second_byte = self.fd.read(1)[0]
|
||||
diff_green = (byte & 0b00111111) - 32
|
||||
diff_red = ((second_byte & 0b11110000) >> 4) - 8
|
||||
diff_blue = (second_byte & 0b00001111) - 8
|
||||
|
||||
value = tuple(
|
||||
(self._previous_pixel[i] + diff_green + diff) % 256
|
||||
for i, diff in enumerate((diff_red, 0, diff_blue))
|
||||
)
|
||||
value += (self._previous_pixel[3],)
|
||||
elif op == 3: # QOI_OP_RUN
|
||||
run_length = (byte & 0b00111111) + 1
|
||||
value = self._previous_pixel
|
||||
if bands == 3:
|
||||
value = value[:3]
|
||||
data += value * run_length
|
||||
continue
|
||||
value = b"".join(o8(i) for i in value)
|
||||
self._add_to_previous_pixels(value)
|
||||
|
||||
if bands == 3:
|
||||
value = value[:3]
|
||||
data += value
|
||||
self.set_as_raw(bytes(data))
|
||||
return -1, 0
|
||||
|
||||
|
||||
Image.register_open(QoiImageFile.format, QoiImageFile, _accept)
|
||||
Image.register_decoder("qoi", QoiDecoder)
|
||||
Image.register_extension(QoiImageFile.format, ".qoi")
|
|
@ -425,6 +425,9 @@ class IFDRational(Rational):
|
|||
__ceil__ = _delegate("__ceil__")
|
||||
__floor__ = _delegate("__floor__")
|
||||
__round__ = _delegate("__round__")
|
||||
# Python >= 3.11
|
||||
if hasattr(Fraction, "__int__"):
|
||||
__int__ = _delegate("__int__")
|
||||
|
||||
|
||||
class ImageFileDirectory_v2(MutableMapping):
|
||||
|
@ -1804,7 +1807,7 @@ def _save(im, fp, filename):
|
|||
# Custom items are supported for int, float, unicode, string and byte
|
||||
# values. Other types and tuples require a tagtype.
|
||||
if tag not in TiffTags.LIBTIFF_CORE:
|
||||
if not Image.core.libtiff_support_custom_tags:
|
||||
if not getattr(Image.core, "libtiff_support_custom_tags", False):
|
||||
continue
|
||||
|
||||
if tag in ifd.tagtype:
|
||||
|
|
|
@ -59,6 +59,7 @@ _plugins = [
|
|||
"PngImagePlugin",
|
||||
"PpmImagePlugin",
|
||||
"PsdImagePlugin",
|
||||
"QoiImagePlugin",
|
||||
"SgiImagePlugin",
|
||||
"SpiderImagePlugin",
|
||||
"SunImagePlugin",
|
||||
|
|
|
@ -3816,6 +3816,7 @@ static PyTypeObject PixelAccess_Type = {
|
|||
static PyObject *
|
||||
_get_stats(PyObject *self, PyObject *args) {
|
||||
PyObject *d;
|
||||
PyObject *v;
|
||||
ImagingMemoryArena arena = &ImagingDefaultArena;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ":get_stats")) {
|
||||
|
@ -3826,15 +3827,29 @@ _get_stats(PyObject *self, PyObject *args) {
|
|||
if (!d) {
|
||||
return NULL;
|
||||
}
|
||||
PyDict_SetItemString(d, "new_count", PyLong_FromLong(arena->stats_new_count));
|
||||
PyDict_SetItemString(
|
||||
d, "allocated_blocks", PyLong_FromLong(arena->stats_allocated_blocks));
|
||||
PyDict_SetItemString(
|
||||
d, "reused_blocks", PyLong_FromLong(arena->stats_reused_blocks));
|
||||
PyDict_SetItemString(
|
||||
d, "reallocated_blocks", PyLong_FromLong(arena->stats_reallocated_blocks));
|
||||
PyDict_SetItemString(d, "freed_blocks", PyLong_FromLong(arena->stats_freed_blocks));
|
||||
PyDict_SetItemString(d, "blocks_cached", PyLong_FromLong(arena->blocks_cached));
|
||||
v = PyLong_FromLong(arena->stats_new_count);
|
||||
PyDict_SetItemString(d, "new_count", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = PyLong_FromLong(arena->stats_allocated_blocks);
|
||||
PyDict_SetItemString(d, "allocated_blocks", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = PyLong_FromLong(arena->stats_reused_blocks);
|
||||
PyDict_SetItemString(d, "reused_blocks", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = PyLong_FromLong(arena->stats_reallocated_blocks);
|
||||
PyDict_SetItemString(d, "reallocated_blocks", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = PyLong_FromLong(arena->stats_freed_blocks);
|
||||
PyDict_SetItemString(d, "freed_blocks", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = PyLong_FromLong(arena->blocks_cached);
|
||||
PyDict_SetItemString(d, "blocks_cached", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -4203,28 +4218,33 @@ setup_module(PyObject *m) {
|
|||
#ifdef HAVE_LIBJPEG
|
||||
{
|
||||
extern const char *ImagingJpegVersion(void);
|
||||
PyDict_SetItemString(
|
||||
d, "jpeglib_version", PyUnicode_FromString(ImagingJpegVersion()));
|
||||
PyObject *v = PyUnicode_FromString(ImagingJpegVersion());
|
||||
PyDict_SetItemString(d, "jpeglib_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENJPEG
|
||||
{
|
||||
extern const char *ImagingJpeg2KVersion(void);
|
||||
PyDict_SetItemString(
|
||||
d, "jp2klib_version", PyUnicode_FromString(ImagingJpeg2KVersion()));
|
||||
PyObject *v = PyUnicode_FromString(ImagingJpeg2KVersion());
|
||||
PyDict_SetItemString(d, "jp2klib_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
PyObject *have_libjpegturbo;
|
||||
#ifdef LIBJPEG_TURBO_VERSION
|
||||
have_libjpegturbo = Py_True;
|
||||
{
|
||||
#define tostr1(a) #a
|
||||
#define tostr(a) tostr1(a)
|
||||
PyDict_SetItemString(
|
||||
d, "libjpeg_turbo_version", PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION)));
|
||||
PyObject *v = PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION));
|
||||
PyDict_SetItemString(d, "libjpeg_turbo_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
#undef tostr
|
||||
#undef tostr1
|
||||
}
|
||||
#else
|
||||
have_libjpegturbo = Py_False;
|
||||
#endif
|
||||
|
@ -4236,8 +4256,9 @@ setup_module(PyObject *m) {
|
|||
have_libimagequant = Py_True;
|
||||
{
|
||||
extern const char *ImagingImageQuantVersion(void);
|
||||
PyDict_SetItemString(
|
||||
d, "imagequant_version", PyUnicode_FromString(ImagingImageQuantVersion()));
|
||||
PyObject *v = PyUnicode_FromString(ImagingImageQuantVersion());
|
||||
PyDict_SetItemString(d, "imagequant_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
#else
|
||||
have_libimagequant = Py_False;
|
||||
|
@ -4254,16 +4275,18 @@ setup_module(PyObject *m) {
|
|||
PyModule_AddIntConstant(m, "FIXED", Z_FIXED);
|
||||
{
|
||||
extern const char *ImagingZipVersion(void);
|
||||
PyDict_SetItemString(
|
||||
d, "zlib_version", PyUnicode_FromString(ImagingZipVersion()));
|
||||
PyObject *v = PyUnicode_FromString(ImagingZipVersion());
|
||||
PyDict_SetItemString(d, "zlib_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBTIFF
|
||||
{
|
||||
extern const char *ImagingTiffVersion(void);
|
||||
PyDict_SetItemString(
|
||||
d, "libtiff_version", PyUnicode_FromString(ImagingTiffVersion()));
|
||||
PyObject *v = PyUnicode_FromString(ImagingTiffVersion());
|
||||
PyDict_SetItemString(d, "libtiff_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
// Test for libtiff 4.0 or later, excluding libtiff 3.9.6 and 3.9.7
|
||||
PyObject *support_custom_tags;
|
||||
|
@ -4286,7 +4309,9 @@ setup_module(PyObject *m) {
|
|||
Py_INCREF(have_xcb);
|
||||
PyModule_AddObject(m, "HAVE_XCB", have_xcb);
|
||||
|
||||
PyDict_SetItemString(d, "PILLOW_VERSION", PyUnicode_FromString(version));
|
||||
PyObject *pillow_version = PyUnicode_FromString(version);
|
||||
PyDict_SetItemString(d, "PILLOW_VERSION", pillow_version ? pillow_version : Py_None);
|
||||
Py_XDECREF(pillow_version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -950,6 +950,8 @@ _is_intent_supported(CmsProfileObject *self, int clut) {
|
|||
return Py_None;
|
||||
}
|
||||
PyDict_SetItem(result, id, entry);
|
||||
Py_DECREF(id);
|
||||
Py_DECREF(entry);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1531,7 +1533,8 @@ setup_module(PyObject *m) {
|
|||
} else {
|
||||
v = PyUnicode_FromFormat("%d.%d", vn / 1000, (vn / 10) % 100);
|
||||
}
|
||||
PyDict_SetItemString(d, "littlecms_version", v);
|
||||
PyDict_SetItemString(d, "littlecms_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1139,11 +1139,17 @@ font_getvaraxes(FontObject *self) {
|
|||
if (list_axis == NULL) {
|
||||
failed = 1;
|
||||
} else {
|
||||
PyDict_SetItemString(
|
||||
list_axis, "minimum", PyLong_FromLong(axis.minimum / 65536));
|
||||
PyDict_SetItemString(list_axis, "default", PyLong_FromLong(axis.def / 65536));
|
||||
PyDict_SetItemString(
|
||||
list_axis, "maximum", PyLong_FromLong(axis.maximum / 65536));
|
||||
PyObject *minimum = PyLong_FromLong(axis.minimum / 65536);
|
||||
PyDict_SetItemString(list_axis, "minimum", minimum ? minimum : Py_None);
|
||||
Py_XDECREF(minimum);
|
||||
|
||||
PyObject *def = PyLong_FromLong(axis.def / 65536);
|
||||
PyDict_SetItemString(list_axis, "default", def ? def : Py_None);
|
||||
Py_XDECREF(def);
|
||||
|
||||
PyObject *maximum = PyLong_FromLong(axis.maximum / 65536);
|
||||
PyDict_SetItemString(list_axis, "maximum", maximum ? maximum : Py_None);
|
||||
Py_XDECREF(maximum);
|
||||
|
||||
for (j = 0; j < name_count; j++) {
|
||||
error = FT_Get_Sfnt_Name(self->face, j, &name);
|
||||
|
@ -1155,7 +1161,8 @@ font_getvaraxes(FontObject *self) {
|
|||
|
||||
if (name.name_id == axis.strid) {
|
||||
axis_name = Py_BuildValue("y#", name.string, name.string_len);
|
||||
PyDict_SetItemString(list_axis, "name", axis_name);
|
||||
PyDict_SetItemString(list_axis, "name", axis_name ? axis_name : Py_None);
|
||||
Py_XDECREF(axis_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1382,7 +1389,8 @@ setup_module(PyObject *m) {
|
|||
FT_Library_Version(library, &major, &minor, &patch);
|
||||
|
||||
v = PyUnicode_FromFormat("%d.%d.%d", major, minor, patch);
|
||||
PyDict_SetItemString(d, "freetype2_version", v);
|
||||
PyDict_SetItemString(d, "freetype2_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
#ifdef HAVE_RAQM
|
||||
#if defined(HAVE_RAQM_SYSTEM) || defined(HAVE_FRIBIDI_SYSTEM)
|
||||
|
@ -1400,35 +1408,34 @@ setup_module(PyObject *m) {
|
|||
PyDict_SetItemString(d, "HAVE_RAQM", v);
|
||||
PyDict_SetItemString(d, "HAVE_FRIBIDI", v);
|
||||
PyDict_SetItemString(d, "HAVE_HARFBUZZ", v);
|
||||
Py_DECREF(v);
|
||||
if (have_raqm) {
|
||||
v = NULL;
|
||||
#ifdef RAQM_VERSION_MAJOR
|
||||
v = PyUnicode_FromString(raqm_version_string());
|
||||
#else
|
||||
v = Py_None;
|
||||
#endif
|
||||
PyDict_SetItemString(d, "raqm_version", v);
|
||||
PyDict_SetItemString(d, "raqm_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = NULL;
|
||||
#ifdef FRIBIDI_MAJOR_VERSION
|
||||
{
|
||||
const char *a = strchr(fribidi_version_info, ')');
|
||||
const char *b = strchr(fribidi_version_info, '\n');
|
||||
if (a && b && a + 2 < b) {
|
||||
v = PyUnicode_FromStringAndSize(a + 2, b - (a + 2));
|
||||
} else {
|
||||
v = Py_None;
|
||||
}
|
||||
}
|
||||
#else
|
||||
v = Py_None;
|
||||
#endif
|
||||
PyDict_SetItemString(d, "fribidi_version", v);
|
||||
PyDict_SetItemString(d, "fribidi_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
v = NULL;
|
||||
#ifdef HB_VERSION_STRING
|
||||
v = PyUnicode_FromString(hb_version_string());
|
||||
#else
|
||||
v = Py_None;
|
||||
#endif
|
||||
PyDict_SetItemString(d, "harfbuzz_version", v);
|
||||
PyDict_SetItemString(d, "harfbuzz_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -201,6 +201,7 @@ match(PyObject *self, PyObject *args) {
|
|||
if (lut[lut_idx]) {
|
||||
PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx);
|
||||
PyList_Append(ret, coordObj);
|
||||
Py_XDECREF(coordObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,21 +241,13 @@ get_on_pixels(PyObject *self, PyObject *args) {
|
|||
if (row[col_idx]) {
|
||||
PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx);
|
||||
PyList_Append(ret, coordObj);
|
||||
Py_XDECREF(coordObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_module(PyObject *m) {
|
||||
PyObject *d = PyModule_GetDict(m);
|
||||
|
||||
PyDict_SetItemString(d, "__version", PyUnicode_FromString("0.1"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyMethodDef functions[] = {
|
||||
/* Functions */
|
||||
{"apply", (PyCFunction)apply, METH_VARARGS, NULL},
|
||||
|
@ -276,9 +269,5 @@ PyInit__imagingmorph(void) {
|
|||
|
||||
m = PyModule_Create(&module_def);
|
||||
|
||||
if (setup_module(m) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
|
23
src/_webp.c
23
src/_webp.c
|
@ -949,20 +949,14 @@ addAnimFlagToModule(PyObject *m) {
|
|||
|
||||
void
|
||||
addTransparencyFlagToModule(PyObject *m) {
|
||||
PyModule_AddObject(
|
||||
m, "HAVE_TRANSPARENCY", PyBool_FromLong(!WebPDecoderBuggyAlpha()));
|
||||
PyObject *have_transparency = PyBool_FromLong(!WebPDecoderBuggyAlpha());
|
||||
if (PyModule_AddObject(m, "HAVE_TRANSPARENCY", have_transparency)) {
|
||||
Py_DECREF(have_transparency);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
setup_module(PyObject *m) {
|
||||
PyObject *d = PyModule_GetDict(m);
|
||||
addMuxFlagToModule(m);
|
||||
addAnimFlagToModule(m);
|
||||
addTransparencyFlagToModule(m);
|
||||
|
||||
PyDict_SetItemString(
|
||||
d, "webpdecoder_version", PyUnicode_FromString(WebPDecoderVersion_str()));
|
||||
|
||||
#ifdef HAVE_WEBPANIM
|
||||
/* Ready object types */
|
||||
if (PyType_Ready(&WebPAnimDecoder_Type) < 0 ||
|
||||
|
@ -970,6 +964,15 @@ setup_module(PyObject *m) {
|
|||
return -1;
|
||||
}
|
||||
#endif
|
||||
PyObject *d = PyModule_GetDict(m);
|
||||
addMuxFlagToModule(m);
|
||||
addAnimFlagToModule(m);
|
||||
addTransparencyFlagToModule(m);
|
||||
|
||||
PyObject *v = PyUnicode_FromString(WebPDecoderVersion_str());
|
||||
PyDict_SetItemString(d, "webpdecoder_version", v ? v : Py_None);
|
||||
Py_XDECREF(v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,20 +195,21 @@ _releasedc(ImagingDisplayObject *display, PyObject *args) {
|
|||
|
||||
static PyObject *
|
||||
_frombytes(ImagingDisplayObject *display, PyObject *args) {
|
||||
char *ptr;
|
||||
Py_ssize_t bytes;
|
||||
Py_buffer buffer;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y#:frombytes", &ptr, &bytes)) {
|
||||
if (!PyArg_ParseTuple(args, "y*:frombytes", &buffer)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (display->dib->ysize * display->dib->linesize != bytes) {
|
||||
if (display->dib->ysize * display->dib->linesize != buffer.len) {
|
||||
PyBuffer_Release(&buffer);
|
||||
PyErr_SetString(PyExc_ValueError, "wrong size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(display->dib->bits, ptr, bytes);
|
||||
memcpy(display->dib->bits, buffer.buf, buffer.len);
|
||||
|
||||
PyBuffer_Release(&buffer);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
/* use make_hash.py from the pillow-scripts repository to calculate these values */
|
||||
#define ACCESS_TABLE_SIZE 27
|
||||
#define ACCESS_TABLE_HASH 3078
|
||||
#define ACCESS_TABLE_HASH 33051
|
||||
|
||||
static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE];
|
||||
|
||||
|
@ -92,6 +92,12 @@ get_pixel_16B(Imaging im, int x, int y, void *color) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
get_pixel_16(Imaging im, int x, int y, void *color) {
|
||||
UINT8 *in = (UINT8 *)&im->image[y][x + x];
|
||||
memcpy(color, in, sizeof(UINT16));
|
||||
}
|
||||
|
||||
static void
|
||||
get_pixel_32(Imaging im, int x, int y, void *color) {
|
||||
memcpy(color, &im->image32[y][x], sizeof(INT32));
|
||||
|
@ -186,6 +192,7 @@ ImagingAccessInit() {
|
|||
ADD("I;16", get_pixel_16L, put_pixel_16L);
|
||||
ADD("I;16L", get_pixel_16L, put_pixel_16L);
|
||||
ADD("I;16B", get_pixel_16B, put_pixel_16B);
|
||||
ADD("I;16N", get_pixel_16, put_pixel_16L);
|
||||
ADD("I;32L", get_pixel_32L, put_pixel_32L);
|
||||
ADD("I;32B", get_pixel_32B, put_pixel_32B);
|
||||
ADD("F", get_pixel_32, put_pixel_32);
|
||||
|
|
|
@ -990,6 +990,13 @@ static struct {
|
|||
{"I;16L", "L", I16L_L},
|
||||
{"L", "I;16B", L_I16B},
|
||||
{"I;16B", "L", I16B_L},
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
{"L", "I;16N", L_I16B},
|
||||
{"I;16N", "L", I16B_L},
|
||||
#else
|
||||
{"L", "I;16N", L_I16L},
|
||||
{"I;16N", "L", I16L_L},
|
||||
#endif
|
||||
|
||||
{"I;16", "F", I16L_F},
|
||||
{"I;16L", "F", I16L_F},
|
||||
|
|
|
@ -487,6 +487,10 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) {
|
|||
goto quick_exit;
|
||||
}
|
||||
|
||||
if (strcmp(im->mode, "RGBA") == 0) {
|
||||
image->comps[3].alpha = 1;
|
||||
}
|
||||
|
||||
opj_set_error_handler(codec, j2k_error, context);
|
||||
opj_set_info_handler(codec, j2k_warn, context);
|
||||
opj_set_warning_handler(codec, j2k_warn, context);
|
||||
|
|
|
@ -664,6 +664,7 @@ static struct {
|
|||
#endif
|
||||
{"I;16B", "I;16B", 16, copy2},
|
||||
{"I;16L", "I;16L", 16, copy2},
|
||||
{"I;16N", "I;16N", 16, copy2},
|
||||
{"I;16", "I;16N", 16, packI16N_I16}, // LibTiff native->image endian.
|
||||
{"I;16L", "I;16N", 16, packI16N_I16},
|
||||
{"I;16B", "I;16N", 16, packI16N_I16B},
|
||||
|
|
|
@ -1762,6 +1762,7 @@ static struct {
|
|||
{"I;16", "I;16", 16, copy2},
|
||||
{"I;16B", "I;16B", 16, copy2},
|
||||
{"I;16L", "I;16L", 16, copy2},
|
||||
{"I;16N", "I;16N", 16, copy2},
|
||||
|
||||
{"I;16", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
|
||||
{"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
|
||||
|
|
|
@ -152,9 +152,9 @@ deps = {
|
|||
"libs": [r"*.lib"],
|
||||
},
|
||||
"xz": {
|
||||
"url": SF_PROJECTS + "/lzmautils/files/xz-5.4.1.tar.gz/download",
|
||||
"filename": "xz-5.4.1.tar.gz",
|
||||
"dir": "xz-5.4.1",
|
||||
"url": SF_PROJECTS + "/lzmautils/files/xz-5.4.2.tar.gz/download",
|
||||
"filename": "xz-5.4.2.tar.gz",
|
||||
"dir": "xz-5.4.2",
|
||||
"license": "COPYING",
|
||||
"patch": {
|
||||
r"src\liblzma\api\lzma.h": {
|
||||
|
|
Loading…
Reference in New Issue
Block a user