mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 10:16:17 +03:00
Drop support for EOL Python 2.7 (#4109)
Drop support for EOL Python 2.7
This commit is contained in:
commit
f90a21965a
|
@ -40,11 +40,6 @@ install:
|
||||||
- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\
|
- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\
|
||||||
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
|
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
|
||||||
- cd c:\pillow\winbuild\
|
- cd c:\pillow\winbuild\
|
||||||
- ps: |
|
|
||||||
if ($env:PYTHON -eq "c:/vp/pypy2")
|
|
||||||
{
|
|
||||||
c:\pillow\winbuild\appveyor_install_pypy2.cmd
|
|
||||||
}
|
|
||||||
- ps: |
|
- ps: |
|
||||||
if ($env:PYTHON -eq "c:/vp/pypy3")
|
if ($env:PYTHON -eq "c:/vp/pypy3")
|
||||||
{
|
{
|
||||||
|
|
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
|
@ -9,14 +9,14 @@ Please send a pull request to the master branch. Please include [documentation](
|
||||||
- Fork the Pillow repository.
|
- Fork the Pillow repository.
|
||||||
- Create a branch from master.
|
- Create a branch from master.
|
||||||
- Develop bug fixes, features, tests, etc.
|
- Develop bug fixes, features, tests, etc.
|
||||||
- Run the test suite on Python 2.7 and 3.x. You can enable [Travis CI](https://travis-ci.org/profile/) and [AppVeyor](https://ci.appveyor.com/projects/new) on your repo to catch test failures prior to the pull request, and [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
|
- Run the test suite. You can enable [Travis CI](https://travis-ci.org/profile/) and [AppVeyor](https://ci.appveyor.com/projects/new) on your repo to catch test failures prior to the pull request, and [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
|
||||||
- Create a pull request to pull the changes from your branch to the Pillow master.
|
- Create a pull request to pull the changes from your branch to the Pillow master.
|
||||||
|
|
||||||
### Guidelines
|
### Guidelines
|
||||||
|
|
||||||
- Separate code commits from reformatting commits.
|
- Separate code commits from reformatting commits.
|
||||||
- Provide tests for any newly added code.
|
- Provide tests for any newly added code.
|
||||||
- Follow PEP8.
|
- Follow PEP 8.
|
||||||
- When committing only documentation changes please include [ci skip] in the commit message to avoid running tests on Travis-CI and AppVeyor.
|
- When committing only documentation changes please include [ci skip] in the commit message to avoid running tests on Travis-CI and AppVeyor.
|
||||||
|
|
||||||
## Reporting Issues
|
## Reporting Issues
|
||||||
|
|
|
@ -6,8 +6,8 @@ notifications:
|
||||||
irc: "chat.freenode.net#pil"
|
irc: "chat.freenode.net#pil"
|
||||||
|
|
||||||
# Run fast lint first to get fast feedback.
|
# Run fast lint first to get fast feedback.
|
||||||
# Run slow PyPy* next, to give them a headstart and reduce waiting time.
|
# Run slow PyPy next, to give it a headstart and reduce waiting time.
|
||||||
# Run latest 3.x and 2.x next, to get quick compatibility results.
|
# Run latest 3.x next, to get quick compatibility results.
|
||||||
# Then run the remainder, with fastest Docker jobs last.
|
# Then run the remainder, with fastest Docker jobs last.
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
|
|
@ -11,16 +11,12 @@ coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
|
||||||
|
|
||||||
coverage report
|
coverage report
|
||||||
pip install codecov
|
pip install codecov
|
||||||
if [[ $TRAVIS_PYTHON_VERSION != "2.7_with_system_site_packages" ]]; then
|
pip install coveralls-merge
|
||||||
# Not working here. Just skip it, it's being removed soon.
|
coveralls-merge coverage.c.json
|
||||||
pip install coveralls-merge
|
|
||||||
coveralls-merge coverage.c.json
|
|
||||||
fi
|
|
||||||
codecov
|
codecov
|
||||||
|
|
||||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ] && [ "$DOCKER" == "" ]; then
|
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ] && [ "$DOCKER" == "" ]; then
|
||||||
# Coverage and quality reports on just the latest diff.
|
# Coverage and quality reports on just the latest diff.
|
||||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
|
||||||
depends/diffcover-install.sh
|
depends/diffcover-install.sh
|
||||||
depends/diffcover-run.sh
|
depends/diffcover-run.sh
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -20,8 +20,8 @@ if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
|
||||||
pip install pyqt5
|
pip install pyqt5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# docs only on Python 2.7
|
# docs only on Python 3.7
|
||||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi
|
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then pip install -r requirements.txt ; fi
|
||||||
|
|
||||||
# webp
|
# webp
|
||||||
pushd depends && ./install_webp.sh && popd
|
pushd depends && ./install_webp.sh && popd
|
||||||
|
|
|
@ -5,4 +5,4 @@ set -e
|
||||||
python -m pytest -v -x --cov PIL --cov-report term Tests
|
python -m pytest -v -x --cov PIL --cov-report term Tests
|
||||||
|
|
||||||
# Docs
|
# Docs
|
||||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make doccheck; fi
|
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then make doccheck; fi
|
||||||
|
|
36
Makefile
36
Makefile
|
@ -3,7 +3,7 @@
|
||||||
.DEFAULT_GOAL := release-test
|
.DEFAULT_GOAL := release-test
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
python setup.py clean
|
python3 setup.py clean
|
||||||
rm src/PIL/*.so || true
|
rm src/PIL/*.so || true
|
||||||
rm -r build || true
|
rm -r build || true
|
||||||
find . -name __pycache__ | xargs rm -r || true
|
find . -name __pycache__ | xargs rm -r || true
|
||||||
|
@ -15,8 +15,8 @@ co:
|
||||||
done
|
done
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
python selftest.py
|
python3 selftest.py
|
||||||
python setup.py test
|
python3 setup.py test
|
||||||
rm -r htmlcov || true
|
rm -r htmlcov || true
|
||||||
coverage report
|
coverage report
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ doccheck:
|
||||||
$(MAKE) -C docs linkcheck || true
|
$(MAKE) -C docs linkcheck || true
|
||||||
|
|
||||||
docserve:
|
docserve:
|
||||||
cd docs/_build/html && python -mSimpleHTTPServer 2> /dev/null&
|
cd docs/_build/html && python3 -mSimpleHTTPServer 2> /dev/null&
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Welcome to Pillow development. Please use \`make <target>\` where <target> is one of"
|
@echo "Welcome to Pillow development. Please use \`make <target>\` where <target> is one of"
|
||||||
|
@ -50,22 +50,22 @@ help:
|
||||||
@echo " upload-test build and upload sdists to test.pythonpackages.com"
|
@echo " upload-test build and upload sdists to test.pythonpackages.com"
|
||||||
|
|
||||||
inplace: clean
|
inplace: clean
|
||||||
python setup.py develop build_ext --inplace
|
python3 setup.py develop build_ext --inplace
|
||||||
|
|
||||||
install:
|
install:
|
||||||
python setup.py install
|
python3 setup.py install
|
||||||
python selftest.py
|
python3 selftest.py
|
||||||
|
|
||||||
install-coverage:
|
install-coverage:
|
||||||
CFLAGS="-coverage" python setup.py build_ext install
|
CFLAGS="-coverage" python3 setup.py build_ext install
|
||||||
python selftest.py
|
python3 selftest.py
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
# make a debug version if we don't have a -dbg python. Leaves in symbols
|
# make a debug version if we don't have a -dbg python. Leaves in symbols
|
||||||
# for our stuff, kills optimization, and redirects to dev null so we
|
# for our stuff, kills optimization, and redirects to dev null so we
|
||||||
# see any build failures.
|
# see any build failures.
|
||||||
make clean > /dev/null
|
make clean > /dev/null
|
||||||
CFLAGS='-g -O0' python setup.py build_ext install > /dev/null
|
CFLAGS='-g -O0' python3 setup.py build_ext install > /dev/null
|
||||||
|
|
||||||
install-req:
|
install-req:
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
@ -76,17 +76,17 @@ install-venv:
|
||||||
|
|
||||||
release-test:
|
release-test:
|
||||||
$(MAKE) install-req
|
$(MAKE) install-req
|
||||||
python setup.py develop
|
python3 setup.py develop
|
||||||
python selftest.py
|
python3 selftest.py
|
||||||
python -m pytest Tests
|
python3 -m pytest Tests
|
||||||
python setup.py install
|
python3 setup.py install
|
||||||
python -m pytest -qq
|
python3 -m pytest -qq
|
||||||
check-manifest
|
check-manifest
|
||||||
pyroma .
|
pyroma .
|
||||||
viewdoc
|
viewdoc
|
||||||
|
|
||||||
sdist:
|
sdist:
|
||||||
python setup.py sdist --format=gztar
|
python3 setup.py sdist --format=gztar
|
||||||
|
|
||||||
test:
|
test:
|
||||||
pytest -qq
|
pytest -qq
|
||||||
|
@ -97,10 +97,10 @@ upload-test:
|
||||||
# username:
|
# username:
|
||||||
# password:
|
# password:
|
||||||
# repository = http://test.pythonpackages.com
|
# repository = http://test.pythonpackages.com
|
||||||
python setup.py sdist --format=gztar upload -r test
|
python3 setup.py sdist --format=gztar upload -r test
|
||||||
|
|
||||||
upload:
|
upload:
|
||||||
python setup.py sdist --format=gztar upload
|
python3 setup.py sdist --format=gztar upload
|
||||||
|
|
||||||
readme:
|
readme:
|
||||||
viewdoc
|
viewdoc
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, is_win32, unittest
|
from .helper import PillowTestCase, is_win32, unittest
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""
|
"""
|
||||||
Helper functions.
|
Helper functions.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -12,7 +11,6 @@ import unittest
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from PIL import Image, ImageMath
|
from PIL import Image, ImageMath
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -76,10 +74,13 @@ class PillowTestCase(unittest.TestCase):
|
||||||
def assert_deep_equal(self, a, b, msg=None):
|
def assert_deep_equal(self, a, b, msg=None):
|
||||||
try:
|
try:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(a), len(b), msg or "got length %s, expected %s" % (len(a), len(b))
|
len(a),
|
||||||
|
len(b),
|
||||||
|
msg or "got length {}, expected {}".format(len(a), len(b)),
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
all(x == y for x, y in zip(a, b)), msg or "got %s, expected %s" % (a, b)
|
all(x == y for x, y in zip(a, b)),
|
||||||
|
msg or "got {}, expected {}".format(a, b),
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.assertEqual(a, b, msg)
|
self.assertEqual(a, b, msg)
|
||||||
|
@ -87,20 +88,24 @@ class PillowTestCase(unittest.TestCase):
|
||||||
def assert_image(self, im, mode, size, msg=None):
|
def assert_image(self, im, mode, size, msg=None):
|
||||||
if mode is not None:
|
if mode is not None:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.mode, mode, msg or "got mode %r, expected %r" % (im.mode, mode)
|
im.mode,
|
||||||
|
mode,
|
||||||
|
msg or "got mode {!r}, expected {!r}".format(im.mode, mode),
|
||||||
)
|
)
|
||||||
|
|
||||||
if size is not None:
|
if size is not None:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.size, size, msg or "got size %r, expected %r" % (im.size, size)
|
im.size,
|
||||||
|
size,
|
||||||
|
msg or "got size {!r}, expected {!r}".format(im.size, size),
|
||||||
)
|
)
|
||||||
|
|
||||||
def assert_image_equal(self, a, b, msg=None):
|
def assert_image_equal(self, a, b, msg=None):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
|
a.mode, b.mode, msg or "got mode {!r}, expected {!r}".format(a.mode, b.mode)
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
|
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
|
||||||
)
|
)
|
||||||
if a.tobytes() != b.tobytes():
|
if a.tobytes() != b.tobytes():
|
||||||
if HAS_UPLOADER:
|
if HAS_UPLOADER:
|
||||||
|
@ -121,10 +126,10 @@ class PillowTestCase(unittest.TestCase):
|
||||||
def assert_image_similar(self, a, b, epsilon, msg=None):
|
def assert_image_similar(self, a, b, epsilon, msg=None):
|
||||||
epsilon = float(epsilon)
|
epsilon = float(epsilon)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
|
a.mode, b.mode, msg or "got mode {!r}, expected {!r}".format(a.mode, b.mode)
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
|
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
|
||||||
)
|
)
|
||||||
|
|
||||||
a, b = convert_to_comparable(a, b)
|
a, b = convert_to_comparable(a, b)
|
||||||
|
@ -216,12 +221,12 @@ class PillowTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def open_withImagemagick(self, f):
|
def open_withImagemagick(self, f):
|
||||||
if not imagemagick_available():
|
if not imagemagick_available():
|
||||||
raise IOError()
|
raise OSError()
|
||||||
|
|
||||||
outfile = self.tempfile("temp.png")
|
outfile = self.tempfile("temp.png")
|
||||||
if command_succeeds([IMCONVERT, f, outfile]):
|
if command_succeeds([IMCONVERT, f, outfile]):
|
||||||
return Image.open(outfile)
|
return Image.open(outfile)
|
||||||
raise IOError()
|
raise OSError()
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
|
||||||
|
@ -264,11 +269,6 @@ class PillowLeakTestCase(PillowTestCase):
|
||||||
|
|
||||||
# helpers
|
# helpers
|
||||||
|
|
||||||
if not py3:
|
|
||||||
# Remove DeprecationWarning in Python 3
|
|
||||||
PillowTestCase.assertRaisesRegex = PillowTestCase.assertRaisesRegexp
|
|
||||||
PillowTestCase.assertRegex = PillowTestCase.assertRegexpMatches
|
|
||||||
|
|
||||||
|
|
||||||
def fromstring(data):
|
def fromstring(data):
|
||||||
return Image.open(BytesIO(data))
|
return Image.open(BytesIO(data))
|
||||||
|
@ -306,11 +306,10 @@ def command_succeeds(cmd):
|
||||||
Runs the command, which must be a list of strings. Returns True if the
|
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.
|
command succeeds, or False if an OSError was raised by subprocess.Popen.
|
||||||
"""
|
"""
|
||||||
with open(os.devnull, "wb") as f:
|
try:
|
||||||
try:
|
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||||
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)
|
except OSError:
|
||||||
except OSError:
|
return False
|
||||||
return False
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,7 +372,7 @@ def distro():
|
||||||
return line.strip().split("=")[1]
|
return line.strip().split("=")[1]
|
||||||
|
|
||||||
|
|
||||||
class cached_property(object):
|
class cached_property:
|
||||||
def __init__(self, func):
|
def __init__(self, func):
|
||||||
self.func = func
|
self.func = func
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
# brute-force search for access descriptor hash table
|
# brute-force search for access descriptor hash table
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
modes = [
|
modes = [
|
||||||
"1",
|
"1",
|
||||||
"L",
|
"L",
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
@ -109,4 +107,4 @@ class TestBmpReference(PillowTestCase):
|
||||||
os.path.join(base, "g", "pal4rle.bmp"),
|
os.path.join(base, "g", "pal4rle.bmp"),
|
||||||
)
|
)
|
||||||
if f not in unsupported:
|
if f not in unsupported:
|
||||||
self.fail("Unsupported Image %s: %s" % (f, msg))
|
self.fail("Unsupported Image {}: {}".format(f, msg))
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
from array import array
|
from array import array
|
||||||
|
|
||||||
from PIL import Image, ImageFilter
|
from PIL import Image, ImageFilter
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import division, print_function
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
|
||||||
from PIL import features
|
from PIL import features
|
||||||
|
|
|
@ -91,7 +91,7 @@ class TestFileEps(PillowTestCase):
|
||||||
def test_iobase_object(self):
|
def test_iobase_object(self):
|
||||||
# issue 479
|
# issue 479
|
||||||
with Image.open(file1) as image1:
|
with Image.open(file1) as image1:
|
||||||
with io.open(self.tempfile("temp_iobase.eps"), "wb") as fh:
|
with open(self.tempfile("temp_iobase.eps"), "wb") as fh:
|
||||||
image1.save(fh, "EPS")
|
image1.save(fh, "EPS")
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||||
|
|
|
@ -87,9 +87,7 @@ class TestFileGif(PillowTestCase):
|
||||||
def check(colors, size, expected_palette_length):
|
def check(colors, size, expected_palette_length):
|
||||||
# make an image with empty colors in the start of the palette range
|
# make an image with empty colors in the start of the palette range
|
||||||
im = Image.frombytes(
|
im = Image.frombytes(
|
||||||
"P",
|
"P", (colors, colors), bytes(range(256 - colors, 256)) * colors
|
||||||
(colors, colors),
|
|
||||||
bytes(bytearray(range(256 - colors, 256)) * colors),
|
|
||||||
)
|
)
|
||||||
im = im.resize((size, size))
|
im = im.resize((size, size))
|
||||||
outfile = BytesIO()
|
outfile = BytesIO()
|
||||||
|
@ -119,7 +117,7 @@ class TestFileGif(PillowTestCase):
|
||||||
check(256, 511, 256)
|
check(256, 511, 256)
|
||||||
|
|
||||||
def test_optimize_full_l(self):
|
def test_optimize_full_l(self):
|
||||||
im = Image.frombytes("L", (16, 16), bytes(bytearray(range(256))))
|
im = Image.frombytes("L", (16, 16), bytes(range(256)))
|
||||||
test_file = BytesIO()
|
test_file = BytesIO()
|
||||||
im.save(test_file, "GIF", optimize=True)
|
im.save(test_file, "GIF", optimize=True)
|
||||||
self.assertEqual(im.mode, "L")
|
self.assertEqual(im.mode, "L")
|
||||||
|
@ -632,8 +630,7 @@ class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
# Tests appending using a generator
|
# Tests appending using a generator
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
yield from ims
|
||||||
yield im
|
|
||||||
|
|
||||||
im.save(out, save_all=True, append_images=imGenerator(ims))
|
im.save(out, save_all=True, append_images=imGenerator(ims))
|
||||||
|
|
||||||
|
@ -655,7 +652,7 @@ class TestFileGif(PillowTestCase):
|
||||||
# that's > 128 items where the transparent color is actually
|
# that's > 128 items where the transparent color is actually
|
||||||
# the top palette entry to trigger the bug.
|
# the top palette entry to trigger the bug.
|
||||||
|
|
||||||
data = bytes(bytearray(range(1, 254)))
|
data = bytes(range(1, 254))
|
||||||
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||||
|
|
||||||
im = Image.new("L", (253, 1))
|
im = Image.new("L", (253, 1))
|
||||||
|
@ -703,7 +700,7 @@ class TestFileGif(PillowTestCase):
|
||||||
|
|
||||||
im = hopper("P")
|
im = hopper("P")
|
||||||
im_l = Image.frombytes("L", im.size, im.tobytes())
|
im_l = Image.frombytes("L", im.size, im.tobytes())
|
||||||
palette = bytes(bytearray(im.getpalette()))
|
palette = bytes(im.getpalette())
|
||||||
|
|
||||||
out = self.tempfile("temp.gif")
|
out = self.tempfile("temp.gif")
|
||||||
im_l.save(out, palette=palette)
|
im_l.save(out, palette=palette)
|
||||||
|
@ -718,7 +715,7 @@ class TestFileGif(PillowTestCase):
|
||||||
# Forcing a non-straight grayscale palette.
|
# Forcing a non-straight grayscale palette.
|
||||||
|
|
||||||
im = hopper("P")
|
im = hopper("P")
|
||||||
palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
|
palette = bytes([255 - i // 3 for i in range(768)])
|
||||||
|
|
||||||
out = self.tempfile("temp.gif")
|
out = self.tempfile("temp.gif")
|
||||||
im.save(out, palette=palette)
|
im.save(out, palette=palette)
|
||||||
|
@ -759,7 +756,7 @@ class TestFileGif(PillowTestCase):
|
||||||
im.putpalette(ImagePalette.ImagePalette("RGB"))
|
im.putpalette(ImagePalette.ImagePalette("RGB"))
|
||||||
im.info = {"background": 0}
|
im.info = {"background": 0}
|
||||||
|
|
||||||
passed_palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
|
passed_palette = bytes([255 - i // 3 for i in range(768)])
|
||||||
|
|
||||||
GifImagePlugin._FORCE_OPTIMIZE = True
|
GifImagePlugin._FORCE_OPTIMIZE = True
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import sys
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
from PIL import Image, IptcImagePlugin
|
from PIL import Image, IptcImagePlugin
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper
|
from .helper import PillowTestCase, hopper
|
||||||
|
@ -52,12 +55,6 @@ class TestFileIptc(PillowTestCase):
|
||||||
# Arrange
|
# Arrange
|
||||||
c = b"abc"
|
c = b"abc"
|
||||||
# Temporarily redirect stdout
|
# Temporarily redirect stdout
|
||||||
try:
|
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from io import StringIO
|
|
||||||
import sys
|
|
||||||
|
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
sys.stdout = mystdout = StringIO()
|
sys.stdout = mystdout = StringIO()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import distutils.version
|
import distutils.version
|
||||||
import io
|
import io
|
||||||
|
@ -10,7 +8,6 @@ from collections import namedtuple
|
||||||
from ctypes import c_float
|
from ctypes import c_float
|
||||||
|
|
||||||
from PIL import Image, TiffImagePlugin, TiffTags, features
|
from PIL import Image, TiffImagePlugin, TiffTags, features
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper
|
from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
@ -263,7 +260,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
tc(4.25, TiffTags.FLOAT, True),
|
tc(4.25, TiffTags.FLOAT, True),
|
||||||
tc(4.25, TiffTags.DOUBLE, True),
|
tc(4.25, TiffTags.DOUBLE, True),
|
||||||
tc("custom tag value", TiffTags.ASCII, True),
|
tc("custom tag value", TiffTags.ASCII, True),
|
||||||
tc(u"custom tag value", TiffTags.ASCII, True),
|
|
||||||
tc(b"custom tag value", TiffTags.BYTE, True),
|
tc(b"custom tag value", TiffTags.BYTE, True),
|
||||||
tc((4, 5, 6), TiffTags.SHORT, True),
|
tc((4, 5, 6), TiffTags.SHORT, True),
|
||||||
tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
|
tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
|
||||||
|
@ -361,12 +357,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
# Bytes are in image native order (little endian)
|
# Bytes are in image native order (little endian)
|
||||||
if py3:
|
self.assertEqual(b[0], ord(b"\xe0"))
|
||||||
self.assertEqual(b[0], ord(b"\xe0"))
|
self.assertEqual(b[1], ord(b"\x01"))
|
||||||
self.assertEqual(b[1], ord(b"\x01"))
|
|
||||||
else:
|
|
||||||
self.assertEqual(b[0], b"\xe0")
|
|
||||||
self.assertEqual(b[1], b"\x01")
|
|
||||||
|
|
||||||
out = self.tempfile("temp.tif")
|
out = self.tempfile("temp.tif")
|
||||||
# out = "temp.le.tif"
|
# out = "temp.le.tif"
|
||||||
|
@ -387,12 +379,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
|
|
||||||
# Bytes are in image native order (big endian)
|
# Bytes are in image native order (big endian)
|
||||||
if py3:
|
self.assertEqual(b[0], ord(b"\x01"))
|
||||||
self.assertEqual(b[0], ord(b"\x01"))
|
self.assertEqual(b[1], ord(b"\xe0"))
|
||||||
self.assertEqual(b[1], ord(b"\xe0"))
|
|
||||||
else:
|
|
||||||
self.assertEqual(b[0], b"\x01")
|
|
||||||
self.assertEqual(b[1], b"\xe0")
|
|
||||||
|
|
||||||
out = self.tempfile("temp.tif")
|
out = self.tempfile("temp.tif")
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
|
@ -99,8 +99,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
|
|
||||||
# Test appending using a generator
|
# Test appending using a generator
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
yield from ims
|
||||||
yield im
|
|
||||||
|
|
||||||
im.save(outfile, save_all=True, append_images=imGenerator(ims))
|
im.save(outfile, save_all=True, append_images=imGenerator(ims))
|
||||||
|
|
||||||
|
@ -163,13 +162,10 @@ class TestFilePdf(PillowTestCase):
|
||||||
|
|
||||||
def test_pdf_append_fails_on_nonexistent_file(self):
|
def test_pdf_append_fails_on_nonexistent_file(self):
|
||||||
im = hopper("RGB")
|
im = hopper("RGB")
|
||||||
temp_dir = tempfile.mkdtemp()
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
try:
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
|
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
|
||||||
)
|
)
|
||||||
finally:
|
|
||||||
os.rmdir(temp_dir)
|
|
||||||
|
|
||||||
def check_pdf_pages_consistency(self, pdf):
|
def check_pdf_pages_consistency(self, pdf):
|
||||||
pages_info = pdf.read_indirect(pdf.pages_ref)
|
pages_info = pdf.read_indirect(pdf.pages_ref)
|
||||||
|
@ -207,7 +203,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
# append some info
|
# append some info
|
||||||
pdf.info.Title = "abc"
|
pdf.info.Title = "abc"
|
||||||
pdf.info.Author = "def"
|
pdf.info.Author = "def"
|
||||||
pdf.info.Subject = u"ghi\uABCD"
|
pdf.info.Subject = "ghi\uABCD"
|
||||||
pdf.info.Keywords = "qw)e\\r(ty"
|
pdf.info.Keywords = "qw)e\\r(ty"
|
||||||
pdf.info.Creator = "hopper()"
|
pdf.info.Creator = "hopper()"
|
||||||
pdf.start_writing()
|
pdf.start_writing()
|
||||||
|
@ -235,7 +231,7 @@ class TestFilePdf(PillowTestCase):
|
||||||
self.assertEqual(pdf.info.Title, "abc")
|
self.assertEqual(pdf.info.Title, "abc")
|
||||||
self.assertEqual(pdf.info.Producer, "PdfParser")
|
self.assertEqual(pdf.info.Producer, "PdfParser")
|
||||||
self.assertEqual(pdf.info.Keywords, "qw)e\\r(ty")
|
self.assertEqual(pdf.info.Keywords, "qw)e\\r(ty")
|
||||||
self.assertEqual(pdf.info.Subject, u"ghi\uABCD")
|
self.assertEqual(pdf.info.Subject, "ghi\uABCD")
|
||||||
self.assertIn(b"CreationDate", pdf.info)
|
self.assertIn(b"CreationDate", pdf.info)
|
||||||
self.assertIn(b"ModDate", pdf.info)
|
self.assertIn(b"ModDate", pdf.info)
|
||||||
self.check_pdf_pages_consistency(pdf)
|
self.check_pdf_pages_consistency(pdf)
|
||||||
|
|
|
@ -2,7 +2,6 @@ import zlib
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from PIL import Image, ImageFile, PngImagePlugin
|
from PIL import Image, ImageFile, PngImagePlugin
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowLeakTestCase, PillowTestCase, hopper, is_win32, unittest
|
from .helper import PillowLeakTestCase, PillowTestCase, hopper, is_win32, unittest
|
||||||
|
|
||||||
|
@ -448,9 +447,7 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assertIsInstance(im.info["Text"], str)
|
self.assertIsInstance(im.info["Text"], str)
|
||||||
|
|
||||||
def test_unicode_text(self):
|
def test_unicode_text(self):
|
||||||
# Check preservation of non-ASCII characters on Python 3
|
# Check preservation of non-ASCII characters
|
||||||
# This cannot really be meaningfully tested on Python 2,
|
|
||||||
# since it didn't preserve charsets to begin with.
|
|
||||||
|
|
||||||
def rt_text(value):
|
def rt_text(value):
|
||||||
im = Image.new("RGB", (32, 32))
|
im = Image.new("RGB", (32, 32))
|
||||||
|
@ -459,17 +456,11 @@ class TestFilePng(PillowTestCase):
|
||||||
im = roundtrip(im, pnginfo=info)
|
im = roundtrip(im, pnginfo=info)
|
||||||
self.assertEqual(im.info, {"Text": value})
|
self.assertEqual(im.info, {"Text": value})
|
||||||
|
|
||||||
if py3:
|
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
|
||||||
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
|
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
|
||||||
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
|
# CJK:
|
||||||
rt_text(
|
rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
|
||||||
chr(0x4E00)
|
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
|
||||||
+ chr(0x66F0)
|
|
||||||
+ chr(0x9FBA) # CJK
|
|
||||||
+ chr(0x3042)
|
|
||||||
+ chr(0xAC00)
|
|
||||||
)
|
|
||||||
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
|
|
||||||
|
|
||||||
def test_scary(self):
|
def test_scary(self):
|
||||||
# Check reading of evil PNG file. For information, see:
|
# Check reading of evil PNG file. For information, see:
|
||||||
|
|
|
@ -4,7 +4,6 @@ from io import BytesIO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from PIL import Image, TiffImagePlugin
|
from PIL import Image, TiffImagePlugin
|
||||||
from PIL._util import py3
|
|
||||||
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
|
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper, is_pypy, is_win32, unittest
|
from .helper import PillowTestCase, hopper, is_pypy, is_win32, unittest
|
||||||
|
@ -198,12 +197,8 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
# Bytes are in image native order (little endian)
|
# Bytes are in image native order (little endian)
|
||||||
if py3:
|
self.assertEqual(b[0], ord(b"\xe0"))
|
||||||
self.assertEqual(b[0], ord(b"\xe0"))
|
self.assertEqual(b[1], ord(b"\x01"))
|
||||||
self.assertEqual(b[1], ord(b"\x01"))
|
|
||||||
else:
|
|
||||||
self.assertEqual(b[0], b"\xe0")
|
|
||||||
self.assertEqual(b[1], b"\x01")
|
|
||||||
|
|
||||||
def test_big_endian(self):
|
def test_big_endian(self):
|
||||||
im = Image.open("Tests/images/16bit.MM.cropped.tif")
|
im = Image.open("Tests/images/16bit.MM.cropped.tif")
|
||||||
|
@ -213,12 +208,8 @@ class TestFileTiff(PillowTestCase):
|
||||||
b = im.tobytes()
|
b = im.tobytes()
|
||||||
|
|
||||||
# Bytes are in image native order (big endian)
|
# Bytes are in image native order (big endian)
|
||||||
if py3:
|
self.assertEqual(b[0], ord(b"\x01"))
|
||||||
self.assertEqual(b[0], ord(b"\x01"))
|
self.assertEqual(b[1], ord(b"\xe0"))
|
||||||
self.assertEqual(b[1], ord(b"\xe0"))
|
|
||||||
else:
|
|
||||||
self.assertEqual(b[0], b"\x01")
|
|
||||||
self.assertEqual(b[1], b"\xe0")
|
|
||||||
|
|
||||||
def test_16bit_s(self):
|
def test_16bit_s(self):
|
||||||
im = Image.open("Tests/images/16bit.s.tif")
|
im = Image.open("Tests/images/16bit.s.tif")
|
||||||
|
@ -545,8 +536,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
|
|
||||||
# Test appending using a generator
|
# Test appending using a generator
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
yield from ims
|
||||||
yield im
|
|
||||||
|
|
||||||
mp = BytesIO()
|
mp = BytesIO()
|
||||||
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
|
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
|
||||||
|
|
|
@ -161,13 +161,13 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
self.assert_deep_equal(
|
self.assert_deep_equal(
|
||||||
original[tag],
|
original[tag],
|
||||||
value,
|
value,
|
||||||
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
|
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
original[tag],
|
original[tag],
|
||||||
value,
|
value,
|
||||||
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
|
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
|
||||||
)
|
)
|
||||||
|
|
||||||
for tag, value in original.items():
|
for tag, value in original.items():
|
||||||
|
|
|
@ -91,8 +91,7 @@ class TestFileWebpAnimation(PillowTestCase):
|
||||||
|
|
||||||
# Tests appending using a generator
|
# Tests appending using a generator
|
||||||
def imGenerator(ims):
|
def imGenerator(ims):
|
||||||
for im in ims:
|
yield from ims
|
||||||
yield im
|
|
||||||
|
|
||||||
temp_file2 = self.tempfile("temp_generator.webp")
|
temp_file2 = self.tempfile("temp_generator.webp")
|
||||||
frame1.copy().save(
|
frame1.copy().save(
|
||||||
|
|
|
@ -110,9 +110,9 @@ class TestFileWebpMetadata(PillowTestCase):
|
||||||
if not _webp.HAVE_WEBPANIM:
|
if not _webp.HAVE_WEBPANIM:
|
||||||
self.skipTest("WebP animation support not available")
|
self.skipTest("WebP animation support not available")
|
||||||
|
|
||||||
iccp_data = "<iccp_data>".encode("utf-8")
|
iccp_data = b"<iccp_data>"
|
||||||
exif_data = "<exif_data>".encode("utf-8")
|
exif_data = b"<exif_data>"
|
||||||
xmp_data = "<xmp_data>".encode("utf-8")
|
xmp_data = b"<xmp_data>"
|
||||||
|
|
||||||
temp_file = self.tempfile("temp.webp")
|
temp_file = self.tempfile("temp.webp")
|
||||||
frame1 = Image.open("Tests/images/anim_frame1.webp")
|
frame1 = Image.open("Tests/images/anim_frame1.webp")
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
from PIL import Image, ImageDraw, ImageFont, features
|
from PIL import Image, ImageDraw, ImageFont, features
|
||||||
|
|
||||||
from .helper import PillowLeakTestCase, is_win32, unittest
|
from .helper import PillowLeakTestCase, is_win32, unittest
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile
|
from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
from .helper import PillowTestCase
|
||||||
|
|
||||||
|
@ -74,6 +73,5 @@ class TestFontPcf(PillowTestCase):
|
||||||
def test_high_characters(self):
|
def test_high_characters(self):
|
||||||
message = "".join(chr(i + 1) for i in range(140, 232))
|
message = "".join(chr(i + 1) for i in range(140, 232))
|
||||||
self._test_high_characters(message)
|
self._test_high_characters(message)
|
||||||
# accept bytes instances in Py3.
|
# accept bytes instances.
|
||||||
if py3:
|
self._test_high_characters(message.encode("latin1"))
|
||||||
self._test_high_characters(message.encode("latin1"))
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import colorsys
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper
|
from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
@ -49,27 +48,18 @@ class TestFormatHSV(PillowTestCase):
|
||||||
|
|
||||||
(r, g, b) = im.split()
|
(r, g, b) = im.split()
|
||||||
|
|
||||||
if py3:
|
conv_func = self.int_to_float
|
||||||
conv_func = self.int_to_float
|
|
||||||
else:
|
|
||||||
conv_func = self.str_to_float
|
|
||||||
|
|
||||||
if hasattr(itertools, "izip"):
|
|
||||||
iter_helper = itertools.izip
|
|
||||||
else:
|
|
||||||
iter_helper = itertools.zip_longest
|
|
||||||
|
|
||||||
converted = [
|
converted = [
|
||||||
self.tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
|
self.tuple_to_ints(func(conv_func(_r), conv_func(_g), conv_func(_b)))
|
||||||
for (_r, _g, _b) in iter_helper(r.tobytes(), g.tobytes(), b.tobytes())
|
for (_r, _g, _b) in itertools.zip_longest(
|
||||||
|
r.tobytes(), g.tobytes(), b.tobytes()
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
if py3:
|
new_bytes = b"".join(
|
||||||
new_bytes = b"".join(
|
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
|
||||||
bytes(chr(h) + chr(s) + chr(v), "latin-1") for (h, s, v) in converted
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
new_bytes = b"".join(chr(h) + chr(s) + chr(v) for (h, s, v) in converted)
|
|
||||||
|
|
||||||
hsv = Image.frombytes(mode, r.size, new_bytes)
|
hsv = Image.frombytes(mode, r.size, new_bytes)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from PIL import Image, UnidentifiedImageError
|
from PIL import Image, UnidentifiedImageError
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper, is_win32, unittest
|
from .helper import PillowTestCase, hopper, is_win32, unittest
|
||||||
|
|
||||||
|
@ -83,20 +82,14 @@ class TestImage(PillowTestCase):
|
||||||
im.size = (3, 4)
|
im.size = (3, 4)
|
||||||
|
|
||||||
def test_invalid_image(self):
|
def test_invalid_image(self):
|
||||||
if py3:
|
import io
|
||||||
import io
|
|
||||||
|
|
||||||
im = io.BytesIO(b"")
|
im = io.BytesIO(b"")
|
||||||
else:
|
|
||||||
import StringIO
|
|
||||||
|
|
||||||
im = StringIO.StringIO("")
|
|
||||||
self.assertRaises(UnidentifiedImageError, Image.open, im)
|
self.assertRaises(UnidentifiedImageError, Image.open, im)
|
||||||
|
|
||||||
def test_bad_mode(self):
|
def test_bad_mode(self):
|
||||||
self.assertRaises(ValueError, Image.open, "filename", "bad mode")
|
self.assertRaises(ValueError, Image.open, "filename", "bad mode")
|
||||||
|
|
||||||
@unittest.skipUnless(Image.HAS_PATHLIB, "requires pathlib/pathlib2")
|
|
||||||
def test_pathlib(self):
|
def test_pathlib(self):
|
||||||
from PIL.Image import Path
|
from PIL.Image import Path
|
||||||
|
|
||||||
|
@ -116,7 +109,7 @@ class TestImage(PillowTestCase):
|
||||||
def test_fp_name(self):
|
def test_fp_name(self):
|
||||||
temp_file = self.tempfile("temp.jpg")
|
temp_file = self.tempfile("temp.jpg")
|
||||||
|
|
||||||
class FP(object):
|
class FP:
|
||||||
def write(a, b):
|
def write(a, b):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -595,11 +588,11 @@ class TestImage(PillowTestCase):
|
||||||
try:
|
try:
|
||||||
im.load()
|
im.load()
|
||||||
self.assertFail()
|
self.assertFail()
|
||||||
except IOError as e:
|
except OSError as e:
|
||||||
self.assertEqual(str(e), "buffer overrun when reading image file")
|
self.assertEqual(str(e), "buffer overrun when reading image file")
|
||||||
|
|
||||||
|
|
||||||
class MockEncoder(object):
|
class MockEncoder:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ class TestImageGetPixel(AccessTest):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.getpixel((0, 0)),
|
im.getpixel((0, 0)),
|
||||||
c,
|
c,
|
||||||
"put/getpixel roundtrip failed for mode %s, color %s" % (mode, c),
|
"put/getpixel roundtrip failed for mode {}, color {}".format(mode, c),
|
||||||
)
|
)
|
||||||
|
|
||||||
# check putpixel negative index
|
# check putpixel negative index
|
||||||
|
@ -154,7 +154,7 @@ class TestImageGetPixel(AccessTest):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
im.getpixel((0, 0)),
|
im.getpixel((0, 0)),
|
||||||
c,
|
c,
|
||||||
"initial color failed for mode %s, color %s " % (mode, c),
|
"initial color failed for mode {}, color {} ".format(mode, c),
|
||||||
)
|
)
|
||||||
# check initial color negative index
|
# check initial color negative index
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -348,12 +348,8 @@ class TestEmbeddable(unittest.TestCase):
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
char *home = "%s";
|
char *home = "%s";
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
wchar_t *whome = Py_DecodeLocale(home, NULL);
|
wchar_t *whome = Py_DecodeLocale(home, NULL);
|
||||||
Py_SetPythonHome(whome);
|
Py_SetPythonHome(whome);
|
||||||
#else
|
|
||||||
Py_SetPythonHome(home);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Py_InitializeEx(0);
|
Py_InitializeEx(0);
|
||||||
Py_DECREF(PyImport_ImportModule("PIL.Image"));
|
Py_DECREF(PyImport_ImportModule("PIL.Image"));
|
||||||
|
@ -363,9 +359,7 @@ int main(int argc, char* argv[])
|
||||||
Py_DECREF(PyImport_ImportModule("PIL.Image"));
|
Py_DECREF(PyImport_ImportModule("PIL.Image"));
|
||||||
Py_Finalize();
|
Py_Finalize();
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyMem_RawFree(whome);
|
PyMem_RawFree(whome);
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ class TestImageArray(PillowTestCase):
|
||||||
self.assertEqual(test("RGBX"), (3, (100, 128, 4), "|u1", 51200))
|
self.assertEqual(test("RGBX"), (3, (100, 128, 4), "|u1", 51200))
|
||||||
|
|
||||||
def test_fromarray(self):
|
def test_fromarray(self):
|
||||||
class Wrapper(object):
|
class Wrapper:
|
||||||
""" Class with API matching Image.fromarray """
|
""" Class with API matching Image.fromarray """
|
||||||
|
|
||||||
def __init__(self, img, arr_params):
|
def __init__(self, img, arr_params):
|
||||||
|
|
|
@ -6,7 +6,7 @@ from .test_imageqt import PillowQtTestCase
|
||||||
|
|
||||||
class TestFromQImage(PillowQtTestCase, PillowTestCase):
|
class TestFromQImage(PillowQtTestCase, PillowTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestFromQImage, self).setUp()
|
super().setUp()
|
||||||
self.files_to_test = [
|
self.files_to_test = [
|
||||||
hopper(),
|
hopper(),
|
||||||
Image.open("Tests/images/transparent.png"),
|
Image.open("Tests/images/transparent.png"),
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper
|
from .helper import PillowTestCase, hopper
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +6,5 @@ class TestImageGetIm(PillowTestCase):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
type_repr = repr(type(im.getim()))
|
type_repr = repr(type(im.getim()))
|
||||||
|
|
||||||
if py3:
|
self.assertIn("PyCapsule", type_repr)
|
||||||
self.assertIn("PyCapsule", type_repr)
|
|
||||||
|
|
||||||
self.assertIsInstance(im.im.id, int)
|
self.assertIsInstance(im.im.id, int)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import division, print_function
|
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
|
|
|
@ -35,7 +35,7 @@ class TestImageEnhance(PillowTestCase):
|
||||||
self.assert_image_equal(
|
self.assert_image_equal(
|
||||||
im.getchannel("A"),
|
im.getchannel("A"),
|
||||||
original.getchannel("A"),
|
original.getchannel("A"),
|
||||||
"Diff on %s: %s" % (op, amount),
|
"Diff on {}: {}".format(op, amount),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_alpha(self):
|
def test_alpha(self):
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import copy
|
import copy
|
||||||
import distutils.version
|
import distutils.version
|
||||||
import os
|
import os
|
||||||
|
@ -20,7 +19,7 @@ HAS_FREETYPE = features.check("freetype2")
|
||||||
HAS_RAQM = features.check("raqm")
|
HAS_RAQM = features.check("raqm")
|
||||||
|
|
||||||
|
|
||||||
class SimplePatcher(object):
|
class SimplePatcher:
|
||||||
def __init__(self, parent_obj, attr_name, value):
|
def __init__(self, parent_obj, attr_name, value):
|
||||||
self._parent_obj = parent_obj
|
self._parent_obj = parent_obj
|
||||||
self._attr_name = attr_name
|
self._attr_name = attr_name
|
||||||
|
@ -462,12 +461,12 @@ class TestImageFont(PillowTestCase):
|
||||||
# issue #2826
|
# issue #2826
|
||||||
font = ImageFont.load_default()
|
font = ImageFont.load_default()
|
||||||
with self.assertRaises(UnicodeEncodeError):
|
with self.assertRaises(UnicodeEncodeError):
|
||||||
font.getsize(u"’")
|
font.getsize("’")
|
||||||
|
|
||||||
@unittest.skipIf(sys.version.startswith("2") or is_pypy(), "requires CPython 3.3+")
|
@unittest.skipIf(is_pypy(), "requires CPython")
|
||||||
def test_unicode_extended(self):
|
def test_unicode_extended(self):
|
||||||
# issue #3777
|
# issue #3777
|
||||||
text = u"A\u278A\U0001F12B"
|
text = "A\u278A\U0001F12B"
|
||||||
target = "Tests/images/unicode_extended.png"
|
target = "Tests/images/unicode_extended.png"
|
||||||
|
|
||||||
ttf = ImageFont.truetype(
|
ttf = ImageFont.truetype(
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from PIL import Image, ImageDraw, ImageFont, features
|
from PIL import Image, ImageDraw, ImageFont, features
|
||||||
|
|
||||||
from .helper import PillowTestCase, unittest
|
from .helper import PillowTestCase, unittest
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from PIL import Image, ImageMath
|
from PIL import Image, ImageMath
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
from .helper import PillowTestCase
|
||||||
|
@ -7,7 +5,7 @@ from .helper import PillowTestCase
|
||||||
|
|
||||||
def pixel(im):
|
def pixel(im):
|
||||||
if hasattr(im, "im"):
|
if hasattr(im, "im"):
|
||||||
return "%s %r" % (im.mode, im.getpixel((0, 0)))
|
return "{} {!r}".format(im.mode, im.getpixel((0, 0)))
|
||||||
else:
|
else:
|
||||||
if isinstance(im, int):
|
if isinstance(im, int):
|
||||||
return int(im) # hack to deal with booleans
|
return int(im) # hack to deal with booleans
|
||||||
|
|
|
@ -11,7 +11,7 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
class TestImageOps(PillowTestCase):
|
class TestImageOps(PillowTestCase):
|
||||||
class Deformer(object):
|
class Deformer:
|
||||||
def getmesh(self, im):
|
def getmesh(self, im):
|
||||||
x, y = im.size
|
x, y = im.size
|
||||||
return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))]
|
return [((0, 0, x, y), (0, 0, x, 0, x, y, y, 0))]
|
||||||
|
|
|
@ -5,7 +5,7 @@ from .helper import PillowTestCase
|
||||||
|
|
||||||
class TestImageOpsUsm(PillowTestCase):
|
class TestImageOpsUsm(PillowTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestImageOpsUsm, self).setUp()
|
super().setUp()
|
||||||
self.im = Image.open("Tests/images/hopper.ppm")
|
self.im = Image.open("Tests/images/hopper.ppm")
|
||||||
self.addCleanup(self.im.close)
|
self.addCleanup(self.im.close)
|
||||||
self.snakes = Image.open("Tests/images/color_snakes.png")
|
self.snakes = Image.open("Tests/images/color_snakes.png")
|
||||||
|
|
|
@ -2,7 +2,6 @@ import array
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from PIL import Image, ImagePath
|
from PIL import Image, ImagePath
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase
|
from .helper import PillowTestCase
|
||||||
|
|
||||||
|
@ -75,10 +74,7 @@ class TestImagePath(PillowTestCase):
|
||||||
# This fails due to the invalid malloc above,
|
# This fails due to the invalid malloc above,
|
||||||
# and segfaults
|
# and segfaults
|
||||||
for i in range(200000):
|
for i in range(200000):
|
||||||
if py3:
|
x[i] = b"0" * 16
|
||||||
x[i] = b"0" * 16
|
|
||||||
else:
|
|
||||||
x[i] = "0" * 16
|
|
||||||
|
|
||||||
|
|
||||||
class evil:
|
class evil:
|
||||||
|
|
|
@ -15,7 +15,7 @@ else:
|
||||||
test_case.skipTest("Qt bindings are not installed")
|
test_case.skipTest("Qt bindings are not installed")
|
||||||
|
|
||||||
|
|
||||||
class PillowQtTestCase(object):
|
class PillowQtTestCase:
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
skip_if_qt_is_not_installed(self)
|
skip_if_qt_is_not_installed(self)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL._util import py3
|
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper, unittest
|
from .helper import PillowTestCase, hopper, unittest
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import ImageTk
|
from PIL import ImageTk
|
||||||
|
|
||||||
if py3:
|
import tkinter as tk
|
||||||
import tkinter as tk
|
|
||||||
else:
|
|
||||||
import Tkinter as tk
|
|
||||||
dir(ImageTk)
|
dir(ImageTk)
|
||||||
HAS_TK = True
|
HAS_TK = True
|
||||||
except (OSError, ImportError):
|
except (OSError, ImportError):
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TestLibPack(PillowTestCase):
|
||||||
|
|
||||||
if isinstance(data, int):
|
if isinstance(data, int):
|
||||||
data_len = data * len(pixels)
|
data_len = data * len(pixels)
|
||||||
data = bytes(bytearray(range(1, data_len + 1)))
|
data = bytes(range(1, data_len + 1))
|
||||||
|
|
||||||
self.assertEqual(data, im.tobytes("raw", rawmode))
|
self.assertEqual(data, im.tobytes("raw", rawmode))
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ class TestLibUnpack(PillowTestCase):
|
||||||
"""
|
"""
|
||||||
if isinstance(data, int):
|
if isinstance(data, int):
|
||||||
data_len = data * len(pixels)
|
data_len = data * len(pixels)
|
||||||
data = bytes(bytearray(range(1, data_len + 1)))
|
data = bytes(range(1, data_len + 1))
|
||||||
|
|
||||||
im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1)
|
im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -20,7 +20,11 @@ class TestModeI16(PillowTestCase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
p1,
|
p1,
|
||||||
p2,
|
p2,
|
||||||
("got %r from mode %s at %s, expected %r" % (p1, im1.mode, xy, p2)),
|
(
|
||||||
|
"got {!r} from mode {} at {}, expected {!r}".format(
|
||||||
|
p1, im1.mode, xy, p2
|
||||||
|
)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import PillowTestCase, hopper, unittest
|
from .helper import PillowTestCase, hopper, unittest
|
||||||
|
|
|
@ -22,7 +22,7 @@ class TestPdfParser(PillowTestCase):
|
||||||
self.assertEqual(encode_text("abc"), b"\xFE\xFF\x00a\x00b\x00c")
|
self.assertEqual(encode_text("abc"), b"\xFE\xFF\x00a\x00b\x00c")
|
||||||
self.assertEqual(decode_text(b"\xFE\xFF\x00a\x00b\x00c"), "abc")
|
self.assertEqual(decode_text(b"\xFE\xFF\x00a\x00b\x00c"), "abc")
|
||||||
self.assertEqual(decode_text(b"abc"), "abc")
|
self.assertEqual(decode_text(b"abc"), "abc")
|
||||||
self.assertEqual(decode_text(b"\x1B a \x1C"), u"\u02D9 a \u02DD")
|
self.assertEqual(decode_text(b"\x1B a \x1C"), "\u02D9 a \u02DD")
|
||||||
|
|
||||||
def test_indirect_refs(self):
|
def test_indirect_refs(self):
|
||||||
self.assertEqual(IndirectReference(1, 2), IndirectReference(1, 2))
|
self.assertEqual(IndirectReference(1, 2), IndirectReference(1, 2))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
from PIL import Image, PSDraw
|
from PIL import Image, PSDraw
|
||||||
|
|
||||||
|
@ -47,10 +48,6 @@ class TestPsDraw(PillowTestCase):
|
||||||
|
|
||||||
def test_stdout(self):
|
def test_stdout(self):
|
||||||
# Temporarily redirect stdout
|
# Temporarily redirect stdout
|
||||||
try:
|
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from io import StringIO
|
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
sys.stdout = mystdout = StringIO()
|
sys.stdout = mystdout = StringIO()
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ if ImageQt.qt_is_installed:
|
||||||
|
|
||||||
class Example(QWidget):
|
class Example(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Example, self).__init__()
|
super().__init__()
|
||||||
|
|
||||||
img = hopper().resize((1000, 1000))
|
img = hopper().resize((1000, 1000))
|
||||||
|
|
||||||
|
|
|
@ -4,26 +4,6 @@ from .helper import PillowTestCase, unittest
|
||||||
|
|
||||||
|
|
||||||
class TestUtil(PillowTestCase):
|
class TestUtil(PillowTestCase):
|
||||||
def test_is_string_type(self):
|
|
||||||
# Arrange
|
|
||||||
color = "red"
|
|
||||||
|
|
||||||
# Act
|
|
||||||
it_is = _util.isStringType(color)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertTrue(it_is)
|
|
||||||
|
|
||||||
def test_is_not_string_type(self):
|
|
||||||
# Arrange
|
|
||||||
color = (255, 0, 0)
|
|
||||||
|
|
||||||
# Act
|
|
||||||
it_is_not = _util.isStringType(color)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
self.assertFalse(it_is_not)
|
|
||||||
|
|
||||||
def test_is_path(self):
|
def test_is_path(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
fp = "filename.ext"
|
fp = "filename.ext"
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import queue
|
import queue
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
# This is a sample Dockerfile to build Pillow on Alpine Linux
|
|
||||||
# with all/most of the dependencies working.
|
|
||||||
#
|
|
||||||
# Tcl/Tk isn't detecting
|
|
||||||
# Freetype has different metrics so tests are failing.
|
|
||||||
# sudo and bash are required for the webp build script.
|
|
||||||
|
|
||||||
FROM alpine
|
|
||||||
USER root
|
|
||||||
|
|
||||||
RUN apk --no-cache add python \
|
|
||||||
build-base \
|
|
||||||
python-dev \
|
|
||||||
py-pip \
|
|
||||||
# Pillow dependencies
|
|
||||||
jpeg-dev \
|
|
||||||
zlib-dev \
|
|
||||||
freetype-dev \
|
|
||||||
lcms2-dev \
|
|
||||||
openjpeg-dev \
|
|
||||||
tiff-dev \
|
|
||||||
tk-dev \
|
|
||||||
tcl-dev
|
|
||||||
|
|
||||||
# install from pip, without webp
|
|
||||||
#RUN LIBRARY_PATH=/lib:/usr/lib /bin/sh -c "pip install Pillow"
|
|
||||||
|
|
||||||
# install from git, run tests, including webp
|
|
||||||
RUN apk --no-cache add git \
|
|
||||||
bash \
|
|
||||||
sudo
|
|
||||||
|
|
||||||
RUN git clone https://github.com/python-pillow/Pillow.git /Pillow
|
|
||||||
RUN pip install virtualenv && virtualenv /vpy && source /vpy/bin/activate && pip install nose
|
|
||||||
|
|
||||||
RUN echo "#!/bin/bash" >> /test && \
|
|
||||||
echo "source /vpy/bin/activate && cd /Pillow " >> test && \
|
|
||||||
echo "pushd depends && ./install_webp.sh && ./install_imagequant.sh && popd" >> test && \
|
|
||||||
echo "LIBRARY_PATH=/lib:/usr/lib make install && make test" >> test
|
|
||||||
|
|
||||||
RUN chmod +x /test
|
|
||||||
|
|
||||||
CMD ["/test"]
|
|
|
@ -1,18 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installs all of the dependencies for Pillow for Debian 8.2
|
|
||||||
# for both system Pythons 2.7 and 3.4
|
|
||||||
#
|
|
||||||
# Also works for Raspbian Jessie
|
|
||||||
#
|
|
||||||
|
|
||||||
sudo apt-get -y install python-dev python-setuptools \
|
|
||||||
python3-dev python-virtualenv cmake
|
|
||||||
sudo apt-get -y install libtiff5-dev libjpeg62-turbo-dev zlib1g-dev \
|
|
||||||
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev \
|
|
||||||
python-tk python3-tk libharfbuzz-dev libfribidi-dev
|
|
||||||
|
|
||||||
./install_openjpeg.sh
|
|
||||||
./install_imagequant.sh
|
|
||||||
./install_raqm.sh
|
|
|
@ -1,18 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installs all of the dependencies for Pillow for Fedora 23
|
|
||||||
# for both system Pythons 2.7 and 3.4
|
|
||||||
#
|
|
||||||
# note that Fedora does ship packages for Pillow as python-pillow
|
|
||||||
|
|
||||||
# this is a workaround for
|
|
||||||
# "gcc: error: /usr/lib/rpm/redhat/redhat-hardened-cc1: No such file or directory"
|
|
||||||
# errors when compiling.
|
|
||||||
sudo dnf install redhat-rpm-config
|
|
||||||
|
|
||||||
sudo dnf install python-devel python3-devel python-virtualenv make gcc
|
|
||||||
|
|
||||||
sudo dnf install libtiff-devel libjpeg-devel zlib-devel freetype-devel \
|
|
||||||
lcms2-devel libwebp-devel openjpeg2-devel tkinter python3-tkinter \
|
|
||||||
tcl-devel tk-devel harfbuzz-devel fribidi-devel libraqm-devel
|
|
|
@ -1,13 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installs all of the dependencies for Pillow for Freebsd 10.x
|
|
||||||
# for both system Pythons 2.7 and 3.4
|
|
||||||
#
|
|
||||||
sudo pkg install python2 python3 py27-pip py27-virtualenv wget cmake
|
|
||||||
|
|
||||||
# Openjpeg fails badly using the openjpeg package.
|
|
||||||
# I can't find a python3.4 version of tkinter
|
|
||||||
sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 harfbuzz fribidi py27-tkinter
|
|
||||||
|
|
||||||
./install_raqm_cmake.sh
|
|
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installs all of the dependencies for Pillow for Ubuntu 12.04
|
|
||||||
# for both system Pythons 2.7 and 3.2
|
|
||||||
#
|
|
||||||
|
|
||||||
sudo apt-get -y install python-dev python-setuptools \
|
|
||||||
python3-dev python-virtualenv cmake
|
|
||||||
sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev \
|
|
||||||
libfreetype6-dev liblcms2-dev tcl8.5-dev \
|
|
||||||
tk8.5-dev python-tk python3-tk
|
|
||||||
|
|
||||||
|
|
||||||
./install_openjpeg.sh
|
|
||||||
./install_webp.sh
|
|
||||||
./install_imagequant.sh
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installs all of the dependencies for Pillow for Ubuntu 14.04
|
|
||||||
# for both system Pythons 2.7 and 3.4
|
|
||||||
#
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y install python-dev python-setuptools \
|
|
||||||
python3-dev python-virtualenv cmake
|
|
||||||
sudo apt-get -y install libtiff5-dev libjpeg8-dev zlib1g-dev \
|
|
||||||
libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev \
|
|
||||||
python-tk python3-tk libharfbuzz-dev libfribidi-dev
|
|
||||||
|
|
||||||
./install_openjpeg.sh
|
|
||||||
./install_imagequant.sh
|
|
||||||
./install_raqm.sh
|
|
15
docs/conf.py
15
docs/conf.py
|
@ -1,4 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# Pillow (PIL Fork) documentation build configuration file, created by
|
# Pillow (PIL Fork) documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Sat Apr 4 07:54:11 2015.
|
# sphinx-quickstart on Sat Apr 4 07:54:11 2015.
|
||||||
|
@ -42,9 +41,9 @@ source_suffix = ".rst"
|
||||||
master_doc = "index"
|
master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u"Pillow (PIL Fork)"
|
project = "Pillow (PIL Fork)"
|
||||||
copyright = u"1995-2011 Fredrik Lundh, 2010-2019 Alex Clark and Contributors"
|
copyright = "1995-2011 Fredrik Lundh, 2010-2019 Alex Clark and Contributors"
|
||||||
author = u"Fredrik Lundh, Alex Clark and Contributors"
|
author = "Fredrik Lundh, Alex Clark and Contributors"
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
@ -220,8 +219,8 @@ latex_documents = [
|
||||||
(
|
(
|
||||||
master_doc,
|
master_doc,
|
||||||
"PillowPILFork.tex",
|
"PillowPILFork.tex",
|
||||||
u"Pillow (PIL Fork) Documentation",
|
"Pillow (PIL Fork) Documentation",
|
||||||
u"Alex Clark",
|
"Alex Clark",
|
||||||
"manual",
|
"manual",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
@ -252,7 +251,7 @@ latex_documents = [
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
(master_doc, "pillowpilfork", u"Pillow (PIL Fork) Documentation", [author], 1)
|
(master_doc, "pillowpilfork", "Pillow (PIL Fork) Documentation", [author], 1)
|
||||||
]
|
]
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
|
@ -268,7 +267,7 @@ texinfo_documents = [
|
||||||
(
|
(
|
||||||
master_doc,
|
master_doc,
|
||||||
"PillowPILFork",
|
"PillowPILFork",
|
||||||
u"Pillow (PIL Fork) Documentation",
|
"Pillow (PIL Fork) Documentation",
|
||||||
author,
|
author,
|
||||||
"PillowPILFork",
|
"PillowPILFork",
|
||||||
"Pillow is the friendly PIL fork by Alex Clark and Contributors.",
|
"Pillow is the friendly PIL fork by Alex Clark and Contributors.",
|
||||||
|
|
|
@ -212,10 +212,10 @@ class DdsImageFile(ImageFile.ImageFile):
|
||||||
def _open(self):
|
def _open(self):
|
||||||
magic, header_size = struct.unpack("<II", self.fp.read(8))
|
magic, header_size = struct.unpack("<II", self.fp.read(8))
|
||||||
if header_size != 124:
|
if header_size != 124:
|
||||||
raise IOError("Unsupported header size %r" % (header_size))
|
raise OSError("Unsupported header size %r" % (header_size))
|
||||||
header_bytes = self.fp.read(header_size - 4)
|
header_bytes = self.fp.read(header_size - 4)
|
||||||
if len(header_bytes) != 120:
|
if len(header_bytes) != 120:
|
||||||
raise IOError("Incomplete header: %s bytes" % len(header_bytes))
|
raise OSError("Incomplete header: %s bytes" % len(header_bytes))
|
||||||
header = BytesIO(header_bytes)
|
header = BytesIO(header_bytes)
|
||||||
|
|
||||||
flags, height, width = struct.unpack("<3I", header.read(12))
|
flags, height, width = struct.unpack("<3I", header.read(12))
|
||||||
|
@ -250,7 +250,7 @@ class DXT1Decoder(ImageFile.PyDecoder):
|
||||||
try:
|
try:
|
||||||
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
||||||
except struct.error:
|
except struct.error:
|
||||||
raise IOError("Truncated DDS file")
|
raise OSError("Truncated DDS file")
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ class DXT5Decoder(ImageFile.PyDecoder):
|
||||||
try:
|
try:
|
||||||
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
||||||
except struct.error:
|
except struct.error:
|
||||||
raise IOError("Truncated DDS file")
|
raise OSError("Truncated DDS file")
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ in the :py:mod:`~PIL.Image` module::
|
||||||
If successful, this function returns an :py:class:`~PIL.Image.Image` object.
|
If successful, this function returns an :py:class:`~PIL.Image.Image` object.
|
||||||
You can now use instance attributes to examine the file contents::
|
You can now use instance attributes to examine the file contents::
|
||||||
|
|
||||||
>>> from __future__ import print_function
|
|
||||||
>>> print(im.format, im.size, im.mode)
|
>>> print(im.format, im.size, im.mode)
|
||||||
PPM (512, 512) RGB
|
PPM (512, 512) RGB
|
||||||
|
|
||||||
|
@ -67,7 +66,6 @@ Convert files to JPEG
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import os, sys
|
import os, sys
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
@ -89,7 +87,6 @@ Create JPEG thumbnails
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import os, sys
|
import os, sys
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
@ -120,7 +117,6 @@ Identify Image Files
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import sys
|
import sys
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
|
@ -125,10 +125,9 @@ External Libraries
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
There are scripts to install the dependencies for some operating
|
There are Dockerfiles in our `Docker images repo
|
||||||
systems included in the ``depends`` directory. Also see the
|
<https://github.com/python-pillow/docker-images>`_ to install the
|
||||||
Dockerfiles in our `docker images repo
|
dependencies for some operating systems.
|
||||||
<https://github.com/python-pillow/docker-images>`_.
|
|
||||||
|
|
||||||
Many of Pillow's features require external libraries:
|
Many of Pillow's features require external libraries:
|
||||||
|
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
# A monkey patch of the base distutils.ccompiler to use parallel builds
|
|
||||||
# Tested on 2.7, looks to be identical to 3.3.
|
|
||||||
# Only applied on Python 2.7 because otherwise, it conflicts with Python's
|
|
||||||
# own newly-added support for parallel builds.
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from distutils.ccompiler import CCompiler
|
|
||||||
from multiprocessing import Pool, cpu_count
|
|
||||||
|
|
||||||
try:
|
|
||||||
MAX_PROCS = int(os.environ.get("MAX_CONCURRENCY", min(4, cpu_count())))
|
|
||||||
except NotImplementedError:
|
|
||||||
MAX_PROCS = None
|
|
||||||
|
|
||||||
|
|
||||||
# hideous monkeypatching. but. but. but.
|
|
||||||
def _mp_compile_one(tp):
|
|
||||||
(self, obj, build, cc_args, extra_postargs, pp_opts) = tp
|
|
||||||
try:
|
|
||||||
src, ext = build[obj]
|
|
||||||
except KeyError:
|
|
||||||
return
|
|
||||||
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def _mp_compile(
|
|
||||||
self,
|
|
||||||
sources,
|
|
||||||
output_dir=None,
|
|
||||||
macros=None,
|
|
||||||
include_dirs=None,
|
|
||||||
debug=0,
|
|
||||||
extra_preargs=None,
|
|
||||||
extra_postargs=None,
|
|
||||||
depends=None,
|
|
||||||
):
|
|
||||||
"""Compile one or more source files.
|
|
||||||
|
|
||||||
see distutils.ccompiler.CCompiler.compile for comments.
|
|
||||||
"""
|
|
||||||
# A concrete compiler class can either override this method
|
|
||||||
# entirely or implement _compile().
|
|
||||||
|
|
||||||
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
|
|
||||||
output_dir, macros, include_dirs, sources, depends, extra_postargs
|
|
||||||
)
|
|
||||||
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
|
|
||||||
|
|
||||||
pool = Pool(MAX_PROCS)
|
|
||||||
try:
|
|
||||||
print("Building using %d processes" % pool._processes)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
arr = [(self, obj, build, cc_args, extra_postargs, pp_opts) for obj in objects]
|
|
||||||
pool.map_async(_mp_compile_one, arr)
|
|
||||||
pool.close()
|
|
||||||
pool.join()
|
|
||||||
# Return *all* object filenames, not just the ones we just built.
|
|
||||||
return objects
|
|
||||||
|
|
||||||
|
|
||||||
def install():
|
|
||||||
|
|
||||||
fl_win = sys.platform.startswith("win")
|
|
||||||
fl_cygwin = sys.platform.startswith("cygwin")
|
|
||||||
|
|
||||||
if fl_win or fl_cygwin:
|
|
||||||
# Windows barfs on multiprocessing installs
|
|
||||||
print("Single threaded build for Windows")
|
|
||||||
return
|
|
||||||
|
|
||||||
if MAX_PROCS != 1:
|
|
||||||
# explicitly don't enable if environment says 1 processor
|
|
||||||
try:
|
|
||||||
# bug, only enable if we can make a Pool. see issue #790 and
|
|
||||||
# https://stackoverflow.com/questions/6033599/oserror-38-errno-38-with-multiprocessing
|
|
||||||
Pool(2)
|
|
||||||
CCompiler.compile = _mp_compile
|
|
||||||
except Exception as msg:
|
|
||||||
print("Exception installing mp_compile, proceeding without: %s" % msg)
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
"Single threaded build, not installing mp_compile: %s processes" % MAX_PROCS
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# We monkeypatch Python 2.7
|
|
||||||
if sys.version_info.major < 3:
|
|
||||||
install()
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# minimal sanity check
|
# minimal sanity check
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
42
setup.py
42
setup.py
|
@ -7,7 +7,6 @@
|
||||||
# Final rating: 10/10
|
# Final rating: 10/10
|
||||||
# Your cheese is so fresh most people think it's a cream: Mascarpone
|
# Your cheese is so fresh most people think it's a cream: Mascarpone
|
||||||
# ------------------------------
|
# ------------------------------
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -20,10 +19,6 @@ from distutils.command.build_ext import build_ext
|
||||||
|
|
||||||
from setuptools import Extension, setup
|
from setuptools import Extension, setup
|
||||||
|
|
||||||
# monkey patch import hook. Even though flake8 says it's not used, it is.
|
|
||||||
# comment this out to disable multi threaded builds.
|
|
||||||
import mp_compile
|
|
||||||
|
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
version_file = "src/PIL/_version.py"
|
version_file = "src/PIL/_version.py"
|
||||||
|
@ -189,10 +184,10 @@ def _find_library_dirs_ldconfig():
|
||||||
expr = r".* => (.*)"
|
expr = r".* => (.*)"
|
||||||
env = {}
|
env = {}
|
||||||
|
|
||||||
null = open(os.devnull, "wb")
|
|
||||||
try:
|
try:
|
||||||
with null:
|
p = subprocess.Popen(
|
||||||
p = subprocess.Popen(args, stderr=null, stdout=subprocess.PIPE, env=env)
|
args, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE, env=env
|
||||||
|
)
|
||||||
except OSError: # E.g. command not found
|
except OSError: # E.g. command not found
|
||||||
return []
|
return []
|
||||||
[data, _] = p.communicate()
|
[data, _] = p.communicate()
|
||||||
|
@ -305,8 +300,7 @@ class pil_build_ext(build_ext):
|
||||||
return getattr(self, feat) is None
|
return getattr(self, feat) is None
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for x in self.features:
|
yield from self.features
|
||||||
yield x
|
|
||||||
|
|
||||||
feature = feature()
|
feature = feature()
|
||||||
|
|
||||||
|
@ -334,12 +328,15 @@ class pil_build_ext(build_ext):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
global DEBUG
|
global DEBUG
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
if sys.version_info.major >= 3 and not self.parallel:
|
if not self.parallel:
|
||||||
# For Python 2.7, we monkeypatch distutils to have parallel
|
# If --parallel (or -j) wasn't specified, we want to reproduce the same
|
||||||
# builds. If --parallel (or -j) wasn't specified, we want to
|
# behavior as before, that is, auto-detect the number of jobs.
|
||||||
# reproduce the same behavior as before, that is, auto-detect the
|
try:
|
||||||
# number of jobs.
|
self.parallel = int(
|
||||||
self.parallel = mp_compile.MAX_PROCS
|
os.environ.get("MAX_CONCURRENCY", min(4, os.cpu_count()))
|
||||||
|
)
|
||||||
|
except TypeError:
|
||||||
|
self.parallel = None
|
||||||
for x in self.feature:
|
for x in self.feature:
|
||||||
if getattr(self, "disable_%s" % x):
|
if getattr(self, "disable_%s" % x):
|
||||||
setattr(self.feature, x, False)
|
setattr(self.feature, x, False)
|
||||||
|
@ -347,7 +344,7 @@ class pil_build_ext(build_ext):
|
||||||
_dbg("Disabling %s", x)
|
_dbg("Disabling %s", x)
|
||||||
if getattr(self, "enable_%s" % x):
|
if getattr(self, "enable_%s" % x):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Conflicting options: --enable-%s and --disable-%s" % (x, x)
|
"Conflicting options: --enable-{} and --disable-{}".format(x, x)
|
||||||
)
|
)
|
||||||
if getattr(self, "enable_%s" % x):
|
if getattr(self, "enable_%s" % x):
|
||||||
_dbg("Requiring %s", x)
|
_dbg("Requiring %s", x)
|
||||||
|
@ -719,7 +716,7 @@ class pil_build_ext(build_ext):
|
||||||
defs.append(("HAVE_LIBTIFF", None))
|
defs.append(("HAVE_LIBTIFF", None))
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
libs.extend(["kernel32", "user32", "gdi32"])
|
libs.extend(["kernel32", "user32", "gdi32"])
|
||||||
if struct.unpack("h", "\0\1".encode("ascii"))[0] == 1:
|
if struct.unpack("h", b"\0\1")[0] == 1:
|
||||||
defs.append(("WORDS_BIGENDIAN", None))
|
defs.append(("WORDS_BIGENDIAN", None))
|
||||||
|
|
||||||
if sys.platform == "win32" and not (PLATFORM_PYPY or PLATFORM_MINGW):
|
if sys.platform == "win32" and not (PLATFORM_PYPY or PLATFORM_MINGW):
|
||||||
|
@ -800,7 +797,7 @@ class pil_build_ext(build_ext):
|
||||||
print("-" * 68)
|
print("-" * 68)
|
||||||
print("version Pillow %s" % PILLOW_VERSION)
|
print("version Pillow %s" % PILLOW_VERSION)
|
||||||
v = sys.version.split("[")
|
v = sys.version.split("[")
|
||||||
print("platform %s %s" % (sys.platform, v[0].strip()))
|
print("platform {} {}".format(sys.platform, v[0].strip()))
|
||||||
for v in v[1:]:
|
for v in v[1:]:
|
||||||
print(" [%s" % v.strip())
|
print(" [%s" % v.strip())
|
||||||
print("-" * 68)
|
print("-" * 68)
|
||||||
|
@ -823,7 +820,7 @@ class pil_build_ext(build_ext):
|
||||||
version = ""
|
version = ""
|
||||||
if len(option) >= 3 and option[2]:
|
if len(option) >= 3 and option[2]:
|
||||||
version = " (%s)" % option[2]
|
version = " (%s)" % option[2]
|
||||||
print("--- %s support available%s" % (option[1], version))
|
print("--- {} support available{}".format(option[1], version))
|
||||||
else:
|
else:
|
||||||
print("*** %s support not available" % option[1])
|
print("*** %s support not available" % option[1])
|
||||||
all = 0
|
all = 0
|
||||||
|
@ -868,13 +865,12 @@ try:
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 6 - Mature",
|
"Development Status :: 6 - Mature",
|
||||||
"License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)", # noqa: E501
|
"License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)", # noqa: E501
|
||||||
"Programming Language :: Python :: 2",
|
|
||||||
"Programming Language :: Python :: 2.7",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.5",
|
"Programming Language :: Python :: 3.5",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.6",
|
||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
"Topic :: Multimedia :: Graphics",
|
"Topic :: Multimedia :: Graphics",
|
||||||
|
@ -883,7 +879,7 @@ try:
|
||||||
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
|
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
|
||||||
"Topic :: Multimedia :: Graphics :: Viewers",
|
"Topic :: Multimedia :: Graphics :: Viewers",
|
||||||
],
|
],
|
||||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
|
python_requires=">=3.5",
|
||||||
cmdclass={"build_ext": pil_build_ext},
|
cmdclass={"build_ext": pil_build_ext},
|
||||||
ext_modules=[Extension("PIL._imaging", ["_imaging.c"])],
|
ext_modules=[Extension("PIL._imaging", ["_imaging.c"])],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from . import FontFile, Image
|
from . import FontFile, Image
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,7 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
self._read_blp_header()
|
self._read_blp_header()
|
||||||
self._load()
|
self._load()
|
||||||
except struct.error:
|
except struct.error:
|
||||||
raise IOError("Truncated Blp file")
|
raise OSError("Truncated Blp file")
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
def _read_palette(self):
|
def _read_palette(self):
|
||||||
|
|
|
@ -144,7 +144,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
file_info["a_mask"],
|
file_info["a_mask"],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise IOError("Unsupported BMP header type (%d)" % file_info["header_size"])
|
raise OSError("Unsupported BMP header type (%d)" % file_info["header_size"])
|
||||||
|
|
||||||
# ------------------ Special case : header is reported 40, which
|
# ------------------ Special case : header is reported 40, which
|
||||||
# ---------------------- is shorter than real size for bpp >= 16
|
# ---------------------- is shorter than real size for bpp >= 16
|
||||||
|
@ -159,12 +159,12 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# ------------------------------- Check abnormal values for DOS attacks
|
# ------------------------------- Check abnormal values for DOS attacks
|
||||||
if file_info["width"] * file_info["height"] > 2 ** 31:
|
if file_info["width"] * file_info["height"] > 2 ** 31:
|
||||||
raise IOError("Unsupported BMP Size: (%dx%d)" % self.size)
|
raise OSError("Unsupported BMP Size: (%dx%d)" % self.size)
|
||||||
|
|
||||||
# ---------------------- Check bit depth for unusual unsupported values
|
# ---------------------- Check bit depth for unusual unsupported values
|
||||||
self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
|
self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
|
||||||
if self.mode is None:
|
if self.mode is None:
|
||||||
raise IOError("Unsupported BMP pixel depth (%d)" % file_info["bits"])
|
raise OSError("Unsupported BMP pixel depth (%d)" % file_info["bits"])
|
||||||
|
|
||||||
# ---------------- Process BMP with Bitfields compression (not palette)
|
# ---------------- Process BMP with Bitfields compression (not palette)
|
||||||
if file_info["compression"] == self.BITFIELDS:
|
if file_info["compression"] == self.BITFIELDS:
|
||||||
|
@ -202,21 +202,21 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
):
|
):
|
||||||
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
|
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
|
||||||
else:
|
else:
|
||||||
raise IOError("Unsupported BMP bitfields layout")
|
raise OSError("Unsupported BMP bitfields layout")
|
||||||
else:
|
else:
|
||||||
raise IOError("Unsupported BMP bitfields layout")
|
raise OSError("Unsupported BMP bitfields layout")
|
||||||
elif file_info["compression"] == self.RAW:
|
elif file_info["compression"] == self.RAW:
|
||||||
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
|
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
|
||||||
raw_mode, self.mode = "BGRA", "RGBA"
|
raw_mode, self.mode = "BGRA", "RGBA"
|
||||||
else:
|
else:
|
||||||
raise IOError("Unsupported BMP compression (%d)" % file_info["compression"])
|
raise OSError("Unsupported BMP compression (%d)" % file_info["compression"])
|
||||||
|
|
||||||
# --------------- Once the header is processed, process the palette/LUT
|
# --------------- Once the header is processed, process the palette/LUT
|
||||||
if self.mode == "P": # Paletted for 1, 4 and 8 bit images
|
if self.mode == "P": # Paletted for 1, 4 and 8 bit images
|
||||||
|
|
||||||
# ---------------------------------------------------- 1-bit images
|
# ---------------------------------------------------- 1-bit images
|
||||||
if not (0 < file_info["colors"] <= 65536):
|
if not (0 < file_info["colors"] <= 65536):
|
||||||
raise IOError("Unsupported BMP Palette size (%d)" % file_info["colors"])
|
raise OSError("Unsupported BMP Palette size (%d)" % file_info["colors"])
|
||||||
else:
|
else:
|
||||||
padding = file_info["palette_padding"]
|
padding = file_info["palette_padding"]
|
||||||
palette = read(padding * file_info["colors"])
|
palette = read(padding * file_info["colors"])
|
||||||
|
@ -305,7 +305,7 @@ def _save(im, fp, filename, bitmap_header=True):
|
||||||
try:
|
try:
|
||||||
rawmode, bits, colors = SAVE[im.mode]
|
rawmode, bits, colors = SAVE[im.mode]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise IOError("cannot write mode %s as BMP" % im.mode)
|
raise OSError("cannot write mode %s as BMP" % im.mode)
|
||||||
|
|
||||||
info = im.encoderinfo
|
info = im.encoderinfo
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class BufrStubImageFile(ImageFile.StubImageFile):
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
if _handler is None or not hasattr("_handler", "save"):
|
if _handler is None or not hasattr("_handler", "save"):
|
||||||
raise IOError("BUFR save handler not installed")
|
raise OSError("BUFR save handler not installed")
|
||||||
_handler.save(im, fp, filename)
|
_handler.save(im, fp, filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
import io
|
import io
|
||||||
|
|
||||||
|
|
||||||
class ContainerIO(object):
|
class ContainerIO:
|
||||||
def __init__(self, file, offset, length):
|
def __init__(self, file, offset, length):
|
||||||
"""
|
"""
|
||||||
Create file object.
|
Create file object.
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
#
|
#
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from . import BmpImagePlugin, Image
|
from . import BmpImagePlugin, Image
|
||||||
from ._binary import i8, i16le as i16, i32le as i32
|
from ._binary import i8, i16le as i16, i32le as i32
|
||||||
|
|
||||||
|
|
|
@ -106,10 +106,10 @@ class DdsImageFile(ImageFile.ImageFile):
|
||||||
def _open(self):
|
def _open(self):
|
||||||
magic, header_size = struct.unpack("<II", self.fp.read(8))
|
magic, header_size = struct.unpack("<II", self.fp.read(8))
|
||||||
if header_size != 124:
|
if header_size != 124:
|
||||||
raise IOError("Unsupported header size %r" % (header_size))
|
raise OSError("Unsupported header size %r" % (header_size))
|
||||||
header_bytes = self.fp.read(header_size - 4)
|
header_bytes = self.fp.read(header_size - 4)
|
||||||
if len(header_bytes) != 120:
|
if len(header_bytes) != 120:
|
||||||
raise IOError("Incomplete header: %s bytes" % len(header_bytes))
|
raise OSError("Incomplete header: %s bytes" % len(header_bytes))
|
||||||
header = BytesIO(header_bytes)
|
header = BytesIO(header_bytes)
|
||||||
|
|
||||||
flags, height, width = struct.unpack("<3I", header.read(12))
|
flags, height, width = struct.unpack("<3I", header.read(12))
|
||||||
|
|
|
@ -40,15 +40,8 @@ gs_windows_binary = None
|
||||||
if sys.platform.startswith("win"):
|
if sys.platform.startswith("win"):
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
if hasattr(shutil, "which"):
|
|
||||||
which = shutil.which
|
|
||||||
else:
|
|
||||||
# Python 2
|
|
||||||
import distutils.spawn
|
|
||||||
|
|
||||||
which = distutils.spawn.find_executable
|
|
||||||
for binary in ("gswin32c", "gswin64c", "gs"):
|
for binary in ("gswin32c", "gswin64c", "gs"):
|
||||||
if which(binary) is not None:
|
if shutil.which(binary) is not None:
|
||||||
gs_windows_binary = binary
|
gs_windows_binary = binary
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -60,8 +53,7 @@ def has_ghostscript():
|
||||||
return True
|
return True
|
||||||
if not sys.platform.startswith("win"):
|
if not sys.platform.startswith("win"):
|
||||||
try:
|
try:
|
||||||
with open(os.devnull, "wb") as devnull:
|
subprocess.check_call(["gs", "--version"], stdout=subprocess.DEVNULL)
|
||||||
subprocess.check_call(["gs", "--version"], stdout=devnull)
|
|
||||||
return True
|
return True
|
||||||
except OSError:
|
except OSError:
|
||||||
# No Ghostscript
|
# No Ghostscript
|
||||||
|
@ -139,7 +131,7 @@ def Ghostscript(tile, size, fp, scale=1):
|
||||||
|
|
||||||
if gs_windows_binary is not None:
|
if gs_windows_binary is not None:
|
||||||
if not gs_windows_binary:
|
if not gs_windows_binary:
|
||||||
raise WindowsError("Unable to locate Ghostscript on paths")
|
raise OSError("Unable to locate Ghostscript on paths")
|
||||||
command[0] = gs_windows_binary
|
command[0] = gs_windows_binary
|
||||||
|
|
||||||
# push data through Ghostscript
|
# push data through Ghostscript
|
||||||
|
@ -162,7 +154,7 @@ def Ghostscript(tile, size, fp, scale=1):
|
||||||
return im.im.copy()
|
return im.im.copy()
|
||||||
|
|
||||||
|
|
||||||
class PSFile(object):
|
class PSFile:
|
||||||
"""
|
"""
|
||||||
Wrapper for bytesio object that treats either CR or LF as end of line.
|
Wrapper for bytesio object that treats either CR or LF as end of line.
|
||||||
"""
|
"""
|
||||||
|
@ -272,7 +264,7 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
# tools mistakenly put in the Comments section
|
# tools mistakenly put in the Comments section
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise IOError("bad EPS header")
|
raise OSError("bad EPS header")
|
||||||
|
|
||||||
s_raw = fp.readline()
|
s_raw = fp.readline()
|
||||||
s = s_raw.strip("\r\n")
|
s = s_raw.strip("\r\n")
|
||||||
|
@ -307,7 +299,7 @@ class EpsImageFile(ImageFile.ImageFile):
|
||||||
break
|
break
|
||||||
|
|
||||||
if not box:
|
if not box:
|
||||||
raise IOError("cannot determine EPS bounding box")
|
raise OSError("cannot determine EPS bounding box")
|
||||||
|
|
||||||
def _find_offset(self, fp):
|
def _find_offset(self, fp):
|
||||||
|
|
||||||
|
@ -371,9 +363,8 @@ def _save(im, fp, filename, eps=1):
|
||||||
base_fp = fp
|
base_fp = fp
|
||||||
wrapped_fp = False
|
wrapped_fp = False
|
||||||
if fp != sys.stdout:
|
if fp != sys.stdout:
|
||||||
if sys.version_info.major > 2:
|
fp = io.TextIOWrapper(fp, encoding="latin-1")
|
||||||
fp = io.TextIOWrapper(fp, encoding="latin-1")
|
wrapped_fp = True
|
||||||
wrapped_fp = True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if eps:
|
if eps:
|
||||||
|
|
|
@ -63,7 +63,7 @@ class FITSStubImageFile(ImageFile.StubImageFile):
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
if _handler is None or not hasattr("_handler", "save"):
|
if _handler is None or not hasattr("_handler", "save"):
|
||||||
raise IOError("FITS save handler not installed")
|
raise OSError("FITS save handler not installed")
|
||||||
_handler.save(im, fp, filename)
|
_handler.save(im, fp, filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -35,7 +34,7 @@ def puti16(fp, values):
|
||||||
# Base class for raster font file handlers.
|
# Base class for raster font file handlers.
|
||||||
|
|
||||||
|
|
||||||
class FontFile(object):
|
class FontFile:
|
||||||
|
|
||||||
bitmap = None
|
bitmap = None
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,6 @@
|
||||||
#
|
#
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import olefile
|
import olefile
|
||||||
|
|
||||||
from . import Image, ImageFile
|
from . import Image, ImageFile
|
||||||
|
@ -62,7 +59,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.ole = olefile.OleFileIO(self.fp)
|
self.ole = olefile.OleFileIO(self.fp)
|
||||||
except IOError:
|
except OSError:
|
||||||
raise SyntaxError("not an FPX file; invalid OLE file")
|
raise SyntaxError("not an FPX file; invalid OLE file")
|
||||||
|
|
||||||
if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
|
if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
|
||||||
|
@ -141,7 +138,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
||||||
length = i32(s, 32)
|
length = i32(s, 32)
|
||||||
|
|
||||||
if size != self.size:
|
if size != self.size:
|
||||||
raise IOError("subimage mismatch")
|
raise OSError("subimage mismatch")
|
||||||
|
|
||||||
# get tile descriptors
|
# get tile descriptors
|
||||||
fp.seek(28 + offset)
|
fp.seek(28 + offset)
|
||||||
|
@ -214,7 +211,7 @@ class FpxImageFile(ImageFile.ImageFile):
|
||||||
self.tile_prefix = self.jpeg[jpeg_tables]
|
self.tile_prefix = self.jpeg[jpeg_tables]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise IOError("unknown/invalid compression")
|
raise OSError("unknown/invalid compression")
|
||||||
|
|
||||||
x = x + xtile
|
x = x + xtile
|
||||||
if x >= xsize:
|
if x >= xsize:
|
||||||
|
|
|
@ -618,20 +618,20 @@ def _save_netpbm(im, fp, filename):
|
||||||
|
|
||||||
with open(filename, "wb") as f:
|
with open(filename, "wb") as f:
|
||||||
if im.mode != "RGB":
|
if im.mode != "RGB":
|
||||||
with open(os.devnull, "wb") as devnull:
|
subprocess.check_call(
|
||||||
subprocess.check_call(["ppmtogif", tempfile], stdout=f, stderr=devnull)
|
["ppmtogif", tempfile], stdout=f, stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Pipe ppmquant output into ppmtogif
|
# Pipe ppmquant output into ppmtogif
|
||||||
# "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename)
|
# "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename)
|
||||||
quant_cmd = ["ppmquant", "256", tempfile]
|
quant_cmd = ["ppmquant", "256", tempfile]
|
||||||
togif_cmd = ["ppmtogif"]
|
togif_cmd = ["ppmtogif"]
|
||||||
with open(os.devnull, "wb") as devnull:
|
quant_proc = subprocess.Popen(
|
||||||
quant_proc = subprocess.Popen(
|
quant_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
|
||||||
quant_cmd, stdout=subprocess.PIPE, stderr=devnull
|
)
|
||||||
)
|
togif_proc = subprocess.Popen(
|
||||||
togif_proc = subprocess.Popen(
|
togif_cmd, stdin=quant_proc.stdout, stdout=f, stderr=subprocess.DEVNULL
|
||||||
togif_cmd, stdin=quant_proc.stdout, stdout=f, stderr=devnull
|
)
|
||||||
)
|
|
||||||
|
|
||||||
# Allow ppmquant to receive SIGPIPE if ppmtogif exits
|
# Allow ppmquant to receive SIGPIPE if ppmtogif exits
|
||||||
quant_proc.stdout.close()
|
quant_proc.stdout.close()
|
||||||
|
@ -848,7 +848,7 @@ def getdata(im, offset=(0, 0), **params):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Collector(object):
|
class Collector:
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
|
|
|
@ -60,7 +60,7 @@ def sphere_decreasing(middle, pos):
|
||||||
SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
|
SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
|
||||||
|
|
||||||
|
|
||||||
class GradientFile(object):
|
class GradientFile:
|
||||||
|
|
||||||
gradient = None
|
gradient = None
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class GimpGradientFile(GradientFile):
|
||||||
cspace = int(s[12])
|
cspace = int(s[12])
|
||||||
|
|
||||||
if cspace != 0:
|
if cspace != 0:
|
||||||
raise IOError("cannot handle HSV colour space")
|
raise OSError("cannot handle HSV colour space")
|
||||||
|
|
||||||
gradient.append((x0, x1, xm, rgb0, rgb1, segment))
|
gradient.append((x0, x1, xm, rgb0, rgb1, segment))
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ from ._binary import o8
|
||||||
# File handler for GIMP's palette format.
|
# File handler for GIMP's palette format.
|
||||||
|
|
||||||
|
|
||||||
class GimpPaletteFile(object):
|
class GimpPaletteFile:
|
||||||
|
|
||||||
rawmode = "RGB"
|
rawmode = "RGB"
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ class GribStubImageFile(ImageFile.StubImageFile):
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
if _handler is None or not hasattr("_handler", "save"):
|
if _handler is None or not hasattr("_handler", "save"):
|
||||||
raise IOError("GRIB save handler not installed")
|
raise OSError("GRIB save handler not installed")
|
||||||
_handler.save(im, fp, filename)
|
_handler.save(im, fp, filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class HDF5StubImageFile(ImageFile.StubImageFile):
|
||||||
|
|
||||||
def _save(im, fp, filename):
|
def _save(im, fp, filename):
|
||||||
if _handler is None or not hasattr("_handler", "save"):
|
if _handler is None or not hasattr("_handler", "save"):
|
||||||
raise IOError("HDF5 save handler not installed")
|
raise OSError("HDF5 save handler not installed")
|
||||||
_handler.save(im, fp, filename)
|
_handler.save(im, fp, filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ def read_png_or_jpeg2000(fobj, start_length, size):
|
||||||
raise ValueError("Unsupported icon subimage format")
|
raise ValueError("Unsupported icon subimage format")
|
||||||
|
|
||||||
|
|
||||||
class IcnsFile(object):
|
class IcnsFile:
|
||||||
|
|
||||||
SIZES = {
|
SIZES = {
|
||||||
(512, 512, 2): [(b"ic10", read_png_or_jpeg2000)],
|
(512, 512, 2): [(b"ic10", read_png_or_jpeg2000)],
|
||||||
|
@ -314,42 +314,40 @@ def _save(im, fp, filename):
|
||||||
fp.flush()
|
fp.flush()
|
||||||
|
|
||||||
# create the temporary set of pngs
|
# create the temporary set of pngs
|
||||||
iconset = tempfile.mkdtemp(".iconset")
|
with tempfile.TemporaryDirectory(".iconset") as iconset:
|
||||||
provided_images = {im.width: im for im in im.encoderinfo.get("append_images", [])}
|
provided_images = {
|
||||||
last_w = None
|
im.width: im for im in im.encoderinfo.get("append_images", [])
|
||||||
second_path = None
|
}
|
||||||
for w in [16, 32, 128, 256, 512]:
|
last_w = None
|
||||||
prefix = "icon_{}x{}".format(w, w)
|
second_path = None
|
||||||
|
for w in [16, 32, 128, 256, 512]:
|
||||||
|
prefix = "icon_{}x{}".format(w, w)
|
||||||
|
|
||||||
first_path = os.path.join(iconset, prefix + ".png")
|
first_path = os.path.join(iconset, prefix + ".png")
|
||||||
if last_w == w:
|
if last_w == w:
|
||||||
shutil.copyfile(second_path, first_path)
|
shutil.copyfile(second_path, first_path)
|
||||||
else:
|
else:
|
||||||
im_w = provided_images.get(w, im.resize((w, w), Image.LANCZOS))
|
im_w = provided_images.get(w, im.resize((w, w), Image.LANCZOS))
|
||||||
im_w.save(first_path)
|
im_w.save(first_path)
|
||||||
|
|
||||||
second_path = os.path.join(iconset, prefix + "@2x.png")
|
second_path = os.path.join(iconset, prefix + "@2x.png")
|
||||||
im_w2 = provided_images.get(w * 2, im.resize((w * 2, w * 2), Image.LANCZOS))
|
im_w2 = provided_images.get(w * 2, im.resize((w * 2, w * 2), Image.LANCZOS))
|
||||||
im_w2.save(second_path)
|
im_w2.save(second_path)
|
||||||
last_w = w * 2
|
last_w = w * 2
|
||||||
|
|
||||||
# iconutil -c icns -o {} {}
|
# iconutil -c icns -o {} {}
|
||||||
|
|
||||||
convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
|
convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
|
||||||
with open(os.devnull, "wb") as devnull:
|
|
||||||
convert_proc = subprocess.Popen(
|
convert_proc = subprocess.Popen(
|
||||||
convert_cmd, stdout=subprocess.PIPE, stderr=devnull
|
convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
|
||||||
)
|
)
|
||||||
|
|
||||||
convert_proc.stdout.close()
|
convert_proc.stdout.close()
|
||||||
|
|
||||||
retcode = convert_proc.wait()
|
retcode = convert_proc.wait()
|
||||||
|
|
||||||
# remove the temporary files
|
if retcode:
|
||||||
shutil.rmtree(iconset)
|
raise subprocess.CalledProcessError(retcode, convert_cmd)
|
||||||
|
|
||||||
if retcode:
|
|
||||||
raise subprocess.CalledProcessError(retcode, convert_cmd)
|
|
||||||
|
|
||||||
|
|
||||||
Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")
|
Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")
|
||||||
|
|
|
@ -82,7 +82,7 @@ def _accept(prefix):
|
||||||
return prefix[:4] == _MAGIC
|
return prefix[:4] == _MAGIC
|
||||||
|
|
||||||
|
|
||||||
class IcoFile(object):
|
class IcoFile:
|
||||||
def __init__(self, buf):
|
def __init__(self, buf):
|
||||||
"""
|
"""
|
||||||
Parse image from file-like object containing ico file data
|
Parse image from file-like object containing ico file data
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
|
import builtins
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
@ -34,29 +35,15 @@ import struct
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
|
from collections.abc import Callable, MutableMapping
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
# VERSION was removed in Pillow 6.0.0.
|
# VERSION was removed in Pillow 6.0.0.
|
||||||
# PILLOW_VERSION was removed in Pillow 7.0.0.
|
# PILLOW_VERSION was removed in Pillow 7.0.0.
|
||||||
# Use __version__ instead.
|
# Use __version__ instead.
|
||||||
from . import ImageMode, TiffTags, UnidentifiedImageError, __version__, _plugins
|
from . import ImageMode, TiffTags, UnidentifiedImageError, __version__, _plugins
|
||||||
from ._binary import i8, i32le
|
from ._binary import i8, i32le
|
||||||
from ._util import deferred_error, isPath, isStringType, py3
|
from ._util import deferred_error, isPath
|
||||||
|
|
||||||
try:
|
|
||||||
import builtins
|
|
||||||
except ImportError:
|
|
||||||
import __builtin__
|
|
||||||
|
|
||||||
builtins = __builtin__
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Python 3
|
|
||||||
from collections.abc import Callable, MutableMapping
|
|
||||||
except ImportError:
|
|
||||||
# Python 2.7
|
|
||||||
from collections import Callable, MutableMapping
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -101,22 +88,6 @@ except ImportError as v:
|
||||||
)
|
)
|
||||||
elif str(v).startswith("The _imaging extension"):
|
elif str(v).startswith("The _imaging extension"):
|
||||||
warnings.warn(str(v), RuntimeWarning)
|
warnings.warn(str(v), RuntimeWarning)
|
||||||
elif "Symbol not found: _PyUnicodeUCS2_" in str(v):
|
|
||||||
# should match _PyUnicodeUCS2_FromString and
|
|
||||||
# _PyUnicodeUCS2_AsLatin1String
|
|
||||||
warnings.warn(
|
|
||||||
"The _imaging extension was built for Python with UCS2 support; "
|
|
||||||
"recompile Pillow or build Python --without-wide-unicode. ",
|
|
||||||
RuntimeWarning,
|
|
||||||
)
|
|
||||||
elif "Symbol not found: _PyUnicodeUCS4_" in str(v):
|
|
||||||
# should match _PyUnicodeUCS4_FromString and
|
|
||||||
# _PyUnicodeUCS4_AsLatin1String
|
|
||||||
warnings.warn(
|
|
||||||
"The _imaging extension was built for Python with UCS4 support; "
|
|
||||||
"recompile Pillow or build Python --with-wide-unicode. ",
|
|
||||||
RuntimeWarning,
|
|
||||||
)
|
|
||||||
# Fail here anyway. Don't let people run with a mostly broken Pillow.
|
# Fail here anyway. Don't let people run with a mostly broken Pillow.
|
||||||
# see docs/porting.rst
|
# see docs/porting.rst
|
||||||
raise
|
raise
|
||||||
|
@ -129,18 +100,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
cffi = None
|
cffi = None
|
||||||
|
|
||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
HAS_PATHLIB = True
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from pathlib2 import Path
|
|
||||||
|
|
||||||
HAS_PATHLIB = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_PATHLIB = False
|
|
||||||
|
|
||||||
|
|
||||||
def isImageType(t):
|
def isImageType(t):
|
||||||
"""
|
"""
|
||||||
|
@ -447,7 +406,7 @@ def _getdecoder(mode, decoder_name, args, extra=()):
|
||||||
decoder = getattr(core, decoder_name + "_decoder")
|
decoder = getattr(core, decoder_name + "_decoder")
|
||||||
return decoder(mode, *args + extra)
|
return decoder(mode, *args + extra)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise IOError("decoder %s not available" % decoder_name)
|
raise OSError("decoder %s not available" % decoder_name)
|
||||||
|
|
||||||
|
|
||||||
def _getencoder(mode, encoder_name, args, extra=()):
|
def _getencoder(mode, encoder_name, args, extra=()):
|
||||||
|
@ -468,7 +427,7 @@ def _getencoder(mode, encoder_name, args, extra=()):
|
||||||
encoder = getattr(core, encoder_name + "_encoder")
|
encoder = getattr(core, encoder_name + "_encoder")
|
||||||
return encoder(mode, *args + extra)
|
return encoder(mode, *args + extra)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise IOError("encoder %s not available" % encoder_name)
|
raise OSError("encoder %s not available" % encoder_name)
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -479,7 +438,7 @@ def coerce_e(value):
|
||||||
return value if isinstance(value, _E) else _E(value)
|
return value if isinstance(value, _E) else _E(value)
|
||||||
|
|
||||||
|
|
||||||
class _E(object):
|
class _E:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
|
@ -520,7 +479,7 @@ def _getscaleoffset(expr):
|
||||||
# Implementation wrapper
|
# Implementation wrapper
|
||||||
|
|
||||||
|
|
||||||
class Image(object):
|
class Image:
|
||||||
"""
|
"""
|
||||||
This class represents an image object. To create
|
This class represents an image object. To create
|
||||||
:py:class:`~PIL.Image.Image` objects, use the appropriate factory
|
:py:class:`~PIL.Image.Image` objects, use the appropriate factory
|
||||||
|
@ -662,10 +621,6 @@ class Image(object):
|
||||||
and self.tobytes() == other.tobytes()
|
and self.tobytes() == other.tobytes()
|
||||||
)
|
)
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
eq = self == other
|
|
||||||
return not eq
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
|
return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
|
||||||
self.__class__.__module__,
|
self.__class__.__module__,
|
||||||
|
@ -1335,10 +1290,7 @@ class Image(object):
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
try:
|
try:
|
||||||
if py3:
|
return list(self.im.getpalette())
|
||||||
return list(self.im.getpalette())
|
|
||||||
else:
|
|
||||||
return [i8(c) for c in self.im.getpalette()]
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None # no palette
|
return None # no palette
|
||||||
|
|
||||||
|
@ -1489,7 +1441,7 @@ class Image(object):
|
||||||
raise ValueError("cannot determine region size; use 4-item box")
|
raise ValueError("cannot determine region size; use 4-item box")
|
||||||
box += (box[0] + size[0], box[1] + size[1])
|
box += (box[0] + size[0], box[1] + size[1])
|
||||||
|
|
||||||
if isStringType(im):
|
if isinstance(im, str):
|
||||||
from . import ImageColor
|
from . import ImageColor
|
||||||
|
|
||||||
im = ImageColor.getcolor(im, self.mode)
|
im = ImageColor.getcolor(im, self.mode)
|
||||||
|
@ -1689,10 +1641,7 @@ class Image(object):
|
||||||
palette = ImagePalette.raw(data.rawmode, data.palette)
|
palette = ImagePalette.raw(data.rawmode, data.palette)
|
||||||
else:
|
else:
|
||||||
if not isinstance(data, bytes):
|
if not isinstance(data, bytes):
|
||||||
if py3:
|
data = bytes(data)
|
||||||
data = bytes(data)
|
|
||||||
else:
|
|
||||||
data = "".join(chr(x) for x in data)
|
|
||||||
palette = ImagePalette.raw(rawmode, data)
|
palette = ImagePalette.raw(rawmode, data)
|
||||||
self.mode = "PA" if "A" in self.mode else "P"
|
self.mode = "PA" if "A" in self.mode else "P"
|
||||||
self.palette = palette
|
self.palette = palette
|
||||||
|
@ -2024,7 +1973,7 @@ class Image(object):
|
||||||
if isPath(fp):
|
if isPath(fp):
|
||||||
filename = fp
|
filename = fp
|
||||||
open_fp = True
|
open_fp = True
|
||||||
elif HAS_PATHLIB and isinstance(fp, Path):
|
elif isinstance(fp, Path):
|
||||||
filename = str(fp)
|
filename = str(fp)
|
||||||
open_fp = True
|
open_fp = True
|
||||||
if not filename and hasattr(fp, "name") and isPath(fp.name):
|
if not filename and hasattr(fp, "name") and isPath(fp.name):
|
||||||
|
@ -2146,7 +2095,7 @@ class Image(object):
|
||||||
"""
|
"""
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
if isStringType(channel):
|
if isinstance(channel, str):
|
||||||
try:
|
try:
|
||||||
channel = self.getbands().index(channel)
|
channel = self.getbands().index(channel)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -2411,12 +2360,12 @@ class Image(object):
|
||||||
# Abstract handlers.
|
# Abstract handlers.
|
||||||
|
|
||||||
|
|
||||||
class ImagePointHandler(object):
|
class ImagePointHandler:
|
||||||
# used as a mixin by point transforms (for use with im.point)
|
# used as a mixin by point transforms (for use with im.point)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ImageTransformHandler(object):
|
class ImageTransformHandler:
|
||||||
# used as a mixin by geometry transforms (for use with im.transform)
|
# used as a mixin by geometry transforms (for use with im.transform)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -2474,7 +2423,7 @@ def new(mode, size, color=0):
|
||||||
# don't initialize
|
# don't initialize
|
||||||
return Image()._new(core.new(mode, size))
|
return Image()._new(core.new(mode, size))
|
||||||
|
|
||||||
if isStringType(color):
|
if isinstance(color, str):
|
||||||
# css3-style specifier
|
# css3-style specifier
|
||||||
|
|
||||||
from . import ImageColor
|
from . import ImageColor
|
||||||
|
@ -2736,7 +2685,7 @@ def open(fp, mode="r"):
|
||||||
|
|
||||||
exclusive_fp = False
|
exclusive_fp = False
|
||||||
filename = ""
|
filename = ""
|
||||||
if HAS_PATHLIB and isinstance(fp, Path):
|
if isinstance(fp, Path):
|
||||||
filename = str(fp.resolve())
|
filename = str(fp.resolve())
|
||||||
elif isPath(fp):
|
elif isPath(fp):
|
||||||
filename = fp
|
filename = fp
|
||||||
|
@ -3302,11 +3251,6 @@ class Exif(MutableMapping):
|
||||||
def __contains__(self, tag):
|
def __contains__(self, tag):
|
||||||
return tag in self._data or (self._info is not None and tag in self._info)
|
return tag in self._data or (self._info is not None and tag in self._info)
|
||||||
|
|
||||||
if not py3:
|
|
||||||
|
|
||||||
def has_key(self, tag):
|
|
||||||
return tag in self
|
|
||||||
|
|
||||||
def __setitem__(self, tag, value):
|
def __setitem__(self, tag, value):
|
||||||
if self._info is not None and tag in self._info:
|
if self._info is not None and tag in self._info:
|
||||||
del self._info[tag]
|
del self._info[tag]
|
||||||
|
|
|
@ -15,12 +15,9 @@
|
||||||
# See the README file for information on usage and redistribution. See
|
# See the README file for information on usage and redistribution. See
|
||||||
# below for the original description.
|
# below for the original description.
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL._util import isStringType
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import _imagingcms
|
from PIL import _imagingcms
|
||||||
|
@ -152,7 +149,7 @@ for flag in FLAGS.values():
|
||||||
# Profile.
|
# Profile.
|
||||||
|
|
||||||
|
|
||||||
class ImageCmsProfile(object):
|
class ImageCmsProfile:
|
||||||
def __init__(self, profile):
|
def __init__(self, profile):
|
||||||
"""
|
"""
|
||||||
:param profile: Either a string representing a filename,
|
:param profile: Either a string representing a filename,
|
||||||
|
@ -161,7 +158,7 @@ class ImageCmsProfile(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isStringType(profile):
|
if isinstance(profile, str):
|
||||||
self._set(core.profile_open(profile), profile)
|
self._set(core.profile_open(profile), profile)
|
||||||
elif hasattr(profile, "read"):
|
elif hasattr(profile, "read"):
|
||||||
self._set(core.profile_frombytes(profile.read()))
|
self._set(core.profile_frombytes(profile.read()))
|
||||||
|
@ -374,7 +371,7 @@ def profileToProfile(
|
||||||
imOut = None
|
imOut = None
|
||||||
else:
|
else:
|
||||||
imOut = transform.apply(im)
|
imOut = transform.apply(im)
|
||||||
except (IOError, TypeError, ValueError) as v:
|
except (OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
return imOut
|
return imOut
|
||||||
|
@ -398,7 +395,7 @@ def getOpenProfile(profileFilename):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return ImageCmsProfile(profileFilename)
|
return ImageCmsProfile(profileFilename)
|
||||||
except (IOError, TypeError, ValueError) as v:
|
except (OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -479,7 +476,7 @@ def buildTransform(
|
||||||
return ImageCmsTransform(
|
return ImageCmsTransform(
|
||||||
inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
|
inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
|
||||||
)
|
)
|
||||||
except (IOError, TypeError, ValueError) as v:
|
except (OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -590,7 +587,7 @@ def buildProofTransform(
|
||||||
proofRenderingIntent,
|
proofRenderingIntent,
|
||||||
flags,
|
flags,
|
||||||
)
|
)
|
||||||
except (IOError, TypeError, ValueError) as v:
|
except (OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -733,9 +730,9 @@ def getProfileName(profile):
|
||||||
return (profile.profile.profile_description or "") + "\n"
|
return (profile.profile.profile_description or "") + "\n"
|
||||||
if not manufacturer or len(model) > 30:
|
if not manufacturer or len(model) > 30:
|
||||||
return model + "\n"
|
return model + "\n"
|
||||||
return "%s - %s\n" % (model, manufacturer)
|
return "{} - {}\n".format(model, manufacturer)
|
||||||
|
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -775,7 +772,7 @@ def getProfileInfo(profile):
|
||||||
arr.append(elt)
|
arr.append(elt)
|
||||||
return "\r\n\r\n".join(arr) + "\r\n\r\n"
|
return "\r\n\r\n".join(arr) + "\r\n\r\n"
|
||||||
|
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -803,7 +800,7 @@ def getProfileCopyright(profile):
|
||||||
if not isinstance(profile, ImageCmsProfile):
|
if not isinstance(profile, ImageCmsProfile):
|
||||||
profile = ImageCmsProfile(profile)
|
profile = ImageCmsProfile(profile)
|
||||||
return (profile.profile.copyright or "") + "\n"
|
return (profile.profile.copyright or "") + "\n"
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -831,7 +828,7 @@ def getProfileManufacturer(profile):
|
||||||
if not isinstance(profile, ImageCmsProfile):
|
if not isinstance(profile, ImageCmsProfile):
|
||||||
profile = ImageCmsProfile(profile)
|
profile = ImageCmsProfile(profile)
|
||||||
return (profile.profile.manufacturer or "") + "\n"
|
return (profile.profile.manufacturer or "") + "\n"
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -860,7 +857,7 @@ def getProfileModel(profile):
|
||||||
if not isinstance(profile, ImageCmsProfile):
|
if not isinstance(profile, ImageCmsProfile):
|
||||||
profile = ImageCmsProfile(profile)
|
profile = ImageCmsProfile(profile)
|
||||||
return (profile.profile.model or "") + "\n"
|
return (profile.profile.model or "") + "\n"
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -889,7 +886,7 @@ def getProfileDescription(profile):
|
||||||
if not isinstance(profile, ImageCmsProfile):
|
if not isinstance(profile, ImageCmsProfile):
|
||||||
profile = ImageCmsProfile(profile)
|
profile = ImageCmsProfile(profile)
|
||||||
return (profile.profile.profile_description or "") + "\n"
|
return (profile.profile.profile_description or "") + "\n"
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -928,7 +925,7 @@ def getDefaultIntent(profile):
|
||||||
if not isinstance(profile, ImageCmsProfile):
|
if not isinstance(profile, ImageCmsProfile):
|
||||||
profile = ImageCmsProfile(profile)
|
profile = ImageCmsProfile(profile)
|
||||||
return profile.profile.rendering_intent
|
return profile.profile.rendering_intent
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -979,7 +976,7 @@ def isIntentSupported(profile, intent, direction):
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
return -1
|
return -1
|
||||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||||
raise PyCMSError(v)
|
raise PyCMSError(v)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ import math
|
||||||
import numbers
|
import numbers
|
||||||
|
|
||||||
from . import Image, ImageColor
|
from . import Image, ImageColor
|
||||||
from ._util import isStringType
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -45,7 +44,7 @@ directly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ImageDraw(object):
|
class ImageDraw:
|
||||||
def __init__(self, im, mode=None):
|
def __init__(self, im, mode=None):
|
||||||
"""
|
"""
|
||||||
Create a drawing instance.
|
Create a drawing instance.
|
||||||
|
@ -107,13 +106,13 @@ class ImageDraw(object):
|
||||||
ink = self.ink
|
ink = self.ink
|
||||||
else:
|
else:
|
||||||
if ink is not None:
|
if ink is not None:
|
||||||
if isStringType(ink):
|
if isinstance(ink, str):
|
||||||
ink = ImageColor.getcolor(ink, self.mode)
|
ink = ImageColor.getcolor(ink, self.mode)
|
||||||
if self.palette and not isinstance(ink, numbers.Number):
|
if self.palette and not isinstance(ink, numbers.Number):
|
||||||
ink = self.palette.getcolor(ink)
|
ink = self.palette.getcolor(ink)
|
||||||
ink = self.draw.draw_ink(ink)
|
ink = self.draw.draw_ink(ink)
|
||||||
if fill is not None:
|
if fill is not None:
|
||||||
if isStringType(fill):
|
if isinstance(fill, str):
|
||||||
fill = ImageColor.getcolor(fill, self.mode)
|
fill = ImageColor.getcolor(fill, self.mode)
|
||||||
if self.palette and not isinstance(fill, numbers.Number):
|
if self.palette and not isinstance(fill, numbers.Number):
|
||||||
fill = self.palette.getcolor(fill)
|
fill = self.palette.getcolor(fill)
|
||||||
|
@ -314,7 +313,7 @@ class ImageDraw(object):
|
||||||
language=language,
|
language=language,
|
||||||
stroke_width=stroke_width,
|
stroke_width=stroke_width,
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
coord = coord[0] + offset[0], coord[1] + offset[1]
|
coord = coord[0] + offset[0], coord[1] + offset[1]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -327,7 +326,7 @@ class ImageDraw(object):
|
||||||
language,
|
language,
|
||||||
stroke_width,
|
stroke_width,
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
mask = font.getmask(text)
|
mask = font.getmask(text)
|
||||||
|
|
|
@ -19,25 +19,25 @@
|
||||||
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||||
|
|
||||||
|
|
||||||
class Pen(object):
|
class Pen:
|
||||||
def __init__(self, color, width=1, opacity=255):
|
def __init__(self, color, width=1, opacity=255):
|
||||||
self.color = ImageColor.getrgb(color)
|
self.color = ImageColor.getrgb(color)
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
||||||
|
|
||||||
class Brush(object):
|
class Brush:
|
||||||
def __init__(self, color, opacity=255):
|
def __init__(self, color, opacity=255):
|
||||||
self.color = ImageColor.getrgb(color)
|
self.color = ImageColor.getrgb(color)
|
||||||
|
|
||||||
|
|
||||||
class Font(object):
|
class Font:
|
||||||
def __init__(self, color, file, size=12):
|
def __init__(self, color, file, size=12):
|
||||||
# FIXME: add support for bitmap fonts
|
# FIXME: add support for bitmap fonts
|
||||||
self.color = ImageColor.getrgb(color)
|
self.color = ImageColor.getrgb(color)
|
||||||
self.font = ImageFont.truetype(file, size)
|
self.font = ImageFont.truetype(file, size)
|
||||||
|
|
||||||
|
|
||||||
class Draw(object):
|
class Draw:
|
||||||
def __init__(self, image, size=None, color=None):
|
def __init__(self, image, size=None, color=None):
|
||||||
if not hasattr(image, "im"):
|
if not hasattr(image, "im"):
|
||||||
image = Image.new(image, size, color)
|
image = Image.new(image, size, color)
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
from . import Image, ImageFilter, ImageStat
|
from . import Image, ImageFilter, ImageStat
|
||||||
|
|
||||||
|
|
||||||
class _Enhance(object):
|
class _Enhance:
|
||||||
def enhance(self, factor):
|
def enhance(self, factor):
|
||||||
"""
|
"""
|
||||||
Returns an enhanced image.
|
Returns an enhanced image.
|
||||||
|
|
|
@ -56,7 +56,7 @@ def raise_ioerror(error):
|
||||||
message = ERRORS.get(error)
|
message = ERRORS.get(error)
|
||||||
if not message:
|
if not message:
|
||||||
message = "decoder error %d" % error
|
message = "decoder error %d" % error
|
||||||
raise IOError(message + " when reading image file")
|
raise OSError(message + " when reading image file")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -148,7 +148,7 @@ class ImageFile(Image.Image):
|
||||||
pixel = Image.Image.load(self)
|
pixel = Image.Image.load(self)
|
||||||
|
|
||||||
if self.tile is None:
|
if self.tile is None:
|
||||||
raise IOError("cannot load this image")
|
raise OSError("cannot load this image")
|
||||||
if not self.tile:
|
if not self.tile:
|
||||||
return pixel
|
return pixel
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ class ImageFile(Image.Image):
|
||||||
# we might need to reload the palette data.
|
# we might need to reload the palette data.
|
||||||
if self.palette:
|
if self.palette:
|
||||||
self.palette.dirty = 1
|
self.palette.dirty = 1
|
||||||
except (AttributeError, EnvironmentError, ImportError):
|
except (AttributeError, OSError, ImportError):
|
||||||
self.map = None
|
self.map = None
|
||||||
|
|
||||||
self.load_prepare()
|
self.load_prepare()
|
||||||
|
@ -241,13 +241,13 @@ class ImageFile(Image.Image):
|
||||||
if LOAD_TRUNCATED_IMAGES:
|
if LOAD_TRUNCATED_IMAGES:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise IOError("image file is truncated")
|
raise OSError("image file is truncated")
|
||||||
|
|
||||||
if not s: # truncated jpeg
|
if not s: # truncated jpeg
|
||||||
if LOAD_TRUNCATED_IMAGES:
|
if LOAD_TRUNCATED_IMAGES:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise IOError(
|
raise OSError(
|
||||||
"image file is truncated "
|
"image file is truncated "
|
||||||
"(%d bytes not processed)" % len(b)
|
"(%d bytes not processed)" % len(b)
|
||||||
)
|
)
|
||||||
|
@ -325,7 +325,7 @@ class StubImageFile(ImageFile):
|
||||||
def load(self):
|
def load(self):
|
||||||
loader = self._load()
|
loader = self._load()
|
||||||
if loader is None:
|
if loader is None:
|
||||||
raise IOError("cannot find loader for this %s file" % self.format)
|
raise OSError("cannot find loader for this %s file" % self.format)
|
||||||
image = loader.load(self)
|
image = loader.load(self)
|
||||||
assert image is not None
|
assert image is not None
|
||||||
# become the other object (!)
|
# become the other object (!)
|
||||||
|
@ -337,7 +337,7 @@ class StubImageFile(ImageFile):
|
||||||
raise NotImplementedError("StubImageFile subclass must implement _load")
|
raise NotImplementedError("StubImageFile subclass must implement _load")
|
||||||
|
|
||||||
|
|
||||||
class Parser(object):
|
class Parser:
|
||||||
"""
|
"""
|
||||||
Incremental image parser. This class implements the standard
|
Incremental image parser. This class implements the standard
|
||||||
feed/close consumer interface.
|
feed/close consumer interface.
|
||||||
|
@ -414,7 +414,7 @@ class Parser(object):
|
||||||
try:
|
try:
|
||||||
with io.BytesIO(self.data) as fp:
|
with io.BytesIO(self.data) as fp:
|
||||||
im = Image.open(fp)
|
im = Image.open(fp)
|
||||||
except IOError:
|
except OSError:
|
||||||
# traceback.print_exc()
|
# traceback.print_exc()
|
||||||
pass # not enough data
|
pass # not enough data
|
||||||
else:
|
else:
|
||||||
|
@ -459,9 +459,9 @@ class Parser(object):
|
||||||
self.feed(b"")
|
self.feed(b"")
|
||||||
self.data = self.decoder = None
|
self.data = self.decoder = None
|
||||||
if not self.finished:
|
if not self.finished:
|
||||||
raise IOError("image was incomplete")
|
raise OSError("image was incomplete")
|
||||||
if not self.image:
|
if not self.image:
|
||||||
raise IOError("cannot parse this image")
|
raise OSError("cannot parse this image")
|
||||||
if self.data:
|
if self.data:
|
||||||
# incremental parsing not possible; reopen the file
|
# incremental parsing not possible; reopen the file
|
||||||
# not that we have all data
|
# not that we have all data
|
||||||
|
@ -517,7 +517,7 @@ def _save(im, fp, tile, bufsize=0):
|
||||||
if s:
|
if s:
|
||||||
break
|
break
|
||||||
if s < 0:
|
if s < 0:
|
||||||
raise IOError("encoder error %d when writing image file" % s)
|
raise OSError("encoder error %d when writing image file" % s)
|
||||||
e.cleanup()
|
e.cleanup()
|
||||||
else:
|
else:
|
||||||
# slight speedup: compress to real file object
|
# slight speedup: compress to real file object
|
||||||
|
@ -532,7 +532,7 @@ def _save(im, fp, tile, bufsize=0):
|
||||||
else:
|
else:
|
||||||
s = e.encode_to_file(fh, bufsize)
|
s = e.encode_to_file(fh, bufsize)
|
||||||
if s < 0:
|
if s < 0:
|
||||||
raise IOError("encoder error %d when writing image file" % s)
|
raise OSError("encoder error %d when writing image file" % s)
|
||||||
e.cleanup()
|
e.cleanup()
|
||||||
if hasattr(fp, "flush"):
|
if hasattr(fp, "flush"):
|
||||||
fp.flush()
|
fp.flush()
|
||||||
|
@ -562,7 +562,7 @@ def _safe_read(fp, size):
|
||||||
return b"".join(data)
|
return b"".join(data)
|
||||||
|
|
||||||
|
|
||||||
class PyCodecState(object):
|
class PyCodecState:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.xsize = 0
|
self.xsize = 0
|
||||||
self.ysize = 0
|
self.ysize = 0
|
||||||
|
@ -573,7 +573,7 @@ class PyCodecState(object):
|
||||||
return (self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize)
|
return (self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize)
|
||||||
|
|
||||||
|
|
||||||
class PyDecoder(object):
|
class PyDecoder:
|
||||||
"""
|
"""
|
||||||
Python implementation of a format decoder. Override this class and
|
Python implementation of a format decoder. Override this class and
|
||||||
add the decoding logic in the `decode` method.
|
add the decoding logic in the `decode` method.
|
||||||
|
|
|
@ -14,9 +14,6 @@
|
||||||
#
|
#
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -25,7 +22,7 @@ except ImportError: # pragma: no cover
|
||||||
numpy = None
|
numpy = None
|
||||||
|
|
||||||
|
|
||||||
class Filter(object):
|
class Filter:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -498,7 +495,7 @@ class Color3DLUT(MultibandFilter):
|
||||||
r / (size1D - 1),
|
r / (size1D - 1),
|
||||||
g / (size2D - 1),
|
g / (size2D - 1),
|
||||||
b / (size3D - 1),
|
b / (size3D - 1),
|
||||||
*values
|
*values,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
values = callback(*values)
|
values = callback(*values)
|
||||||
|
|
|
@ -31,13 +31,13 @@ import sys
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from . import Image
|
from . import Image
|
||||||
from ._util import isDirectory, isPath, py3
|
from ._util import isDirectory, isPath
|
||||||
|
|
||||||
LAYOUT_BASIC = 0
|
LAYOUT_BASIC = 0
|
||||||
LAYOUT_RAQM = 1
|
LAYOUT_RAQM = 1
|
||||||
|
|
||||||
|
|
||||||
class _imagingft_not_installed(object):
|
class _imagingft_not_installed:
|
||||||
# module placeholder
|
# module placeholder
|
||||||
def __getattr__(self, id):
|
def __getattr__(self, id):
|
||||||
raise ImportError("The _imagingft C module is not installed")
|
raise ImportError("The _imagingft C module is not installed")
|
||||||
|
@ -65,7 +65,7 @@ except ImportError:
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class ImageFont(object):
|
class ImageFont:
|
||||||
"PIL font wrapper"
|
"PIL font wrapper"
|
||||||
|
|
||||||
def _load_pilfont(self, filename):
|
def _load_pilfont(self, filename):
|
||||||
|
@ -81,7 +81,7 @@ class ImageFont(object):
|
||||||
if image and image.mode in ("1", "L"):
|
if image and image.mode in ("1", "L"):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise IOError("cannot find glyph data file")
|
raise OSError("cannot find glyph data file")
|
||||||
|
|
||||||
self.file = fullname
|
self.file = fullname
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ class ImageFont(object):
|
||||||
# <b>truetype</b> factory function to create font objects.
|
# <b>truetype</b> factory function to create font objects.
|
||||||
|
|
||||||
|
|
||||||
class FreeTypeFont(object):
|
class FreeTypeFont:
|
||||||
"FreeType font wrapper (requires _imagingft service)"
|
"FreeType font wrapper (requires _imagingft service)"
|
||||||
|
|
||||||
def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None):
|
def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None):
|
||||||
|
@ -544,7 +544,7 @@ class FreeTypeFont(object):
|
||||||
raise NotImplementedError("FreeType 2.9.1 or greater is required")
|
raise NotImplementedError("FreeType 2.9.1 or greater is required")
|
||||||
|
|
||||||
|
|
||||||
class TransposedFont(object):
|
class TransposedFont:
|
||||||
"Wrapper for writing rotated or mirrored text"
|
"Wrapper for writing rotated or mirrored text"
|
||||||
|
|
||||||
def __init__(self, font, orientation=None):
|
def __init__(self, font, orientation=None):
|
||||||
|
@ -640,7 +640,7 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return freetype(font)
|
return freetype(font)
|
||||||
except IOError:
|
except OSError:
|
||||||
if not isPath(font):
|
if not isPath(font):
|
||||||
raise
|
raise
|
||||||
ttf_filename = os.path.basename(font)
|
ttf_filename = os.path.basename(font)
|
||||||
|
@ -697,15 +697,12 @@ def load_path(filename):
|
||||||
for directory in sys.path:
|
for directory in sys.path:
|
||||||
if isDirectory(directory):
|
if isDirectory(directory):
|
||||||
if not isinstance(filename, str):
|
if not isinstance(filename, str):
|
||||||
if py3:
|
filename = filename.decode("utf-8")
|
||||||
filename = filename.decode("utf-8")
|
|
||||||
else:
|
|
||||||
filename = filename.encode("utf-8")
|
|
||||||
try:
|
try:
|
||||||
return load(os.path.join(directory, filename))
|
return load(os.path.join(directory, filename))
|
||||||
except IOError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
raise IOError("cannot find font file")
|
raise OSError("cannot find font file")
|
||||||
|
|
||||||
|
|
||||||
def load_default():
|
def load_default():
|
||||||
|
|
|
@ -15,15 +15,9 @@
|
||||||
# See the README file for information on usage and redistribution.
|
# See the README file for information on usage and redistribution.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import builtins
|
||||||
|
|
||||||
from . import Image, _imagingmath
|
from . import Image, _imagingmath
|
||||||
from ._util import py3
|
|
||||||
|
|
||||||
try:
|
|
||||||
import builtins
|
|
||||||
except ImportError:
|
|
||||||
import __builtin__
|
|
||||||
|
|
||||||
builtins = __builtin__
|
|
||||||
|
|
||||||
VERBOSE = 0
|
VERBOSE = 0
|
||||||
|
|
||||||
|
@ -32,7 +26,7 @@ def _isconstant(v):
|
||||||
return isinstance(v, (int, float))
|
return isinstance(v, (int, float))
|
||||||
|
|
||||||
|
|
||||||
class _Operand(object):
|
class _Operand:
|
||||||
"""Wraps an image operand, providing standard operators"""
|
"""Wraps an image operand, providing standard operators"""
|
||||||
|
|
||||||
def __init__(self, im):
|
def __init__(self, im):
|
||||||
|
@ -101,11 +95,6 @@ class _Operand(object):
|
||||||
# an image is "true" if it contains at least one non-zero pixel
|
# an image is "true" if it contains at least one non-zero pixel
|
||||||
return self.im.getbbox() is not None
|
return self.im.getbbox() is not None
|
||||||
|
|
||||||
if not py3:
|
|
||||||
# Provide __nonzero__ for pre-Py3k
|
|
||||||
__nonzero__ = __bool__
|
|
||||||
del __bool__
|
|
||||||
|
|
||||||
def __abs__(self):
|
def __abs__(self):
|
||||||
return self.apply("abs", self)
|
return self.apply("abs", self)
|
||||||
|
|
||||||
|
@ -152,13 +141,6 @@ class _Operand(object):
|
||||||
def __rpow__(self, other):
|
def __rpow__(self, other):
|
||||||
return self.apply("pow", other, self)
|
return self.apply("pow", other, self)
|
||||||
|
|
||||||
if not py3:
|
|
||||||
# Provide __div__ and __rdiv__ for pre-Py3k
|
|
||||||
__div__ = __truediv__
|
|
||||||
__rdiv__ = __rtruediv__
|
|
||||||
del __truediv__
|
|
||||||
del __rtruediv__
|
|
||||||
|
|
||||||
# bitwise
|
# bitwise
|
||||||
def __invert__(self):
|
def __invert__(self):
|
||||||
return self.apply("invert", self)
|
return self.apply("invert", self)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
_modes = None
|
_modes = None
|
||||||
|
|
||||||
|
|
||||||
class ModeDescriptor(object):
|
class ModeDescriptor:
|
||||||
"""Wrapper for mode strings."""
|
"""Wrapper for mode strings."""
|
||||||
|
|
||||||
def __init__(self, mode, bands, basemode, basetype):
|
def __init__(self, mode, bands, basemode, basetype):
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
|
# Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from . import Image, _imagingmorph
|
from . import Image, _imagingmorph
|
||||||
|
@ -27,7 +25,7 @@ MIRROR_MATRIX = [
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
class LutBuilder(object):
|
class LutBuilder:
|
||||||
"""A class for building a MorphLut from a descriptive language
|
"""A class for building a MorphLut from a descriptive language
|
||||||
|
|
||||||
The input patterns is a list of a strings sequences like these::
|
The input patterns is a list of a strings sequences like these::
|
||||||
|
@ -178,7 +176,7 @@ class LutBuilder(object):
|
||||||
return self.lut
|
return self.lut
|
||||||
|
|
||||||
|
|
||||||
class MorphOp(object):
|
class MorphOp:
|
||||||
"""A class for binary morphological operators"""
|
"""A class for binary morphological operators"""
|
||||||
|
|
||||||
def __init__(self, lut=None, op_name=None, patterns=None):
|
def __init__(self, lut=None, op_name=None, patterns=None):
|
||||||
|
|
|
@ -21,7 +21,6 @@ import functools
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
from . import Image
|
from . import Image
|
||||||
from ._util import isStringType
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# helpers
|
# helpers
|
||||||
|
@ -39,7 +38,7 @@ def _border(border):
|
||||||
|
|
||||||
|
|
||||||
def _color(color, mode):
|
def _color(color, mode):
|
||||||
if isStringType(color):
|
if isinstance(color, str):
|
||||||
from . import ImageColor
|
from . import ImageColor
|
||||||
|
|
||||||
color = ImageColor.getcolor(color, mode)
|
color = ImageColor.getcolor(color, mode)
|
||||||
|
@ -55,7 +54,7 @@ def _lut(image, lut):
|
||||||
lut = lut + lut + lut
|
lut = lut + lut + lut
|
||||||
return image.point(lut)
|
return image.point(lut)
|
||||||
else:
|
else:
|
||||||
raise IOError("not supported for this image mode")
|
raise OSError("not supported for this image mode")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -21,7 +21,7 @@ import array
|
||||||
from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
|
from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
|
||||||
|
|
||||||
|
|
||||||
class ImagePalette(object):
|
class ImagePalette:
|
||||||
"""
|
"""
|
||||||
Color palette for palette mapped images
|
Color palette for palette mapped images
|
||||||
|
|
||||||
|
@ -216,6 +216,6 @@ def load(filename):
|
||||||
# traceback.print_exc()
|
# traceback.print_exc()
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise IOError("cannot load palette")
|
raise OSError("cannot load palette")
|
||||||
|
|
||||||
return lut # data, rawmode
|
return lut # data, rawmode
|
||||||
|
|
|
@ -20,7 +20,7 @@ import sys
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from . import Image
|
from . import Image
|
||||||
from ._util import isPath, py3
|
from ._util import isPath
|
||||||
|
|
||||||
qt_versions = [["5", "PyQt5"], ["side2", "PySide2"]]
|
qt_versions = [["5", "PyQt5"], ["side2", "PySide2"]]
|
||||||
|
|
||||||
|
@ -65,11 +65,7 @@ def fromqimage(im):
|
||||||
im.save(buffer, "ppm")
|
im.save(buffer, "ppm")
|
||||||
|
|
||||||
b = BytesIO()
|
b = BytesIO()
|
||||||
try:
|
b.write(buffer.data())
|
||||||
b.write(buffer.data())
|
|
||||||
except TypeError:
|
|
||||||
# workaround for Python 2
|
|
||||||
b.write(str(buffer.data()))
|
|
||||||
buffer.close()
|
buffer.close()
|
||||||
b.seek(0)
|
b.seek(0)
|
||||||
|
|
||||||
|
@ -125,10 +121,7 @@ def _toqclass_helper(im):
|
||||||
# handle filename, if given instead of image name
|
# handle filename, if given instead of image name
|
||||||
if hasattr(im, "toUtf8"):
|
if hasattr(im, "toUtf8"):
|
||||||
# FIXME - is this really the best way to do this?
|
# FIXME - is this really the best way to do this?
|
||||||
if py3:
|
im = str(im.toUtf8(), "utf-8")
|
||||||
im = str(im.toUtf8(), "utf-8")
|
|
||||||
else:
|
|
||||||
im = unicode(im.toUtf8(), "utf-8") # noqa: F821
|
|
||||||
if isPath(im):
|
if isPath(im):
|
||||||
im = Image.open(im)
|
im = Image.open(im)
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user