From a18325afe16cb53d592ae1bf0ecb531b38c28d71 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 09:34:23 +0300 Subject: [PATCH 01/16] remove WITH_FILTERS --- libImaging/Geometry.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index 97cbcf2ed..c0db7ce38 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -27,9 +27,6 @@ #include "Imaging.h" -/* Undef if you don't need resampling filters */ -#define WITH_FILTERS - /* For large images rotation is an inefficient operation in terms of CPU cache. One row in the source image affects each column in destination. Rotating in chunks that fit in the cache can speed up rotation @@ -321,8 +318,6 @@ quad_transform(double* xin, double* yin, int x, int y, void* data) /* transform filters (ImagingTransformFilter) */ -#ifdef WITH_FILTERS - static int nearest_filter8(void* out, Imaging im, double xin, double yin, void* data) { @@ -631,10 +626,6 @@ getfilter(Imaging im, int filterid) return NULL; } -#else -#define getfilter(im, id) NULL -#endif - /* transformation engines */ Imaging From e5b2cbe4adac648f966cb8448ff011d0049f9be2 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 09:55:06 +0300 Subject: [PATCH 02/16] undef local defines add section cookie for affine_fixed --- libImaging/Geometry.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index c0db7ce38..866861d28 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -69,6 +69,8 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) ImagingSectionLeave(&cookie); +#undef FLIP_HORIZ + return imOut; } @@ -88,7 +90,7 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) ImagingSectionEnter(&cookie); - yr = imIn->ysize-1; + yr = imIn->ysize - 1; for (y = 0; y < imIn->ysize; y++, yr--) memcpy(imOut->image[yr], imIn->image[y], imIn->linesize); @@ -134,6 +136,8 @@ ImagingRotate90(Imaging imOut, Imaging imIn) ImagingSectionLeave(&cookie); +#undef ROTATE_90 + return imOut; } @@ -149,6 +153,8 @@ ImagingTranspose(Imaging imOut, Imaging imIn) if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) return (Imaging) ImagingError_Mismatch(); + ImagingCopyInfo(imOut, imIn); + #define TRANSPOSE(image) \ for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ @@ -162,15 +168,17 @@ ImagingTranspose(Imaging imOut, Imaging imIn) } \ } - ImagingCopyInfo(imOut, imIn); - ImagingSectionEnter(&cookie); + if (imIn->image8) TRANSPOSE(image8) else TRANSPOSE(image32) + ImagingSectionLeave(&cookie); +#undef TRANSPOSE + return imOut; } @@ -203,8 +211,6 @@ ImagingRotate180(Imaging imOut, Imaging imIn) ImagingCopyInfo(imOut, imIn); - yr = imIn->ysize-1; - #define ROTATE_180(image)\ for (y = 0; y < imIn->ysize; y++, yr--) {\ xr = imIn->xsize-1;\ @@ -214,6 +220,7 @@ ImagingRotate180(Imaging imOut, Imaging imIn) ImagingSectionEnter(&cookie); + yr = imIn->ysize-1; if (imIn->image8) ROTATE_180(image8) else @@ -221,6 +228,8 @@ ImagingRotate180(Imaging imOut, Imaging imIn) ImagingSectionLeave(&cookie); +#undef ROTATE_180 + return imOut; } @@ -261,6 +270,8 @@ ImagingRotate270(Imaging imOut, Imaging imIn) ImagingSectionLeave(&cookie); +#undef ROTATE_270 + return imOut; } @@ -437,6 +448,10 @@ bilinear_filter32RGB(void* out, Imaging im, double xin, double yin, void* data) return 1; } +#undef BILINEAR +#undef BILINEAR_HEAD +#undef BILINEAR_BODY + #define BICUBIC(v, v1, v2, v3, v4, d) {\ double p1 = v2;\ double p2 = -v1 + v3;\ @@ -565,6 +580,10 @@ bicubic_filter32RGB(void* out, Imaging im, double xin, double yin, void* data) return 1; } +#undef BICUBIC +#undef BICUBIC_HEAD +#undef BICUBIC_BODY + static ImagingTransformFilter getfilter(Imaging im, int filterid) { @@ -753,6 +772,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, ImagingSectionLeave(&cookie); +#undef AFFINE_SCALE + free(xintab); return imOut; @@ -773,6 +794,7 @@ affine_fixed(Imaging imOut, Imaging imIn, /* affine transform, nearest neighbour resampling, fixed point arithmetics */ + ImagingSectionCookie cookie; int x, y; int xin, yin; int xsize, ysize; @@ -790,6 +812,8 @@ affine_fixed(Imaging imOut, Imaging imIn, a0 = FIX(a[0]); a1 = FIX(a[1]); a2 = FIX(a[2]); a3 = FIX(a[3]); a4 = FIX(a[4]); a5 = FIX(a[5]); +#undef FIX + #define AFFINE_TRANSFORM_FIXED(pixel, image)\ for (y = y0; y < y1; y++) {\ pixel *out;\ @@ -812,11 +836,17 @@ affine_fixed(Imaging imOut, Imaging imIn, a3 += a5;\ } + ImagingSectionEnter(&cookie); + if (imIn->image8) AFFINE_TRANSFORM_FIXED(UINT8, image8) else AFFINE_TRANSFORM_FIXED(INT32, image32) + ImagingSectionLeave(&cookie); + +#undef AFFINE_TRANSFORM_FIXED + return imOut; } @@ -913,6 +943,8 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, ImagingSectionLeave(&cookie); +#undef AFFINE_TRANSFORM + return imOut; } From 3fa3b48ae9b05f33308ca9f5bac9d40423f8224f Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 09:56:50 +0300 Subject: [PATCH 03/16] ImagingTransposeToNew not used anymore --- libImaging/Geometry.c | 42 ------------------------------------------ libImaging/Imaging.h | 1 - 2 files changed, 43 deletions(-) diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index 866861d28..c4fea5c54 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -1,30 +1,3 @@ -/* - * The Python Imaging Library - * $Id$ - * - * the imaging geometry methods - * - * history: - * 1995-06-15 fl Created - * 1996-04-15 fl Changed origin - * 1996-05-18 fl Fixed rotate90/270 for rectangular images - * 1996-05-27 fl Added general purpose transform - * 1996-11-22 fl Don't crash when resizing from outside source image - * 1997-08-09 fl Fixed rounding error in resize - * 1998-09-21 fl Incorporated transformation patches (from Zircon #2) - * 1998-09-22 fl Added bounding box to transform engines - * 1999-02-03 fl Fixed bicubic filtering for RGB images - * 1999-02-16 fl Added fixed-point version of affine transform - * 2001-03-28 fl Fixed transform(EXTENT) for xoffset < 0 - * 2003-03-10 fl Compiler tweaks - * 2004-09-19 fl Fixed bilinear/bicubic filtering of LA images - * - * Copyright (c) 1997-2003 by Secret Labs AB - * Copyright (c) 1995-1997 by Fredrik Lundh - * - * See the README file for information on usage and redistribution. - */ - #include "Imaging.h" /* For large images rotation is an inefficient operation in terms of CPU cache. @@ -183,21 +156,6 @@ ImagingTranspose(Imaging imOut, Imaging imIn) } -Imaging -ImagingTransposeToNew(Imaging imIn) -{ - Imaging imTemp = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize); - if ( ! imTemp) - return NULL; - - if ( ! ImagingTranspose(imTemp, imIn)) { - ImagingDelete(imTemp); - return NULL; - } - return imTemp; -} - - Imaging ImagingRotate180(Imaging imOut, Imaging imIn) { diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index bbef0440d..42135e110 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -293,7 +293,6 @@ extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter); extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); -extern Imaging ImagingTransposeToNew(Imaging imIn); extern Imaging ImagingTransformPerspective( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, double a[8], int filter, int fill); From f680b5417b2eab31a265b3c4d9ed5713d9adc0c6 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 10:06:49 +0300 Subject: [PATCH 04/16] one code style for all methods --- PIL/Image.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 7479865e9..30861cd60 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -995,8 +995,7 @@ class Image(object): im = self.im.convert("P", 1, palette.im) return self._makeself(im) - im = self.im.quantize(colors, method, kmeans) - return self._new(im) + return self._new(self.im.quantize(colors, method, kmeans)) def copy(self): """ @@ -1007,8 +1006,7 @@ class Image(object): :returns: An :py:class:`~PIL.Image.Image` object. """ self.load() - im = self.im.copy() - return self._new(im) + return self._new(self.im.copy()) __copy__ = copy @@ -1935,8 +1933,7 @@ class Image(object): :param distance: Distance to spread pixels. """ self.load() - im = self.im.effect_spread(distance) - return self._new(im) + return self._new(self.im.effect_spread(distance)) def toqimage(self): """Returns a QImage copy of this image""" From 8203a43d262d349f71bcfa3da46e5f3e30fe99e0 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 10:57:55 +0300 Subject: [PATCH 05/16] Fast paths for rotation --- PIL/Image.py | 22 ++++++++++++++++++++-- _imaging.c | 6 ++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 30861cd60..f6aeb4502 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1569,6 +1569,18 @@ class Image(object): :returns: An :py:class:`~PIL.Image.Image` object. """ + angle = angle % 360.0 + + # Fast paths regardless of filter + if angle == 0: + return self._new(self.im) + if angle == 180: + return self.transpose(ROTATE_180) + if angle == 90 and expand: + return self.transpose(ROTATE_90) + if angle == 270 and expand: + return self.transpose(ROTATE_270) + if expand: import math angle = -angle * math.pi / 180 @@ -1843,9 +1855,11 @@ class Image(object): if isinstance(method, ImageTransformHandler): return method.transform(size, self, resample=resample, fill=fill) + if hasattr(method, "getdata"): # compatibility w. old-style transform objects method, data = method.getdata() + if data is None: raise ValueError("missing method data") @@ -1864,13 +1878,14 @@ class Image(object): # FIXME: this should be turned into a lazy operation (?) - w = box[2]-box[0] - h = box[3]-box[1] + w = box[2] - box[0] + h = box[3] - box[1] if method == AFFINE: # change argument order to match implementation data = (data[2], data[0], data[1], data[5], data[3], data[4]) + elif method == EXTENT: # convert extent to an affine transform x0, y0, x1, y1 = data @@ -1878,11 +1893,13 @@ class Image(object): ys = float(y1 - y0) / h method = AFFINE data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys) + elif method == PERSPECTIVE: # change argument order to match implementation data = (data[2], data[0], data[1], data[5], data[3], data[4], data[6], data[7]) + elif method == QUAD: # quadrilateral warp. data specifies the four corners # given as NW, SW, SE, and NE. @@ -1897,6 +1914,7 @@ class Image(object): (se[0]-sw[0]-ne[0]+x0)*As*At, y0, (ne[1]-y0)*As, (sw[1]-y0)*At, (se[1]-sw[1]-ne[1]+y0)*As*At) + else: raise ValueError("unknown transformation method") diff --git a/_imaging.c b/_imaging.c index 1077f0b57..5c4781165 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1581,12 +1581,13 @@ _rotate(ImagingObject* self, PyObject* args) theta = fmod(theta, 360.0); if (theta < 0.0) - theta += 360; + theta += 360; if (filter && imIn->type != IMAGING_TYPE_SPECIAL) { /* Rotate with resampling filter */ imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); - (void) ImagingRotate(imOut, imIn, theta, filter); + (void) ImagingRotate(imOut, imIn, theta, filter); + } else if ((theta == 90.0 || theta == 270.0) && (expand || imIn->xsize == imIn->ysize)) { /* Use fast version */ @@ -1597,6 +1598,7 @@ _rotate(ImagingObject* self, PyObject* args) else (void) ImagingRotate270(imOut, imIn); } + } else { imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); if (imOut) { From 7687ce829e50635838707f5153079fb4d34cd41e Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 11:24:45 +0300 Subject: [PATCH 06/16] round results of sin and cos functions because there is no possible float-point value of radians which cos will exactly 0. --- PIL/Image.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index f6aeb4502..ee9f860db 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1583,10 +1583,10 @@ class Image(object): if expand: import math - angle = -angle * math.pi / 180 + angle = - math.radians(angle) matrix = [ - math.cos(angle), math.sin(angle), 0.0, - -math.sin(angle), math.cos(angle), 0.0 + round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0, + round(-math.sin(angle), 15), round(math.cos(angle), 15), 0.0 ] def transform(x, y, matrix=matrix): From 709078efd14cfcffaedf59e883f56aa16d61926e Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 11:36:41 +0300 Subject: [PATCH 07/16] use one self.transform for rotation --- PIL/Image.py | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index ee9f860db..4abfab20b 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -30,6 +30,7 @@ from PIL import VERSION, PILLOW_VERSION, _plugins import logging import warnings +import math logger = logging.getLogger(__name__) @@ -1581,20 +1582,20 @@ class Image(object): if angle == 270 and expand: return self.transpose(ROTATE_270) + + angle = - math.radians(angle) + matrix = [ + round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0, + round(-math.sin(angle), 15), round(math.cos(angle), 15), 0.0 + ] + + def transform(x, y, matrix=matrix): + (a, b, c, d, e, f) = matrix + return a*x + b*y + c, d*x + e*y + f + + w, h = self.size if expand: - import math - angle = - math.radians(angle) - matrix = [ - round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0, - round(-math.sin(angle), 15), round(math.cos(angle), 15), 0.0 - ] - - def transform(x, y, matrix=matrix): - (a, b, c, d, e, f) = matrix - return a*x + b*y + c, d*x + e*y + f - # calculate output size - w, h = self.size xx = [] yy = [] for x, y in ((0, 0), (w, 0), (w, h), (0, h)): @@ -1604,22 +1605,12 @@ class Image(object): w = int(math.ceil(max(xx)) - math.floor(min(xx))) h = int(math.ceil(max(yy)) - math.floor(min(yy))) - # adjust center - x, y = transform(w / 2.0, h / 2.0) - matrix[2] = self.size[0] / 2.0 - x - matrix[5] = self.size[1] / 2.0 - y + # adjust center + x, y = transform(w / 2.0, h / 2.0) + matrix[2] = self.size[0] / 2.0 - x + matrix[5] = self.size[1] / 2.0 - y - return self.transform((w, h), AFFINE, matrix, resample) - - if resample not in (NEAREST, BILINEAR, BICUBIC): - raise ValueError("unknown resampling filter") - - self.load() - - if self.mode in ("1", "P"): - resample = NEAREST - - return self._new(self.im.rotate(angle, resample, expand)) + return self.transform((w, h), AFFINE, matrix, resample) def save(self, fp, format=None, **params): """ From 1f8c2527baaff6357f31761b6340d2016920781f Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 11:44:10 +0300 Subject: [PATCH 08/16] internal rotating functions not used anymore --- PIL/Image.py | 1 - _imaging.c | 52 ------------------------------------------- libImaging/Geometry.c | 31 -------------------------- libImaging/Imaging.h | 2 -- 4 files changed, 86 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 4abfab20b..5e79e4bd8 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1582,7 +1582,6 @@ class Image(object): if angle == 270 and expand: return self.transpose(ROTATE_270) - angle = - math.radians(angle) matrix = [ round(math.cos(angle), 15), round(math.sin(angle), 15), 0.0, diff --git a/_imaging.c b/_imaging.c index 5c4781165..8b87a8108 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1565,57 +1565,6 @@ _resize(ImagingObject* self, PyObject* args) return PyImagingNew(imOut); } -static PyObject* -_rotate(ImagingObject* self, PyObject* args) -{ - Imaging imOut; - Imaging imIn; - - double theta; - int filter = IMAGING_TRANSFORM_NEAREST; - int expand; - if (!PyArg_ParseTuple(args, "d|i|i", &theta, &filter, &expand)) - return NULL; - - imIn = self->image; - - theta = fmod(theta, 360.0); - if (theta < 0.0) - theta += 360; - - if (filter && imIn->type != IMAGING_TYPE_SPECIAL) { - /* Rotate with resampling filter */ - imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); - (void) ImagingRotate(imOut, imIn, theta, filter); - - } else if ((theta == 90.0 || theta == 270.0) - && (expand || imIn->xsize == imIn->ysize)) { - /* Use fast version */ - imOut = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize); - if (imOut) { - if (theta == 90.0) - (void) ImagingRotate90(imOut, imIn); - else - (void) ImagingRotate270(imOut, imIn); - } - - } else { - imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); - if (imOut) { - if (theta == 0.0) - /* No rotation: simply copy the input image */ - (void) ImagingCopy2(imOut, imIn); - else if (theta == 180.0) - /* Use fast version */ - (void) ImagingRotate180(imOut, imIn); - else - /* Use ordinary version */ - (void) ImagingRotate(imOut, imIn, theta, 0); - } - } - - return PyImagingNew(imOut); -} #define IS_RGB(mode)\ (!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX")) @@ -3050,7 +2999,6 @@ static struct PyMethodDef methods[] = { // 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}, {"transpose", (PyCFunction)_transpose, 1}, {"transform2", (PyCFunction)_transform2, 1}, diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index c4fea5c54..793cb9519 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -939,34 +939,3 @@ ImagingTransformQuad(Imaging imOut, Imaging imIn, filter, NULL, fill); } - -/* -------------------------------------------------------------------- */ -/* Convenience functions */ - -Imaging -ImagingRotate(Imaging imOut, Imaging imIn, double theta, int filterid) -{ - int xsize, ysize; - double sintheta, costheta; - double a[6]; - - /* Setup an affine transform to rotate around the image center */ - theta = -theta * M_PI / 180.0; - sintheta = sin(theta); - costheta = cos(theta); - - xsize = imOut->xsize; - ysize = imOut->ysize; - - a[0] = -costheta * xsize/2 - sintheta * ysize/2 + xsize/2; - a[1] = costheta; - a[2] = sintheta; - a[3] = sintheta * xsize/2 - costheta * ysize/2 + ysize/2; - a[4] = -sintheta; - a[5] = costheta; - - return ImagingTransformAffine( - imOut, imIn, - 0, 0, imOut->xsize, imOut->ysize, - a, filterid, 1); -} diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 42135e110..ebcafd548 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -286,8 +286,6 @@ extern Imaging ImagingPointTransform( Imaging imIn, double scale, double offset); extern Imaging ImagingPutBand(Imaging im, Imaging imIn, int band); extern Imaging ImagingRankFilter(Imaging im, int size, int rank); -extern Imaging ImagingRotate( - Imaging imOut, Imaging imIn, double theta, int filter); extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); From 6be3df2a432bdc61d0705ebacfc878b93cc86b9c Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 14:20:41 +0300 Subject: [PATCH 09/16] remove internal ImagingTransform from headers rename to ImagingGenericTransform --- PIL/Image.py | 3 --- libImaging/Geometry.c | 8 ++++---- libImaging/Imaging.h | 5 ----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 5e79e4bd8..226d0b41e 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1865,9 +1865,6 @@ class Image(object): def __transformer(self, box, image, method, data, resample=NEAREST, fill=1): - - # FIXME: this should be turned into a lazy operation (?) - w = box[2] - box[0] h = box[3] - box[1] diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index 793cb9519..6d32aa271 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -606,7 +606,7 @@ getfilter(Imaging im, int filterid) /* transformation engines */ Imaging -ImagingTransform( +ImagingGenericTransform( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, ImagingTransformMap transform, void* transform_data, ImagingTransformFilter filter, void* filter_data, @@ -828,7 +828,7 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, ImagingTransformFilter filter = getfilter(imIn, filterid); if (!filter) return (Imaging) ImagingError_ValueError("unknown filter"); - return ImagingTransform( + return ImagingGenericTransform( imOut, imIn, x0, y0, x1, y1, affine_transform, a, @@ -915,7 +915,7 @@ ImagingTransformPerspective(Imaging imOut, Imaging imIn, if (!filter) return (Imaging) ImagingError_ValueError("bad filter number"); - return ImagingTransform( + return ImagingGenericTransform( imOut, imIn, x0, y0, x1, y1, perspective_transform, a, @@ -932,7 +932,7 @@ ImagingTransformQuad(Imaging imOut, Imaging imIn, if (!filter) return (Imaging) ImagingError_ValueError("bad filter number"); - return ImagingTransform( + return ImagingGenericTransform( imOut, imIn, x0, y0, x1, y1, quad_transform, a, diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index ebcafd548..9db7c5858 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -300,11 +300,6 @@ extern Imaging ImagingTransformAffine( extern Imaging ImagingTransformQuad( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, double a[8], int filter, int fill); -extern Imaging ImagingTransform( - Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, - ImagingTransformMap transform, void* transform_data, - ImagingTransformFilter filter, void* filter_data, - int fill); extern Imaging ImagingUnsharpMask( Imaging imOut, Imaging im, float radius, int percent, int threshold); extern Imaging ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n); From 2e914af758a25193e538cf2cfb48a705f25595a2 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 15:21:38 +0300 Subject: [PATCH 10/16] unused --- libImaging/Imaging.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 9db7c5858..547523518 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -330,12 +330,6 @@ extern Imaging ImagingChopXor(Imaging imIn1, Imaging imIn2); extern void ImagingCrack(Imaging im, int x0, int y0); /* Graphics */ -struct ImagingAffineMatrixInstance { - float a[9]; -}; - -typedef struct ImagingAffineMatrixInstance *ImagingAffineMatrix; - extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1, float start, float end, const void* ink, int op); extern int ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, From 9902d2e1c50712a7fa1d308fab124bf5c71f018e Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 15:47:27 +0300 Subject: [PATCH 11/16] move transform dispatcher into libImaging --- _imaging.c | 32 ++++------------------- libImaging/Geometry.c | 59 +++++++++++++++++++------------------------ libImaging/Imaging.h | 12 +++------ 3 files changed, 34 insertions(+), 69 deletions(-) diff --git a/_imaging.c b/_imaging.c index 8b87a8108..fa4258163 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1553,8 +1553,8 @@ _resize(ImagingObject* self, PyObject* args) imOut = ImagingNew(imIn->mode, xsize, ysize); - imOut = ImagingTransformAffine( - imOut, imIn, + imOut = ImagingTransform( + imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1); } @@ -1613,7 +1613,6 @@ _transform2(ImagingObject* self, PyObject* args) { static const char* wrong_number = "wrong number of matrix entries"; - Imaging imIn; Imaging imOut; int n; double *a; @@ -1649,30 +1648,9 @@ _transform2(ImagingObject* self, PyObject* args) if (!a) return NULL; - imOut = self->image; - imIn = imagep->image; - - /* FIXME: move transform dispatcher into libImaging */ - - switch (method) { - case IMAGING_TRANSFORM_AFFINE: - imOut = ImagingTransformAffine( - imOut, imIn, x0, y0, x1, y1, a, filter, 1 - ); - break; - case IMAGING_TRANSFORM_PERSPECTIVE: - imOut = ImagingTransformPerspective( - imOut, imIn, x0, y0, x1, y1, a, filter, 1 - ); - break; - case IMAGING_TRANSFORM_QUAD: - imOut = ImagingTransformQuad( - imOut, imIn, x0, y0, x1, y1, a, filter, 1 - ); - break; - default: - (void) ImagingError_ValueError("bad transform method"); - } + imOut = ImagingTransform( + self->image, imagep->image, method, + x0, y0, x1, y1, a, filter, 1); free(a); diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index 6d32aa271..8dea4d48e 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -609,8 +609,7 @@ Imaging ImagingGenericTransform( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, ImagingTransformMap transform, void* transform_data, - ImagingTransformFilter filter, void* filter_data, - int fill) + int filterid, void* filter_data, int fill) { /* slow generic transformation. use ImagingTransformAffine or ImagingScaleAffine where possible. */ @@ -620,6 +619,10 @@ ImagingGenericTransform( char *out; double xx, yy; + ImagingTransformFilter filter = getfilter(imIn, filterid); + if (!filter) + return (Imaging) ImagingError_ValueError("bad filter number"); + if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) return (Imaging) ImagingError_ModeError(); @@ -824,15 +827,11 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, double xo, yo; if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) { - /* Filtered transform */ - ImagingTransformFilter filter = getfilter(imIn, filterid); - if (!filter) - return (Imaging) ImagingError_ValueError("unknown filter"); return ImagingGenericTransform( imOut, imIn, x0, y0, x1, y1, affine_transform, a, - filter, NULL, fill); + filterid, NULL, fill); } if (a[2] == 0 && a[4] == 0) @@ -907,35 +906,29 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, } Imaging -ImagingTransformPerspective(Imaging imOut, Imaging imIn, - int x0, int y0, int x1, int y1, - double a[8], int filterid, int fill) +ImagingTransform(Imaging imOut, Imaging imIn, int method, + int x0, int y0, int x1, int y1, + double a[8], int filterid, int fill) { - ImagingTransformFilter filter = getfilter(imIn, filterid); - if (!filter) - return (Imaging) ImagingError_ValueError("bad filter number"); + ImagingTransformMap transform; + + switch(method) { + case IMAGING_TRANSFORM_AFFINE: + return ImagingTransformAffine( + imOut, imIn, x0, y0, x1, y1, a, filterid, fill); + break; + case IMAGING_TRANSFORM_PERSPECTIVE: + transform = perspective_transform; + break; + case IMAGING_TRANSFORM_QUAD: + transform = quad_transform; + break; + default: + return (Imaging) ImagingError_ValueError("bad transform method"); + } return ImagingGenericTransform( imOut, imIn, x0, y0, x1, y1, - perspective_transform, a, - filter, NULL, - fill); -} - -Imaging -ImagingTransformQuad(Imaging imOut, Imaging imIn, - int x0, int y0, int x1, int y1, - double a[8], int filterid, int fill) -{ - ImagingTransformFilter filter = getfilter(imIn, filterid); - if (!filter) - return (Imaging) ImagingError_ValueError("bad filter number"); - - return ImagingGenericTransform( - imOut, imIn, - x0, y0, x1, y1, - quad_transform, a, - filter, NULL, - fill); + transform, a, filterid, NULL, fill); } diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 547523518..084e5592f 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -291,15 +291,9 @@ extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter); extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); -extern Imaging ImagingTransformPerspective( - Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, - double a[8], int filter, int fill); -extern Imaging ImagingTransformAffine( - Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, - double a[6], int filter, int fill); -extern Imaging ImagingTransformQuad( - Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, - double a[8], int filter, int fill); +extern Imaging ImagingTransform( + Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1, + double *a, int filter, int fill); extern Imaging ImagingUnsharpMask( Imaging imOut, Imaging im, float radius, int percent, int threshold); extern Imaging ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n); From bc51928171b873d1e2f0d86979f0123a6f8b5b61 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 16:23:42 +0300 Subject: [PATCH 12/16] move ImagingCopyInfo after affine_fixed --- libImaging/Geometry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index 8dea4d48e..f91ec2c1f 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -850,8 +850,6 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, if (y1 > imOut->ysize) y1 = imOut->ysize; - ImagingCopyInfo(imOut, imIn); - /* translate all four corners to check if they are within the range that can be represented by the fixed point arithmetics */ @@ -862,6 +860,8 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, /* FIXME: cannot really think of any reasonable case when the following code is used. maybe we should fall back on the slow generic transform engine in this case? */ + + ImagingCopyInfo(imOut, imIn); xsize = (int) imIn->xsize; ysize = (int) imIn->ysize; From 4cfc791a5bacd0ec9cd147c02b5197ef346a3e22 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 18:33:17 +0300 Subject: [PATCH 13/16] remove unused filter_data --- libImaging/Geometry.c | 66 +++++++++++++++++++++---------------------- libImaging/Imaging.h | 3 +- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index f91ec2c1f..2c2bc587e 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -288,7 +288,7 @@ quad_transform(double* xin, double* yin, int x, int y, void* data) /* transform filters (ImagingTransformFilter) */ static int -nearest_filter8(void* out, Imaging im, double xin, double yin, void* data) +nearest_filter8(void* out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); @@ -299,7 +299,7 @@ nearest_filter8(void* out, Imaging im, double xin, double yin, void* data) } static int -nearest_filter16(void* out, Imaging im, double xin, double yin, void* data) +nearest_filter16(void* out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); @@ -310,7 +310,7 @@ nearest_filter16(void* out, Imaging im, double xin, double yin, void* data) } static int -nearest_filter32(void* out, Imaging im, double xin, double yin, void* data) +nearest_filter32(void* out, Imaging im, double xin, double yin) { int x = COORD(xin); int y = COORD(yin); @@ -355,7 +355,7 @@ nearest_filter32(void* out, Imaging im, double xin, double yin, void* data) } static int -bilinear_filter8(void* out, Imaging im, double xin, double yin, void* data) +bilinear_filter8(void* out, Imaging im, double xin, double yin) { BILINEAR_HEAD(UINT8); BILINEAR_BODY(UINT8, im->image8, 1, 0); @@ -364,7 +364,7 @@ bilinear_filter8(void* out, Imaging im, double xin, double yin, void* data) } static int -bilinear_filter32I(void* out, Imaging im, double xin, double yin, void* data) +bilinear_filter32I(void* out, Imaging im, double xin, double yin) { BILINEAR_HEAD(INT32); BILINEAR_BODY(INT32, im->image32, 1, 0); @@ -373,7 +373,7 @@ bilinear_filter32I(void* out, Imaging im, double xin, double yin, void* data) } static int -bilinear_filter32F(void* out, Imaging im, double xin, double yin, void* data) +bilinear_filter32F(void* out, Imaging im, double xin, double yin) { BILINEAR_HEAD(FLOAT32); BILINEAR_BODY(FLOAT32, im->image32, 1, 0); @@ -382,7 +382,7 @@ bilinear_filter32F(void* out, Imaging im, double xin, double yin, void* data) } static int -bilinear_filter32LA(void* out, Imaging im, double xin, double yin, void* data) +bilinear_filter32LA(void* out, Imaging im, double xin, double yin) { BILINEAR_HEAD(UINT8); BILINEAR_BODY(UINT8, im->image, 4, 0); @@ -395,7 +395,7 @@ bilinear_filter32LA(void* out, Imaging im, double xin, double yin, void* data) } static int -bilinear_filter32RGB(void* out, Imaging im, double xin, double yin, void* data) +bilinear_filter32RGB(void* out, Imaging im, double xin, double yin) { int b; BILINEAR_HEAD(UINT8); @@ -462,7 +462,7 @@ bilinear_filter32RGB(void* out, Imaging im, double xin, double yin, void* data) static int -bicubic_filter8(void* out, Imaging im, double xin, double yin, void* data) +bicubic_filter8(void* out, Imaging im, double xin, double yin) { BICUBIC_HEAD(UINT8); BICUBIC_BODY(UINT8, im->image8, 1, 0); @@ -476,7 +476,7 @@ bicubic_filter8(void* out, Imaging im, double xin, double yin, void* data) } static int -bicubic_filter32I(void* out, Imaging im, double xin, double yin, void* data) +bicubic_filter32I(void* out, Imaging im, double xin, double yin) { BICUBIC_HEAD(INT32); BICUBIC_BODY(INT32, im->image32, 1, 0); @@ -485,7 +485,7 @@ bicubic_filter32I(void* out, Imaging im, double xin, double yin, void* data) } static int -bicubic_filter32F(void* out, Imaging im, double xin, double yin, void* data) +bicubic_filter32F(void* out, Imaging im, double xin, double yin) { BICUBIC_HEAD(FLOAT32); BICUBIC_BODY(FLOAT32, im->image32, 1, 0); @@ -494,7 +494,7 @@ bicubic_filter32F(void* out, Imaging im, double xin, double yin, void* data) } static int -bicubic_filter32LA(void* out, Imaging im, double xin, double yin, void* data) +bicubic_filter32LA(void* out, Imaging im, double xin, double yin) { BICUBIC_HEAD(UINT8); BICUBIC_BODY(UINT8, im->image, 4, 0); @@ -522,7 +522,7 @@ bicubic_filter32LA(void* out, Imaging im, double xin, double yin, void* data) } static int -bicubic_filter32RGB(void* out, Imaging im, double xin, double yin, void* data) +bicubic_filter32RGB(void* out, Imaging im, double xin, double yin) { int b; BICUBIC_HEAD(UINT8); @@ -550,51 +550,51 @@ getfilter(Imaging im, int filterid) if (im->image8) switch (im->type) { case IMAGING_TYPE_UINT8: - return (ImagingTransformFilter) nearest_filter8; + return nearest_filter8; case IMAGING_TYPE_SPECIAL: switch (im->pixelsize) { case 1: - return (ImagingTransformFilter) nearest_filter8; + return nearest_filter8; case 2: - return (ImagingTransformFilter) nearest_filter16; + return nearest_filter16; case 4: - return (ImagingTransformFilter) nearest_filter32; + return nearest_filter32; } } else - return (ImagingTransformFilter) nearest_filter32; + return nearest_filter32; break; case IMAGING_TRANSFORM_BILINEAR: if (im->image8) - return (ImagingTransformFilter) bilinear_filter8; + return bilinear_filter8; else if (im->image32) { switch (im->type) { case IMAGING_TYPE_UINT8: if (im->bands == 2) - return (ImagingTransformFilter) bilinear_filter32LA; + return bilinear_filter32LA; else - return (ImagingTransformFilter) bilinear_filter32RGB; + return bilinear_filter32RGB; case IMAGING_TYPE_INT32: - return (ImagingTransformFilter) bilinear_filter32I; + return bilinear_filter32I; case IMAGING_TYPE_FLOAT32: - return (ImagingTransformFilter) bilinear_filter32F; + return bilinear_filter32F; } } break; case IMAGING_TRANSFORM_BICUBIC: if (im->image8) - return (ImagingTransformFilter) bicubic_filter8; + return bicubic_filter8; else if (im->image32) { switch (im->type) { case IMAGING_TYPE_UINT8: if (im->bands == 2) - return (ImagingTransformFilter) bicubic_filter32LA; + return bicubic_filter32LA; else - return (ImagingTransformFilter) bicubic_filter32RGB; + return bicubic_filter32RGB; case IMAGING_TYPE_INT32: - return (ImagingTransformFilter) bicubic_filter32I; + return bicubic_filter32I; case IMAGING_TYPE_FLOAT32: - return (ImagingTransformFilter) bicubic_filter32F; + return bicubic_filter32F; } } break; @@ -609,7 +609,7 @@ Imaging ImagingGenericTransform( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, ImagingTransformMap transform, void* transform_data, - int filterid, void* filter_data, int fill) + int filterid, int fill) { /* slow generic transformation. use ImagingTransformAffine or ImagingScaleAffine where possible. */ @@ -642,8 +642,8 @@ ImagingGenericTransform( for (y = y0; y < y1; y++) { out = imOut->image[y] + x0*imOut->pixelsize; for (x = x0; x < x1; x++) { - if (!transform(&xx, &yy, x-x0, y-y0, transform_data) || - !filter(out, imIn, xx, yy, filter_data)) { + if ( ! transform(&xx, &yy, x-x0, y-y0, transform_data) || + ! filter(out, imIn, xx, yy)) { if (fill) memset(out, 0, imOut->pixelsize); } @@ -831,7 +831,7 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, imOut, imIn, x0, y0, x1, y1, affine_transform, a, - filterid, NULL, fill); + filterid, fill); } if (a[2] == 0 && a[4] == 0) @@ -930,5 +930,5 @@ ImagingTransform(Imaging imOut, Imaging imIn, int method, return ImagingGenericTransform( imOut, imIn, x0, y0, x1, y1, - transform, a, filterid, NULL, fill); + transform, a, filterid, fill); } diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 084e5592f..cdda4ae40 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -236,8 +236,7 @@ extern void ImagingError_Clear(void); typedef int (*ImagingTransformMap)(double* X, double* Y, int x, int y, void* data); typedef int (*ImagingTransformFilter)(void* out, Imaging im, - double x, double y, - void* data); + double x, double y); /* Image Manipulation Methods */ /* -------------------------- */ From 2b77b1cec7fae15112be03dd5c1bfbb0169c3e0b Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 21:58:42 +0300 Subject: [PATCH 14/16] make affine transform arguments order more common --- PIL/Image.py | 6 ++---- _imaging.c | 6 +++--- libImaging/Geometry.c | 42 +++++++++++++++++++++--------------------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 226d0b41e..5bac01665 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1869,9 +1869,7 @@ class Image(object): h = box[3] - box[1] if method == AFFINE: - # change argument order to match implementation - data = (data[2], data[0], data[1], - data[5], data[3], data[4]) + data = data[0:6] elif method == EXTENT: # convert extent to an affine transform @@ -1879,7 +1877,7 @@ class Image(object): xs = float(x1 - x0) / w ys = float(y1 - y0) / h method = AFFINE - data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys) + data = (xs, 0, x0 + xs/2, 0, ys, y0 + ys/2) elif method == PERSPECTIVE: # change argument order to match implementation diff --git a/_imaging.c b/_imaging.c index fa4258163..a282bb36a 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1544,12 +1544,12 @@ _resize(ImagingObject* self, PyObject* args) if (imIn->xsize == xsize && imIn->ysize == ysize) { imOut = ImagingCopy(imIn); } - else if ( ! filter) { + else if (filter == IMAGING_TRANSFORM_NEAREST) { double a[6]; memset(a, 0, sizeof a); - a[1] = (double) imIn->xsize / xsize; - a[5] = (double) imIn->ysize / ysize; + a[0] = (double) imIn->xsize / xsize; + a[4] = (double) imIn->ysize / ysize; imOut = ImagingNew(imIn->mode, xsize, ysize); diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index 2c2bc587e..e09eef62e 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -250,8 +250,8 @@ affine_transform(double* xin, double* yin, int x, int y, void* data) double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3]; double a4 = a[4]; double a5 = a[5]; - xin[0] = a0 + a1*x + a2*y; - yin[0] = a3 + a4*x + a5*y; + xin[0] = a0*x + a1*y + a2; + yin[0] = a3*x + a4*y + a5; return 1; } @@ -690,8 +690,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, return (Imaging) ImagingError_MemoryError(); } - xo = a[0]; - yo = a[3]; + xo = a[2]; + yo = a[5]; xmin = x1; xmax = x0; @@ -705,7 +705,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, xmin = x; xintab[x] = xin; } - xo += a[1]; + xo += a[0]; } #define AFFINE_SCALE(pixel, image)\ @@ -720,7 +720,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, for (x = xmin; x < xmax; x++)\ out[x] = in[xintab[x]];\ }\ - yo += a[5];\ + yo += a[4];\ } ImagingSectionEnter(&cookie); @@ -743,8 +743,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, static inline int check_fixed(double a[6], int x, int y) { - return (fabs(a[0] + x*a[1] + y*a[2]) < 32768.0 && - fabs(a[3] + x*a[4] + y*a[5]) < 32768.0); + return (fabs(x*a[0] + y*a[1] + a[2]) < 32768.0 && + fabs(x*a[3] + y*a[4] + a[5]) < 32768.0); } static inline Imaging @@ -778,8 +778,8 @@ affine_fixed(Imaging imOut, Imaging imIn, #define AFFINE_TRANSFORM_FIXED(pixel, image)\ for (y = y0; y < y1; y++) {\ pixel *out;\ - xx = a0;\ - yy = a3;\ + xx = a2;\ + yy = a5;\ out = imOut->image[y];\ if (fill && x1 > x0)\ memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ @@ -790,11 +790,11 @@ affine_fixed(Imaging imOut, Imaging imIn, if (yin >= 0 && yin < ysize)\ *out = imIn->image[yin][xin];\ }\ - xx += a1;\ - yy += a4;\ + xx += a0;\ + yy += a3;\ }\ - a0 += a2;\ - a3 += a5;\ + a2 += a1;\ + a5 += a4;\ } ImagingSectionEnter(&cookie); @@ -834,7 +834,7 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, filterid, fill); } - if (a[2] == 0 && a[4] == 0) + if (a[1] == 0 && a[3] == 0) /* Scaling */ return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill); @@ -866,8 +866,8 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, xsize = (int) imIn->xsize; ysize = (int) imIn->ysize; - xo = a[0]; - yo = a[3]; + xo = a[2]; + yo = a[5]; #define AFFINE_TRANSFORM(pixel, image)\ for (y = y0; y < y1; y++) {\ @@ -884,11 +884,11 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, if (yin >= 0 && yin < ysize)\ *out = imIn->image[yin][xin];\ }\ - xx += a[1];\ - yy += a[4];\ + xx += a[0];\ + yy += a[3];\ }\ - xo += a[2];\ - yo += a[5];\ + xo += a[1];\ + yo += a[4];\ } ImagingSectionEnter(&cookie); From 3d622d60cf7c6c609cfc48b774ee0d8aef2d1d85 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 23:47:45 +0300 Subject: [PATCH 15/16] make perspecive transform arguments order more common --- PIL/Image.py | 4 +--- libImaging/Geometry.c | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 5bac01665..a6fd4e95d 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1881,9 +1881,7 @@ class Image(object): elif method == PERSPECTIVE: # change argument order to match implementation - data = (data[2], data[0], data[1], - data[5], data[3], data[4], - data[6], data[7]) + data = data[0:8] elif method == QUAD: # quadrilateral warp. data specifies the four corners diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index e09eef62e..103b75e53 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -264,8 +264,8 @@ perspective_transform(double* xin, double* yin, int x, int y, void* data) double a3 = a[3]; double a4 = a[4]; double a5 = a[5]; double a6 = a[6]; double a7 = a[7]; - xin[0] = (a0 + a1*x + a2*y) / (a6*x + a7*y + 1); - yin[0] = (a3 + a4*x + a5*y) / (a6*x + a7*y + 1); + xin[0] = (a0*x + a1*y + a2) / (a6*x + a7*y + 1); + yin[0] = (a3*x + a4*y + a5) / (a6*x + a7*y + 1); return 1; } From 78242e4acdb2074250d3a07d79c31c81d0720b19 Mon Sep 17 00:00:00 2001 From: homm Date: Wed, 8 Jun 2016 16:47:26 +0300 Subject: [PATCH 16/16] remove stale comment --- PIL/Image.py | 1 - 1 file changed, 1 deletion(-) diff --git a/PIL/Image.py b/PIL/Image.py index a6fd4e95d..2e407ca80 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1880,7 +1880,6 @@ class Image(object): data = (xs, 0, x0 + xs/2, 0, ys, y0 + ys/2) elif method == PERSPECTIVE: - # change argument order to match implementation data = data[0:8] elif method == QUAD: