From 8203a43d262d349f71bcfa3da46e5f3e30fe99e0 Mon Sep 17 00:00:00 2001 From: homm Date: Thu, 2 Jun 2016 10:57:55 +0300 Subject: [PATCH] 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) {