Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 43 additions & 45 deletions PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import logging
import warnings
import math

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -995,8 +996,7 @@ def quantize(self, colors=256, method=None, kmeans=0, palette=None):
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):
"""
Expand All @@ -1007,8 +1007,7 @@ def copy(self):
: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

Expand Down Expand Up @@ -1571,20 +1570,31 @@ def rotate(self, angle, resample=NEAREST, expand=0):
:returns: An :py:class:`~PIL.Image.Image` object.
"""

if expand:
import math
angle = -angle * math.pi / 180
matrix = [
math.cos(angle), math.sin(angle), 0.0,
-math.sin(angle), math.cos(angle), 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
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)

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:
# calculate output size
w, h = self.size
xx = []
yy = []
for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
Expand All @@ -1594,22 +1604,12 @@ def transform(x, y, matrix=matrix):
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

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
# 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._new(self.im.rotate(angle, resample, expand))
return self.transform((w, h), AFFINE, matrix, resample)

def save(self, fp, format=None, **params):
"""
Expand Down Expand Up @@ -1845,9 +1845,11 @@ def transform(self, size, method, data=None, resample=NEAREST, fill=1):

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")

Expand All @@ -1863,28 +1865,24 @@ def transform(self, size, method, data=None, resample=NEAREST, fill=1):

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]
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])
data = data[0:6]

elif method == EXTENT:
# convert extent to an affine transform
x0, y0, x1, y1 = data
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't apply anymore, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, removed

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
# given as NW, SW, SE, and NE.
Expand All @@ -1899,6 +1897,7 @@ def __transformer(self, box, image, method, data,
(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")

Expand Down Expand Up @@ -1935,8 +1934,7 @@ def effect_spread(self, distance):
: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"""
Expand Down
88 changes: 8 additions & 80 deletions _imaging.c
Original file line number Diff line number Diff line change
Expand Up @@ -1544,17 +1544,17 @@ _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);

imOut = ImagingTransformAffine(
imOut, imIn,
imOut = ImagingTransform(
imOut, imIn, IMAGING_TRANSFORM_AFFINE,
0, 0, xsize, ysize,
a, filter, 1);
}
Expand All @@ -1565,55 +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"))
Expand Down Expand Up @@ -1662,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;
Expand Down Expand Up @@ -1698,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);

Expand Down Expand Up @@ -3048,7 +2977,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},

Expand Down
Loading