mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-10 08:12:33 +03:00
Merge pull request #1941 from uploadcare/cleanup-transforms
Cleanup transforms
This commit is contained in:
commit
ebd3c35de5
89
PIL/Image.py
89
PIL/Image.py
|
@ -30,6 +30,7 @@ from PIL import VERSION, PILLOW_VERSION, _plugins
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import warnings
|
import warnings
|
||||||
|
import math
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -995,8 +996,7 @@ class Image(object):
|
||||||
im = self.im.convert("P", 1, palette.im)
|
im = self.im.convert("P", 1, palette.im)
|
||||||
return self._makeself(im)
|
return self._makeself(im)
|
||||||
|
|
||||||
im = self.im.quantize(colors, method, kmeans)
|
return self._new(self.im.quantize(colors, method, kmeans))
|
||||||
return self._new(im)
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1007,8 +1007,7 @@ class Image(object):
|
||||||
:returns: An :py:class:`~PIL.Image.Image` object.
|
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||||
"""
|
"""
|
||||||
self.load()
|
self.load()
|
||||||
im = self.im.copy()
|
return self._new(self.im.copy())
|
||||||
return self._new(im)
|
|
||||||
|
|
||||||
__copy__ = copy
|
__copy__ = copy
|
||||||
|
|
||||||
|
@ -1571,20 +1570,31 @@ class Image(object):
|
||||||
:returns: An :py:class:`~PIL.Image.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:
|
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
|
# calculate output size
|
||||||
w, h = self.size
|
|
||||||
xx = []
|
xx = []
|
||||||
yy = []
|
yy = []
|
||||||
for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
|
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)))
|
w = int(math.ceil(max(xx)) - math.floor(min(xx)))
|
||||||
h = int(math.ceil(max(yy)) - math.floor(min(yy)))
|
h = int(math.ceil(max(yy)) - math.floor(min(yy)))
|
||||||
|
|
||||||
# adjust center
|
# adjust center
|
||||||
x, y = transform(w / 2.0, h / 2.0)
|
x, y = transform(w / 2.0, h / 2.0)
|
||||||
matrix[2] = self.size[0] / 2.0 - x
|
matrix[2] = self.size[0] / 2.0 - x
|
||||||
matrix[5] = self.size[1] / 2.0 - y
|
matrix[5] = self.size[1] / 2.0 - y
|
||||||
|
|
||||||
return self.transform((w, h), AFFINE, matrix, resample)
|
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))
|
|
||||||
|
|
||||||
def save(self, fp, format=None, **params):
|
def save(self, fp, format=None, **params):
|
||||||
"""
|
"""
|
||||||
|
@ -1845,9 +1845,11 @@ class Image(object):
|
||||||
|
|
||||||
if isinstance(method, ImageTransformHandler):
|
if isinstance(method, ImageTransformHandler):
|
||||||
return method.transform(size, self, resample=resample, fill=fill)
|
return method.transform(size, self, resample=resample, fill=fill)
|
||||||
|
|
||||||
if hasattr(method, "getdata"):
|
if hasattr(method, "getdata"):
|
||||||
# compatibility w. old-style transform objects
|
# compatibility w. old-style transform objects
|
||||||
method, data = method.getdata()
|
method, data = method.getdata()
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
raise ValueError("missing method data")
|
raise ValueError("missing method data")
|
||||||
|
|
||||||
|
@ -1863,28 +1865,23 @@ class Image(object):
|
||||||
|
|
||||||
def __transformer(self, box, image, method, data,
|
def __transformer(self, box, image, method, data,
|
||||||
resample=NEAREST, fill=1):
|
resample=NEAREST, fill=1):
|
||||||
|
w = box[2] - box[0]
|
||||||
# FIXME: this should be turned into a lazy operation (?)
|
h = box[3] - box[1]
|
||||||
|
|
||||||
w = box[2]-box[0]
|
|
||||||
h = box[3]-box[1]
|
|
||||||
|
|
||||||
if method == AFFINE:
|
if method == AFFINE:
|
||||||
# change argument order to match implementation
|
data = data[0:6]
|
||||||
data = (data[2], data[0], data[1],
|
|
||||||
data[5], data[3], data[4])
|
|
||||||
elif method == EXTENT:
|
elif method == EXTENT:
|
||||||
# convert extent to an affine transform
|
# convert extent to an affine transform
|
||||||
x0, y0, x1, y1 = data
|
x0, y0, x1, y1 = data
|
||||||
xs = float(x1 - x0) / w
|
xs = float(x1 - x0) / w
|
||||||
ys = float(y1 - y0) / h
|
ys = float(y1 - y0) / h
|
||||||
method = AFFINE
|
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:
|
elif method == PERSPECTIVE:
|
||||||
# change argument order to match implementation
|
data = data[0:8]
|
||||||
data = (data[2], data[0], data[1],
|
|
||||||
data[5], data[3], data[4],
|
|
||||||
data[6], data[7])
|
|
||||||
elif method == QUAD:
|
elif method == QUAD:
|
||||||
# quadrilateral warp. data specifies the four corners
|
# quadrilateral warp. data specifies the four corners
|
||||||
# given as NW, SW, SE, and NE.
|
# given as NW, SW, SE, and NE.
|
||||||
|
@ -1899,6 +1896,7 @@ class Image(object):
|
||||||
(se[0]-sw[0]-ne[0]+x0)*As*At,
|
(se[0]-sw[0]-ne[0]+x0)*As*At,
|
||||||
y0, (ne[1]-y0)*As, (sw[1]-y0)*At,
|
y0, (ne[1]-y0)*As, (sw[1]-y0)*At,
|
||||||
(se[1]-sw[1]-ne[1]+y0)*As*At)
|
(se[1]-sw[1]-ne[1]+y0)*As*At)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("unknown transformation method")
|
raise ValueError("unknown transformation method")
|
||||||
|
|
||||||
|
@ -1935,8 +1933,7 @@ class Image(object):
|
||||||
:param distance: Distance to spread pixels.
|
:param distance: Distance to spread pixels.
|
||||||
"""
|
"""
|
||||||
self.load()
|
self.load()
|
||||||
im = self.im.effect_spread(distance)
|
return self._new(self.im.effect_spread(distance))
|
||||||
return self._new(im)
|
|
||||||
|
|
||||||
def toqimage(self):
|
def toqimage(self):
|
||||||
"""Returns a QImage copy of this image"""
|
"""Returns a QImage copy of this image"""
|
||||||
|
|
88
_imaging.c
88
_imaging.c
|
@ -1544,17 +1544,17 @@ _resize(ImagingObject* self, PyObject* args)
|
||||||
if (imIn->xsize == xsize && imIn->ysize == ysize) {
|
if (imIn->xsize == xsize && imIn->ysize == ysize) {
|
||||||
imOut = ImagingCopy(imIn);
|
imOut = ImagingCopy(imIn);
|
||||||
}
|
}
|
||||||
else if ( ! filter) {
|
else if (filter == IMAGING_TRANSFORM_NEAREST) {
|
||||||
double a[6];
|
double a[6];
|
||||||
|
|
||||||
memset(a, 0, sizeof a);
|
memset(a, 0, sizeof a);
|
||||||
a[1] = (double) imIn->xsize / xsize;
|
a[0] = (double) imIn->xsize / xsize;
|
||||||
a[5] = (double) imIn->ysize / ysize;
|
a[4] = (double) imIn->ysize / ysize;
|
||||||
|
|
||||||
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
imOut = ImagingNew(imIn->mode, xsize, ysize);
|
||||||
|
|
||||||
imOut = ImagingTransformAffine(
|
imOut = ImagingTransform(
|
||||||
imOut, imIn,
|
imOut, imIn, IMAGING_TRANSFORM_AFFINE,
|
||||||
0, 0, xsize, ysize,
|
0, 0, xsize, ysize,
|
||||||
a, filter, 1);
|
a, filter, 1);
|
||||||
}
|
}
|
||||||
|
@ -1565,55 +1565,6 @@ _resize(ImagingObject* self, PyObject* args)
|
||||||
return PyImagingNew(imOut);
|
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)\
|
#define IS_RGB(mode)\
|
||||||
(!strcmp(mode, "RGB") || !strcmp(mode, "RGBA") || !strcmp(mode, "RGBX"))
|
(!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";
|
static const char* wrong_number = "wrong number of matrix entries";
|
||||||
|
|
||||||
Imaging imIn;
|
|
||||||
Imaging imOut;
|
Imaging imOut;
|
||||||
int n;
|
int n;
|
||||||
double *a;
|
double *a;
|
||||||
|
@ -1698,30 +1648,9 @@ _transform2(ImagingObject* self, PyObject* args)
|
||||||
if (!a)
|
if (!a)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
imOut = self->image;
|
imOut = ImagingTransform(
|
||||||
imIn = imagep->image;
|
self->image, imagep->image, method,
|
||||||
|
x0, y0, x1, y1, a, filter, 1);
|
||||||
/* 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(a);
|
free(a);
|
||||||
|
|
||||||
|
@ -3048,7 +2977,6 @@ static struct PyMethodDef methods[] = {
|
||||||
// There were two methods for image resize before.
|
// There were two methods for image resize before.
|
||||||
// Starting from Pillow 2.7.0 stretch is depreciated.
|
// Starting from Pillow 2.7.0 stretch is depreciated.
|
||||||
{"stretch", (PyCFunction)_resize, 1},
|
{"stretch", (PyCFunction)_resize, 1},
|
||||||
{"rotate", (PyCFunction)_rotate, 1},
|
|
||||||
{"transpose", (PyCFunction)_transpose, 1},
|
{"transpose", (PyCFunction)_transpose, 1},
|
||||||
{"transform2", (PyCFunction)_transform2, 1},
|
{"transform2", (PyCFunction)_transform2, 1},
|
||||||
|
|
||||||
|
|
|
@ -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"
|
#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.
|
/* For large images rotation is an inefficient operation in terms of CPU cache.
|
||||||
One row in the source image affects each column in destination.
|
One row in the source image affects each column in destination.
|
||||||
Rotating in chunks that fit in the cache can speed up rotation
|
Rotating in chunks that fit in the cache can speed up rotation
|
||||||
|
@ -72,6 +42,8 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef FLIP_HORIZ
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +63,7 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
yr = imIn->ysize-1;
|
yr = imIn->ysize - 1;
|
||||||
for (y = 0; y < imIn->ysize; y++, yr--)
|
for (y = 0; y < imIn->ysize; y++, yr--)
|
||||||
memcpy(imOut->image[yr], imIn->image[y], imIn->linesize);
|
memcpy(imOut->image[yr], imIn->image[y], imIn->linesize);
|
||||||
|
|
||||||
|
@ -137,6 +109,8 @@ ImagingRotate90(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef ROTATE_90
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +126,8 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
|
||||||
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
|
if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize)
|
||||||
return (Imaging) ImagingError_Mismatch();
|
return (Imaging) ImagingError_Mismatch();
|
||||||
|
|
||||||
|
ImagingCopyInfo(imOut, imIn);
|
||||||
|
|
||||||
#define TRANSPOSE(image) \
|
#define TRANSPOSE(image) \
|
||||||
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
|
for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
|
||||||
for (x = 0; x < imIn->xsize; x += 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);
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
if (imIn->image8)
|
if (imIn->image8)
|
||||||
TRANSPOSE(image8)
|
TRANSPOSE(image8)
|
||||||
else
|
else
|
||||||
TRANSPOSE(image32)
|
TRANSPOSE(image32)
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef TRANSPOSE
|
||||||
|
|
||||||
return imOut;
|
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
|
Imaging
|
||||||
ImagingRotate180(Imaging imOut, Imaging imIn)
|
ImagingRotate180(Imaging imOut, Imaging imIn)
|
||||||
{
|
{
|
||||||
|
@ -206,8 +169,6 @@ ImagingRotate180(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingCopyInfo(imOut, imIn);
|
ImagingCopyInfo(imOut, imIn);
|
||||||
|
|
||||||
yr = imIn->ysize-1;
|
|
||||||
|
|
||||||
#define ROTATE_180(image)\
|
#define ROTATE_180(image)\
|
||||||
for (y = 0; y < imIn->ysize; y++, yr--) {\
|
for (y = 0; y < imIn->ysize; y++, yr--) {\
|
||||||
xr = imIn->xsize-1;\
|
xr = imIn->xsize-1;\
|
||||||
|
@ -217,6 +178,7 @@ ImagingRotate180(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
|
yr = imIn->ysize-1;
|
||||||
if (imIn->image8)
|
if (imIn->image8)
|
||||||
ROTATE_180(image8)
|
ROTATE_180(image8)
|
||||||
else
|
else
|
||||||
|
@ -224,6 +186,8 @@ ImagingRotate180(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef ROTATE_180
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,6 +228,8 @@ ImagingRotate270(Imaging imOut, Imaging imIn)
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef ROTATE_270
|
||||||
|
|
||||||
return imOut;
|
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 a0 = a[0]; double a1 = a[1]; double a2 = a[2];
|
||||||
double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
|
double a3 = a[3]; double a4 = a[4]; double a5 = a[5];
|
||||||
|
|
||||||
xin[0] = a0 + a1*x + a2*y;
|
xin[0] = a0*x + a1*y + a2;
|
||||||
yin[0] = a3 + a4*x + a5*y;
|
yin[0] = a3*x + a4*y + a5;
|
||||||
|
|
||||||
return 1;
|
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 a3 = a[3]; double a4 = a[4]; double a5 = a[5];
|
||||||
double a6 = a[6]; double a7 = a[7];
|
double a6 = a[6]; double a7 = a[7];
|
||||||
|
|
||||||
xin[0] = (a0 + a1*x + a2*y) / (a6*x + a7*y + 1);
|
xin[0] = (a0*x + a1*y + a2) / (a6*x + a7*y + 1);
|
||||||
yin[0] = (a3 + a4*x + a5*y) / (a6*x + a7*y + 1);
|
yin[0] = (a3*x + a4*y + a5) / (a6*x + a7*y + 1);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -321,10 +287,8 @@ quad_transform(double* xin, double* yin, int x, int y, void* data)
|
||||||
|
|
||||||
/* transform filters (ImagingTransformFilter) */
|
/* transform filters (ImagingTransformFilter) */
|
||||||
|
|
||||||
#ifdef WITH_FILTERS
|
|
||||||
|
|
||||||
static int
|
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 x = COORD(xin);
|
||||||
int y = COORD(yin);
|
int y = COORD(yin);
|
||||||
|
@ -335,7 +299,7 @@ nearest_filter8(void* out, Imaging im, double xin, double yin, void* data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 x = COORD(xin);
|
||||||
int y = COORD(yin);
|
int y = COORD(yin);
|
||||||
|
@ -346,7 +310,7 @@ nearest_filter16(void* out, Imaging im, double xin, double yin, void* data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 x = COORD(xin);
|
||||||
int y = COORD(yin);
|
int y = COORD(yin);
|
||||||
|
@ -391,7 +355,7 @@ nearest_filter32(void* out, Imaging im, double xin, double yin, void* data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_HEAD(UINT8);
|
||||||
BILINEAR_BODY(UINT8, im->image8, 1, 0);
|
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
|
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_HEAD(INT32);
|
||||||
BILINEAR_BODY(INT32, im->image32, 1, 0);
|
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
|
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_HEAD(FLOAT32);
|
||||||
BILINEAR_BODY(FLOAT32, im->image32, 1, 0);
|
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
|
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_HEAD(UINT8);
|
||||||
BILINEAR_BODY(UINT8, im->image, 4, 0);
|
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
|
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;
|
int b;
|
||||||
BILINEAR_HEAD(UINT8);
|
BILINEAR_HEAD(UINT8);
|
||||||
|
@ -442,6 +406,10 @@ bilinear_filter32RGB(void* out, Imaging im, double xin, double yin, void* data)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef BILINEAR
|
||||||
|
#undef BILINEAR_HEAD
|
||||||
|
#undef BILINEAR_BODY
|
||||||
|
|
||||||
#define BICUBIC(v, v1, v2, v3, v4, d) {\
|
#define BICUBIC(v, v1, v2, v3, v4, d) {\
|
||||||
double p1 = v2;\
|
double p1 = v2;\
|
||||||
double p2 = -v1 + v3;\
|
double p2 = -v1 + v3;\
|
||||||
|
@ -494,7 +462,7 @@ bilinear_filter32RGB(void* out, Imaging im, double xin, double yin, void* data)
|
||||||
|
|
||||||
|
|
||||||
static int
|
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_HEAD(UINT8);
|
||||||
BICUBIC_BODY(UINT8, im->image8, 1, 0);
|
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
|
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_HEAD(INT32);
|
||||||
BICUBIC_BODY(INT32, im->image32, 1, 0);
|
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
|
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_HEAD(FLOAT32);
|
||||||
BICUBIC_BODY(FLOAT32, im->image32, 1, 0);
|
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
|
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_HEAD(UINT8);
|
||||||
BICUBIC_BODY(UINT8, im->image, 4, 0);
|
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
|
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;
|
int b;
|
||||||
BICUBIC_HEAD(UINT8);
|
BICUBIC_HEAD(UINT8);
|
||||||
|
@ -570,6 +538,10 @@ bicubic_filter32RGB(void* out, Imaging im, double xin, double yin, void* data)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef BICUBIC
|
||||||
|
#undef BICUBIC_HEAD
|
||||||
|
#undef BICUBIC_BODY
|
||||||
|
|
||||||
static ImagingTransformFilter
|
static ImagingTransformFilter
|
||||||
getfilter(Imaging im, int filterid)
|
getfilter(Imaging im, int filterid)
|
||||||
{
|
{
|
||||||
|
@ -578,51 +550,51 @@ getfilter(Imaging im, int filterid)
|
||||||
if (im->image8)
|
if (im->image8)
|
||||||
switch (im->type) {
|
switch (im->type) {
|
||||||
case IMAGING_TYPE_UINT8:
|
case IMAGING_TYPE_UINT8:
|
||||||
return (ImagingTransformFilter) nearest_filter8;
|
return nearest_filter8;
|
||||||
case IMAGING_TYPE_SPECIAL:
|
case IMAGING_TYPE_SPECIAL:
|
||||||
switch (im->pixelsize) {
|
switch (im->pixelsize) {
|
||||||
case 1:
|
case 1:
|
||||||
return (ImagingTransformFilter) nearest_filter8;
|
return nearest_filter8;
|
||||||
case 2:
|
case 2:
|
||||||
return (ImagingTransformFilter) nearest_filter16;
|
return nearest_filter16;
|
||||||
case 4:
|
case 4:
|
||||||
return (ImagingTransformFilter) nearest_filter32;
|
return nearest_filter32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return (ImagingTransformFilter) nearest_filter32;
|
return nearest_filter32;
|
||||||
break;
|
break;
|
||||||
case IMAGING_TRANSFORM_BILINEAR:
|
case IMAGING_TRANSFORM_BILINEAR:
|
||||||
if (im->image8)
|
if (im->image8)
|
||||||
return (ImagingTransformFilter) bilinear_filter8;
|
return bilinear_filter8;
|
||||||
else if (im->image32) {
|
else if (im->image32) {
|
||||||
switch (im->type) {
|
switch (im->type) {
|
||||||
case IMAGING_TYPE_UINT8:
|
case IMAGING_TYPE_UINT8:
|
||||||
if (im->bands == 2)
|
if (im->bands == 2)
|
||||||
return (ImagingTransformFilter) bilinear_filter32LA;
|
return bilinear_filter32LA;
|
||||||
else
|
else
|
||||||
return (ImagingTransformFilter) bilinear_filter32RGB;
|
return bilinear_filter32RGB;
|
||||||
case IMAGING_TYPE_INT32:
|
case IMAGING_TYPE_INT32:
|
||||||
return (ImagingTransformFilter) bilinear_filter32I;
|
return bilinear_filter32I;
|
||||||
case IMAGING_TYPE_FLOAT32:
|
case IMAGING_TYPE_FLOAT32:
|
||||||
return (ImagingTransformFilter) bilinear_filter32F;
|
return bilinear_filter32F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IMAGING_TRANSFORM_BICUBIC:
|
case IMAGING_TRANSFORM_BICUBIC:
|
||||||
if (im->image8)
|
if (im->image8)
|
||||||
return (ImagingTransformFilter) bicubic_filter8;
|
return bicubic_filter8;
|
||||||
else if (im->image32) {
|
else if (im->image32) {
|
||||||
switch (im->type) {
|
switch (im->type) {
|
||||||
case IMAGING_TYPE_UINT8:
|
case IMAGING_TYPE_UINT8:
|
||||||
if (im->bands == 2)
|
if (im->bands == 2)
|
||||||
return (ImagingTransformFilter) bicubic_filter32LA;
|
return bicubic_filter32LA;
|
||||||
else
|
else
|
||||||
return (ImagingTransformFilter) bicubic_filter32RGB;
|
return bicubic_filter32RGB;
|
||||||
case IMAGING_TYPE_INT32:
|
case IMAGING_TYPE_INT32:
|
||||||
return (ImagingTransformFilter) bicubic_filter32I;
|
return bicubic_filter32I;
|
||||||
case IMAGING_TYPE_FLOAT32:
|
case IMAGING_TYPE_FLOAT32:
|
||||||
return (ImagingTransformFilter) bicubic_filter32F;
|
return bicubic_filter32F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -631,18 +603,13 @@ getfilter(Imaging im, int filterid)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
#define getfilter(im, id) NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* transformation engines */
|
/* transformation engines */
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingTransform(
|
ImagingGenericTransform(
|
||||||
Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
|
Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
|
||||||
ImagingTransformMap transform, void* transform_data,
|
ImagingTransformMap transform, void* transform_data,
|
||||||
ImagingTransformFilter filter, void* filter_data,
|
int filterid, int fill)
|
||||||
int fill)
|
|
||||||
{
|
{
|
||||||
/* slow generic transformation. use ImagingTransformAffine or
|
/* slow generic transformation. use ImagingTransformAffine or
|
||||||
ImagingScaleAffine where possible. */
|
ImagingScaleAffine where possible. */
|
||||||
|
@ -652,6 +619,10 @@ ImagingTransform(
|
||||||
char *out;
|
char *out;
|
||||||
double xx, yy;
|
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)
|
if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
|
||||||
return (Imaging) ImagingError_ModeError();
|
return (Imaging) ImagingError_ModeError();
|
||||||
|
|
||||||
|
@ -671,8 +642,8 @@ ImagingTransform(
|
||||||
for (y = y0; y < y1; y++) {
|
for (y = y0; y < y1; y++) {
|
||||||
out = imOut->image[y] + x0*imOut->pixelsize;
|
out = imOut->image[y] + x0*imOut->pixelsize;
|
||||||
for (x = x0; x < x1; x++) {
|
for (x = x0; x < x1; x++) {
|
||||||
if (!transform(&xx, &yy, x-x0, y-y0, transform_data) ||
|
if ( ! transform(&xx, &yy, x-x0, y-y0, transform_data) ||
|
||||||
!filter(out, imIn, xx, yy, filter_data)) {
|
! filter(out, imIn, xx, yy)) {
|
||||||
if (fill)
|
if (fill)
|
||||||
memset(out, 0, imOut->pixelsize);
|
memset(out, 0, imOut->pixelsize);
|
||||||
}
|
}
|
||||||
|
@ -719,8 +690,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
|
||||||
return (Imaging) ImagingError_MemoryError();
|
return (Imaging) ImagingError_MemoryError();
|
||||||
}
|
}
|
||||||
|
|
||||||
xo = a[0];
|
xo = a[2];
|
||||||
yo = a[3];
|
yo = a[5];
|
||||||
|
|
||||||
xmin = x1;
|
xmin = x1;
|
||||||
xmax = x0;
|
xmax = x0;
|
||||||
|
@ -734,7 +705,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
|
||||||
xmin = x;
|
xmin = x;
|
||||||
xintab[x] = xin;
|
xintab[x] = xin;
|
||||||
}
|
}
|
||||||
xo += a[1];
|
xo += a[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AFFINE_SCALE(pixel, image)\
|
#define AFFINE_SCALE(pixel, image)\
|
||||||
|
@ -749,7 +720,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
|
||||||
for (x = xmin; x < xmax; x++)\
|
for (x = xmin; x < xmax; x++)\
|
||||||
out[x] = in[xintab[x]];\
|
out[x] = in[xintab[x]];\
|
||||||
}\
|
}\
|
||||||
yo += a[5];\
|
yo += a[4];\
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
|
@ -762,6 +733,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef AFFINE_SCALE
|
||||||
|
|
||||||
free(xintab);
|
free(xintab);
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
|
@ -770,8 +743,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
|
||||||
static inline int
|
static inline int
|
||||||
check_fixed(double a[6], int x, int y)
|
check_fixed(double a[6], int x, int y)
|
||||||
{
|
{
|
||||||
return (fabs(a[0] + x*a[1] + y*a[2]) < 32768.0 &&
|
return (fabs(x*a[0] + y*a[1] + a[2]) < 32768.0 &&
|
||||||
fabs(a[3] + x*a[4] + y*a[5]) < 32768.0);
|
fabs(x*a[3] + y*a[4] + a[5]) < 32768.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Imaging
|
static inline Imaging
|
||||||
|
@ -782,6 +755,7 @@ affine_fixed(Imaging imOut, Imaging imIn,
|
||||||
/* affine transform, nearest neighbour resampling, fixed point
|
/* affine transform, nearest neighbour resampling, fixed point
|
||||||
arithmetics */
|
arithmetics */
|
||||||
|
|
||||||
|
ImagingSectionCookie cookie;
|
||||||
int x, y;
|
int x, y;
|
||||||
int xin, yin;
|
int xin, yin;
|
||||||
int xsize, ysize;
|
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]);
|
a0 = FIX(a[0]); a1 = FIX(a[1]); a2 = FIX(a[2]);
|
||||||
a3 = FIX(a[3]); a4 = FIX(a[4]); a5 = FIX(a[5]);
|
a3 = FIX(a[3]); a4 = FIX(a[4]); a5 = FIX(a[5]);
|
||||||
|
|
||||||
|
#undef FIX
|
||||||
|
|
||||||
#define AFFINE_TRANSFORM_FIXED(pixel, image)\
|
#define AFFINE_TRANSFORM_FIXED(pixel, image)\
|
||||||
for (y = y0; y < y1; y++) {\
|
for (y = y0; y < y1; y++) {\
|
||||||
pixel *out;\
|
pixel *out;\
|
||||||
xx = a0;\
|
xx = a2;\
|
||||||
yy = a3;\
|
yy = a5;\
|
||||||
out = imOut->image[y];\
|
out = imOut->image[y];\
|
||||||
if (fill && x1 > x0)\
|
if (fill && x1 > x0)\
|
||||||
memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
|
memset(out+x0, 0, (x1-x0)*sizeof(pixel));\
|
||||||
|
@ -814,18 +790,24 @@ affine_fixed(Imaging imOut, Imaging imIn,
|
||||||
if (yin >= 0 && yin < ysize)\
|
if (yin >= 0 && yin < ysize)\
|
||||||
*out = imIn->image[yin][xin];\
|
*out = imIn->image[yin][xin];\
|
||||||
}\
|
}\
|
||||||
xx += a1;\
|
xx += a0;\
|
||||||
yy += a4;\
|
yy += a3;\
|
||||||
}\
|
}\
|
||||||
a0 += a2;\
|
a2 += a1;\
|
||||||
a3 += a5;\
|
a5 += a4;\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImagingSectionEnter(&cookie);
|
||||||
|
|
||||||
if (imIn->image8)
|
if (imIn->image8)
|
||||||
AFFINE_TRANSFORM_FIXED(UINT8, image8)
|
AFFINE_TRANSFORM_FIXED(UINT8, image8)
|
||||||
else
|
else
|
||||||
AFFINE_TRANSFORM_FIXED(INT32, image32)
|
AFFINE_TRANSFORM_FIXED(INT32, image32)
|
||||||
|
|
||||||
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef AFFINE_TRANSFORM_FIXED
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,18 +827,14 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
|
||||||
double xo, yo;
|
double xo, yo;
|
||||||
|
|
||||||
if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) {
|
if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) {
|
||||||
/* Filtered transform */
|
return ImagingGenericTransform(
|
||||||
ImagingTransformFilter filter = getfilter(imIn, filterid);
|
|
||||||
if (!filter)
|
|
||||||
return (Imaging) ImagingError_ValueError("unknown filter");
|
|
||||||
return ImagingTransform(
|
|
||||||
imOut, imIn,
|
imOut, imIn,
|
||||||
x0, y0, x1, y1,
|
x0, y0, x1, y1,
|
||||||
affine_transform, a,
|
affine_transform, a,
|
||||||
filter, NULL, fill);
|
filterid, fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a[2] == 0 && a[4] == 0)
|
if (a[1] == 0 && a[3] == 0)
|
||||||
/* Scaling */
|
/* Scaling */
|
||||||
return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
|
return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
|
||||||
|
|
||||||
|
@ -872,8 +850,6 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
|
||||||
if (y1 > imOut->ysize)
|
if (y1 > imOut->ysize)
|
||||||
y1 = imOut->ysize;
|
y1 = imOut->ysize;
|
||||||
|
|
||||||
ImagingCopyInfo(imOut, imIn);
|
|
||||||
|
|
||||||
/* translate all four corners to check if they are within the
|
/* translate all four corners to check if they are within the
|
||||||
range that can be represented by the fixed point arithmetics */
|
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
|
/* FIXME: cannot really think of any reasonable case when the
|
||||||
following code is used. maybe we should fall back on the slow
|
following code is used. maybe we should fall back on the slow
|
||||||
generic transform engine in this case? */
|
generic transform engine in this case? */
|
||||||
|
|
||||||
|
ImagingCopyInfo(imOut, imIn);
|
||||||
|
|
||||||
xsize = (int) imIn->xsize;
|
xsize = (int) imIn->xsize;
|
||||||
ysize = (int) imIn->ysize;
|
ysize = (int) imIn->ysize;
|
||||||
|
|
||||||
xo = a[0];
|
xo = a[2];
|
||||||
yo = a[3];
|
yo = a[5];
|
||||||
|
|
||||||
#define AFFINE_TRANSFORM(pixel, image)\
|
#define AFFINE_TRANSFORM(pixel, image)\
|
||||||
for (y = y0; y < y1; y++) {\
|
for (y = y0; y < y1; y++) {\
|
||||||
|
@ -906,11 +884,11 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
|
||||||
if (yin >= 0 && yin < ysize)\
|
if (yin >= 0 && yin < ysize)\
|
||||||
*out = imIn->image[yin][xin];\
|
*out = imIn->image[yin][xin];\
|
||||||
}\
|
}\
|
||||||
xx += a[1];\
|
xx += a[0];\
|
||||||
yy += a[4];\
|
yy += a[3];\
|
||||||
}\
|
}\
|
||||||
xo += a[2];\
|
xo += a[1];\
|
||||||
yo += a[5];\
|
yo += a[4];\
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagingSectionEnter(&cookie);
|
ImagingSectionEnter(&cookie);
|
||||||
|
@ -922,70 +900,35 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn,
|
||||||
|
|
||||||
ImagingSectionLeave(&cookie);
|
ImagingSectionLeave(&cookie);
|
||||||
|
|
||||||
|
#undef AFFINE_TRANSFORM
|
||||||
|
|
||||||
return imOut;
|
return imOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
Imaging
|
Imaging
|
||||||
ImagingTransformPerspective(Imaging imOut, Imaging imIn,
|
ImagingTransform(Imaging imOut, Imaging imIn, int method,
|
||||||
int x0, int y0, int x1, int y1,
|
int x0, int y0, int x1, int y1,
|
||||||
double a[8], int filterid, int fill)
|
double a[8], int filterid, int fill)
|
||||||
{
|
{
|
||||||
ImagingTransformFilter filter = getfilter(imIn, filterid);
|
ImagingTransformMap transform;
|
||||||
if (!filter)
|
|
||||||
return (Imaging) ImagingError_ValueError("bad filter number");
|
|
||||||
|
|
||||||
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,
|
imOut, imIn,
|
||||||
x0, y0, x1, y1,
|
x0, y0, x1, y1,
|
||||||
perspective_transform, a,
|
transform, a, filterid, fill);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,8 +236,7 @@ extern void ImagingError_Clear(void);
|
||||||
typedef int (*ImagingTransformMap)(double* X, double* Y,
|
typedef int (*ImagingTransformMap)(double* X, double* Y,
|
||||||
int x, int y, void* data);
|
int x, int y, void* data);
|
||||||
typedef int (*ImagingTransformFilter)(void* out, Imaging im,
|
typedef int (*ImagingTransformFilter)(void* out, Imaging im,
|
||||||
double x, double y,
|
double x, double y);
|
||||||
void* data);
|
|
||||||
|
|
||||||
/* Image Manipulation Methods */
|
/* Image Manipulation Methods */
|
||||||
/* -------------------------- */
|
/* -------------------------- */
|
||||||
|
@ -286,28 +285,14 @@ 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 ImagingRotate(
|
|
||||||
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 ImagingResample(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 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(
|
extern Imaging ImagingTransform(
|
||||||
Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
|
Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1,
|
||||||
ImagingTransformMap transform, void* transform_data,
|
double *a, int filter, int fill);
|
||||||
ImagingTransformFilter filter, void* filter_data,
|
|
||||||
int fill);
|
|
||||||
extern Imaging ImagingUnsharpMask(
|
extern Imaging ImagingUnsharpMask(
|
||||||
Imaging imOut, Imaging im, float radius, int percent, int threshold);
|
Imaging imOut, Imaging im, float radius, int percent, int threshold);
|
||||||
extern Imaging ImagingBoxBlur(Imaging imOut, Imaging imIn, float radius, int n);
|
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);
|
extern void ImagingCrack(Imaging im, int x0, int y0);
|
||||||
|
|
||||||
/* Graphics */
|
/* Graphics */
|
||||||
struct ImagingAffineMatrixInstance {
|
|
||||||
float a[9];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ImagingAffineMatrixInstance *ImagingAffineMatrix;
|
|
||||||
|
|
||||||
extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1,
|
extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1,
|
||||||
float start, float end, const void* ink, int op);
|
float start, float end, const void* ink, int op);
|
||||||
extern int ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap,
|
extern int ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user