Merge branch 'master' into HEAD
|
@ -9,3 +9,6 @@ exclude_lines =
|
||||||
# Don't complain if non-runnable code isn't run:
|
# Don't complain if non-runnable code isn't run:
|
||||||
if 0:
|
if 0:
|
||||||
if __name__ == .__main__.:
|
if __name__ == .__main__.:
|
||||||
|
# Don't complain about debug code
|
||||||
|
if Image.DEBUG:
|
||||||
|
if DEBUG:
|
13
.travis.yml
|
@ -3,7 +3,7 @@ language: python
|
||||||
notifications:
|
notifications:
|
||||||
irc: "chat.freenode.net#pil"
|
irc: "chat.freenode.net#pil"
|
||||||
|
|
||||||
env: MAX_CONCURRENCY=4
|
env: MAX_CONCURRENCY=4 NOSE_PROCESSES=4 NOSE_PROCESS_TIMEOUT=30
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- "pypy"
|
- "pypy"
|
||||||
|
@ -14,9 +14,9 @@ python:
|
||||||
- 3.4
|
- 3.4
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake"
|
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake"
|
||||||
- "pip install cffi"
|
- "pip install cffi"
|
||||||
- "pip install coveralls nose pyroma"
|
- "pip install coveralls nose pyroma nose-cov"
|
||||||
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi
|
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi
|
||||||
|
|
||||||
# webp
|
# webp
|
||||||
|
@ -35,10 +35,13 @@ script:
|
||||||
- if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then time nosetests Tests/test_*.py; fi
|
- if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then time nosetests Tests/test_*.py; fi
|
||||||
|
|
||||||
# Cover the others
|
# Cover the others
|
||||||
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then time coverage run --append --include=PIL/* selftest.py; fi
|
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then coverage run --parallel-mode --include=PIL/* selftest.py; fi
|
||||||
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then time coverage run --append --include=PIL/* -m nose Tests/test_*.py; fi
|
# write html report, then ignore. Coverage needs to be combined first
|
||||||
|
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then nosetests --with-cov --cov='PIL/' --cov-report=html Tests/test_*.py; fi
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
|
- ls -l .coverage*
|
||||||
|
- coverage combine
|
||||||
- coverage report
|
- coverage report
|
||||||
- coveralls
|
- coveralls
|
||||||
- pip install pep8 pyflakes
|
- pip install pep8 pyflakes
|
||||||
|
|
39
CHANGES.rst
|
@ -4,6 +4,12 @@ Changelog (Pillow)
|
||||||
2.5.0 (unreleased)
|
2.5.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Imagedraw rewrite
|
||||||
|
[terseus, wiredfool]
|
||||||
|
|
||||||
|
- Add support for multithreaded test execution
|
||||||
|
[wiredfool]
|
||||||
|
|
||||||
- Prevent shell injection #748
|
- Prevent shell injection #748
|
||||||
[mbrown1413, wiredfool]
|
[mbrown1413, wiredfool]
|
||||||
|
|
||||||
|
@ -495,6 +501,10 @@ Changelog (Pillow)
|
||||||
2.0.0 (2013-03-15)
|
2.0.0 (2013-03-15)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
.. Note:: Special thanks to Christoph Gohlke and Eric Soroos for assisting with a pre-PyCon 2013 release!
|
||||||
|
|
||||||
|
- Many other bug fixes and enhancements by many other people.
|
||||||
|
|
||||||
- Add Python 3 support. (Pillow >= 2.0.0 supports Python 2.6, 2.7, 3.2, 3.3. Pillow < 2.0.0 supports Python 2.4, 2.5, 2.6, 2.7.)
|
- Add Python 3 support. (Pillow >= 2.0.0 supports Python 2.6, 2.7, 3.2, 3.3. Pillow < 2.0.0 supports Python 2.4, 2.5, 2.6, 2.7.)
|
||||||
[fluggo]
|
[fluggo]
|
||||||
|
|
||||||
|
@ -518,10 +528,6 @@ Changelog (Pillow)
|
||||||
- Added support for PNG images with transparency palette.
|
- Added support for PNG images with transparency palette.
|
||||||
[d-schmidt]
|
[d-schmidt]
|
||||||
|
|
||||||
- Many other bug fixes and enhancements by many other people (see commit log and/or docs/CONTRIBUTORS.txt).
|
|
||||||
|
|
||||||
- Special thanks to Christoph Gohlke and Eric Soroos for rallying around the effort to get a release out for PyCon 2013.
|
|
||||||
|
|
||||||
1.7.8 (2012-11-01)
|
1.7.8 (2012-11-01)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -594,44 +600,55 @@ Changelog (Pillow)
|
||||||
[elro]
|
[elro]
|
||||||
|
|
||||||
- Doc fixes
|
- Doc fixes
|
||||||
|
[aclark]
|
||||||
|
|
||||||
1.5 (11/28/2010)
|
1.5 (11/28/2010)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
- Module and package fixes
|
- Module and package fixes
|
||||||
|
[aclark]
|
||||||
|
|
||||||
1.4 (11/28/2010)
|
1.4 (11/28/2010)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
- Doc fixes
|
- Doc fixes
|
||||||
|
[aclark]
|
||||||
|
|
||||||
1.3 (11/28/2010)
|
1.3 (11/28/2010)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
- Add support for /lib64 and /usr/lib64 library directories on Linux
|
- Add support for /lib64 and /usr/lib64 library directories on Linux
|
||||||
|
[aclark]
|
||||||
|
|
||||||
- Doc fixes
|
- Doc fixes
|
||||||
|
[aclark]
|
||||||
|
|
||||||
1.2 (08/02/2010)
|
1.2 (08/02/2010)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
- On OS X also check for freetype2 in the X11 path [jezdez]
|
- On OS X also check for freetype2 in the X11 path
|
||||||
- Doc fixes [aclark]
|
[jezdez]
|
||||||
|
|
||||||
|
- Doc fixes
|
||||||
|
[aclark]
|
||||||
|
|
||||||
1.1 (07/31/2010)
|
1.1 (07/31/2010)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
- Removed setuptools_hg requirement
|
- Removed setuptools_hg requirement
|
||||||
|
[aclark]
|
||||||
|
|
||||||
- Doc fixes
|
- Doc fixes
|
||||||
|
[aclark]
|
||||||
|
|
||||||
1.0 (07/30/2010)
|
1.0 (07/30/2010)
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
- Forked PIL based on Hanno Schlichting's re-packaging
|
- Remove support for ``import Image``, etc. from the standard namespace. ``from PIL import Image`` etc. now required.
|
||||||
(http://dist.plone.org/thirdparty/PIL-1.1.7.tar.gz)
|
- Forked PIL based on `Hanno Schlichting's re-packaging <http://dist.plone.org/thirdparty/PIL-1.1.7.tar.gz>`_
|
||||||
|
[aclark]
|
||||||
|
|
||||||
- Remove support for importing from the standard namespace
|
.. Note:: What follows is the original PIL 1.1.7 CHANGES
|
||||||
|
|
||||||
.. Note:: What follows is the original PIL 1.1.7 CHANGES file contents
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|
31
Makefile
|
@ -1,3 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
pre:
|
pre:
|
||||||
virtualenv .
|
virtualenv .
|
||||||
bin/pip install -r requirements.txt
|
bin/pip install -r requirements.txt
|
||||||
|
@ -9,3 +11,32 @@ pre:
|
||||||
check-manifest
|
check-manifest
|
||||||
pyroma .
|
pyroma .
|
||||||
viewdoc
|
viewdoc
|
||||||
|
|
||||||
|
clean:
|
||||||
|
python setup.py clean
|
||||||
|
rm PIL/*.so || true
|
||||||
|
find . -name __pycache__ | xargs rm -r
|
||||||
|
|
||||||
|
install:
|
||||||
|
python setup.py install
|
||||||
|
python selftest.py --installed
|
||||||
|
|
||||||
|
test: install
|
||||||
|
python test-installed.py
|
||||||
|
|
||||||
|
inplace: clean
|
||||||
|
python setup.py build_ext --inplace
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
# requires nose-cov
|
||||||
|
coverage erase
|
||||||
|
coverage run --parallel-mode --include=PIL/* selftest.py
|
||||||
|
nosetests --with-cov --cov='PIL/' --cov-report=html Tests/test_*.py
|
||||||
|
# doesn't combine properly before report,
|
||||||
|
# writing report instead of displaying invalid report
|
||||||
|
rm -r htmlcov || true
|
||||||
|
coverage combine
|
||||||
|
coverage report
|
||||||
|
|
||||||
|
test-dep:
|
||||||
|
pip install coveralls nose nose-cov pep8 pyflakes
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# ;-)
|
# ;-)
|
||||||
|
|
||||||
VERSION = '1.1.7' # PIL version
|
VERSION = '1.1.7' # PIL version
|
||||||
PILLOW_VERSION = '2.4.0' # Pillow
|
PILLOW_VERSION = '2.5.0' # Pillow
|
||||||
|
|
||||||
_plugins = ['BmpImagePlugin',
|
_plugins = ['BmpImagePlugin',
|
||||||
'BufrStubImagePlugin',
|
'BufrStubImagePlugin',
|
||||||
|
|
|
@ -3,7 +3,7 @@ Pillow
|
||||||
|
|
||||||
*Python Imaging Library (Fork)*
|
*Python Imaging Library (Fork)*
|
||||||
|
|
||||||
Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. For more information, please `read the documentation <http://pillow.readthedocs.org/>`_.
|
||||||
|
|
||||||
.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master
|
.. image:: https://travis-ci.org/python-pillow/Pillow.svg?branch=master
|
||||||
:target: https://travis-ci.org/python-pillow/Pillow
|
:target: https://travis-ci.org/python-pillow/Pillow
|
||||||
|
@ -20,4 +20,3 @@ Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Pyt
|
||||||
.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.png?branch=master
|
.. image:: https://coveralls.io/repos/python-pillow/Pillow/badge.png?branch=master
|
||||||
:target: https://coveralls.io/r/python-pillow/Pillow?branch=master
|
:target: https://coveralls.io/r/python-pillow/Pillow?branch=master
|
||||||
|
|
||||||
The documentation is hosted at http://pillow.readthedocs.org/. It contains installation instructions, tutorials, reference, compatibility details, and more.
|
|
||||||
|
|
|
@ -3,39 +3,30 @@ Helper functions.
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
|
||||||
if sys.version_info[:2] <= (2, 6):
|
if sys.version_info[:2] <= (2, 6):
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
else:
|
else:
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
# This should be imported into every test_XXX.py file to report
|
|
||||||
# any remaining temp files at the end of the run.
|
|
||||||
def tearDownModule():
|
def tearDownModule():
|
||||||
import glob
|
#remove me later
|
||||||
import os
|
pass
|
||||||
import tempfile
|
|
||||||
temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
|
|
||||||
tempfiles = glob.glob(os.path.join(temp_root, "temp_*"))
|
|
||||||
if tempfiles:
|
|
||||||
print("===", "remaining temporary files")
|
|
||||||
for file in tempfiles:
|
|
||||||
print(file)
|
|
||||||
print("-"*68)
|
|
||||||
|
|
||||||
|
|
||||||
class PillowTestCase(unittest.TestCase):
|
class PillowTestCase(unittest.TestCase):
|
||||||
|
|
||||||
currentResult = None # holds last result object passed to run method
|
def __init__(self, *args, **kwargs):
|
||||||
_tempfiles = []
|
unittest.TestCase.__init__(self, *args, **kwargs)
|
||||||
|
self.currentResult = None # holds last result object passed to run method
|
||||||
|
|
||||||
def run(self, result=None):
|
def run(self, result=None):
|
||||||
self.addCleanup(self.delete_tempfiles)
|
|
||||||
self.currentResult = result # remember result for use later
|
self.currentResult = result # remember result for use later
|
||||||
unittest.TestCase.run(self, result) # call superclass run method
|
unittest.TestCase.run(self, result) # call superclass run method
|
||||||
|
|
||||||
def delete_tempfiles(self):
|
def delete_tempfile(self, path):
|
||||||
try:
|
try:
|
||||||
ok = self.currentResult.wasSuccessful()
|
ok = self.currentResult.wasSuccessful()
|
||||||
except AttributeError: # for nosetests
|
except AttributeError: # for nosetests
|
||||||
|
@ -44,19 +35,12 @@ class PillowTestCase(unittest.TestCase):
|
||||||
|
|
||||||
if ok:
|
if ok:
|
||||||
# only clean out tempfiles if test passed
|
# only clean out tempfiles if test passed
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import tempfile
|
|
||||||
for file in self._tempfiles:
|
|
||||||
try:
|
try:
|
||||||
os.remove(file)
|
os.remove(path)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass # report?
|
pass # report?
|
||||||
temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
|
else:
|
||||||
try:
|
print("=== orphaned temp file: %s" %path)
|
||||||
os.rmdir(temp_root)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def assert_almost_equal(self, a, b, msg=None, eps=1e-6):
|
def assert_almost_equal(self, a, b, msg=None, eps=1e-6):
|
||||||
self.assertLess(
|
self.assertLess(
|
||||||
|
@ -139,27 +123,13 @@ class PillowTestCase(unittest.TestCase):
|
||||||
self.assertTrue(found)
|
self.assertTrue(found)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def tempfile(self, template, *extra):
|
def tempfile(self, template):
|
||||||
import os
|
assert template[:5] in ("temp.", "temp_")
|
||||||
import os.path
|
(fd, path) = tempfile.mkstemp(template[4:], template[:4])
|
||||||
import sys
|
os.close(fd)
|
||||||
import tempfile
|
|
||||||
files = []
|
|
||||||
root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
|
|
||||||
try:
|
|
||||||
os.mkdir(root)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
for temp in (template,) + extra:
|
|
||||||
assert temp[:5] in ("temp.", "temp_")
|
|
||||||
name = os.path.basename(sys.argv[0])
|
|
||||||
name = temp[:4] + os.path.splitext(name)[0][4:]
|
|
||||||
name = name + "_%d" % len(self._tempfiles) + temp[4:]
|
|
||||||
name = os.path.join(root, name)
|
|
||||||
files.append(name)
|
|
||||||
self._tempfiles.extend(files)
|
|
||||||
return files[0]
|
|
||||||
|
|
||||||
|
self.addCleanup(self.delete_tempfile, path)
|
||||||
|
return path
|
||||||
|
|
||||||
# helpers
|
# helpers
|
||||||
|
|
||||||
|
|
BIN
Tests/images/imagedraw/line_horizontal_slope1px_w2px.png
Normal file
After Width: | Height: | Size: 147 B |
BIN
Tests/images/imagedraw/line_horizontal_w101px.png
Normal file
After Width: | Height: | Size: 368 B |
BIN
Tests/images/imagedraw/line_horizontal_w2px_inverted.png
Normal file
After Width: | Height: | Size: 143 B |
BIN
Tests/images/imagedraw/line_horizontal_w2px_normal.png
Normal file
After Width: | Height: | Size: 141 B |
BIN
Tests/images/imagedraw/line_horizontal_w3px.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
Tests/images/imagedraw/line_oblique_45_w3px_a.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
Tests/images/imagedraw/line_oblique_45_w3px_b.png
Normal file
After Width: | Height: | Size: 179 B |
BIN
Tests/images/imagedraw/line_vertical_slope1px_w2px.png
Normal file
After Width: | Height: | Size: 153 B |
BIN
Tests/images/imagedraw/line_vertical_w101px.png
Normal file
After Width: | Height: | Size: 438 B |
BIN
Tests/images/imagedraw/line_vertical_w2px_inverted.png
Normal file
After Width: | Height: | Size: 145 B |
BIN
Tests/images/imagedraw/line_vertical_w2px_normal.png
Normal file
After Width: | Height: | Size: 144 B |
BIN
Tests/images/imagedraw/line_vertical_w3px.png
Normal file
After Width: | Height: | Size: 142 B |
BIN
Tests/images/imagedraw/square.png
Normal file
After Width: | Height: | Size: 135 B |
BIN
Tests/images/imagedraw/triangle_right.png
Normal file
After Width: | Height: | Size: 168 B |
Before Width: | Height: | Size: 491 B After Width: | Height: | Size: 466 B |
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 247 B |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 293 B |
|
@ -1,3 +1,5 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
from helper import *
|
from helper import *
|
||||||
|
|
||||||
# This test is not run automatically.
|
# This test is not run automatically.
|
||||||
|
@ -18,6 +20,7 @@ YDIM = 32769
|
||||||
XDIM = 48000
|
XDIM = 48000
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64 bit system")
|
||||||
class LargeMemoryNumpyTest(PillowTestCase):
|
class LargeMemoryNumpyTest(PillowTestCase):
|
||||||
|
|
||||||
def _write_png(self, xdim, ydim):
|
def _write_png(self, xdim, ydim):
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
from helper import *
|
from helper import *
|
||||||
|
|
||||||
# This test is not run automatically.
|
# This test is not run automatically.
|
||||||
|
@ -14,6 +16,7 @@ YDIM = 32769
|
||||||
XDIM = 48000
|
XDIM = 48000
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64 bit system")
|
||||||
class LargeMemoryTest(PillowTestCase):
|
class LargeMemoryTest(PillowTestCase):
|
||||||
|
|
||||||
def _write_png(self, xdim, ydim):
|
def _write_png(self, xdim, ydim):
|
||||||
|
|
|
@ -22,7 +22,8 @@ class TestFontPcf(PillowTestCase):
|
||||||
self.assertIsInstance(font, FontFile.FontFile)
|
self.assertIsInstance(font, FontFile.FontFile)
|
||||||
self.assertEqual(len([_f for _f in font.glyph if _f]), 192)
|
self.assertEqual(len([_f for _f in font.glyph if _f]), 192)
|
||||||
|
|
||||||
tempname = self.tempfile("temp.pil", "temp.pbm")
|
tempname = self.tempfile("temp.pil")
|
||||||
|
self.addCleanup(self.delete_tempfile, tempname[:-4]+'.pbm')
|
||||||
font.save(tempname)
|
font.save(tempname)
|
||||||
return tempname
|
return tempname
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,13 @@ from helper import unittest, PillowTestCase, tearDownModule, lena
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL import ImageColor
|
from PIL import ImageColor
|
||||||
from PIL import ImageDraw
|
from PIL import ImageDraw
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
BLACK = (0, 0, 0)
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
GRAY = (190, 190, 190)
|
||||||
|
DEFAULT_MODE = 'RGB'
|
||||||
|
IMAGES_PATH = os.path.join('Tests', 'images', 'imagedraw')
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -249,7 +256,129 @@ class TestImageDraw(PillowTestCase):
|
||||||
im, Image.open("Tests/images/imagedraw_floodfill2.png"))
|
im, Image.open("Tests/images/imagedraw_floodfill2.png"))
|
||||||
|
|
||||||
|
|
||||||
|
def create_base_image_draw(self, size,
|
||||||
|
mode=DEFAULT_MODE,
|
||||||
|
background1=WHITE,
|
||||||
|
background2=GRAY):
|
||||||
|
img = Image.new(mode, size, background1)
|
||||||
|
for x in range(0, size[0]):
|
||||||
|
for y in range(0, size[1]):
|
||||||
|
if (x + y) % 2 == 0:
|
||||||
|
img.putpixel((x, y), background2)
|
||||||
|
return (img, ImageDraw.Draw(img))
|
||||||
|
|
||||||
|
|
||||||
|
def test_square(self):
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'square.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((10, 10))
|
||||||
|
draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK)
|
||||||
|
self.assert_image_equal(img, expected, 'square as normal polygon failed')
|
||||||
|
img, draw = self.create_base_image_draw((10, 10))
|
||||||
|
draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK)
|
||||||
|
self.assert_image_equal(img, expected, 'square as inverted polygon failed')
|
||||||
|
img, draw = self.create_base_image_draw((10, 10))
|
||||||
|
draw.rectangle((2, 2, 7, 7), BLACK)
|
||||||
|
self.assert_image_equal(img, expected, 'square as normal rectangle failed')
|
||||||
|
img, draw = self.create_base_image_draw((10, 10))
|
||||||
|
draw.rectangle((7, 7, 2, 2), BLACK)
|
||||||
|
self.assert_image_equal(img, expected, 'square as inverted rectangle failed')
|
||||||
|
|
||||||
|
|
||||||
|
def test_triangle_right(self):
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'triangle_right.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK)
|
||||||
|
self.assert_image_equal(img, expected, 'triangle right failed')
|
||||||
|
|
||||||
|
|
||||||
|
def test_line_horizontal(self):
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_horizontal_w2px_normal.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 14, 5), BLACK, 2)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth horizontal normal 2px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_horizontal_w2px_inverted.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((14, 5, 5, 5), BLACK, 2)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth horizontal inverted 2px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_horizontal_w3px.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 14, 5), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth horizontal normal 3px wide failed')
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((14, 5, 5, 5), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth horizontal inverted 3px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_horizontal_w101px.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((200, 110))
|
||||||
|
draw.line((5, 55, 195, 55), BLACK, 101)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth horizontal 101px wide failed')
|
||||||
|
|
||||||
|
def test_line_h_s1_w2(self):
|
||||||
|
self.skipTest('failing')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_horizontal_slope1px_w2px.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 14, 6), BLACK, 2)
|
||||||
|
self.assert_image_equal(img, expected, 'line horizontal 1px slope 2px wide failed')
|
||||||
|
|
||||||
|
|
||||||
|
def test_line_vertical(self):
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_vertical_w2px_normal.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 5, 14), BLACK, 2)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth vertical normal 2px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_vertical_w2px_inverted.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 14, 5, 5), BLACK, 2)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth vertical inverted 2px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_vertical_w3px.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 5, 14), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth vertical normal 3px wide failed')
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 14, 5, 5), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth vertical inverted 3px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_vertical_w101px.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((110, 200))
|
||||||
|
draw.line((55, 5, 55, 195), BLACK, 101)
|
||||||
|
self.assert_image_equal(img, expected, 'line straigth vertical 101px wide failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_vertical_slope1px_w2px.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 6, 14), BLACK, 2)
|
||||||
|
self.assert_image_equal(img, expected, 'line vertical 1px slope 2px wide failed')
|
||||||
|
|
||||||
|
|
||||||
|
def test_line_oblique_45(self):
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_oblique_45_w3px_a.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 5, 14, 14), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line oblique 45 normal 3px wide A failed')
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((14, 14, 5, 5), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line oblique 45 inverted 3px wide A failed')
|
||||||
|
expected = Image.open(os.path.join(IMAGES_PATH, 'line_oblique_45_w3px_b.png'))
|
||||||
|
expected.load()
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((14, 5, 5, 14), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line oblique 45 normal 3px wide B failed')
|
||||||
|
img, draw = self.create_base_image_draw((20, 20))
|
||||||
|
draw.line((5, 14, 14, 5), BLACK, 3)
|
||||||
|
self.assert_image_equal(img, expected, 'line oblique 45 inverted 3px wide B failed')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
# End of file
|
# End of file
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PILLOW_VERSION "2.4.0"
|
#define PILLOW_VERSION "2.5.0"
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
|
|
17
docs/developer.rst
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Developer
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. Note:: When committing only trivial changes, please include [ci skip] in the commit message to avoid running tests on Travis-CI. Thank you!
|
||||||
|
|
||||||
|
|
||||||
|
Release
|
||||||
|
-------
|
||||||
|
|
||||||
|
Details about making a Pillow release.
|
||||||
|
|
||||||
|
Version number
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The version number is currently stored in 3 places::
|
||||||
|
|
||||||
|
PIL/__init__.py _imaging.c setup.py
|
|
@ -8,3 +8,4 @@ Guides
|
||||||
handbook/tutorial
|
handbook/tutorial
|
||||||
handbook/concepts
|
handbook/concepts
|
||||||
porting-pil-to-pillow
|
porting-pil-to-pillow
|
||||||
|
developer
|
||||||
|
|
|
@ -49,6 +49,13 @@
|
||||||
#define BLEND(mask, in1, in2, tmp1, tmp2)\
|
#define BLEND(mask, in1, in2, tmp1, tmp2)\
|
||||||
(MULDIV255(in1, 255 - mask, tmp1) + MULDIV255(in2, mask, tmp2))
|
(MULDIV255(in1, 255 - mask, tmp1) + MULDIV255(in2, mask, tmp2))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rounds around zero (up=away from zero, down=torwards zero)
|
||||||
|
* This guarantees that ROUND_UP|DOWN(f) == -ROUND_UP|DOWN(-f)
|
||||||
|
*/
|
||||||
|
#define ROUND_UP(f) ((int) ((f) >= 0.0 ? floor((f) + 0.5F) : -floor(fabs(f) + 0.5F)))
|
||||||
|
#define ROUND_DOWN(f) ((int) ((f) >= 0.0 ? ceil((f) - 0.5F) : -ceil(fabs(f) - 0.5F)))
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Primitives */
|
/* Primitives */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -61,6 +68,9 @@ typedef struct {
|
||||||
float dx;
|
float dx;
|
||||||
} Edge;
|
} Edge;
|
||||||
|
|
||||||
|
/* Type used in "polygon*" functions */
|
||||||
|
typedef void (*hline_handler)(Imaging, int, int, int, int);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
point8(Imaging im, int x, int y, int ink)
|
point8(Imaging im, int x, int y, int ink)
|
||||||
{
|
{
|
||||||
|
@ -403,177 +413,100 @@ x_cmp(const void *x0, const void *x1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filled polygon draw function using scan line algorithm.
|
||||||
|
*/
|
||||||
static inline int
|
static inline int
|
||||||
polygon8(Imaging im, int n, Edge *e, int ink, int eofill)
|
polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill,
|
||||||
|
hline_handler hline)
|
||||||
{
|
{
|
||||||
int i, j;
|
|
||||||
float *xx;
|
|
||||||
int ymin, ymax;
|
|
||||||
float y;
|
|
||||||
|
|
||||||
if (n <= 0)
|
Edge** edge_table;
|
||||||
|
float* xx;
|
||||||
|
int edge_count = 0;
|
||||||
|
int ymin = im->ysize - 1;
|
||||||
|
int ymax = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Find upper and lower polygon boundary (within image) */
|
|
||||||
|
|
||||||
ymin = e[0].ymin;
|
|
||||||
ymax = e[0].ymax;
|
|
||||||
for (i = 1; i < n; i++) {
|
|
||||||
if (e[i].ymin < ymin) ymin = e[i].ymin;
|
|
||||||
if (e[i].ymax > ymax) ymax = e[i].ymax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ymin < 0)
|
/* Initialize the edge table and find polygon boundaries */
|
||||||
ymin = 0;
|
edge_table = malloc(sizeof(Edge*) * n);
|
||||||
if (ymax >= im->ysize)
|
if (!edge_table) {
|
||||||
ymax = im->ysize-1;
|
|
||||||
|
|
||||||
/* Process polygon edges */
|
|
||||||
|
|
||||||
xx = malloc(n * sizeof(float));
|
|
||||||
if (!xx)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
for (;ymin <= ymax; ymin++) {
|
|
||||||
y = ymin+0.5F;
|
|
||||||
for (i = j = 0; i < n; i++)
|
|
||||||
if (y >= e[i].ymin && y <= e[i].ymax) {
|
|
||||||
if (e[i].d == 0)
|
|
||||||
hline8(im, e[i].xmin, ymin, e[i].xmax, ink);
|
|
||||||
else
|
|
||||||
xx[j++] = (y-e[i].y0) * e[i].dx + e[i].x0;
|
|
||||||
}
|
}
|
||||||
if (j == 2) {
|
|
||||||
if (xx[0] < xx[1])
|
for (i = 0; i < n; i++) {
|
||||||
hline8(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
|
/* This causes that the pixels of horizontal edges are drawn twice :(
|
||||||
else
|
* but without it there are inconsistencies in ellipses */
|
||||||
hline8(im, CEIL(xx[1]-0.5), ymin, FLOOR(xx[0]+0.5), ink);
|
if (e[i].ymin == e[i].ymax) {
|
||||||
} else {
|
(*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ymin > e[i].ymin) {
|
||||||
|
ymin = e[i].ymin;
|
||||||
|
}
|
||||||
|
if (ymax < e[i].ymax) {
|
||||||
|
ymax = e[i].ymax;
|
||||||
|
}
|
||||||
|
edge_table[edge_count++] = (e + i);
|
||||||
|
}
|
||||||
|
if (ymin < 0) {
|
||||||
|
ymin = 0;
|
||||||
|
}
|
||||||
|
if (ymax >= im->ysize) {
|
||||||
|
ymax = im->ysize - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the edge table with a scan line searching for intersections */
|
||||||
|
xx = malloc(sizeof(float) * edge_count * 2);
|
||||||
|
if (!xx) {
|
||||||
|
free(edge_table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (; ymin <= ymax; ymin++) {
|
||||||
|
int j = 0;
|
||||||
|
for (i = 0; i < edge_count; i++) {
|
||||||
|
Edge* current = edge_table[i];
|
||||||
|
if (ymin >= current->ymin && ymin <= current->ymax) {
|
||||||
|
xx[j++] = (ymin - current->y0) * current->dx + current->x0;
|
||||||
|
}
|
||||||
|
/* Needed to draw consistent polygons */
|
||||||
|
if (ymin == current->ymax && ymin < ymax) {
|
||||||
|
xx[j] = xx[j - 1];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
qsort(xx, j, sizeof(float), x_cmp);
|
qsort(xx, j, sizeof(float), x_cmp);
|
||||||
for (i = 0; i < j-1 ; i += 2)
|
for (i = 1; i < j; i += 2) {
|
||||||
hline8(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
|
(*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(xx);
|
free(xx);
|
||||||
|
free(edge_table);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
polygon8(Imaging im, int n, Edge *e, int ink, int eofill)
|
||||||
|
{
|
||||||
|
return polygon_generic(im, n, e, ink, eofill, hline8);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
polygon32(Imaging im, int n, Edge *e, int ink, int eofill)
|
polygon32(Imaging im, int n, Edge *e, int ink, int eofill)
|
||||||
{
|
{
|
||||||
int i, j;
|
return polygon_generic(im, n, e, ink, eofill, hline32);
|
||||||
float *xx;
|
|
||||||
int ymin, ymax;
|
|
||||||
float y;
|
|
||||||
|
|
||||||
if (n <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Find upper and lower polygon boundary (within image) */
|
|
||||||
|
|
||||||
ymin = e[0].ymin;
|
|
||||||
ymax = e[0].ymax;
|
|
||||||
for (i = 1; i < n; i++) {
|
|
||||||
if (e[i].ymin < ymin) ymin = e[i].ymin;
|
|
||||||
if (e[i].ymax > ymax) ymax = e[i].ymax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ymin < 0)
|
|
||||||
ymin = 0;
|
|
||||||
if (ymax >= im->ysize)
|
|
||||||
ymax = im->ysize-1;
|
|
||||||
|
|
||||||
/* Process polygon edges */
|
|
||||||
|
|
||||||
xx = malloc(n * sizeof(float));
|
|
||||||
if (!xx)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (;ymin <= ymax; ymin++) {
|
|
||||||
y = ymin+0.5F;
|
|
||||||
for (i = j = 0; i < n; i++) {
|
|
||||||
if (y >= e[i].ymin && y <= e[i].ymax) {
|
|
||||||
if (e[i].d == 0)
|
|
||||||
hline32(im, e[i].xmin, ymin, e[i].xmax, ink);
|
|
||||||
else
|
|
||||||
xx[j++] = (y-e[i].y0) * e[i].dx + e[i].x0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j == 2) {
|
|
||||||
if (xx[0] < xx[1])
|
|
||||||
hline32(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
|
|
||||||
else
|
|
||||||
hline32(im, CEIL(xx[1]-0.5), ymin, FLOOR(xx[0]+0.5), ink);
|
|
||||||
} else {
|
|
||||||
qsort(xx, j, sizeof(float), x_cmp);
|
|
||||||
for (i = 0; i < j-1 ; i += 2)
|
|
||||||
hline32(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(xx);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill)
|
polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill)
|
||||||
{
|
{
|
||||||
int i, j;
|
return polygon_generic(im, n, e, ink, eofill, hline32rgba);
|
||||||
float *xx;
|
|
||||||
int ymin, ymax;
|
|
||||||
float y;
|
|
||||||
|
|
||||||
if (n <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Find upper and lower polygon boundary (within image) */
|
|
||||||
|
|
||||||
ymin = e[0].ymin;
|
|
||||||
ymax = e[0].ymax;
|
|
||||||
for (i = 1; i < n; i++) {
|
|
||||||
if (e[i].ymin < ymin) ymin = e[i].ymin;
|
|
||||||
if (e[i].ymax > ymax) ymax = e[i].ymax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ymin < 0)
|
|
||||||
ymin = 0;
|
|
||||||
if (ymax >= im->ysize)
|
|
||||||
ymax = im->ysize-1;
|
|
||||||
|
|
||||||
/* Process polygon edges */
|
|
||||||
|
|
||||||
xx = malloc(n * sizeof(float));
|
|
||||||
if (!xx)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (;ymin <= ymax; ymin++) {
|
|
||||||
y = ymin+0.5F;
|
|
||||||
for (i = j = 0; i < n; i++) {
|
|
||||||
if (y >= e[i].ymin && y <= e[i].ymax) {
|
|
||||||
if (e[i].d == 0)
|
|
||||||
hline32rgba(im, e[i].xmin, ymin, e[i].xmax, ink);
|
|
||||||
else
|
|
||||||
xx[j++] = (y-e[i].y0) * e[i].dx + e[i].x0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j == 2) {
|
|
||||||
if (xx[0] < xx[1])
|
|
||||||
hline32rgba(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
|
|
||||||
else
|
|
||||||
hline32rgba(im, CEIL(xx[1]-0.5), ymin, FLOOR(xx[0]+0.5), ink);
|
|
||||||
} else {
|
|
||||||
qsort(xx, j, sizeof(float), x_cmp);
|
|
||||||
for (i = 0; i < j-1 ; i += 2)
|
|
||||||
hline32rgba(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(xx);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -663,11 +596,11 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
|
||||||
{
|
{
|
||||||
DRAW* draw;
|
DRAW* draw;
|
||||||
INT32 ink;
|
INT32 ink;
|
||||||
|
|
||||||
Edge e[4];
|
|
||||||
|
|
||||||
int dx, dy;
|
int dx, dy;
|
||||||
double d;
|
double big_hypotenuse, small_hypotenuse, ratio_max, ratio_min;
|
||||||
|
int dxmin, dxmax, dymin, dymax;
|
||||||
|
Edge e[4];
|
||||||
|
int vertices[4][2];
|
||||||
|
|
||||||
DRAWINIT();
|
DRAWINIT();
|
||||||
|
|
||||||
|
@ -678,24 +611,35 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
|
||||||
|
|
||||||
dx = x1-x0;
|
dx = x1-x0;
|
||||||
dy = y1-y0;
|
dy = y1-y0;
|
||||||
|
|
||||||
if (dx == 0 && dy == 0) {
|
if (dx == 0 && dy == 0) {
|
||||||
draw->point(im, x0, y0, ink);
|
draw->point(im, x0, y0, ink);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
d = width / sqrt((float) (dx*dx + dy*dy)) / 2.0;
|
big_hypotenuse = sqrt((double) (dx*dx + dy*dy));
|
||||||
|
small_hypotenuse = (width - 1) / 2.0;
|
||||||
|
ratio_max = ROUND_UP(small_hypotenuse) / big_hypotenuse;
|
||||||
|
ratio_min = ROUND_DOWN(small_hypotenuse) / big_hypotenuse;
|
||||||
|
|
||||||
dx = (int) floor(d * (y1-y0) + 0.5);
|
dxmin = ROUND_DOWN(ratio_min * dy);
|
||||||
dy = (int) floor(d * (x1-x0) + 0.5);
|
dxmax = ROUND_DOWN(ratio_max * dy);
|
||||||
|
dymin = ROUND_DOWN(ratio_min * dx);
|
||||||
|
dymax = ROUND_DOWN(ratio_max * dx);
|
||||||
|
{
|
||||||
|
int vertices[4][2] = {
|
||||||
|
{x0 - dxmin, y0 + dymax},
|
||||||
|
{x1 - dxmin, y1 + dymax},
|
||||||
|
{x1 + dxmax, y1 - dymin},
|
||||||
|
{x0 + dxmax, y0 - dymin}
|
||||||
|
};
|
||||||
|
|
||||||
add_edge(e+0, x0 - dx, y0 + dy, x1 - dx, y1 + dy);
|
add_edge(e+0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]);
|
||||||
add_edge(e+1, x1 - dx, y1 + dy, x1 + dx, y1 - dy);
|
add_edge(e+1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]);
|
||||||
add_edge(e+2, x1 + dx, y1 - dy, x0 + dx, y0 - dy);
|
add_edge(e+2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
|
||||||
add_edge(e+3, x0 + dx, y0 - dy, x0 - dx, y0 + dy);
|
add_edge(e+3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
|
||||||
|
|
||||||
draw->polygon(im, 4, e, ink, 0);
|
draw->polygon(im, 4, e, ink, 0);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#error Sorry, this library requires ANSI header files.
|
#error Sorry, this library requires ANSI header files.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(PIL_USE_INLINE)
|
#if defined(PIL_NO_INLINE)
|
||||||
#define inline
|
#define inline
|
||||||
#else
|
#else
|
||||||
#if defined(_MSC_VER) && !defined(__GNUC__)
|
#if defined(_MSC_VER) && !defined(__GNUC__)
|
||||||
|
|
6
setup.py
|
@ -90,7 +90,7 @@ except (ImportError, OSError):
|
||||||
|
|
||||||
|
|
||||||
NAME = 'Pillow'
|
NAME = 'Pillow'
|
||||||
VERSION = '2.4.0'
|
PILLOW_VERSION = '2.5.0'
|
||||||
TCL_ROOT = None
|
TCL_ROOT = None
|
||||||
JPEG_ROOT = None
|
JPEG_ROOT = None
|
||||||
JPEG2K_ROOT = None
|
JPEG2K_ROOT = None
|
||||||
|
@ -622,7 +622,7 @@ class pil_build_ext(build_ext):
|
||||||
print("-" * 68)
|
print("-" * 68)
|
||||||
print("PIL SETUP SUMMARY")
|
print("PIL SETUP SUMMARY")
|
||||||
print("-" * 68)
|
print("-" * 68)
|
||||||
print("version Pillow %s" % 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 %s %s" % (sys.platform, v[0].strip()))
|
||||||
for v in v[1:]:
|
for v in v[1:]:
|
||||||
|
@ -718,7 +718,7 @@ class pil_build_ext(build_ext):
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
version=VERSION,
|
version=PILLOW_VERSION,
|
||||||
description='Python Imaging Library (Fork)',
|
description='Python Imaging Library (Fork)',
|
||||||
long_description=(
|
long_description=(
|
||||||
_read('README.rst') + b'\n' +
|
_read('README.rst') + b'\n' +
|
||||||
|
|
|
@ -20,5 +20,13 @@ if len(sys.argv) == 1:
|
||||||
if ('--no-path-adjustment' not in sys.argv) and ('-P' not in sys.argv):
|
if ('--no-path-adjustment' not in sys.argv) and ('-P' not in sys.argv):
|
||||||
sys.argv.insert(1, '--no-path-adjustment')
|
sys.argv.insert(1, '--no-path-adjustment')
|
||||||
|
|
||||||
|
if 'NOSE_PROCESSES' not in os.environ:
|
||||||
|
for arg in sys.argv:
|
||||||
|
if '--processes' in arg:
|
||||||
|
break
|
||||||
|
else: # for
|
||||||
|
sys.argv.insert(1, '--processes=-1') # -1 == number of cores
|
||||||
|
sys.argv.insert(1, '--process-timeout=30')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
nose.main()
|
nose.main()
|
||||||
|
|