Merge pull request #1941 from uploadcare/cleanup-transforms

Cleanup transforms
This commit is contained in:
wiredfool 2016-06-11 15:25:34 +01:00 committed by GitHub
commit ebd3c35de5
4 changed files with 175 additions and 328 deletions

View File

@ -30,6 +30,7 @@ from PIL import VERSION, PILLOW_VERSION, _plugins
import logging
import warnings
import math
logger = logging.getLogger(__name__)
@ -995,8 +996,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 +1007,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
@ -1571,20 +1570,31 @@ 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)
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 = -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
# calculate output size
w, h = self.size
xx = []
yy = []
for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
@ -1594,22 +1604,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):
"""
@ -1845,9 +1845,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")
@ -1863,28 +1865,23 @@ 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]
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
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.
@ -1899,6 +1896,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")
@ -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"""

View File

@ -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);
}
@ -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"))
@ -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;
@ -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);
@ -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},

View File

@ -1,35 +1,5 @@
/*
* 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"
/* 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
@ -72,6 +42,8 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn)
ImagingSectionLeave(&cookie);
#undef FLIP_HORIZ
return imOut;
}
@ -91,7 +63,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);
@ -137,6 +109,8 @@ ImagingRotate90(Imaging imOut, Imaging imIn)
ImagingSectionLeave(&cookie);
#undef ROTATE_90
return imOut;
}
@ -152,6 +126,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) { \
@ -165,34 +141,21 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
} \
}
ImagingCopyInfo(imOut, imIn);
ImagingSectionEnter(&cookie);
if (imIn->image8)
TRANSPOSE(image8)
else
TRANSPOSE(image32)
ImagingSectionLeave(&cookie);
#undef TRANSPOSE
return imOut;
}
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)
{
@ -206,8 +169,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;\
@ -217,6 +178,7 @@ ImagingRotate180(Imaging imOut, Imaging imIn)
ImagingSectionEnter(&cookie);
yr = imIn->ysize-1;
if (imIn->image8)
ROTATE_180(image8)
else
@ -224,6 +186,8 @@ ImagingRotate180(Imaging imOut, Imaging imIn)
ImagingSectionLeave(&cookie);
#undef ROTATE_180
return imOut;
}
@ -264,6 +228,8 @@ ImagingRotate270(Imaging imOut, Imaging imIn)
ImagingSectionLeave(&cookie);
#undef ROTATE_270
return imOut;
}
@ -284,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;
}
@ -298,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;
}
@ -321,10 +287,8 @@ 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)
nearest_filter8(void* out, Imaging im, double xin, double yin)
{
int x = COORD(xin);
int y = COORD(yin);
@ -335,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);
@ -346,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);
@ -391,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);
@ -400,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);
@ -409,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);
@ -418,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);
@ -431,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);
@ -442,6 +406,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;\
@ -494,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);
@ -508,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);
@ -517,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);
@ -526,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);
@ -554,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);
@ -570,6 +538,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)
{
@ -578,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;
@ -631,18 +603,13 @@ getfilter(Imaging im, int filterid)
return NULL;
}
#else
#define getfilter(im, id) NULL
#endif
/* 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,
int fill)
int filterid, int fill)
{
/* slow generic transformation. use ImagingTransformAffine or
ImagingScaleAffine where possible. */
@ -652,6 +619,10 @@ ImagingTransform(
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();
@ -671,8 +642,8 @@ ImagingTransform(
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);
}
@ -719,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;
@ -734,7 +705,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
xmin = x;
xintab[x] = xin;
}
xo += a[1];
xo += a[0];
}
#define AFFINE_SCALE(pixel, image)\
@ -749,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);
@ -762,6 +733,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
ImagingSectionLeave(&cookie);
#undef AFFINE_SCALE
free(xintab);
return imOut;
@ -770,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
@ -782,6 +755,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;
@ -799,11 +773,13 @@ 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;\
xx = a0;\
yy = a3;\
xx = a2;\
yy = a5;\
out = imOut->image[y];\
if (fill && x1 > x0)\
memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
@ -814,18 +790,24 @@ 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);
if (imIn->image8)
AFFINE_TRANSFORM_FIXED(UINT8, image8)
else
AFFINE_TRANSFORM_FIXED(INT32, image32)
ImagingSectionLeave(&cookie);
#undef AFFINE_TRANSFORM_FIXED
return imOut;
}
@ -845,18 +827,14 @@ 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 ImagingTransform(
return ImagingGenericTransform(
imOut, imIn,
x0, y0, x1, y1,
affine_transform, a,
filter, NULL, fill);
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);
@ -872,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 */
@ -884,12 +860,14 @@ 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;
xo = a[0];
yo = a[3];
xo = a[2];
yo = a[5];
#define AFFINE_TRANSFORM(pixel, image)\
for (y = y0; y < y1; y++) {\
@ -906,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);
@ -922,70 +900,35 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
ImagingSectionLeave(&cookie);
#undef AFFINE_TRANSFORM
return imOut;
}
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;
return ImagingTransform(
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 ImagingTransform(
imOut, imIn,
x0, y0, x1, y1,
quad_transform, a,
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);
transform, a, filterid, fill);
}

View File

@ -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 */
/* -------------------------- */
@ -286,28 +285,14 @@ 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);
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);
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 x0, int y0, int x1, int y1,
ImagingTransformMap transform, void* transform_data,
ImagingTransformFilter filter, void* filter_data,
int fill);
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);
@ -338,12 +323,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,