mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +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 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"""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										88
									
								
								_imaging.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								_imaging.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -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},
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user