Merge branch 'master' into rm-2.7

This commit is contained in:
Hugo van Kemenade 2019-11-03 22:48:26 +02:00 committed by GitHub
commit 5006401d0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 159 additions and 100 deletions

View File

@ -68,11 +68,14 @@ class TestFeatures(PillowTestCase):
lines = out.splitlines() lines = out.splitlines()
self.assertEqual(lines[0], "-" * 68) self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Pillow ")) self.assertTrue(lines[1].startswith("Pillow "))
self.assertEqual(lines[2], "-" * 68) self.assertTrue(lines[2].startswith("Python "))
self.assertTrue(lines[3].startswith("Python modules loaded from ")) lines = lines[3:]
self.assertTrue(lines[4].startswith("Binary modules loaded from ")) while lines[0].startswith(" "):
self.assertEqual(lines[5], "-" * 68) lines = lines[1:]
self.assertTrue(lines[6].startswith("Python ")) self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Python modules loaded from "))
self.assertTrue(lines[2].startswith("Binary modules loaded from "))
self.assertEqual(lines[3], "-" * 68)
jpeg = ( jpeg = (
"\n" "\n"
+ "-" * 68 + "-" * 68

View File

@ -2,6 +2,7 @@ import logging
import os import os
from io import BytesIO from io import BytesIO
import pytest
from PIL import Image, TiffImagePlugin from PIL import Image, TiffImagePlugin
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
@ -584,6 +585,9 @@ class TestFileTiff(PillowTestCase):
im.load() im.load()
self.assertFalse(fp.closed) self.assertFalse(fp.closed)
# Ignore this UserWarning which triggers for four tags:
# "Possibly corrupt EXIF data. Expecting to read 50404352 bytes but..."
@pytest.mark.filterwarnings("ignore:Possibly corrupt EXIF data")
def test_string_dimension(self): def test_string_dimension(self):
# Assert that an error is raised if one of the dimensions is a string # Assert that an error is raised if one of the dimensions is a string
with self.assertRaises(ValueError): with self.assertRaises(ValueError):

View File

@ -16,11 +16,14 @@ class TestMain(TestCase):
lines = out.splitlines() lines = out.splitlines()
self.assertEqual(lines[0], "-" * 68) self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Pillow ")) self.assertTrue(lines[1].startswith("Pillow "))
self.assertEqual(lines[2], "-" * 68) self.assertTrue(lines[2].startswith("Python "))
self.assertTrue(lines[3].startswith("Python modules loaded from ")) lines = lines[3:]
self.assertTrue(lines[4].startswith("Binary modules loaded from ")) while lines[0].startswith(" "):
self.assertEqual(lines[5], "-" * 68) lines = lines[1:]
self.assertTrue(lines[6].startswith("Python ")) self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Python modules loaded from "))
self.assertTrue(lines[2].startswith("Binary modules loaded from "))
self.assertEqual(lines[3], "-" * 68)
jpeg = ( jpeg = (
os.linesep os.linesep
+ "-" * 68 + "-" * 68

View File

@ -12,29 +12,6 @@ Deprecated features
Below are features which are considered deprecated. Where appropriate, Below are features which are considered deprecated. Where appropriate,
a ``DeprecationWarning`` is issued. a ``DeprecationWarning`` is issued.
Image.__del__
~~~~~~~~~~~~~
.. deprecated:: 6.1.0
Implicitly closing the image's underlying file in ``Image.__del__`` has been deprecated.
Use a context manager or call ``Image.close()`` instead to close the file in a
deterministic way.
Deprecated:
.. code-block:: python
im = Image.open("hopper.png")
im.save("out.jpg")
Use instead:
.. code-block:: python
with Image.open("hopper.png") as im:
im.save("out.jpg")
Python 2.7 Python 2.7
~~~~~~~~~~ ~~~~~~~~~~
@ -96,6 +73,29 @@ Removed features
Deprecated features are only removed in major releases after an appropriate Deprecated features are only removed in major releases after an appropriate
period of deprecation has passed. period of deprecation has passed.
Image.__del__
~~~~~~~~~~~~~
*Removed in version 7.0.0.*
Implicitly closing the image's underlying file in ``Image.__del__`` has been removed.
Use a context manager or call ``Image.close()`` instead to close the file in a
deterministic way.
Previous method:
.. code-block:: python
im = Image.open("hopper.png")
im.save("out.jpg")
Use instead:
.. code-block:: python
with Image.open("hopper.png") as im:
im.save("out.jpg")
PILLOW_VERSION constant PILLOW_VERSION constant
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,71 @@
7.0.0
-----
Backwards Incompatible Changes
==============================
PILLOW_VERSION constant
^^^^^^^^^^^^^^^^^^^^^^^
``PILLOW_VERSION`` has been removed. Use ``__version__`` instead.
PyQt4 and PySide
^^^^^^^^^^^^^^^^
Qt 4 reached end-of-life on 2015-12-19. Its Python bindings are also EOL: PyQt4 since
2018-08-31 and PySide since 2015-10-14.
Support for PyQt4 and PySide has been removed from ``ImageQt``. Please upgrade to PyQt5
or PySide2.
Setting the size of TIFF images
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Setting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws
an error. Use ``Image.resize`` instead.
API Changes
===========
Deprecations
^^^^^^^^^^^^
TODO
~~~~
TODO
API Additions
=============
TODO
^^^^
TODO
Other Changes
=============
Image.__del__
^^^^^^^^^^^^^
Implicitly closing the image's underlying file in ``Image.__del__`` has been removed.
Use a context manager or call ``Image.close()`` instead to close the file in a
deterministic way.
Previous method:
.. code-block:: python
im = Image.open("hopper.png")
im.save("out.jpg")
Use instead:
.. code-block:: python
with Image.open("hopper.png") as im:
im.save("out.jpg")

View File

@ -6,6 +6,7 @@ Release Notes
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
7.0.0
6.2.1 6.2.1
6.2.0 6.2.0
6.1.0 6.1.0

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# minimal sanity check # minimal sanity check
import os
import sys import sys
from PIL import Image, features from PIL import Image, features
@ -161,32 +160,7 @@ if __name__ == "__main__":
exit_status = 0 exit_status = 0
print("-" * 68) features.pilinfo(sys.stdout, False)
print("Pillow", Image.__version__, "TEST SUMMARY ")
print("-" * 68)
print("Python modules loaded from", os.path.dirname(Image.__file__))
print("Binary modules loaded from", os.path.dirname(Image.core.__file__))
print("-" * 68)
for name, feature in [
("pil", "PIL CORE"),
("tkinter", "TKINTER"),
("freetype2", "FREETYPE2"),
("littlecms2", "LITTLECMS2"),
("webp", "WEBP"),
("transp_webp", "WEBP Transparency"),
("webp_mux", "WEBPMUX"),
("webp_anim", "WEBP Animation"),
("jpg", "JPEG"),
("jpg_2000", "OPENJPEG (JPEG2000)"),
("zlib", "ZLIB (PNG/ZIP)"),
("libtiff", "LIBTIFF"),
("raqm", "RAQM (Bidirectional Text)"),
]:
if features.check(name):
print("---", feature, "support ok")
else:
print("***", feature, "support not installed")
print("-" * 68)
# use doctest to make sure the test program behaves as documented! # use doctest to make sure the test program behaves as documented!
import doctest import doctest

View File

@ -56,12 +56,6 @@ class DecompressionBombError(Exception):
pass pass
class _imaging_not_installed:
# module placeholder
def __getattr__(self, id):
raise ImportError("The _imaging C module is not installed")
# Limit to around a quarter gigabyte for a 24 bit (3 bpp) image # Limit to around a quarter gigabyte for a 24 bit (3 bpp) image
MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 // 4 // 3) MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 // 4 // 3)
@ -82,7 +76,7 @@ try:
) )
except ImportError as v: except ImportError as v:
core = _imaging_not_installed() core = deferred_error(ImportError("The _imaging C module is not installed."))
# Explanations for ways that we know we might have an import error # Explanations for ways that we know we might have an import error
if str(v).startswith("Module use of python"): if str(v).startswith("Module use of python"):
# The _imaging C module is present, but not compiled for # The _imaging C module is present, but not compiled for

View File

@ -54,6 +54,7 @@ features = {
"transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"), "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"),
"raqm": ("PIL._imagingft", "HAVE_RAQM"), "raqm": ("PIL._imagingft", "HAVE_RAQM"),
"libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO"), "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO"),
"libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT"),
} }
@ -92,7 +93,7 @@ def get_supported():
return ret return ret
def pilinfo(out=None): def pilinfo(out=None, supported_formats=True):
if out is None: if out is None:
out = sys.stdout out = sys.stdout
@ -100,6 +101,10 @@ def pilinfo(out=None):
print("-" * 68, file=out) print("-" * 68, file=out)
print("Pillow {}".format(PIL.__version__), file=out) print("Pillow {}".format(PIL.__version__), file=out)
py_version = sys.version.splitlines()
print("Python {}".format(py_version[0].strip()), file=out)
for py_version in py_version[1:]:
print(" {}".format(py_version.strip()), file=out)
print("-" * 68, file=out) print("-" * 68, file=out)
print( print(
"Python modules loaded from {}".format(os.path.dirname(Image.__file__)), "Python modules loaded from {}".format(os.path.dirname(Image.__file__)),
@ -111,12 +116,6 @@ def pilinfo(out=None):
) )
print("-" * 68, file=out) print("-" * 68, file=out)
v = sys.version.splitlines()
print("Python {}".format(v[0].strip()), file=out)
for v in v[1:]:
print(" {}".format(v.strip()), file=out)
print("-" * 68, file=out)
for name, feature in [ for name, feature in [
("pil", "PIL CORE"), ("pil", "PIL CORE"),
("tkinter", "TKINTER"), ("tkinter", "TKINTER"),
@ -131,6 +130,7 @@ def pilinfo(out=None):
("zlib", "ZLIB (PNG/ZIP)"), ("zlib", "ZLIB (PNG/ZIP)"),
("libtiff", "LIBTIFF"), ("libtiff", "LIBTIFF"),
("raqm", "RAQM (Bidirectional Text)"), ("raqm", "RAQM (Bidirectional Text)"),
("libimagequant", "LIBIMAGEQUANT (Quantization method)"),
]: ]:
if check(name): if check(name):
print("---", feature, "support ok", file=out) print("---", feature, "support ok", file=out)
@ -138,6 +138,7 @@ def pilinfo(out=None):
print("***", feature, "support not installed", file=out) print("***", feature, "support not installed", file=out)
print("-" * 68, file=out) print("-" * 68, file=out)
if supported_formats:
extensions = collections.defaultdict(list) extensions = collections.defaultdict(list)
for ext, i in Image.EXTENSION.items(): for ext, i in Image.EXTENSION.items():
extensions[i].append(ext) extensions[i].append(ext)
@ -149,7 +150,9 @@ def pilinfo(out=None):
print(line, file=out) print(line, file=out)
if i in extensions: if i in extensions:
print("Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out) print(
"Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out
)
features = [] features = []
if i in Image.OPEN: if i in Image.OPEN:

View File

@ -3892,6 +3892,12 @@ setup_module(PyObject* m) {
PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_False); PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_False);
#endif #endif
#ifdef HAVE_LIBIMAGEQUANT
PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_True);
#else
PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_False);
#endif
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
/* zip encoding strategies */ /* zip encoding strategies */
PyModule_AddIntConstant(m, "DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY); PyModule_AddIntConstant(m, "DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY);

View File

@ -845,8 +845,6 @@ font_render(FontObject* self, PyObject* args)
bitmap = bitmap_glyph->bitmap; bitmap = bitmap_glyph->bitmap;
left = bitmap_glyph->left; left = bitmap_glyph->left;
FT_Done_Glyph(glyph);
} else { } else {
bitmap = glyph_slot->bitmap; bitmap = glyph_slot->bitmap;
left = glyph_slot->bitmap_left; left = glyph_slot->bitmap_left;
@ -908,6 +906,9 @@ font_render(FontObject* self, PyObject* args)
} }
x += glyph_info[i].x_advance; x += glyph_info[i].x_advance;
y -= glyph_info[i].y_advance; y -= glyph_info[i].y_advance;
if (stroker != NULL) {
FT_Done_Glyph(glyph);
}
} }
FT_Stroker_Done(stroker); FT_Stroker_Done(stroker);

View File

@ -1,7 +1,6 @@
import os import os
SF_MIRROR = "https://iweb.dl.sourceforge.net" SF_MIRROR = "https://iweb.dl.sourceforge.net"
PILLOW_DEPENDS_DIR = "C:\\pillow-depends\\"
pythons = { pythons = {
# for AppVeyor # for AppVeyor