Merge branch 'master' into perfperf-improv-ImageDraw-floodfill

This commit is contained in:
Andrew Murray 2018-09-01 20:58:53 +10:00 committed by GitHub
commit 5e2d6c951a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 419 additions and 152 deletions

View File

@ -71,7 +71,7 @@ build_script:
test_script:
- cd c:\pillow
- '%PYTHON%\%PIP_DIR%\pip.exe install "pytest<3.7" pytest-cov'
- '%PYTHON%\%PIP_DIR%\pip.exe install pytest pytest-cov'
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov-report term --cov-report xml Tests'
#- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest?

View File

@ -1,3 +1,5 @@
dist: xenial
sudo: required
language: python
cache: pip
@ -12,13 +14,24 @@ matrix:
fast_finish: true
include:
- python: "pypy"
dist: trusty
- python: "pypy3"
- python: '3.7-dev'
dist: trusty
- python: '3.7'
- python: '2.7'
- python: '2.7'
dist: trusty
- python: "2.7_with_system_site_packages" # For PyQt4
- python: "2.7_with_system_site_packages" # For PyQt4
dist: trusty
- python: '3.6'
- python: '3.6'
dist: trusty
- python: '3.5'
- python: '3.5'
dist: trusty
- python: '3.4'
dist: trusty
- env: DOCKER="alpine" DOCKER_TAG="pytest"
- env: DOCKER="arch" DOCKER_TAG="pytest" # contains PyQt5
- env: DOCKER="ubuntu-trusty-x86" DOCKER_TAG="pytest"
@ -31,10 +44,6 @@ matrix:
- env: DOCKER="fedora-26-amd64" DOCKER_TAG="pytest"
- env: DOCKER="fedora-27-amd64" DOCKER_TAG="pytest"
dist: trusty
sudo: required
services:
- docker

View File

@ -5,6 +5,27 @@ Changelog (Pillow)
5.3.0 (unreleased)
------------------
- Changed ImageFilter.Kernel to subclass ImageFilter.BuiltinFilter, instead of the other way around #3273
[radarhere]
- Remove unused draw.draw_line, draw.draw_point and font.getabc methods #3232
[hugovk]
- Tests: Added ImageFilter tests #3295
[radarhere]
- Tests: Added ImageChops tests #3230
[hugovk, radarhere]
- AppVeyor: Download lib if not present in pillow-depends #3316
[radarhere]
- Travis CI: Add Python 3.7 and Xenial #3234
[hugovk]
- Docs: Added documentation for NumPy conversion #3301
[radarhere]
- Depends: Update libimagequant to 2.12.1 #3281
[radarhere]

View File

@ -89,12 +89,12 @@ Released as needed privately to individual vendors for critical security-related
$ git clone https://github.com/python-pillow/pillow-wheels
$ cd pillow-wheels
$ git submodule init
$ git submodule update
$ git submodule update Pillow
$ cd Pillow
$ git fetch --all
$ git checkout [[release tag]]
$ cd ..
$ git commit -m "Pillow -> 2.9.0" Pillow
$ git commit -m "Pillow -> 5.2.0" Pillow
$ git push
```
* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).

View File

@ -146,13 +146,13 @@ class TestFileJpeg2k(PillowTestCase):
self.assertEqual(j2k.mode, 'I;16')
self.assertEqual(jp2.mode, 'I;16')
def test_16bit_monchrome_jp2_like_tiff(self):
def test_16bit_monochrome_jp2_like_tiff(self):
tiff_16bit = Image.open('Tests/images/16bit.cropped.tif')
jp2 = Image.open('Tests/images/16bit.cropped.jp2')
self.assert_image_similar(jp2, tiff_16bit, 1e-3)
def test_16bit_monchrome_j2k_like_tiff(self):
def test_16bit_monochrome_j2k_like_tiff(self):
tiff_16bit = Image.open('Tests/images/16bit.cropped.tif')
j2k = Image.open('Tests/images/16bit.cropped.j2k')

View File

@ -12,7 +12,7 @@ class TestFileTar(PillowTestCase):
def setUp(self):
if "zip_decoder" not in codecs and "jpeg_decoder" not in codecs:
self.skipTest("neither jpeg nor zip support not available")
self.skipTest("neither jpeg nor zip support available")
def test_sanity(self):
if "zip_decoder" in codecs:

View File

@ -94,6 +94,15 @@ class TestImageFilter(PillowTestCase):
self.assertEqual(rankfilter.size, 1)
self.assertEqual(rankfilter.rank, 2)
def test_builtinfilter_p(self):
builtinFilter = ImageFilter.BuiltinFilter()
self.assertRaises(ValueError, builtinFilter.filter, hopper("P"))
def test_kernel_not_enough_coefficients(self):
self.assertRaises(ValueError,
lambda: ImageFilter.Kernel((3, 3), (0, 0)))
def test_consistency_3x3(self):
source = Image.open("Tests/images/hopper.bmp")
reference = Image.open("Tests/images/hopper_emboss.bmp")

View File

@ -3,6 +3,16 @@ from helper import unittest, PillowTestCase, hopper
from PIL import Image
from PIL import ImageChops
BLACK = (0, 0, 0)
BROWN = (127, 64, 0)
CYAN = (0, 255, 255)
DARK_GREEN = (0, 128, 0)
GREEN = (0, 255, 0)
ORANGE = (255, 128, 0)
WHITE = (255, 255, 255)
GREY = 128
class TestImageChops(PillowTestCase):
@ -35,6 +45,303 @@ class TestImageChops(PillowTestCase):
ImageChops.offset(im, 10)
ImageChops.offset(im, 10, 20)
def test_add(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_ellipse_RGB.png")
im2 = Image.open("Tests/images/imagedraw_floodfill.png")
# Act
new = ImageChops.add(im1, im2)
# Assert
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
self.assertEqual(new.getpixel((50, 50)), ORANGE)
def test_add_scale_offset(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_ellipse_RGB.png")
im2 = Image.open("Tests/images/imagedraw_floodfill.png")
# Act
new = ImageChops.add(im1, im2, scale=2.5, offset=100)
# Assert
self.assertEqual(new.getbbox(), (0, 0, 100, 100))
self.assertEqual(new.getpixel((50, 50)), (202, 151, 100))
def test_add_clip(self):
# Arrange
im = hopper()
# Act
new = ImageChops.add(im, im)
# Assert
self.assertEqual(new.getpixel((50, 50)), (255, 255, 254))
def test_add_modulo(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_ellipse_RGB.png")
im2 = Image.open("Tests/images/imagedraw_floodfill.png")
# Act
new = ImageChops.add_modulo(im1, im2)
# Assert
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
self.assertEqual(new.getpixel((50, 50)), ORANGE)
def test_add_modulo_no_clip(self):
# Arrange
im = hopper()
# Act
new = ImageChops.add_modulo(im, im)
# Assert
self.assertEqual(new.getpixel((50, 50)), (224, 76, 254))
def test_blend(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_ellipse_RGB.png")
im2 = Image.open("Tests/images/imagedraw_floodfill.png")
# Act
new = ImageChops.blend(im1, im2, 0.5)
# Assert
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
self.assertEqual(new.getpixel((50, 50)), BROWN)
def test_constant(self):
# Arrange
im = Image.new("RGB", (20, 10))
# Act
new = ImageChops.constant(im, GREY)
# Assert
self.assertEqual(new.size, im.size)
self.assertEqual(new.getpixel((0, 0)), GREY)
self.assertEqual(new.getpixel((19, 9)), GREY)
def test_darker_image(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_chord_RGB.png")
im2 = Image.open("Tests/images/imagedraw_outline_chord_RGB.png")
# Act
new = ImageChops.darker(im1, im2)
# Assert
self.assert_image_equal(new, im2)
def test_darker_pixel(self):
# Arrange
im1 = hopper()
im2 = Image.open("Tests/images/imagedraw_chord_RGB.png")
# Act
new = ImageChops.darker(im1, im2)
# Assert
self.assertEqual(new.getpixel((50, 50)), (240, 166, 0))
def test_difference(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_arc_end_le_start.png")
im2 = Image.open("Tests/images/imagedraw_arc_no_loops.png")
# Act
new = ImageChops.difference(im1, im2)
# Assert
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
def test_difference_pixel(self):
# Arrange
im1 = hopper()
im2 = Image.open("Tests/images/imagedraw_polygon_kite_RGB.png")
# Act
new = ImageChops.difference(im1, im2)
# Assert
self.assertEqual(new.getpixel((50, 50)), (240, 166, 128))
def test_duplicate(self):
# Arrange
im = hopper()
# Act
new = ImageChops.duplicate(im)
# Assert
self.assert_image_equal(new, im)
def test_invert(self):
# Arrange
im = Image.open("Tests/images/imagedraw_floodfill.png")
# Act
new = ImageChops.invert(im)
# Assert
self.assertEqual(new.getbbox(), (0, 0, 100, 100))
self.assertEqual(new.getpixel((0, 0)), WHITE)
self.assertEqual(new.getpixel((50, 50)), CYAN)
def test_lighter_image(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_chord_RGB.png")
im2 = Image.open("Tests/images/imagedraw_outline_chord_RGB.png")
# Act
new = ImageChops.lighter(im1, im2)
# Assert
self.assert_image_equal(new, im1)
def test_lighter_pixel(self):
# Arrange
im1 = hopper()
im2 = Image.open("Tests/images/imagedraw_chord_RGB.png")
# Act
new = ImageChops.lighter(im1, im2)
# Assert
self.assertEqual(new.getpixel((50, 50)), (255, 255, 127))
def test_multiply_black(self):
"""If you multiply an image with a solid black image,
the result is black."""
# Arrange
im1 = hopper()
black = Image.new("RGB", im1.size, "black")
# Act
new = ImageChops.multiply(im1, black)
# Assert
self.assert_image_equal(new, black)
def test_multiply_green(self):
# Arrange
im = Image.open("Tests/images/imagedraw_floodfill.png")
green = Image.new("RGB", im.size, "green")
# Act
new = ImageChops.multiply(im, green)
# Assert
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
self.assertEqual(new.getpixel((25, 25)), DARK_GREEN)
self.assertEqual(new.getpixel((50, 50)), BLACK)
def test_multiply_white(self):
"""If you multiply with a solid white image,
the image is unaffected."""
# Arrange
im1 = hopper()
white = Image.new("RGB", im1.size, "white")
# Act
new = ImageChops.multiply(im1, white)
# Assert
self.assert_image_equal(new, im1)
def test_offset(self):
# Arrange
im = Image.open("Tests/images/imagedraw_ellipse_RGB.png")
xoffset = 45
yoffset = 20
# Act
new = ImageChops.offset(im, xoffset, yoffset)
# Assert
self.assertEqual(new.getbbox(), (0, 45, 100, 96))
self.assertEqual(new.getpixel((50, 50)), BLACK)
self.assertEqual(new.getpixel((50+xoffset, 50+yoffset)), DARK_GREEN)
# Test no yoffset
self.assertEqual(ImageChops.offset(im, xoffset),
ImageChops.offset(im, xoffset, xoffset))
def test_screen(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_ellipse_RGB.png")
im2 = Image.open("Tests/images/imagedraw_floodfill.png")
# Act
new = ImageChops.screen(im1, im2)
# Assert
self.assertEqual(new.getbbox(), (25, 25, 76, 76))
self.assertEqual(new.getpixel((50, 50)), ORANGE)
def test_subtract(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_chord_RGB.png")
im2 = Image.open("Tests/images/imagedraw_outline_chord_RGB.png")
# Act
new = ImageChops.subtract(im1, im2)
# Assert
self.assertEqual(new.getbbox(), (25, 50, 76, 76))
self.assertEqual(new.getpixel((50, 50)), GREEN)
self.assertEqual(new.getpixel((50, 51)), BLACK)
def test_subtract_scale_offset(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_chord_RGB.png")
im2 = Image.open("Tests/images/imagedraw_outline_chord_RGB.png")
# Act
new = ImageChops.subtract(im1, im2, scale=2.5, offset=100)
# Assert
self.assertEqual(new.getbbox(), (0, 0, 100, 100))
self.assertEqual(new.getpixel((50, 50)), (100, 202, 100))
def test_subtract_clip(self):
# Arrange
im1 = hopper()
im2 = Image.open("Tests/images/imagedraw_chord_RGB.png")
# Act
new = ImageChops.subtract(im1, im2)
# Assert
self.assertEqual(new.getpixel((50, 50)), (0, 0, 127))
def test_subtract_modulo(self):
# Arrange
im1 = Image.open("Tests/images/imagedraw_chord_RGB.png")
im2 = Image.open("Tests/images/imagedraw_outline_chord_RGB.png")
# Act
new = ImageChops.subtract_modulo(im1, im2)
# Assert
self.assertEqual(new.getbbox(), (25, 50, 76, 76))
self.assertEqual(new.getpixel((50, 50)), GREEN)
self.assertEqual(new.getpixel((50, 51)), BLACK)
def test_subtract_modulo_no_clip(self):
# Arrange
im1 = hopper()
im2 = Image.open("Tests/images/imagedraw_chord_RGB.png")
# Act
new = ImageChops.subtract_modulo(im1, im2)
# Assert
self.assertEqual(new.getpixel((50, 50)), (241, 167, 127))
def test_logical(self):
def table(op, a, b):

View File

@ -366,6 +366,11 @@ class TestImageDraw(PillowTestCase):
ImageDraw.floodfill(im, (W, H), red)
self.assert_image_equal(im, im_floodfill)
# Test filling at the edge of an image
im = Image.new("RGB", (1, 1))
ImageDraw.floodfill(im, (0, 0), red)
self.assert_image_equal(im, Image.new("RGB", (1, 1), red))
def test_floodfill_border(self):
# floodfill() is experimental

View File

@ -1,5 +1,5 @@
from helper import unittest, PillowTestCase, hopper
from test_imageqt import PillowQtTestCase, PillowQPixmapTestCase
from test_imageqt import PillowQPixmapTestCase
from PIL import ImageQt
@ -7,7 +7,6 @@ from PIL import ImageQt
class TestFromQPixmap(PillowQPixmapTestCase, PillowTestCase):
def roundtrip(self, expected):
PillowQtTestCase.setUp(self)
result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected))
# Qt saves all pixmaps as rgb
self.assert_image_equal(result, expected.convert('RGB'))

View File

@ -25,7 +25,6 @@ if ImageQt.qt_is_installed:
class TestToQImage(PillowQtTestCase, PillowTestCase):
def test_sanity(self):
PillowQtTestCase.setUp(self)
for mode in ('RGB', 'RGBA', 'L', 'P', '1'):
src = hopper(mode)
data = ImageQt.toqimage(src)
@ -61,8 +60,6 @@ class TestToQImage(PillowQtTestCase, PillowTestCase):
self.assert_image_equal(reloaded, src)
def test_segfault(self):
PillowQtTestCase.setUp(self)
app = QApplication([])
ex = Example()
assert(app) # Silence warning

View File

@ -1,5 +1,5 @@
from helper import unittest, PillowTestCase, hopper
from test_imageqt import PillowQtTestCase, PillowQPixmapTestCase
from test_imageqt import PillowQPixmapTestCase
from PIL import ImageQt
@ -10,8 +10,6 @@ if ImageQt.qt_is_installed:
class TestToQPixmap(PillowQPixmapTestCase, PillowTestCase):
def test_sanity(self):
PillowQtTestCase.setUp(self)
for mode in ('1', 'RGB', 'RGBA', 'L', 'P'):
data = ImageQt.toqpixmap(hopper(mode))

View File

@ -1,7 +1,7 @@
#!/bin/bash
# install extra test images
rm -r test_images
rm -rf test_images
# Use SVN to just fetch a single git subdirectory
svn checkout https://github.com/python-pillow/pillow-depends/trunk/test_images

View File

@ -1,4 +1,4 @@
<h3>Need help?</h3>
<p>
You can get help via IRC at <a href="irc://irc.freenode.net#pil">irc://irc.freenode.net#pil</a>, <a href="https://gitter.im/python-pillow/Pillow">Gitter</a> or Stack Overflow <a href="https://stackoverflow.com/questions/tagged/pillow">here</a> and <a href="https://stackoverflow.com/questions/tagged/python-imaging-library">here</a>. Please <a href="https://github.com/python-pillow/Pillow/issues/new">report issues on GitHub</a>.
You can get help via IRC at <a href="irc://irc.freenode.net#pil">irc://irc.freenode.net#pil</a>, <a href="https://gitter.im/python-pillow/Pillow">Gitter</a> or <a href="https://stackoverflow.com/questions/tagged/python-imaging-library">Stack Overflow</a>. Please <a href="https://github.com/python-pillow/Pillow/issues/new">report issues on GitHub</a>.
</p>

View File

@ -529,8 +529,8 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
.. note::
To enable PNG support, you need to build and install the ZLIB compression
library before building the Python Imaging Library. See the installation
documentation for details.
library before building the Python Imaging Library. See the `installation
documentation <../installation.html>`_ for details.
PPM
^^^

View File

@ -178,7 +178,7 @@ Many of Pillow's features require external libraries:
shaping (using HarfBuzz), and proper script itemization. As a
result, Raqm can support most writing systems covered by Unicode.
* libraqm depends on the following libraries: FreeType, HarfBuzz,
FriBiDi, make sure that you install them before install libraqm
FriBiDi, make sure that you install them before installing libraqm
if not available as package in your system.
* setting text direction or font features is not supported without
libraqm.

View File

@ -6,9 +6,10 @@ Added Complex Text Rendering
Pillow now supports complex text rendering for scripts requiring glyph
composition and bidirectional flow. This optional feature adds three
dependencies: harfbuzz, fribidi, and raqm. See the install
documentation for further details. This feature is tested and works on
Unix and Mac, but has not yet been built on Windows platforms.
dependencies: harfbuzz, fribidi, and raqm. See the `install
documentation <../installation.html>`_ for further details. This feature is
tested and works on Unix and Mac, but has not yet been built on Windows
platforms.
New Optional Parameters
=======================

View File

@ -2440,9 +2440,20 @@ def fromarray(obj, mode=None):
Creates an image memory from an object exporting the array interface
(using the buffer protocol).
If obj is not contiguous, then the tobytes method is called
If **obj** is not contiguous, then the tobytes method is called
and :py:func:`~PIL.Image.frombuffer` is used.
If you have an image in NumPy::
from PIL import Image
import numpy as np
im = Image.open('hopper.jpg')
a = numpy.asarray(im)
Then this can be used to convert it to a Pillow image::
im = Image.fromarray(a)
:param obj: Object with array interface
:param mode: Mode to use (will be determined from type if None)
See: :ref:`concept-modes`.

View File

@ -353,42 +353,27 @@ def floodfill(image, xy, value, border=None, thresh=0):
return # seed point outside image
edge = {(x, y)}
full_edge = set() # use a set to record each unique pixel processed
if border is None:
while edge:
new_edge = set()
for (x, y) in edge: # 4 adjacent method
for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
if (s, t) in full_edge:
continue # if already processed, skip
try:
p = pixel[s, t]
except IndexError:
pass
while edge:
new_edge = set()
for (x, y) in edge: # 4 adjacent method
for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
if (s, t) in full_edge:
continue # if already processed, skip
try:
p = pixel[s, t]
except (ValueError, IndexError):
pass
else:
if border is None:
fill = _color_diff(p, background) <= thresh
else:
if _color_diff(p, background) <= thresh:
pixel[s, t] = value
new_edge.add((s, t))
full_edge.add((s, t))
full_edge = edge # do not record useless pixels to reduce memory consumption
edge = new_edge
else:
while edge:
new_edge = set()
for (x, y) in edge:
for (s, t) in ((x+1, y), (x-1, y), (x, y+1), (x, y-1)):
if (s, t) in full_edge:
continue
try:
p = pixel[s, t]
except IndexError:
pass
else:
if p != value and p != border:
pixel[s, t] = value
new_edge.add((s, t))
full_edge.add((s, t))
full_edge = edge
edge = new_edge
fill = p != value and p != border
if fill:
pixel[s, t] = value
new_edge.add((s, t))
full_edge.add((s, t))
full_edge = edge # do not record useless pixels to reduce memory consumption
edge = new_edge
def _color_diff(rgb1, rgb2):

View File

@ -33,7 +33,14 @@ class MultibandFilter(Filter):
pass
class Kernel(MultibandFilter):
class BuiltinFilter(MultibandFilter):
def filter(self, image):
if image.mode == "P":
raise ValueError("cannot filter palette images")
return image.filter(*self.filterargs)
class Kernel(BuiltinFilter):
"""
Create a convolution kernel. The current version only
supports 3x3 and 5x5 integer and floating point kernels.
@ -60,16 +67,6 @@ class Kernel(MultibandFilter):
raise ValueError("not enough coefficients in kernel")
self.filterargs = size, scale, offset, kernel
def filter(self, image):
if image.mode == "P":
raise ValueError("cannot filter palette images")
return image.filter(*self.filterargs)
class BuiltinFilter(Kernel):
def __init__(self):
pass
class RankFilter(Filter):
"""

View File

@ -59,7 +59,7 @@ class ImagePalette(object):
def getdata(self):
"""
Get palette contents in format suitable # for the low-level
Get palette contents in format suitable for the low-level
``im.putpalette`` primitive.
.. warning:: This method is experimental.

View File

@ -793,7 +793,7 @@ def jpeg_factory(fp=None, filename=None):
return im
# -------------------------------------------------------------------q-
# ---------------------------------------------------------------------
# Registry stuff
Image.register_open(JpegImageFile.format, jpeg_factory, _accept)

View File

@ -85,7 +85,7 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
return self.__frame
# -------------------------------------------------------------------q-
# ---------------------------------------------------------------------
# Registry stuff
# Note that since MPO shares a factory with JPEG, we do not need to do a

View File

@ -2697,22 +2697,6 @@ _draw_ellipse(ImagingDrawObject* self, PyObject* args)
return Py_None;
}
static PyObject*
_draw_line(ImagingDrawObject* self, PyObject* args)
{
int x0, y0, x1, y1;
int ink;
if (!PyArg_ParseTuple(args, "(ii)(ii)i", &x0, &y0, &x1, &y1, &ink))
return NULL;
if (ImagingDrawLine(self->image->image, x0, y0, x1, y1,
&ink, self->blend) < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
_draw_lines(ImagingDrawObject* self, PyObject* args)
{
@ -2766,21 +2750,6 @@ _draw_lines(ImagingDrawObject* self, PyObject* args)
return Py_None;
}
static PyObject*
_draw_point(ImagingDrawObject* self, PyObject* args)
{
int x, y;
int ink;
if (!PyArg_ParseTuple(args, "(ii)i", &x, &y, &ink))
return NULL;
if (ImagingDrawPoint(self->image->image, x, y, &ink, self->blend) < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
_draw_points(ImagingDrawObject* self, PyObject* args)
{
@ -2961,14 +2930,12 @@ _draw_rectangle(ImagingDrawObject* self, PyObject* args)
static struct PyMethodDef _draw_methods[] = {
#ifdef WITH_IMAGEDRAW
/* Graphics (ImageDraw) */
{"draw_line", (PyCFunction)_draw_line, 1},
{"draw_lines", (PyCFunction)_draw_lines, 1},
#ifdef WITH_ARROW
{"draw_outline", (PyCFunction)_draw_outline, 1},
#endif
{"draw_polygon", (PyCFunction)_draw_polygon, 1},
{"draw_rectangle", (PyCFunction)_draw_rectangle, 1},
{"draw_point", (PyCFunction)_draw_point, 1},
{"draw_points", (PyCFunction)_draw_points, 1},
{"draw_arc", (PyCFunction)_draw_arc, 1},
{"draw_bitmap", (PyCFunction)_draw_bitmap, 1},

View File

@ -674,47 +674,6 @@ font_getsize(FontObject* self, PyObject* args)
);
}
static PyObject*
font_getabc(FontObject* self, PyObject* args)
{
FT_ULong ch;
FT_Face face;
double a, b, c;
/* calculate ABC values for a given string */
PyObject* string;
if (!PyArg_ParseTuple(args, "O:getabc", &string))
return NULL;
#if PY_VERSION_HEX >= 0x03000000
if (!PyUnicode_Check(string)) {
#else
if (!PyUnicode_Check(string) && !PyString_Check(string)) {
#endif
PyErr_SetString(PyExc_TypeError, "expected string");
return NULL;
}
if (font_getchar(string, 0, &ch)) {
int index, error;
face = self->face;
index = FT_Get_Char_Index(face, ch);
/* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */
error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
if (error)
return geterror(error);
a = face->glyph->metrics.horiBearingX / 64.0;
b = face->glyph->metrics.width / 64.0;
c = (face->glyph->metrics.horiAdvance -
face->glyph->metrics.horiBearingX -
face->glyph->metrics.width) / 64.0;
} else
a = b = c = 0.0;
return Py_BuildValue("ddd", a, b, c);
}
static PyObject*
font_render(FontObject* self, PyObject* args)
{
@ -854,7 +813,6 @@ font_dealloc(FontObject* self)
static PyMethodDef font_methods[] = {
{"render", (PyCFunction) font_render, METH_VARARGS},
{"getsize", (PyCFunction) font_getsize, METH_VARARGS},
{"getabc", (PyCFunction) font_getabc, METH_VARARGS},
{NULL, NULL}
};

View File

@ -2,6 +2,7 @@ from unzip import unzip
from untar import untar
import os
from fetch import fetch
from config import compilers, compiler_from_env, libs
@ -44,6 +45,8 @@ def extract(src, dest):
def extract_libs():
for name, lib in libs.items():
filename = lib['filename']
if not os.path.exists(filename):
filename = fetch(lib['url'])
if name == 'openjpeg':
for compiler in compilers.values():
if not os.path.exists(os.path.join(