Merge pull request #997 from homm/replace-resize

Replace resize method
This commit is contained in:
wiredfool 2014-11-27 10:26:48 -08:00
commit e16ee15f2c
11 changed files with 151 additions and 216 deletions

View File

@ -24,7 +24,7 @@ Changelog (Pillow)
- Use PyQt4 if it has already been imported, otherwise prefer PyQt5. #1003 - Use PyQt4 if it has already been imported, otherwise prefer PyQt5. #1003
[AurelienBallier] [AurelienBallier]
- Speedup stretch implementation up to 2.5 times. #977 - Speedup resample implementation up to 2.5 times. #977
[homm] [homm]
- Speed up rotation by using cache aware loops, added transpose to rotations. #994 - Speed up rotation by using cache aware loops, added transpose to rotations. #994

View File

@ -1523,9 +1523,8 @@ class Image:
(width, height). (width, height).
:param resample: An optional resampling filter. This can be :param resample: An optional resampling filter. This can be
one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour), one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour),
:py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2 :py:attr:`PIL.Image.BILINEAR` (linear interpolation),
environment), :py:attr:`PIL.Image.BICUBIC` (cubic spline :py:attr:`PIL.Image.BICUBIC` (cubic spline interpolation), or
interpolation in a 4x4 environment), or
:py:attr:`PIL.Image.ANTIALIAS` (a high-quality downsampling filter). :py:attr:`PIL.Image.ANTIALIAS` (a high-quality downsampling filter).
If omitted, or if the image has mode "1" or "P", it is If omitted, or if the image has mode "1" or "P", it is
set :py:attr:`PIL.Image.NEAREST`. set :py:attr:`PIL.Image.NEAREST`.
@ -1547,16 +1546,7 @@ class Image:
if self.mode == 'RGBA': if self.mode == 'RGBA':
return self.convert('RGBa').resize(size, resample).convert('RGBA') return self.convert('RGBa').resize(size, resample).convert('RGBA')
if resample == ANTIALIAS: return self._new(self.im.resize(size, resample))
# requires stretch support (imToolkit & PIL 1.1.3)
try:
im = self.im.stretch(size, resample)
except AttributeError:
raise ValueError("unsupported resampling filter")
else:
im = self.im.resize(size, resample)
return self._new(im)
def rotate(self, angle, resample=NEAREST, expand=0): def rotate(self, angle, resample=NEAREST, expand=0):
""" """
@ -1772,12 +1762,7 @@ class Image:
:py:meth:`~PIL.Image.Image.draft` method to configure the file reader :py:meth:`~PIL.Image.Image.draft` method to configure the file reader
(where applicable), and finally resizes the image. (where applicable), and finally resizes the image.
Note that the bilinear and bicubic filters in the current Note that this function modifies the :py:class:`~PIL.Image.Image`
version of PIL are not well-suited for thumbnail generation.
You should use :py:attr:`PIL.Image.ANTIALIAS` unless speed is much more
important than quality.
Also note that this function modifies the :py:class:`~PIL.Image.Image`
object in place. If you need to use the full resolution image as well, object in place. If you need to use the full resolution image as well,
apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original
image. image.
@ -1785,10 +1770,9 @@ class Image:
:param size: Requested size. :param size: Requested size.
:param resample: Optional resampling filter. This can be one :param resample: Optional resampling filter. This can be one
of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`, of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
:py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.ANTIALIAS` :py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.ANTIALIAS`.
(best quality). If omitted, it defaults to If omitted, it defaults to :py:attr:`PIL.Image.ANTIALIAS`.
:py:attr:`PIL.Image.ANTIALIAS`. (was :py:attr:`PIL.Image.NEAREST` (was :py:attr:`PIL.Image.NEAREST` prior to version 2.5.0)
prior to version 2.5.0)
:returns: None :returns: None
""" """
@ -1807,14 +1791,7 @@ class Image:
self.draft(None, size) self.draft(None, size)
self.load()
try:
im = self.resize(size, resample) im = self.resize(size, resample)
except ValueError:
if resample != ANTIALIAS:
raise
im = self.resize(size, NEAREST) # fallback
self.im = im.im self.im = im.im
self.mode = im.mode self.mode = im.mode

View File

@ -1,5 +1,91 @@
"""
Tests for resize functionality.
"""
from itertools import permutations
from helper import unittest, PillowTestCase, hopper from helper import unittest, PillowTestCase, hopper
from PIL import Image
class TestImagingCoreResize(PillowTestCase):
def resize(self, im, size, f):
# Image class independent version of resize.
im.load()
return im._new(im.im.resize(size, f))
def test_nearest_mode(self):
for mode in ["1", "P", "L", "I", "F", "RGB", "RGBA", "CMYK", "YCbCr",
"I;16"]: # exotic mode
im = hopper(mode)
r = self.resize(im, (15, 12), Image.NEAREST)
self.assertEqual(r.mode, mode)
self.assertEqual(r.size, (15, 12) )
self.assertEqual(r.im.bands, im.im.bands)
def test_convolution_modes(self):
self.assertRaises(ValueError, self.resize, hopper("1"),
(15, 12), Image.BILINEAR)
self.assertRaises(ValueError, self.resize, hopper("P"),
(15, 12), Image.BILINEAR)
self.assertRaises(ValueError, self.resize, hopper("I;16"),
(15, 12), Image.BILINEAR)
for mode in ["L", "I", "F", "RGB", "RGBA", "CMYK", "YCbCr"]:
im = hopper(mode)
r = self.resize(im, (15, 12), Image.BILINEAR)
self.assertEqual(r.mode, mode)
self.assertEqual(r.size, (15, 12) )
self.assertEqual(r.im.bands, im.im.bands)
def test_reduce_filters(self):
for f in [Image.LINEAR, Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
r = self.resize(hopper("RGB"), (15, 12), f)
self.assertEqual(r.mode, "RGB")
self.assertEqual(r.size, (15, 12))
def test_enlarge_filters(self):
for f in [Image.LINEAR, Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
r = self.resize(hopper("RGB"), (212, 195), f)
self.assertEqual(r.mode, "RGB")
self.assertEqual(r.size, (212, 195))
def test_endianness(self):
# Make an image with one colored pixel, in one channel.
# When resized, that channel should be the same as a GS image.
# Other channels should be unaffected.
# The R and A channels should not swap, which is indicitive of
# an endianness issues.
samples = {
'blank': Image.new('L', (2, 2), 0),
'filled': Image.new('L', (2, 2), 255),
'dirty': Image.new('L', (2, 2), 0),
}
samples['dirty'].putpixel((1, 1), 128)
for f in [Image.LINEAR, Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
# samples resized with current filter
references = dict(
(name, self.resize(ch, (4, 4), f))
for name, ch in samples.items()
)
for mode, channels_set in [
('RGB', ('blank', 'filled', 'dirty')),
('RGBA', ('blank', 'blank', 'filled', 'dirty')),
('LA', ('filled', 'dirty')),
]:
for channels in set(permutations(channels_set)):
# compile image from different channels permutations
im = Image.merge(mode, [samples[ch] for ch in channels])
resized = self.resize(im, (4, 4), f)
for i, ch in enumerate(resized.split()):
# check what resized channel in image is the same
# as separately resized channel
self.assert_image_equal(ch, references[channels[i]])
class TestImageResize(PillowTestCase): class TestImageResize(PillowTestCase):
@ -9,8 +95,8 @@ class TestImageResize(PillowTestCase):
self.assertEqual(out.mode, mode) self.assertEqual(out.mode, mode)
self.assertEqual(out.size, size) self.assertEqual(out.size, size)
for mode in "1", "P", "L", "RGB", "I", "F": for mode in "1", "P", "L", "RGB", "I", "F":
resize(mode, (100, 100)) resize(mode, (112, 103))
resize(mode, (200, 200)) resize(mode, (188, 214))
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -44,7 +44,9 @@ class TestImageTransform(PillowTestCase):
w//2, h//2, w//2, 0), w//2, h//2, w//2, 0),
Image.BILINEAR) Image.BILINEAR)
scaled = im.resize((w*2, h*2), Image.BILINEAR).crop((0, 0, w, h)) scaled = im.transform((w, h), Image.AFFINE,
(.5, 0, 0, 0, .5, 0),
Image.BILINEAR)
self.assert_image_equal(transformed, scaled) self.assert_image_equal(transformed, scaled)
@ -61,9 +63,9 @@ class TestImageTransform(PillowTestCase):
w, h, w, 0))], # ul -> ccw around quad w, h, w, 0))], # ul -> ccw around quad
Image.BILINEAR) Image.BILINEAR)
# transformed.save('transformed.png') scaled = im.transform((w//2, h//2), Image.AFFINE,
(2, 0, 0, 0, 2, 0),
scaled = im.resize((w//2, h//2), Image.BILINEAR) Image.BILINEAR)
checker = Image.new('RGBA', im.size) checker = Image.new('RGBA', im.size)
checker.paste(scaled, (0, 0)) checker.paste(scaled, (0, 0))
@ -128,7 +130,8 @@ class TestImageTransform(PillowTestCase):
foo = [ foo = [
Image.new('RGBA', (1024, 1024), (a, a, a, a)) Image.new('RGBA', (1024, 1024), (a, a, a, a))
for a in range(1, 65)] for a in range(1, 65)
]
# Yeah. Watch some JIT optimize this out. # Yeah. Watch some JIT optimize this out.
foo = None foo = None

View File

@ -1,86 +0,0 @@
"""
Tests for ImagingCore.stretch functionality.
"""
from itertools import permutations
from helper import unittest, PillowTestCase
from PIL import Image
im = Image.open("Tests/images/hopper.ppm").copy()
class TestImagingStretch(PillowTestCase):
def stretch(self, im, size, f):
return im._new(im.im.stretch(size, f))
def test_modes(self):
self.assertRaises(ValueError, im.convert("1").im.stretch,
(15, 12), Image.ANTIALIAS)
self.assertRaises(ValueError, im.convert("P").im.stretch,
(15, 12), Image.ANTIALIAS)
for mode in ["L", "I", "F", "RGB", "RGBA", "CMYK", "YCbCr"]:
s = im.convert(mode).im
r = s.stretch((15, 12), Image.ANTIALIAS)
self.assertEqual(r.mode, mode)
self.assertEqual(r.size, (15, 12))
self.assertEqual(r.bands, s.bands)
def test_reduce_filters(self):
# There is no Image.NEAREST because im.stretch implementation
# is not NEAREST for reduction. It should be removed
# or renamed to supersampling.
for f in [Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
r = im.im.stretch((15, 12), f)
self.assertEqual(r.mode, "RGB")
self.assertEqual(r.size, (15, 12))
def test_enlarge_filters(self):
for f in [Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
r = im.im.stretch((764, 414), f)
self.assertEqual(r.mode, "RGB")
self.assertEqual(r.size, (764, 414))
def test_endianness(self):
# Make an image with one colored pixel, in one channel.
# When stretched, that channel should be the same as a GS image.
# Other channels should be unaffected.
# The R and A channels should not swap, which is indicitive of
# an endianness issues.
samples = {
'blank': Image.new('L', (2, 2), 0),
'filled': Image.new('L', (2, 2), 255),
'dirty': Image.new('L', (2, 2), 0),
}
samples['dirty'].putpixel((1, 1), 128)
for f in [Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
# samples resized with current filter
resized = dict(
(name, self.stretch(ch, (4, 4), f))
for name, ch in samples.items()
)
for mode, channels_set in [
('RGB', ('blank', 'filled', 'dirty')),
('RGBA', ('blank', 'blank', 'filled', 'dirty')),
('LA', ('filled', 'dirty')),
]:
for channels in set(permutations(channels_set)):
# compile image from different channels permutations
im = Image.merge(mode, [samples[ch] for ch in channels])
stretched = self.stretch(im, (4, 4), f)
for i, ch in enumerate(stretched.split()):
# check what resized channel in image is the same
# as separately resized channel
self.assert_image_equal(ch, resized[channels[i]])
if __name__ == '__main__':
unittest.main()
# End of file

View File

@ -1514,9 +1514,26 @@ _resize(ImagingObject* self, PyObject* args)
imIn = self->image; imIn = self->image;
if (imIn->xsize == xsize && imIn->ysize == ysize) {
imOut = ImagingCopy(imIn);
}
else if ( ! filter) {
double a[6];
memset(a, 0, sizeof a);
a[1] = (double) imIn->xsize / xsize;
a[5] = (double) imIn->ysize / ysize;
imOut = ImagingNew(imIn->mode, xsize, ysize); imOut = ImagingNew(imIn->mode, xsize, ysize);
if (imOut)
(void) ImagingResize(imOut, imIn, filter); imOut = ImagingTransformAffine(
imOut, imIn,
0, 0, xsize, ysize,
a, filter, 1);
}
else {
imOut = ImagingResample(imIn, xsize, ysize, filter);
}
return PyImagingNew(imOut); return PyImagingNew(imOut);
} }
@ -1610,25 +1627,6 @@ im_setmode(ImagingObject* self, PyObject* args)
return Py_None; return Py_None;
} }
static PyObject*
_stretch(ImagingObject* self, PyObject* args)
{
Imaging imIn, imOut;
int xsize, ysize;
int filter = IMAGING_TRANSFORM_NEAREST;
if (!PyArg_ParseTuple(args, "(ii)|i", &xsize, &ysize, &filter))
return NULL;
imIn = self->image;
imOut = ImagingStretch(imIn, xsize, ysize, filter);
if ( ! imOut) {
return NULL;
}
return PyImagingNew(imOut);
}
static PyObject* static PyObject*
_transform2(ImagingObject* self, PyObject* args) _transform2(ImagingObject* self, PyObject* args)
@ -3031,8 +3029,10 @@ static struct PyMethodDef methods[] = {
{"rankfilter", (PyCFunction)_rankfilter, 1}, {"rankfilter", (PyCFunction)_rankfilter, 1},
#endif #endif
{"resize", (PyCFunction)_resize, 1}, {"resize", (PyCFunction)_resize, 1},
// There were two methods for image resize before.
// Starting from Pillow 2.7.0 stretch is depreciated.
{"stretch", (PyCFunction)_resize, 1},
{"rotate", (PyCFunction)_rotate, 1}, {"rotate", (PyCFunction)_rotate, 1},
{"stretch", (PyCFunction)_stretch, 1},
{"transpose", (PyCFunction)_transpose, 1}, {"transpose", (PyCFunction)_transpose, 1},
{"transform2", (PyCFunction)_transform2, 1}, {"transform2", (PyCFunction)_transform2, 1},

View File

@ -89,25 +89,21 @@ pixel, the Python Imaging Library provides four different resampling *filters*.
Pick the nearest pixel from the input image. Ignore all other input pixels. Pick the nearest pixel from the input image. Ignore all other input pixels.
``BILINEAR`` ``BILINEAR``
Use linear interpolation over a 2x2 environment in the input image. Note For resize calculate the output pixel value using linear interpolation
that in the current version of PIL, this filter uses a fixed input on all pixels that may contribute to the output value.
environment when downsampling. For other transformations linear interpolation over a 2x2 environment
in the input image is used.
``BICUBIC`` ``BICUBIC``
Use cubic interpolation over a 4x4 environment in the input image. Note For resize calculate the output pixel value using cubic interpolation
that in the current version of PIL, this filter uses a fixed input on all pixels that may contribute to the output value.
environment when downsampling. For other transformations cubic interpolation over a 4x4 environment
in the input image is used.
``ANTIALIAS`` ``ANTIALIAS``
Calculate the output pixel value using a high-quality resampling filter (a Calculate the output pixel value using a high-quality Lanczos filter (a
truncated sinc) on all pixels that may contribute to the output value. In truncated sinc) on all pixels that may contribute to the output value. In
the current version of PIL, this filter can only be used with the resize the current version of PIL, this filter can only be used with the resize
and thumbnail methods. and thumbnail methods.
.. versionadded:: 1.1.3 .. versionadded:: 1.1.3
Note that in the current version of PIL, the ``ANTIALIAS`` filter is the only
filter that behaves properly when downsampling (that is, when converting a
large image to a small one). The ``BILINEAR`` and ``BICUBIC`` filters use a
fixed input environment, and are best used for scale-preserving geometric
transforms and upsamping.

View File

@ -979,30 +979,6 @@ ImagingTransformQuad(Imaging imOut, Imaging imIn,
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Convenience functions */ /* Convenience functions */
Imaging
ImagingResize(Imaging imOut, Imaging imIn, int filterid)
{
double a[6];
if (imOut->xsize == imIn->xsize && imOut->ysize == imIn->ysize)
return ImagingCopy2(imOut, imIn);
memset(a, 0, sizeof a);
a[1] = (double) imIn->xsize / imOut->xsize;
a[5] = (double) imIn->ysize / imOut->ysize;
if (!filterid && imIn->type != IMAGING_TYPE_SPECIAL)
return ImagingScaleAffine(
imOut, imIn,
0, 0, imOut->xsize, imOut->ysize,
a, 1);
return ImagingTransformAffine(
imOut, imIn,
0, 0, imOut->xsize, imOut->ysize,
a, filterid, 1);
}
Imaging Imaging
ImagingRotate(Imaging imOut, Imaging imIn, double theta, int filterid) ImagingRotate(Imaging imOut, Imaging imIn, double theta, int filterid)
{ {

View File

@ -286,13 +286,12 @@ extern Imaging ImagingPointTransform(
Imaging imIn, double scale, double offset); Imaging imIn, double scale, double offset);
extern Imaging ImagingPutBand(Imaging im, Imaging imIn, int band); extern Imaging ImagingPutBand(Imaging im, Imaging imIn, int band);
extern Imaging ImagingRankFilter(Imaging im, int size, int rank); extern Imaging ImagingRankFilter(Imaging im, int size, int rank);
extern Imaging ImagingResize(Imaging imOut, Imaging imIn, int filter);
extern Imaging ImagingRotate( extern Imaging ImagingRotate(
Imaging imOut, Imaging imIn, double theta, int filter); Imaging imOut, Imaging imIn, double theta, int filter);
extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn);
extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn);
extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn);
extern Imaging ImagingStretch(Imaging imIn, int xsize, int ysize, int filter); extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter);
extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn);
extern Imaging ImagingTransposeToNew(Imaging imIn); extern Imaging ImagingTransposeToNew(Imaging imIn);
extern Imaging ImagingTransformPerspective( extern Imaging ImagingTransformPerspective(

View File

@ -2,7 +2,7 @@
* The Python Imaging Library * The Python Imaging Library
* $Id$ * $Id$
* *
* pilopen antialiasing support * Pillow image resamling support
* *
* history: * history:
* 2002-03-09 fl Created (for PIL 1.1.3) * 2002-03-09 fl Created (for PIL 1.1.3)
@ -17,8 +17,6 @@
#include <math.h> #include <math.h>
/* resampling filters (from antialias.py) */
struct filter { struct filter {
float (*filter)(float x); float (*filter)(float x);
float support; float support;
@ -42,15 +40,6 @@ static inline float antialias_filter(float x)
static struct filter ANTIALIAS = { antialias_filter, 3.0 }; static struct filter ANTIALIAS = { antialias_filter, 3.0 };
static inline float nearest_filter(float x)
{
if (-0.5 <= x && x < 0.5)
return 1.0;
return 0.0;
}
static struct filter NEAREST = { nearest_filter, 0.5 };
static inline float bilinear_filter(float x) static inline float bilinear_filter(float x)
{ {
if (x < 0.0) if (x < 0.0)
@ -106,7 +95,7 @@ static float inline i2f(int v) { return (float) v; }
Imaging Imaging
ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) ImagingResampleHorizontal(Imaging imIn, int xsize, int filter)
{ {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
Imaging imOut; Imaging imOut;
@ -119,9 +108,6 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter)
/* check filter */ /* check filter */
switch (filter) { switch (filter) {
case IMAGING_TRANSFORM_NEAREST:
filterp = &NEAREST;
break;
case IMAGING_TRANSFORM_ANTIALIAS: case IMAGING_TRANSFORM_ANTIALIAS:
filterp = &ANTIALIAS; filterp = &ANTIALIAS;
break; break;
@ -152,7 +138,7 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter)
/* maximum number of coofs */ /* maximum number of coofs */
kmax = (int) ceil(support) * 2 + 1; kmax = (int) ceil(support) * 2 + 1;
/* coefficient buffer (with rounding safety margin) */ /* coefficient buffer */
kk = malloc(xsize * kmax * sizeof(float)); kk = malloc(xsize * kmax * sizeof(float));
if ( ! kk) if ( ! kk)
return (Imaging) ImagingError_MemoryError(); return (Imaging) ImagingError_MemoryError();
@ -208,7 +194,7 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter)
ss += i2f(imIn->image8[yy][x]) * k[x - xmin]; ss += i2f(imIn->image8[yy][x]) * k[x - xmin];
imOut->image8[yy][xx] = clip8(ss); imOut->image8[yy][xx] = clip8(ss);
} }
} else } else {
switch(imIn->type) { switch(imIn->type) {
case IMAGING_TYPE_UINT8: case IMAGING_TYPE_UINT8:
/* n-bit grayscale */ /* n-bit grayscale */
@ -283,12 +269,7 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter)
IMAGING_PIXEL_F(imOut, xx, yy) = ss; IMAGING_PIXEL_F(imOut, xx, yy) = ss;
} }
break; break;
default: }
ImagingSectionLeave(&cookie);
ImagingDelete(imOut);
free(kk);
free(xbounds);
return (Imaging) ImagingError_ModeError();
} }
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
@ -299,7 +280,7 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter)
Imaging Imaging
ImagingStretch(Imaging imIn, int xsize, int ysize, int filter) ImagingResample(Imaging imIn, int xsize, int ysize, int filter)
{ {
Imaging imTemp1, imTemp2, imTemp3; Imaging imTemp1, imTemp2, imTemp3;
Imaging imOut; Imaging imOut;
@ -307,8 +288,11 @@ ImagingStretch(Imaging imIn, int xsize, int ysize, int filter)
if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
if (imIn->type == IMAGING_TYPE_SPECIAL)
return (Imaging) ImagingError_ModeError();
/* two-pass resize, first pass */ /* two-pass resize, first pass */
imTemp1 = ImagingStretchHorizontal(imIn, xsize, filter); imTemp1 = ImagingResampleHorizontal(imIn, xsize, filter);
if ( ! imTemp1) if ( ! imTemp1)
return NULL; return NULL;
@ -319,7 +303,7 @@ ImagingStretch(Imaging imIn, int xsize, int ysize, int filter)
return NULL; return NULL;
/* second pass */ /* second pass */
imTemp3 = ImagingStretchHorizontal(imTemp2, ysize, filter); imTemp3 = ImagingResampleHorizontal(imTemp2, ysize, filter);
ImagingDelete(imTemp2); ImagingDelete(imTemp2);
if ( ! imTemp3) if ( ! imTemp3)
return NULL; return NULL;

View File

@ -26,7 +26,7 @@ _IMAGING = (
"decode", "encode", "map", "display", "outline", "path") "decode", "encode", "map", "display", "outline", "path")
_LIB_IMAGING = ( _LIB_IMAGING = (
"Access", "AlphaComposite", "Antialias", "Bands", "BitDecode", "Blend", "Access", "AlphaComposite", "Resample", "Bands", "BitDecode", "Blend",
"Chops", "Convert", "ConvertYCbCr", "Copy", "Crc32", "Crop", "Dib", "Draw", "Chops", "Convert", "ConvertYCbCr", "Copy", "Crc32", "Crop", "Dib", "Draw",
"Effects", "EpsEncode", "File", "Fill", "Filter", "FliDecode", "Effects", "EpsEncode", "File", "Fill", "Filter", "FliDecode",
"Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode", "Geometry", "GetBBox", "GifDecode", "GifEncode", "HexDecode",