Merge branch 'master' into gha-win

This commit is contained in:
nulano 2019-10-08 12:56:43 +01:00 committed by GitHub
commit a0a5601689
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 370 additions and 294 deletions

View File

@ -30,6 +30,10 @@ environment:
PIP_DIR: bin
TEST_OPTIONS: --processes=0
DEPLOY: NO
- PYTHON: C:/vp/pypy3
EXECUTABLE: bin/pypy.exe
PIP_DIR: bin
VENV: YES
install:
@ -43,7 +47,12 @@ install:
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy2")
{
c:\pillow\winbuild\appveyor_install_pypy.cmd
c:\pillow\winbuild\appveyor_install_pypy2.cmd
}
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy3")
{
c:\pillow\winbuild\appveyor_install_pypy3.cmd
}
- ps: |
if ($env:PYTHON -eq "c:/msys64/mingw32")

View File

@ -22,19 +22,20 @@ matrix:
name: "PyPy3 Xenial"
- python: '3.7'
name: "3.7 Xenial"
services: xvfb
- python: '2.7'
name: "2.7 Xenial"
- python: "2.7_with_system_site_packages" # For PyQt4
name: "2.7_with_system_site_packages Xenial"
services: xvfb
- python: '3.6'
name: "3.6 Xenial PYTHONOPTIMIZE=1"
env: PYTHONOPTIMIZE=1
services: xvfb
- python: '3.5'
name: "3.5 Xenial PYTHONOPTIMIZE=2"
env: PYTHONOPTIMIZE=2
services: xvfb
- python: "3.8-dev"
name: "3.8-dev Xenial"
services: xvfb
- env: DOCKER="alpine" DOCKER_TAG="master"
- env: DOCKER="arch" DOCKER_TAG="master" # contains PyQt5
- env: DOCKER="ubuntu-16.04-xenial-amd64" DOCKER_TAG="master"

View File

@ -3,7 +3,7 @@
set -e
sudo apt-get update
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk python-qt4\
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake imagemagick libharfbuzz-dev libfribidi-dev
@ -15,6 +15,10 @@ pip install -U pytest-cov
pip install pyroma
pip install test-image-results
pip install numpy
if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
sudo apt-get -qq install pyqt5-dev-tools
pip install pyqt5
fi
# docs only on Python 2.7
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi

View File

@ -2,11 +2,50 @@
Changelog (Pillow)
==================
6.2.0 (unreleased)
7.0.0 (unreleased)
------------------
- Drop support for EOL PyQt4 and PySide #4108
[hugovk, radarhere]
- Removed deprecated setting of TIFF image sizes #4114
[radarhere]
- Removed deprecated PILLOW_VERSION #4107
[hugovk]
- Changed default frombuffer raw decoder args #1730
[radarhere]
6.2.0 (2019-10-01)
------------------
- This is the last Pillow release to support Python 2.7 #3642
- Catch buffer overruns #4104
[radarhere]
- Initialize rows_per_strip when RowsPerStrip tag is missing #4034
[cgohlke, radarhere]
- Raise error if TIFF dimension is a string #4103
[radarhere]
- Added decompression bomb checks #4102
[radarhere]
- Fix ImageGrab.grab DPI scaling on Windows 10 version 1607+ #4000
[nulano, radarhere]
- Corrected negative seeks #4101
[radarhere]
- Added argument to capture all screens on Windows #3950
[nulano, radarhere]
- Updated warning to specify when Image.frombuffer defaults will change #4086
[radarhere]
- Changed WindowsViewer format to PNG #4080
[radarhere]

View File

@ -92,7 +92,7 @@ Released as needed privately to individual vendors for critical security-related
```
* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).
```bash
wget -m -A 'Pillow-<VERSION>*' \
wget -m -A 'Pillow-<VERSION>-*' \
http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
```

View File

@ -4,9 +4,5 @@
from io import BytesIO
from PIL import Image
from PIL._util import py3
if py3:
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00", "latin-1")))
else:
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00")))
Image.open(BytesIO(b"icns\x00\x00\x00\x10hang\x00\x00\x00\x00"))

View File

@ -4,19 +4,5 @@
from io import BytesIO
from PIL import Image
from PIL._util import py3
if py3:
Image.open(
BytesIO(
bytes(
"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang",
"latin-1",
)
)
)
else:
Image.open(
BytesIO(bytes("\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang"))
)
Image.open(BytesIO(b"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang"))

View File

@ -5,9 +5,11 @@ from __future__ import print_function
import logging
import os
import subprocess
import sys
import tempfile
import unittest
from io import BytesIO
from PIL import Image, ImageMath
from PIL._util import py3
@ -284,14 +286,10 @@ if not py3:
def fromstring(data):
from io import BytesIO
return Image.open(BytesIO(data))
def tostring(im, string_format, **options):
from io import BytesIO
out = BytesIO()
im.save(out, string_format, **options)
return out.getvalue()
@ -323,8 +321,6 @@ def command_succeeds(cmd):
Runs the command, which must be a list of strings. Returns True if the
command succeeds, or False if an OSError was raised by subprocess.Popen.
"""
import subprocess
with open(os.devnull, "wb") as f:
try:
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -41,6 +41,14 @@ class TestDecompressionBomb(PillowTestCase):
self.assertRaises(Image.DecompressionBombError, lambda: Image.open(TEST_FILE))
def test_exception_ico(self):
with self.assertRaises(Image.DecompressionBombError):
Image.open("Tests/images/decompression_bomb.ico")
def test_exception_gif(self):
with self.assertRaises(Image.DecompressionBombError):
Image.open("Tests/images/decompression_bomb.gif")
class TestDecompressionCrop(PillowTestCase):
def setUp(self):

View File

@ -1,5 +1,6 @@
from __future__ import print_function
import base64
import distutils.version
import io
import itertools
@ -832,6 +833,13 @@ class TestFileLibTiff(LibTiffTestCase):
im, "Tests/images/old-style-jpeg-compression.png"
)
def test_no_rows_per_strip(self):
# This image does not have a RowsPerStrip TIFF tag
infile = "Tests/images/no_rows_per_strip.tif"
im = Image.open(infile)
im.load()
self.assertEqual(im.size, (950, 975))
def test_orientation(self):
base_im = Image.open("Tests/images/g4_orientation_1.tif")
@ -840,3 +848,24 @@ class TestFileLibTiff(LibTiffTestCase):
im.load()
self.assert_image_similar(base_im, im, 0.7)
def test_sampleformat_not_corrupted(self):
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
# when saving to a new file.
# Pillow 6.0 fails with "OSError: cannot identify image file".
tiff = io.BytesIO(
base64.b64decode(
b"SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAAQAAAAEBBAABAAAAAQAA"
b"AAIBAwADAAAAwgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAA"
b"4AAAABUBAwABAAAAAwAAABYBBAABAAAAAQAAABcBBAABAAAACwAAABoBBQAB"
b"AAAAyAAAABsBBQABAAAA0AAAABwBAwABAAAAAQAAACgBAwABAAAAAQAAAFMB"
b"AwADAAAA2AAAAAAAAAAIAAgACAABAAAAAQAAAAEAAAABAAAAAQABAAEAAAB4"
b"nGNgYAAAAAMAAQ=="
)
)
out = io.BytesIO()
with Image.open(tiff) as im:
im.save(out, format="tiff")
out.seek(0)
with Image.open(out) as im:
im.load()

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .test_file_libtiff import LibTiffTestCase
@ -25,8 +27,6 @@ class TestFileLibTiffSmall(LibTiffTestCase):
def test_g4_hopper_bytesio(self):
"""Testing the bytesio loading code path"""
from io import BytesIO
test_file = "Tests/images/hopper_g4.tif"
s = BytesIO()
with open(test_file, "rb") as f:

View File

@ -87,3 +87,12 @@ class TestImagePsd(PillowTestCase):
im = Image.open("Tests/images/hopper_merged.psd")
self.assertNotIn("icc_profile", im.info)
def test_combined_larger_than_size(self):
# The 'combined' sizes of the individual parts is larger than the
# declared 'size' of the extra data field, resulting in a backwards seek.
# If we instead take the 'size' of the extra data field as the source of truth,
# then the seek can't be negative
with self.assertRaises(IOError):
Image.open("Tests/images/combined_larger_than_size.psd")

View File

@ -1,4 +1,5 @@
import tempfile
from io import BytesIO
from PIL import Image, ImageSequence, SpiderImagePlugin
@ -117,3 +118,14 @@ class TestImageSpider(PillowTestCase):
for i, frame in enumerate(ImageSequence.Iterator(im)):
if i > 1:
self.fail("Non-stack DOS file test failed")
# for issue #4093
def test_odd_size(self):
data = BytesIO()
width = 100
im = Image.new("F", (width, 64))
im.save(data, format="SPIDER")
data.seek(0)
im2 = Image.open(data)
self.assert_image_equal(im, im2)

View File

@ -1,7 +1,8 @@
import logging
import os
from io import BytesIO
from PIL import Image, TiffImagePlugin, features
from PIL import Image, TiffImagePlugin
from PIL._util import py3
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
@ -72,15 +73,6 @@ class TestFileTiff(PillowTestCase):
ifd.legacy_api = None
self.assertEqual(str(e.exception), "Not allowing setting of legacy api")
def test_size(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
def set_size():
im.size = (256, 256)
self.assert_warning(DeprecationWarning, set_size)
def test_xyres_tiff(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
@ -512,10 +504,7 @@ class TestFileTiff(PillowTestCase):
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
def test_tiff_save_all(self):
import io
import os
mp = io.BytesIO()
mp = BytesIO()
with Image.open("Tests/images/multipage.tiff") as im:
im.save(mp, format="tiff", save_all=True)
@ -524,7 +513,7 @@ class TestFileTiff(PillowTestCase):
self.assertEqual(im.n_frames, 3)
# Test appending images
mp = io.BytesIO()
mp = BytesIO()
im = Image.new("RGB", (100, 100), "#f00")
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
im.copy().save(mp, format="TIFF", save_all=True, append_images=ims)
@ -538,7 +527,7 @@ class TestFileTiff(PillowTestCase):
for im in ims:
yield im
mp = io.BytesIO()
mp = BytesIO()
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
mp.seek(0, os.SEEK_SET)
@ -586,36 +575,16 @@ class TestFileTiff(PillowTestCase):
im.load()
self.assertFalse(fp.closed)
@unittest.skipUnless(features.check("libtiff"), "libtiff not installed")
def test_sampleformat_not_corrupted(self):
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
# when saving to a new file.
# Pillow 6.0 fails with "OSError: cannot identify image file".
import base64
tiff = BytesIO(
base64.b64decode(
b"SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAAQAAAAEBBAABAAAAAQAA"
b"AAIBAwADAAAAwgAAAAMBAwABAAAACAAAAAYBAwABAAAAAgAAABEBBAABAAAA"
b"4AAAABUBAwABAAAAAwAAABYBBAABAAAAAQAAABcBBAABAAAACwAAABoBBQAB"
b"AAAAyAAAABsBBQABAAAA0AAAABwBAwABAAAAAQAAACgBAwABAAAAAQAAAFMB"
b"AwADAAAA2AAAAAAAAAAIAAgACAABAAAAAQAAAAEAAAABAAAAAQABAAEAAAB4"
b"nGNgYAAAAAMAAQ=="
)
)
out = BytesIO()
with Image.open(tiff) as im:
im.save(out, format="tiff")
out.seek(0)
with Image.open(out) as im:
im.load()
def test_string_dimension(self):
# Assert that an error is raised if one of the dimensions is a string
with self.assertRaises(ValueError):
Image.open("Tests/images/string_dimension.tiff")
@unittest.skipUnless(is_win32(), "Windows only")
class TestFileTiffW32(PillowTestCase):
def test_fd_leak(self):
tmpfile = self.tempfile("temp.tif")
import os
# this is an mmaped file.
with Image.open("Tests/images/uint16_1_4660.tif") as im:

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
@ -39,8 +41,6 @@ class TestFileWebpMetadata(PillowTestCase):
self.assertEqual(exif_data, expected_exif)
def test_write_exif_metadata(self):
from io import BytesIO
file_path = "Tests/images/flower.jpg"
image = Image.open(file_path)
expected_exif = image.info["exif"]
@ -73,8 +73,6 @@ class TestFileWebpMetadata(PillowTestCase):
self.assertEqual(icc, expected_icc)
def test_write_icc_metadata(self):
from io import BytesIO
file_path = "Tests/images/flower2.jpg"
image = Image.open(file_path)
expected_icc_profile = image.info["icc_profile"]
@ -95,8 +93,6 @@ class TestFileWebpMetadata(PillowTestCase):
)
def test_read_no_exif(self):
from io import BytesIO
file_path = "Tests/images/flower.jpg"
image = Image.open(file_path)
self.assertIn("exif", image.info)

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
@ -28,8 +30,6 @@ static char basic_bits[] = {
class TestFileXbm(PillowTestCase):
def test_pil151(self):
from io import BytesIO
im = Image.open(BytesIO(PIL151))
im.load()

View File

@ -1,5 +1,6 @@
import os
import shutil
import tempfile
from PIL import Image
from PIL._util import py3
@ -125,8 +126,6 @@ class TestImage(PillowTestCase):
def test_tempfile(self):
# see #1460, pathlib support breaks tempfile.TemporaryFile on py27
# Will error out on save on 3.0.0
import tempfile
im = hopper()
with tempfile.TemporaryFile() as fp:
im.save(fp, "JPEG")
@ -586,6 +585,15 @@ class TestImage(PillowTestCase):
self.assertFalse(fp.closed)
def test_overrun(self):
for file in ["fli_overrun.bin", "sgi_overrun.bin", "pcx_overrun.bin"]:
im = Image.open(os.path.join("Tests/images", file))
try:
im.load()
self.assertFail()
except IOError as e:
self.assertEqual(str(e), "buffer overrun when reading image file")
class MockEncoder(object):
pass

View File

@ -1,5 +1,8 @@
import ctypes
import os
import subprocess
import sys
from distutils import ccompiler, sysconfig
from PIL import Image
@ -337,10 +340,6 @@ class TestEmbeddable(unittest.TestCase):
"Failing on AppVeyor / GitHub Actions when run from subprocess, not from shell",
)
def test_embeddable(self):
import subprocess
import ctypes
from distutils import ccompiler, sysconfig
with open("embed_pil.c", "w") as fh:
fh.write(
"""

View File

@ -103,6 +103,14 @@ class TestImageFile(PillowTestCase):
parser = ImageFile.Parser()
parser.feed(1)
def test_negative_stride(self):
with open("Tests/images/raw_negative_stride.bin", "rb") as f:
input = f.read()
p = ImageFile.Parser()
p.feed(input)
with self.assertRaises(IOError):
p.close()
def test_truncated_with_errors(self):
if "zip_encoder" not in codecs:
self.skipTest("PNG (zlib) encoder not available")

View File

@ -8,7 +8,11 @@ try:
class TestImageGrab(PillowTestCase):
def test_grab(self):
for im in [ImageGrab.grab(), ImageGrab.grab(include_layered_windows=True)]:
for im in [
ImageGrab.grab(),
ImageGrab.grab(include_layered_windows=True),
ImageGrab.grab(all_screens=True),
]:
self.assert_image(im, im.mode, im.size)
def test_grabclipboard(self):

View File

@ -81,6 +81,16 @@ class TestImageOps(PillowTestCase):
newimg = ImageOps.fit(hopper("RGB").resize((100, 1)), (35, 35))
self.assertEqual(newimg.size, (35, 35))
def test_fit_same_ratio(self):
# The ratio for this image is 1000.0 / 755 = 1.3245033112582782
# If the ratios are not acknowledged to be the same,
# and Pillow attempts to adjust the width to
# 1.3245033112582782 * 755 = 1000.0000000000001
# then centering this greater width causes a negative x offset when cropping
with Image.new("RGB", (1000, 755)) as im:
new_im = ImageOps.fit(im, (1000, 755))
self.assertEqual(new_im.size, (1000, 755))
def test_pad(self):
# Same ratio
im = hopper()

View File

@ -1,13 +1,7 @@
import sys
import warnings
from PIL import ImageQt
from .helper import PillowTestCase, hopper
if sys.version_info.major >= 3:
from importlib import reload
if ImageQt.qt_is_installed:
from PIL.ImageQt import qRgba
@ -35,10 +29,6 @@ class PillowQPixmapTestCase(PillowQtTestCase):
try:
if ImageQt.qt_version == "5":
from PyQt5.QtGui import QGuiApplication
elif ImageQt.qt_version == "4":
from PyQt4.QtGui import QGuiApplication
elif ImageQt.qt_version == "side":
from PySide.QtGui import QGuiApplication
elif ImageQt.qt_version == "side2":
from PySide2.QtGui import QGuiApplication
except ImportError:
@ -59,10 +49,6 @@ class TestImageQt(PillowQtTestCase, PillowTestCase):
# equivalent to an unsigned int.
if ImageQt.qt_version == "5":
from PyQt5.QtGui import qRgb
elif ImageQt.qt_version == "4":
from PyQt4.QtGui import qRgb
elif ImageQt.qt_version == "side":
from PySide.QtGui import qRgb
elif ImageQt.qt_version == "side2":
from PySide2.QtGui import qRgb
@ -83,13 +69,3 @@ class TestImageQt(PillowQtTestCase, PillowTestCase):
def test_image(self):
for mode in ("1", "RGB", "RGBA", "L", "P"):
ImageQt.ImageQt(hopper(mode))
def test_deprecated(self):
with warnings.catch_warnings(record=True) as w:
reload(ImageQt)
if ImageQt.qt_version in ["4", "side"]:
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, DeprecationWarning))
else:
# No warning.
self.assertEqual(w, [])

View File

@ -31,4 +31,8 @@ class TestLocale(PillowTestCase):
locale.setlocale(locale.LC_ALL, "polish")
except locale.Error:
unittest.skip("Polish locale not available")
Image.open(path)
try:
Image.open(path)
finally:
locale.setlocale(locale.LC_ALL, (None, None))

View File

@ -9,25 +9,9 @@ if ImageQt.qt_is_installed:
try:
from PyQt5 import QtGui
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QApplication
QT_VERSION = 5
except (ImportError, RuntimeError):
try:
from PySide2 import QtGui
from PySide2.QtWidgets import QWidget, QHBoxLayout, QLabel, QApplication
QT_VERSION = 5
except (ImportError, RuntimeError):
try:
from PyQt4 import QtGui
from PyQt4.QtGui import QWidget, QHBoxLayout, QLabel, QApplication
QT_VERSION = 4
except (ImportError, RuntimeError):
from PySide import QtGui
from PySide.QtGui import QWidget, QHBoxLayout, QLabel, QApplication
QT_VERSION = 4
from PySide2 import QtGui
from PySide2.QtWidgets import QWidget, QHBoxLayout, QLabel, QApplication
class TestToQImage(PillowQtTestCase, PillowTestCase):
@ -60,10 +44,6 @@ class TestToQImage(PillowQtTestCase, PillowTestCase):
# Check that it actually worked.
reloaded = Image.open(tempfile)
# Gray images appear to come back in palette mode.
# They're roughly equivalent
if QT_VERSION == 4 and mode == "L":
src = src.convert("P")
self.assert_image_equal(reloaded, src)
def test_segfault(self):

View File

@ -45,17 +45,6 @@ Python 2.7 reaches end-of-life on 2020-01-01.
Pillow 7.0.0 will be released on 2020-01-01 and will drop support for Python 2.7, making
Pillow 6.x the last series to support Python 2.
PyQt4 and PySide
~~~~~~~~~~~~~~~~
.. deprecated:: 6.0.0
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 deprecated from ``ImageQt`` and will be removed in
a future version. Please upgrade to PyQt5 or PySide2.
PIL.*ImagePlugin.__version__ attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -81,27 +70,6 @@ Deprecated Deprecated Deprecated
``IptcImagePlugin.__version__`` ``PixarImagePlugin.__version__``
=============================== ================================= ==================================
Setting the size of TIFF images
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.3.0
Setting the image size of a TIFF image (eg. ``im.size = (256, 256)``) issues
a ``DeprecationWarning``:
.. code-block:: none
Setting the size of a TIFF image directly is deprecated, and will
be removed in a future version. Use the resize method instead.
PILLOW_VERSION constant
~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 5.2.0
``PILLOW_VERSION`` has been deprecated and will be removed in 7.0.0. Use ``__version__``
instead.
ImageCms.CmsProfile attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -128,6 +96,32 @@ Removed features
Deprecated features are only removed in major releases after an appropriate
period of deprecation has passed.
PILLOW_VERSION constant
~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 7.0.0.*
``PILLOW_VERSION`` has been removed. Use ``__version__`` instead.
PyQt4 and PySide
~~~~~~~~~~~~~~~~
*Removed in version 7.0.0.*
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 7.0.0.*
Setting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws
an error. Use ``Image.resize`` instead.
VERSION constant
~~~~~~~~~~~~~~~~

View File

@ -113,8 +113,8 @@ to seek to the next frame (``im.seek(im.tell() + 1)``).
Saving
~~~~~~
When calling :py:meth:`~PIL.Image.Image.save`, the following options
are available::
When calling :py:meth:`~PIL.Image.Image.save` to write a GIF file, the
following options are available::
im.save(out, save_all=True, append_images=[im1, im2, ...])
@ -813,8 +813,9 @@ Saving sequences
library is v0.5.0 or later. You can check webp animation support at
runtime by calling ``features.check("webp_anim")``.
When calling :py:meth:`~PIL.Image.Image.save`, the following options
are available when the ``save_all`` argument is present and true.
When calling :py:meth:`~PIL.Image.Image.save` to write a WebP file, the
following options are available when the ``save_all`` argument is present and
true.
**append_images**
A list of images to append as additional frames. Each of the

View File

@ -11,7 +11,7 @@ or the clipboard to a PIL image memory.
.. versionadded:: 1.1.3
.. py:function:: PIL.ImageGrab.grab(bbox=None, include_layered_windows=False)
.. py:function:: PIL.ImageGrab.grab(bbox=None, include_layered_windows=False, all_screens=False)
Take a snapshot of the screen. The pixels inside the bounding box are
returned as an "RGB" image on Windows or "RGBA" on macOS.
@ -20,7 +20,13 @@ or the clipboard to a PIL image memory.
.. versionadded:: 1.1.3 (Windows), 3.0.0 (macOS)
:param bbox: What region to copy. Default is the entire screen.
Note that on Windows OS, the top-left point may be negative if ``all_screens=True`` is used.
:param include_layered_windows: Includes layered windows. Windows OS only.
.. versionadded:: 6.1.0
:param all_screens: Capture all monitors. Windows OS only.
.. versionadded:: 6.2.0
:return: An image
.. py:function:: PIL.ImageGrab.grabclipboard()

View File

@ -8,13 +8,13 @@ The :py:mod:`ImageOps` module contains a number of ready-made image
processing operations. This module is somewhat experimental, and most operators
only work on L and RGB images.
Only bug fixes have been added since the Pillow fork.
.. versionadded:: 1.1.3
.. autofunction:: autocontrast
.. autofunction:: colorize
.. autofunction:: pad
.. autofunction:: crop
.. autofunction:: scale
.. autofunction:: deform
.. autofunction:: equalize
.. autofunction:: expand
@ -25,3 +25,4 @@ Only bug fixes have been added since the Pillow fork.
.. autofunction:: mirror
.. autofunction:: posterize
.. autofunction:: solarize
.. autofunction:: exif_transpose

View File

@ -4,14 +4,8 @@
:py:mod:`ImageQt` Module
========================
The :py:mod:`ImageQt` module contains support for creating PyQt4, PyQt5, PySide or
PySide2 QImage objects from PIL images.
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 is deprecated since Pillow 6.0.0 and will be removed in a
future version. Please upgrade to PyQt5 or PySide2.
The :py:mod:`ImageQt` module contains support for creating PyQt5 or PySide2 QImage
objects from PIL images.
.. versionadded:: 1.1.6
@ -20,7 +14,7 @@ future version. Please upgrade to PyQt5 or PySide2.
Creates an :py:class:`~PIL.ImageQt.ImageQt` object from a PIL
:py:class:`~PIL.Image.Image` object. This class is a subclass of
QtGui.QImage, which means that you can pass the resulting objects directly
to PyQt4/PyQt5/PySide API functions and methods.
to PyQt5/PySide2 API functions and methods.
This operation is currently supported for mode 1, L, P, RGB, and RGBA
images. To handle other modes, you need to convert the image first.

View File

@ -44,6 +44,12 @@ creates the following image:
.. image:: ../../Tests/images/imagedraw_stroke_different.png
ImageGrab on multi-monitor Windows
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An ``all_screens`` argument has been added to ``ImageGrab.grab``. If ``True``,
all monitors will be included in the created image.
API Changes
===========
@ -64,6 +70,13 @@ Python 2.7 reaches end-of-life on 2020-01-01.
Pillow 7.0.0 will be released on 2020-01-01 and will drop support for Python
2.7, making Pillow 6.2.x the last release series to support Python 2.
Image.frombuffer
~~~~~~~~~~~~~~~~
There has been a longstanding warning that the defaults of ``Image.frombuffer``
may change in the future for the "raw" decoder. The change will now take place
in Pillow 7.0.
Other Changes
=============

View File

@ -23,7 +23,9 @@
import io
import os
import re
import subprocess
import sys
import tempfile
from . import Image, ImageFile
from ._binary import i32le as i32
@ -61,8 +63,6 @@ def has_ghostscript():
if gs_windows_binary:
return True
if not sys.platform.startswith("win"):
import subprocess
try:
with open(os.devnull, "wb") as devnull:
subprocess.check_call(["gs", "--version"], stdout=devnull)
@ -91,9 +91,6 @@ def Ghostscript(tile, size, fp, scale=1):
float((72.0 * size[1]) / (bbox[3] - bbox[1])),
)
import subprocess
import tempfile
out_fd, outfile = tempfile.mkstemp()
os.close(out_fd)

View File

@ -25,6 +25,8 @@
#
import itertools
import os
import subprocess
from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence
from ._binary import i8, i16le as i16, o8, o16le as o16
@ -265,6 +267,7 @@ class GifImageFile(ImageFile.ImageFile):
self.dispose = None
elif self.disposal_method == 2:
# replace with background colour
Image._decompression_bomb_check(self.size)
self.dispose = Image.core.fill("P", self.size, self.info["background"])
else:
# replace with previous contents
@ -616,24 +619,22 @@ def _save_netpbm(im, fp, filename):
# If you need real GIF compression and/or RGB quantization, you
# can use the external NETPBM/PBMPLUS utilities. See comments
# below for information on how to enable this.
import os
from subprocess import Popen, check_call, PIPE, CalledProcessError
tempfile = im._dump()
with open(filename, "wb") as f:
if im.mode != "RGB":
with open(os.devnull, "wb") as devnull:
check_call(["ppmtogif", tempfile], stdout=f, stderr=devnull)
subprocess.check_call(["ppmtogif", tempfile], stdout=f, stderr=devnull)
else:
# Pipe ppmquant output into ppmtogif
# "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename)
quant_cmd = ["ppmquant", "256", tempfile]
togif_cmd = ["ppmtogif"]
with open(os.devnull, "wb") as devnull:
quant_proc = Popen(quant_cmd, stdout=PIPE, stderr=devnull)
togif_proc = Popen(
quant_proc = subprocess.Popen(
quant_cmd, stdout=subprocess.PIPE, stderr=devnull
)
togif_proc = subprocess.Popen(
togif_cmd, stdin=quant_proc.stdout, stdout=f, stderr=devnull
)
@ -642,11 +643,11 @@ def _save_netpbm(im, fp, filename):
retcode = quant_proc.wait()
if retcode:
raise CalledProcessError(retcode, quant_cmd)
raise subprocess.CalledProcessError(retcode, quant_cmd)
retcode = togif_proc.wait()
if retcode:
raise CalledProcessError(retcode, togif_cmd)
raise subprocess.CalledProcessError(retcode, togif_cmd)
try:
os.unlink(tempfile)

View File

@ -19,6 +19,7 @@ import io
import os
import shutil
import struct
import subprocess
import sys
import tempfile
@ -333,11 +334,12 @@ def _save(im, fp, filename):
last_w = w * 2
# iconutil -c icns -o {} {}
from subprocess import Popen, PIPE, CalledProcessError
convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
with open(os.devnull, "wb") as devnull:
convert_proc = Popen(convert_cmd, stdout=PIPE, stderr=devnull)
convert_proc = subprocess.Popen(
convert_cmd, stdout=subprocess.PIPE, stderr=devnull
)
convert_proc.stdout.close()
@ -347,7 +349,7 @@ def _save(im, fp, filename):
shutil.rmtree(iconset)
if retcode:
raise CalledProcessError(retcode, convert_cmd)
raise subprocess.CalledProcessError(retcode, convert_cmd)
Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")

View File

@ -180,6 +180,7 @@ class IcoFile(object):
else:
# XOR + AND mask bmp frame
im = BmpImagePlugin.DibImageFile(self.buf)
Image._decompression_bomb_check(im.size)
# change tile dimension to only encompass XOR image
im._size = (im.size[0], int(im.size[1] / 2))

View File

@ -32,12 +32,13 @@ import numbers
import os
import struct
import sys
import tempfile
import warnings
# VERSION was removed in Pillow 6.0.0.
# PILLOW_VERSION is deprecated and will be removed in Pillow 7.0.0.
# PILLOW_VERSION was removed in Pillow 7.0.0.
# Use __version__ instead.
from . import PILLOW_VERSION, ImageMode, TiffTags, __version__, _plugins
from . import ImageMode, TiffTags, __version__, _plugins
from ._binary import i8, i32le
from ._util import deferred_error, isPath, isStringType, py3
@ -57,9 +58,6 @@ except ImportError:
from collections import Callable, MutableMapping
# Silence warning
assert PILLOW_VERSION
logger = logging.getLogger(__name__)
@ -642,8 +640,6 @@ class Image(object):
self.load()
def _dump(self, file=None, format=None, **options):
import tempfile
suffix = ""
if format:
suffix = "." + format
@ -2592,14 +2588,7 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
if decoder_name == "raw":
if args == ():
warnings.warn(
"the frombuffer defaults may change in a future release; "
"for portability, change the call to read:\n"
" frombuffer(mode, size, data, 'raw', mode, 0, 1)",
RuntimeWarning,
stacklevel=2,
)
args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6
args = mode, 0, 1
if args[0] in _MAPMODES:
im = new(mode, (1, 1))
im = im._new(core.map_buffer(data, size, decoder_name, None, 0, args))

View File

@ -25,8 +25,10 @@
# See the README file for information on usage and redistribution.
#
import base64
import os
import sys
from io import BytesIO
from . import Image
from ._util import isDirectory, isPath, py3
@ -713,9 +715,6 @@ def load_default():
:return: A font object.
"""
from io import BytesIO
import base64
f = ImageFont()
f._load_pilfont_data(
# courB08

View File

@ -15,21 +15,18 @@
# See the README file for information on usage and redistribution.
#
import os
import subprocess
import sys
import tempfile
from . import Image
if sys.platform == "win32":
grabber = Image.core.grabscreen
elif sys.platform == "darwin":
import os
import tempfile
import subprocess
else:
if sys.platform not in ["win32", "darwin"]:
raise ImportError("ImageGrab is macOS and Windows only")
def grab(bbox=None, include_layered_windows=False):
def grab(bbox=None, include_layered_windows=False, all_screens=False):
if sys.platform == "darwin":
fh, filepath = tempfile.mkstemp(".png")
os.close(fh)
@ -37,8 +34,10 @@ def grab(bbox=None, include_layered_windows=False):
im = Image.open(filepath)
im.load()
os.unlink(filepath)
if bbox:
im = im.crop(bbox)
else:
size, data = grabber(include_layered_windows)
offset, size, data = Image.core.grabscreen(include_layered_windows, all_screens)
im = Image.frombytes(
"RGB",
size,
@ -49,8 +48,10 @@ def grab(bbox=None, include_layered_windows=False):
(size[0] * 3 + 3) & -4,
-1,
)
if bbox:
im = im.crop(bbox)
if bbox:
x0, y0 = offset
left, top, right, bottom = bbox
im = im.crop((left - x0, top - y0, right - x0, bottom - y0))
return im

View File

@ -426,7 +426,11 @@ def fit(image, size, method=Image.NEAREST, bleed=0.0, centering=(0.5, 0.5)):
output_ratio = float(size[0]) / size[1]
# figure out if the sides or top/bottom will be cropped off
if live_size_ratio >= output_ratio:
if live_size_ratio == output_ratio:
# live_size is already the needed ratio
crop_width = live_size[0]
crop_height = live_size[1]
elif live_size_ratio >= output_ratio:
# live_size is wider than what's needed, crop the sides
crop_width = output_ratio * live_size[1]
crop_height = live_size[1]

View File

@ -17,18 +17,12 @@
#
import sys
import warnings
from io import BytesIO
from . import Image
from ._util import isPath, py3
qt_versions = [["5", "PyQt5"], ["side2", "PySide2"], ["4", "PyQt4"], ["side", "PySide"]]
WARNING_TEXT = (
"Support for EOL {} is deprecated and will be removed in a future version. "
"Please upgrade to PyQt5 or PySide2."
)
qt_versions = [["5", "PyQt5"], ["side2", "PySide2"]]
# If a version has already been imported, attempt it first
qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True)
@ -40,16 +34,6 @@ for qt_version, qt_module in qt_versions:
elif qt_module == "PySide2":
from PySide2.QtGui import QImage, qRgba, QPixmap
from PySide2.QtCore import QBuffer, QIODevice
elif qt_module == "PyQt4":
from PyQt4.QtGui import QImage, qRgba, QPixmap
from PyQt4.QtCore import QBuffer, QIODevice
warnings.warn(WARNING_TEXT.format(qt_module), DeprecationWarning)
elif qt_module == "PySide":
from PySide.QtGui import QImage, qRgba, QPixmap
from PySide.QtCore import QBuffer, QIODevice
warnings.warn(WARNING_TEXT.format(qt_module), DeprecationWarning)
except (ImportError, RuntimeError):
continue
qt_is_installed = True

View File

@ -36,7 +36,10 @@ from __future__ import print_function
import array
import io
import os
import struct
import subprocess
import tempfile
import warnings
from . import Image, ImageFile, TiffImagePlugin
@ -444,10 +447,6 @@ class JpegImageFile(ImageFile.ImageFile):
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
import subprocess
import tempfile
import os
f, path = tempfile.mkstemp()
os.close(f)
if os.path.exists(self.filename):
@ -772,9 +771,6 @@ def _save(im, fp, filename):
def _save_cjpeg(im, fp, filename):
# ALTERNATIVE: handle JPEGs via the IJG command line utilities.
import os
import subprocess
tempfile = im._dump()
subprocess.check_call(["cjpeg", "-outfile", filename, tempfile])
try:

View File

@ -224,9 +224,11 @@ def _layerinfo(file):
# skip over blend flags and extra information
read(12) # filler
name = ""
size = i32(read(4))
size = i32(read(4)) # length of the extra data field
combined = 0
if size:
data_end = file.tell() + size
length = i32(read(4))
if length:
file.seek(length - 16, io.SEEK_CUR)
@ -244,7 +246,7 @@ def _layerinfo(file):
name = read(length).decode("latin-1", "replace")
combined += length + 1
file.seek(size - combined, io.SEEK_CUR)
file.seek(data_end)
layers.append((name, mode, (x0, y0, x1, y1)))
# get tiles

View File

@ -236,7 +236,7 @@ def loadImageSeries(filelist=None):
def makeSpiderHeader(im):
nsam, nrow = im.size
lenbyt = nsam * 4 # There are labrec records in the header
labrec = 1024 / lenbyt
labrec = int(1024 / lenbyt)
if 1024 % lenbyt != 0:
labrec += 1
labbyt = labrec * lenbyt

View File

@ -854,7 +854,7 @@ class ImageFileDirectory_v2(MutableMapping):
# pass 2: write entries to file
for tag, typ, count, value, data in entries:
if DEBUG > 1:
if DEBUG:
print(tag, typ, count, repr(value), repr(data))
result += self._pack("HHL4s", tag, typ, count, value)
@ -1079,19 +1079,6 @@ class TiffImageFile(ImageFile.ImageFile):
"""Return the current frame number"""
return self.__frame
@property
def size(self):
return self._size
@size.setter
def size(self, value):
warnings.warn(
"Setting the size of a TIFF image directly is deprecated, and will"
" be removed in a future version. Use the resize method instead.",
DeprecationWarning,
)
self._size = value
def load(self):
if self.use_load_libtiff:
return self._load_libtiff()
@ -1239,8 +1226,8 @@ class TiffImageFile(ImageFile.ImageFile):
print("- YCbCr subsampling:", self.tag.get(530))
# size
xsize = self.tag_v2.get(IMAGEWIDTH)
ysize = self.tag_v2.get(IMAGELENGTH)
xsize = int(self.tag_v2.get(IMAGEWIDTH))
ysize = int(self.tag_v2.get(IMAGELENGTH))
self._size = xsize, ysize
if DEBUG:

View File

@ -120,7 +120,7 @@ TAGS_V2 = {
277: ("SamplesPerPixel", SHORT, 1),
278: ("RowsPerStrip", LONG, 1),
279: ("StripByteCounts", LONG, 0),
280: ("MinSampleValue", LONG, 0),
280: ("MinSampleValue", SHORT, 0),
281: ("MaxSampleValue", SHORT, 0),
282: ("XResolution", RATIONAL, 1),
283: ("YResolution", RATIONAL, 1),
@ -182,7 +182,7 @@ TAGS_V2 = {
# FIXME add more tags here
34665: ("ExifIFD", LONG, 1),
34675: ("ICCProfile", UNDEFINED, 1),
34853: ("GPSInfoIFD", BYTE, 1),
34853: ("GPSInfoIFD", LONG, 1),
# MPInfo
45056: ("MPFVersion", UNDEFINED, 1),
45057: ("NumberOfImages", LONG, 1),

View File

@ -9,7 +9,6 @@ PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
Copyright (c) 1999 by Secret Labs AB.
Use PIL.__version__ for this Pillow version.
PIL.VERSION is the old PIL version and will be removed in the future.
;-)
"""
@ -17,9 +16,9 @@ PIL.VERSION is the old PIL version and will be removed in the future.
from . import _version
# VERSION was removed in Pillow 6.0.0.
# PILLOW_VERSION is deprecated and will be removed in Pillow 7.0.0.
# PILLOW_VERSION was removed in Pillow 7.0.0.
# Use __version__ instead.
PILLOW_VERSION = __version__ = _version.__version__
__version__ = _version.__version__
del _version

View File

@ -1,2 +1,2 @@
# Master version for Pillow
__version__ = "6.2.0.dev0"
__version__ = "7.0.0.dev0"

View File

@ -319,18 +319,23 @@ PyImaging_DisplayModeWin32(PyObject* self, PyObject* args)
/* -------------------------------------------------------------------- */
/* Windows screen grabber */
typedef HANDLE(__stdcall* Func_SetThreadDpiAwarenessContext)(HANDLE);
PyObject*
PyImaging_GrabScreenWin32(PyObject* self, PyObject* args)
{
int width, height;
int includeLayeredWindows = 0;
int x = 0, y = 0, width, height;
int includeLayeredWindows = 0, all_screens = 0;
HBITMAP bitmap;
BITMAPCOREHEADER core;
HDC screen, screen_copy;
DWORD rop;
PyObject* buffer;
HANDLE dpiAwareness;
HMODULE user32;
Func_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContext_function;
if (!PyArg_ParseTuple(args, "|i", &includeLayeredWindows))
if (!PyArg_ParseTuple(args, "|ii", &includeLayeredWindows, &all_screens))
return NULL;
/* step 1: create a memory DC large enough to hold the
@ -339,8 +344,32 @@ PyImaging_GrabScreenWin32(PyObject* self, PyObject* args)
screen = CreateDC("DISPLAY", NULL, NULL, NULL);
screen_copy = CreateCompatibleDC(screen);
width = GetDeviceCaps(screen, HORZRES);
height = GetDeviceCaps(screen, VERTRES);
// added in Windows 10 (1607)
// loaded dynamically to avoid link errors
user32 = LoadLibraryA("User32.dll");
SetThreadDpiAwarenessContext_function =
(Func_SetThreadDpiAwarenessContext)
GetProcAddress(user32, "SetThreadDpiAwarenessContext");
if (SetThreadDpiAwarenessContext_function != NULL) {
// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ((DPI_CONTEXT_HANDLE)-3)
dpiAwareness = SetThreadDpiAwarenessContext_function((HANDLE) -3);
}
if (all_screens) {
x = GetSystemMetrics(SM_XVIRTUALSCREEN);
y = GetSystemMetrics(SM_YVIRTUALSCREEN);
width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
} else {
width = GetDeviceCaps(screen, HORZRES);
height = GetDeviceCaps(screen, VERTRES);
}
if (SetThreadDpiAwarenessContext_function != NULL) {
SetThreadDpiAwarenessContext_function(dpiAwareness);
}
FreeLibrary(user32);
bitmap = CreateCompatibleBitmap(screen, width, height);
if (!bitmap)
@ -354,7 +383,7 @@ PyImaging_GrabScreenWin32(PyObject* self, PyObject* args)
rop = SRCCOPY;
if (includeLayeredWindows)
rop |= CAPTUREBLT;
if (!BitBlt(screen_copy, 0, 0, width, height, screen, 0, 0, rop))
if (!BitBlt(screen_copy, 0, 0, width, height, screen, x, y, rop))
goto error;
/* step 3: extract bits from bitmap */
@ -376,7 +405,7 @@ PyImaging_GrabScreenWin32(PyObject* self, PyObject* args)
DeleteDC(screen_copy);
DeleteDC(screen);
return Py_BuildValue("(ii)N", width, height, buffer);
return Py_BuildValue("(ii)(ii)N", x, y, width, height, buffer);
error:
PyErr_SetString(PyExc_IOError, "screen grab failed");

View File

@ -30,7 +30,7 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
{
UINT8* ptr;
int framesize;
int c, chunks;
int c, chunks, advance;
int l, lines;
int i, j, x = 0, y, ymax;
@ -59,10 +59,16 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
chunks = I16(ptr+6);
ptr += 16;
bytes -= 16;
/* Process subchunks */
for (c = 0; c < chunks; c++) {
UINT8 *data = ptr + 6;
UINT8* data;
if (bytes < 10) {
state->errcode = IMAGING_CODEC_OVERRUN;
return -1;
}
data = ptr + 6;
switch (I16(ptr+4)) {
case 4: case 11:
/* FLI COLOR chunk */
@ -198,7 +204,9 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
state->errcode = IMAGING_CODEC_UNKNOWN;
return -1;
}
ptr += I32(ptr);
advance = I32(ptr);
ptr += advance;
bytes -= advance;
}
return -1; /* end of frame */

View File

@ -22,6 +22,11 @@ ImagingPcxDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
UINT8 n;
UINT8* ptr;
if (strcmp(im->mode, "1") == 0 && state->xsize > state->bytes * 8) {
state->errcode = IMAGING_CODEC_OVERRUN;
return -1;
}
ptr = buf;
for (;;) {

View File

@ -33,8 +33,15 @@ ImagingRawDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
/* get size of image data and padding */
state->bytes = (state->xsize * state->bits + 7) / 8;
rawstate->skip = (rawstate->stride) ?
rawstate->stride - state->bytes : 0;
if (rawstate->stride) {
rawstate->skip = rawstate->stride - state->bytes;
if (rawstate->skip < 0) {
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
}
} else {
rawstate->skip = 0;
}
/* check image orientation */
if (state->ystep < 0) {

View File

@ -157,6 +157,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize];
c->rleoffset -= SGI_HEADER_SIZE;
if (c->rleoffset + c->rlelength > c->bufsize) {
state->errcode = IMAGING_CODEC_OVERRUN;
return -1;
}
/* row decompression */
if (c->bpc ==1) {
if(expandrow(&state->buffer[c->channo], &ptr[c->rleoffset], c->rlelength, im->bands))

View File

@ -405,8 +405,12 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_
UINT32 strip_row, row_byte_size;
UINT8 *new_data;
UINT32 rows_per_strip;
int ret;
TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
if (ret != 1) {
rows_per_strip = state->ysize;
}
TRACE(("RowsPerStrip: %u \n", rows_per_strip));
// We could use TIFFStripSize, but for YCbCr data it returns subsampled data size

View File

@ -0,0 +1,3 @@
curl -fsSL -o pypy3.zip http://buildbot.pypy.org/nightly/py3.6/pypy-c-jit-97588-7392d01b93d0-win32.zip
7z x pypy3.zip -oc:\
c:\Python37\Scripts\virtualenv.exe -p c:\pypy-c-jit-97588-7392d01b93d0-win32\pypy3.exe c:\vp\pypy3

View File

@ -9,6 +9,7 @@ pythons = {
"pypy2": {"compiler": 7, "vc": 2010},
"35": {"compiler": 7.1, "vc": 2015},
"36": {"compiler": 7.1, "vc": 2015},
"pypy3": {"compiler": 7.1, "vc": 2015},
"37": {"compiler": 7.1, "vc": 2015},
# for GitHub Actions
"3.5": {"compiler": 7.1, "vc": 2015},