Merge branch 'master' into HEAD

This commit is contained in:
wiredfool 2014-07-02 08:59:16 -07:00
commit a035ecc2ca
36 changed files with 365 additions and 236 deletions

View File

@ -9,3 +9,6 @@ exclude_lines =
# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:
# Don't complain about debug code
if Image.DEBUG:
if DEBUG:

View File

@ -3,7 +3,7 @@ language: python
notifications:
irc: "chat.freenode.net#pil"
env: MAX_CONCURRENCY=4
env: MAX_CONCURRENCY=4 NOSE_PROCESSES=4 NOSE_PROCESS_TIMEOUT=30
python:
- "pypy"
@ -14,9 +14,9 @@ python:
- 3.4
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 coveralls nose pyroma"
- "pip install coveralls nose pyroma nose-cov"
- if [ "$TRAVIS_PYTHON_VERSION" == "2.6" ]; then pip install unittest2; fi
# webp
@ -35,10 +35,13 @@ script:
- if [ "$TRAVIS_PYTHON_VERSION" == "pypy" ]; then time nosetests Tests/test_*.py; fi
# Cover the others
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then time coverage run --append --include=PIL/* selftest.py; fi
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then time coverage run --append --include=PIL/* -m nose Tests/test_*.py; fi
- if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then coverage run --parallel-mode --include=PIL/* selftest.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:
- ls -l .coverage*
- coverage combine
- coverage report
- coveralls
- pip install pep8 pyflakes

View File

@ -4,6 +4,12 @@ Changelog (Pillow)
2.5.0 (unreleased)
------------------
- Imagedraw rewrite
[terseus, wiredfool]
- Add support for multithreaded test execution
[wiredfool]
- Prevent shell injection #748
[mbrown1413, wiredfool]
@ -495,6 +501,10 @@ Changelog (Pillow)
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.)
[fluggo]
@ -518,10 +528,6 @@ Changelog (Pillow)
- Added support for PNG images with transparency palette.
[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)
------------------
@ -594,44 +600,55 @@ Changelog (Pillow)
[elro]
- Doc fixes
[aclark]
1.5 (11/28/2010)
----------------
- Module and package fixes
[aclark]
1.4 (11/28/2010)
----------------
- Doc fixes
[aclark]
1.3 (11/28/2010)
----------------
- Add support for /lib64 and /usr/lib64 library directories on Linux
[aclark]
- Doc fixes
[aclark]
1.2 (08/02/2010)
----------------
- On OS X also check for freetype2 in the X11 path [jezdez]
- Doc fixes [aclark]
- On OS X also check for freetype2 in the X11 path
[jezdez]
- Doc fixes
[aclark]
1.1 (07/31/2010)
----------------
- Removed setuptools_hg requirement
[aclark]
- Doc fixes
[aclark]
1.0 (07/30/2010)
----------------
- Forked PIL based on Hanno Schlichting's re-packaging
(http://dist.plone.org/thirdparty/PIL-1.1.7.tar.gz)
- Remove support for ``import Image``, etc. from the standard namespace. ``from PIL import Image`` etc. now required.
- 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 file contents
.. Note:: What follows is the original PIL 1.1.7 CHANGES
::

View File

@ -1,3 +1,5 @@
pre:
virtualenv .
bin/pip install -r requirements.txt
@ -9,3 +11,32 @@ pre:
check-manifest
pyroma .
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

View File

@ -12,7 +12,7 @@
# ;-)
VERSION = '1.1.7' # PIL version
PILLOW_VERSION = '2.4.0' # Pillow
PILLOW_VERSION = '2.5.0' # Pillow
_plugins = ['BmpImagePlugin',
'BufrStubImagePlugin',

View File

@ -3,7 +3,7 @@ Pillow
*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
: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
: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.

View File

@ -3,39 +3,30 @@ Helper functions.
"""
from __future__ import print_function
import sys
import tempfile
import os
import glob
if sys.version_info[:2] <= (2, 6):
import unittest2 as unittest
else:
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():
import glob
import os
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)
#remove me later
pass
class PillowTestCase(unittest.TestCase):
currentResult = None # holds last result object passed to run method
_tempfiles = []
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
self.currentResult = None # holds last result object passed to run method
def run(self, result=None):
self.addCleanup(self.delete_tempfiles)
self.currentResult = result # remember result for use later
unittest.TestCase.run(self, result) # call superclass run method
def delete_tempfiles(self):
def delete_tempfile(self, path):
try:
ok = self.currentResult.wasSuccessful()
except AttributeError: # for nosetests
@ -44,19 +35,12 @@ class PillowTestCase(unittest.TestCase):
if ok:
# only clean out tempfiles if test passed
import os
import os.path
import tempfile
for file in self._tempfiles:
try:
os.remove(file)
except OSError:
pass # report?
temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
try:
os.rmdir(temp_root)
os.remove(path)
except OSError:
pass
pass # report?
else:
print("=== orphaned temp file: %s" %path)
def assert_almost_equal(self, a, b, msg=None, eps=1e-6):
self.assertLess(
@ -139,27 +123,13 @@ class PillowTestCase(unittest.TestCase):
self.assertTrue(found)
return result
def tempfile(self, template, *extra):
import os
import os.path
import sys
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]
def tempfile(self, template):
assert template[:5] in ("temp.", "temp_")
(fd, path) = tempfile.mkstemp(template[4:], template[:4])
os.close(fd)
self.addCleanup(self.delete_tempfile, path)
return path
# helpers

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 B

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 293 B

View File

@ -1,3 +1,5 @@
import sys
from helper import *
# This test is not run automatically.
@ -18,6 +20,7 @@ YDIM = 32769
XDIM = 48000
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64 bit system")
class LargeMemoryNumpyTest(PillowTestCase):
def _write_png(self, xdim, ydim):

View File

@ -1,3 +1,5 @@
import sys
from helper import *
# This test is not run automatically.
@ -14,6 +16,7 @@ YDIM = 32769
XDIM = 48000
@unittest.skipIf(sys.maxsize <= 2**32, "requires 64 bit system")
class LargeMemoryTest(PillowTestCase):
def _write_png(self, xdim, ydim):

View File

@ -22,7 +22,8 @@ class TestFontPcf(PillowTestCase):
self.assertIsInstance(font, FontFile.FontFile)
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)
return tempname

View File

@ -3,6 +3,13 @@ from helper import unittest, PillowTestCase, tearDownModule, lena
from PIL import Image
from PIL import ImageColor
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
@ -249,7 +256,129 @@ class TestImageDraw(PillowTestCase):
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__':
unittest.main()
# End of file

View File

@ -71,7 +71,7 @@
* 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"

17
docs/developer.rst Normal file
View 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

View File

@ -8,3 +8,4 @@ Guides
handbook/tutorial
handbook/concepts
porting-pil-to-pillow
developer

View File

@ -49,6 +49,13 @@
#define BLEND(mask, in1, in2, tmp1, 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 */
/* -------------------------------------------------------------------- */
@ -61,6 +68,9 @@ typedef struct {
float dx;
} Edge;
/* Type used in "polygon*" functions */
typedef void (*hline_handler)(Imaging, int, int, int, int);
static inline void
point8(Imaging im, int x, int y, int ink)
{
@ -403,177 +413,100 @@ x_cmp(const void *x0, const void *x1)
return 0;
}
/*
* Filled polygon draw function using scan line algorithm.
*/
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;
/* 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)
/* Initialize the edge table and find polygon boundaries */
edge_table = malloc(sizeof(Edge*) * n);
if (!edge_table) {
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;
for (i = 0; i < n; i++) {
/* This causes that the pixels of horizontal edges are drawn twice :(
* but without it there are inconsistencies in ellipses */
if (e[i].ymin == e[i].ymax) {
(*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;
}
if (j == 2) {
if (xx[0] < xx[1])
hline8(im, CEIL(xx[0]-0.5), ymin, FLOOR(xx[1]+0.5), ink);
else
hline8(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)
hline8(im, CEIL(xx[i]-0.5), ymin, FLOOR(xx[i+1]+0.5), ink);
/* Needed to draw consistent polygons */
if (ymin == current->ymax && ymin < ymax) {
xx[j] = xx[j - 1];
j++;
}
}
qsort(xx, j, sizeof(float), x_cmp);
for (i = 1; i < j; i += 2) {
(*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
}
}
free(xx);
free(edge_table);
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
polygon32(Imaging im, int n, Edge *e, int ink, int eofill)
{
int i, j;
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;
return polygon_generic(im, n, e, ink, eofill, hline32);
}
static inline int
polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill)
{
int i, j;
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;
return polygon_generic(im, n, e, ink, eofill, hline32rgba);
}
static inline void
@ -663,11 +596,11 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
{
DRAW* draw;
INT32 ink;
Edge e[4];
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();
@ -678,24 +611,35 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
dx = x1-x0;
dy = y1-y0;
if (dx == 0 && dy == 0) {
draw->point(im, x0, y0, ink);
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);
dy = (int) floor(d * (x1-x0) + 0.5);
dxmin = ROUND_DOWN(ratio_min * dy);
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+1, x1 - dx, y1 + dy, x1 + dx, y1 - dy);
add_edge(e+2, x1 + dx, y1 - dy, x0 + dx, y0 - dy);
add_edge(e+3, x0 + dx, y0 - dy, x0 - dx, y0 + dy);
draw->polygon(im, 4, e, ink, 0);
add_edge(e+0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]);
add_edge(e+1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]);
add_edge(e+2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
add_edge(e+3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
draw->polygon(im, 4, e, ink, 0);
}
return 0;
}

View File

@ -17,7 +17,7 @@
#error Sorry, this library requires ANSI header files.
#endif
#if !defined(PIL_USE_INLINE)
#if defined(PIL_NO_INLINE)
#define inline
#else
#if defined(_MSC_VER) && !defined(__GNUC__)

View File

@ -90,7 +90,7 @@ except (ImportError, OSError):
NAME = 'Pillow'
VERSION = '2.4.0'
PILLOW_VERSION = '2.5.0'
TCL_ROOT = None
JPEG_ROOT = None
JPEG2K_ROOT = None
@ -622,7 +622,7 @@ class pil_build_ext(build_ext):
print("-" * 68)
print("PIL SETUP SUMMARY")
print("-" * 68)
print("version Pillow %s" % VERSION)
print("version Pillow %s" % PILLOW_VERSION)
v = sys.version.split("[")
print("platform %s %s" % (sys.platform, v[0].strip()))
for v in v[1:]:
@ -718,7 +718,7 @@ class pil_build_ext(build_ext):
setup(
name=NAME,
version=VERSION,
version=PILLOW_VERSION,
description='Python Imaging Library (Fork)',
long_description=(
_read('README.rst') + b'\n' +

View File

@ -20,5 +20,13 @@ if len(sys.argv) == 1:
if ('--no-path-adjustment' not in sys.argv) and ('-P' not in sys.argv):
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__':
nose.main()