mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	Merge pull request #977 from homm/fast-stretch
Imaging.stretch optimization
This commit is contained in:
		
						commit
						d781d56aa5
					
				| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
Tests for ImagingCore.stretch functionality.
 | 
					Tests for ImagingCore.stretch functionality.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					from itertools import permutations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from helper import unittest, PillowTestCase
 | 
					from helper import unittest, PillowTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +13,9 @@ im = Image.open("Tests/images/hopper.ppm").copy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestImagingStretch(PillowTestCase):
 | 
					class TestImagingStretch(PillowTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stretch(self, im, size, f):
 | 
				
			||||||
 | 
					        return im._new(im.im.stretch(size, f))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modes(self):
 | 
					    def test_modes(self):
 | 
				
			||||||
        self.assertRaises(ValueError, im.convert("1").im.stretch,
 | 
					        self.assertRaises(ValueError, im.convert("1").im.stretch,
 | 
				
			||||||
                          (15, 12), Image.ANTIALIAS)
 | 
					                          (15, 12), Image.ANTIALIAS)
 | 
				
			||||||
| 
						 | 
					@ -39,6 +43,42 @@ class TestImagingStretch(PillowTestCase):
 | 
				
			||||||
            self.assertEqual(r.mode, "RGB")
 | 
					            self.assertEqual(r.mode, "RGB")
 | 
				
			||||||
            self.assertEqual(r.size, (764, 414))
 | 
					            self.assertEqual(r.size, (764, 414))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_endianness(self):
 | 
				
			||||||
 | 
					        # Make an image with one colored pixel, in one channel.
 | 
				
			||||||
 | 
					        # When stretched, that channel should be the same as a GS image.
 | 
				
			||||||
 | 
					        # Other channels should be unaffected.
 | 
				
			||||||
 | 
					        # The R and A channels should not swap, which is indicitive of
 | 
				
			||||||
 | 
					        # an endianness issues.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        samples = {
 | 
				
			||||||
 | 
					            'blank': Image.new('L', (2, 2), 0),
 | 
				
			||||||
 | 
					            'filled': Image.new('L', (2, 2), 255),
 | 
				
			||||||
 | 
					            'dirty': Image.new('L', (2, 2), 0),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        samples['dirty'].putpixel((1, 1), 128)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for f in [Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]:
 | 
				
			||||||
 | 
					            # samples resized with current filter
 | 
				
			||||||
 | 
					            resized = dict(
 | 
				
			||||||
 | 
					                (name, self.stretch(ch, (4, 4), f))
 | 
				
			||||||
 | 
					                for name, ch in samples.items()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for mode, channels_set in [
 | 
				
			||||||
 | 
					                ('RGB', ('blank', 'filled', 'dirty')),
 | 
				
			||||||
 | 
					                ('RGBA', ('blank', 'blank', 'filled', 'dirty')),
 | 
				
			||||||
 | 
					                ('LA', ('filled', 'dirty')),
 | 
				
			||||||
 | 
					            ]:
 | 
				
			||||||
 | 
					                for channels in set(permutations(channels_set)):
 | 
				
			||||||
 | 
					                    # compile image from different channels permutations
 | 
				
			||||||
 | 
					                    im = Image.merge(mode, [samples[ch] for ch in channels])
 | 
				
			||||||
 | 
					                    stretched = self.stretch(im, (4, 4), f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for i, ch in enumerate(stretched.split()):
 | 
				
			||||||
 | 
					                        # check what resized channel in image is the same
 | 
				
			||||||
 | 
					                        # as separately resized channel
 | 
				
			||||||
 | 
					                        self.assert_image_equal(ch, resized[channels[i]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										32
									
								
								_imaging.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								_imaging.c
									
									
									
									
									
								
							| 
						 | 
					@ -1612,9 +1612,7 @@ im_setmode(ImagingObject* self, PyObject* args)
 | 
				
			||||||
static PyObject*
 | 
					static PyObject*
 | 
				
			||||||
_stretch(ImagingObject* self, PyObject* args)
 | 
					_stretch(ImagingObject* self, PyObject* args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Imaging imIn;
 | 
					    Imaging imIn, imOut;
 | 
				
			||||||
    Imaging imTemp;
 | 
					 | 
				
			||||||
    Imaging imOut;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int xsize, ysize;
 | 
					    int xsize, ysize;
 | 
				
			||||||
    int filter = IMAGING_TRANSFORM_NEAREST;
 | 
					    int filter = IMAGING_TRANSFORM_NEAREST;
 | 
				
			||||||
| 
						 | 
					@ -1623,35 +1621,11 @@ _stretch(ImagingObject* self, PyObject* args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    imIn = self->image;
 | 
					    imIn = self->image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* two-pass resize: minimize size of intermediate image */
 | 
					    imOut = ImagingStretch(imIn, xsize, ysize, filter);
 | 
				
			||||||
    if ((Py_ssize_t) imIn->xsize * ysize < (Py_ssize_t) xsize * imIn->ysize)
 | 
					    if ( ! imOut) {
 | 
				
			||||||
        imTemp = ImagingNew(imIn->mode, imIn->xsize, ysize);
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        imTemp = ImagingNew(imIn->mode, xsize, imIn->ysize);
 | 
					 | 
				
			||||||
    if (!imTemp)
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* first pass */
 | 
					 | 
				
			||||||
    if (!ImagingStretch(imTemp, imIn, filter)) {
 | 
					 | 
				
			||||||
        ImagingDelete(imTemp);
 | 
					 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    imOut = ImagingNew(imIn->mode, xsize, ysize);
 | 
					 | 
				
			||||||
    if (!imOut) {
 | 
					 | 
				
			||||||
        ImagingDelete(imTemp);
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* second pass */
 | 
					 | 
				
			||||||
    if (!ImagingStretch(imOut, imTemp, filter)) {
 | 
					 | 
				
			||||||
        ImagingDelete(imOut);
 | 
					 | 
				
			||||||
        ImagingDelete(imTemp);
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ImagingDelete(imTemp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return PyImagingNew(imOut);
 | 
					    return PyImagingNew(imOut);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,25 +78,44 @@ static inline float bicubic_filter(float x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct filter BICUBIC = { bicubic_filter, 2.0 };
 | 
					static struct filter BICUBIC = { bicubic_filter, 2.0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Imaging
 | 
					 | 
				
			||||||
ImagingStretch(Imaging imOut, Imaging imIn, int filter)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* FIXME: this is a quick and straightforward translation from a
 | 
					 | 
				
			||||||
       python prototype.  might need some further C-ification... */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline UINT8 clip8(float in)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int out = (int) in;
 | 
				
			||||||
 | 
					    if (out >= 255)
 | 
				
			||||||
 | 
					       return 255;
 | 
				
			||||||
 | 
					    if (out <= 0)
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    return (UINT8) out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This is work around bug in GCC prior 4.9 in 64 bit mode.
 | 
				
			||||||
 | 
					   GCC generates code with partial dependency which 3 times slower.
 | 
				
			||||||
 | 
					   See: http://stackoverflow.com/a/26588074/253146 */
 | 
				
			||||||
 | 
					#if defined(__x86_64__) && defined(__SSE__) && \
 | 
				
			||||||
 | 
					    ! defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
 | 
				
			||||||
 | 
					static float __attribute__((always_inline)) i2f(int v) {
 | 
				
			||||||
 | 
					    float x;
 | 
				
			||||||
 | 
					    __asm__("xorps %0, %0; cvtsi2ss %1, %0" : "=X"(x) : "r"(v) );
 | 
				
			||||||
 | 
					    return x;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static float inline i2f(int v) { return (float) v; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imaging
 | 
				
			||||||
 | 
					ImagingStretchHorizontal(Imaging imIn, int xsize, int filter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    ImagingSectionCookie cookie;
 | 
					    ImagingSectionCookie cookie;
 | 
				
			||||||
 | 
					    Imaging imOut;
 | 
				
			||||||
    struct filter *filterp;
 | 
					    struct filter *filterp;
 | 
				
			||||||
    float support, scale, filterscale;
 | 
					    float support, scale, filterscale;
 | 
				
			||||||
    float center, ww, ss, ymin, ymax, xmin, xmax;
 | 
					    float center, ww, ss, ss0, ss1, ss2, ss3;
 | 
				
			||||||
    int xx, yy, x, y, b;
 | 
					    int xx, yy, x, kmax, xmin, xmax;
 | 
				
			||||||
    float *k;
 | 
					    int *xbounds;
 | 
				
			||||||
 | 
					    float *k, *kk;
 | 
				
			||||||
    /* check modes */
 | 
					 | 
				
			||||||
    if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
 | 
					 | 
				
			||||||
        return (Imaging) ImagingError_ModeError();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
 | 
					 | 
				
			||||||
        return (Imaging) ImagingError_ModeError();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* check filter */
 | 
					    /* check filter */
 | 
				
			||||||
    switch (filter) {
 | 
					    switch (filter) {
 | 
				
			||||||
| 
						 | 
					@ -118,14 +137,8 @@ ImagingStretch(Imaging imOut, Imaging imIn, int filter)
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (imIn->ysize == imOut->ysize) {
 | 
					 | 
				
			||||||
    /* prepare for horizontal stretch */
 | 
					    /* prepare for horizontal stretch */
 | 
				
			||||||
        filterscale = scale = (float) imIn->xsize / imOut->xsize;
 | 
					    filterscale = scale = (float) imIn->xsize / xsize;
 | 
				
			||||||
    } else if (imIn->xsize == imOut->xsize) {
 | 
					 | 
				
			||||||
        /* prepare for vertical stretch */
 | 
					 | 
				
			||||||
        filterscale = scale = (float) imIn->ysize / imOut->ysize;
 | 
					 | 
				
			||||||
    } else
 | 
					 | 
				
			||||||
        return (Imaging) ImagingError_Mismatch();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* determine support size (length of resampling filter) */
 | 
					    /* determine support size (length of resampling filter) */
 | 
				
			||||||
    support = filterp->support;
 | 
					    support = filterp->support;
 | 
				
			||||||
| 
						 | 
					@ -136,172 +149,186 @@ ImagingStretch(Imaging imOut, Imaging imIn, int filter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    support = support * filterscale;
 | 
					    support = support * filterscale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* maximum number of coofs */
 | 
				
			||||||
 | 
					    kmax = (int) ceil(support) * 2 + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* coefficient buffer (with rounding safety margin) */
 | 
					    /* coefficient buffer (with rounding safety margin) */
 | 
				
			||||||
    k = malloc(((int) support * 2 + 10) * sizeof(float));
 | 
					    kk = malloc(xsize * kmax * sizeof(float));
 | 
				
			||||||
    if (!k)
 | 
					    if ( ! kk)
 | 
				
			||||||
        return (Imaging) ImagingError_MemoryError();
 | 
					        return (Imaging) ImagingError_MemoryError();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImagingSectionEnter(&cookie);
 | 
					    xbounds = malloc(xsize * 2 * sizeof(int));
 | 
				
			||||||
    if (imIn->xsize == imOut->xsize) {
 | 
					    if ( ! xbounds) {
 | 
				
			||||||
        /* vertical stretch */
 | 
					        free(kk);
 | 
				
			||||||
        for (yy = 0; yy < imOut->ysize; yy++) {
 | 
					        return (Imaging) ImagingError_MemoryError();
 | 
				
			||||||
            center = (yy + 0.5) * scale;
 | 
					 | 
				
			||||||
            ww = 0.0;
 | 
					 | 
				
			||||||
            ss = 1.0 / filterscale;
 | 
					 | 
				
			||||||
            /* calculate filter weights */
 | 
					 | 
				
			||||||
            ymin = floor(center - support);
 | 
					 | 
				
			||||||
            if (ymin < 0.0)
 | 
					 | 
				
			||||||
                ymin = 0.0;
 | 
					 | 
				
			||||||
            ymax = ceil(center + support);
 | 
					 | 
				
			||||||
            if (ymax > (float) imIn->ysize)
 | 
					 | 
				
			||||||
                ymax = (float) imIn->ysize;
 | 
					 | 
				
			||||||
            for (y = (int) ymin; y < (int) ymax; y++) {
 | 
					 | 
				
			||||||
                float w = filterp->filter((y - center + 0.5) * ss) * ss;
 | 
					 | 
				
			||||||
                k[y - (int) ymin] = w;
 | 
					 | 
				
			||||||
                ww = ww + w;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            if (ww == 0.0)
 | 
					
 | 
				
			||||||
                ww = 1.0;
 | 
					    for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
            else
 | 
					        k = &kk[xx * kmax];
 | 
				
			||||||
                ww = 1.0 / ww;
 | 
					 | 
				
			||||||
            if (imIn->image8) {
 | 
					 | 
				
			||||||
                /* 8-bit grayscale */
 | 
					 | 
				
			||||||
                for (xx = 0; xx < imOut->xsize; xx++) {
 | 
					 | 
				
			||||||
                    ss = 0.0;
 | 
					 | 
				
			||||||
                    for (y = (int) ymin; y < (int) ymax; y++)
 | 
					 | 
				
			||||||
                        ss = ss + imIn->image8[y][xx] * k[y - (int) ymin];
 | 
					 | 
				
			||||||
                    ss = ss * ww + 0.5;
 | 
					 | 
				
			||||||
                    if (ss < 0.5)
 | 
					 | 
				
			||||||
                        imOut->image8[yy][xx] = 0;
 | 
					 | 
				
			||||||
                    else if (ss >= 255.0)
 | 
					 | 
				
			||||||
                        imOut->image8[yy][xx] = 255;
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                        imOut->image8[yy][xx] = (UINT8) ss;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else
 | 
					 | 
				
			||||||
                switch(imIn->type) {
 | 
					 | 
				
			||||||
                case IMAGING_TYPE_UINT8:
 | 
					 | 
				
			||||||
                    /* n-bit grayscale */
 | 
					 | 
				
			||||||
                    for (xx = 0; xx < imOut->xsize*4; xx++) {
 | 
					 | 
				
			||||||
                        /* FIXME: skip over unused pixels */
 | 
					 | 
				
			||||||
                        ss = 0.0;
 | 
					 | 
				
			||||||
                        for (y = (int) ymin; y < (int) ymax; y++)
 | 
					 | 
				
			||||||
                            ss = ss + (UINT8) imIn->image[y][xx] * k[y-(int) ymin];
 | 
					 | 
				
			||||||
                        ss = ss * ww + 0.5;
 | 
					 | 
				
			||||||
                        if (ss < 0.5)
 | 
					 | 
				
			||||||
                            imOut->image[yy][xx] = (UINT8) 0;
 | 
					 | 
				
			||||||
                        else if (ss >= 255.0)
 | 
					 | 
				
			||||||
                            imOut->image[yy][xx] = (UINT8) 255;
 | 
					 | 
				
			||||||
                        else
 | 
					 | 
				
			||||||
                            imOut->image[yy][xx] = (UINT8) ss;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case IMAGING_TYPE_INT32:
 | 
					 | 
				
			||||||
                    /* 32-bit integer */
 | 
					 | 
				
			||||||
                    for (xx = 0; xx < imOut->xsize; xx++) {
 | 
					 | 
				
			||||||
                        ss = 0.0;
 | 
					 | 
				
			||||||
                        for (y = (int) ymin; y < (int) ymax; y++)
 | 
					 | 
				
			||||||
                            ss = ss + IMAGING_PIXEL_I(imIn, xx, y) * k[y - (int) ymin];
 | 
					 | 
				
			||||||
                        IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case IMAGING_TYPE_FLOAT32:
 | 
					 | 
				
			||||||
                    /* 32-bit float */
 | 
					 | 
				
			||||||
                    for (xx = 0; xx < imOut->xsize; xx++) {
 | 
					 | 
				
			||||||
                        ss = 0.0;
 | 
					 | 
				
			||||||
                        for (y = (int) ymin; y < (int) ymax; y++)
 | 
					 | 
				
			||||||
                            ss = ss + IMAGING_PIXEL_F(imIn, xx, y) * k[y - (int) ymin];
 | 
					 | 
				
			||||||
                        IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                default:
 | 
					 | 
				
			||||||
                    ImagingSectionLeave(&cookie);
 | 
					 | 
				
			||||||
                    return (Imaging) ImagingError_ModeError();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        /* horizontal stretch */
 | 
					 | 
				
			||||||
        for (xx = 0; xx < imOut->xsize; xx++) {
 | 
					 | 
				
			||||||
        center = (xx + 0.5) * scale;
 | 
					        center = (xx + 0.5) * scale;
 | 
				
			||||||
        ww = 0.0;
 | 
					        ww = 0.0;
 | 
				
			||||||
        ss = 1.0 / filterscale;
 | 
					        ss = 1.0 / filterscale;
 | 
				
			||||||
            xmin = floor(center - support);
 | 
					        xmin = (int) floor(center - support);
 | 
				
			||||||
            if (xmin < 0.0)
 | 
					        if (xmin < 0)
 | 
				
			||||||
                xmin = 0.0;
 | 
					            xmin = 0;
 | 
				
			||||||
            xmax = ceil(center + support);
 | 
					        xmax = (int) ceil(center + support);
 | 
				
			||||||
            if (xmax > (float) imIn->xsize)
 | 
					        if (xmax > imIn->xsize)
 | 
				
			||||||
                xmax = (float) imIn->xsize;
 | 
					            xmax = imIn->xsize;
 | 
				
			||||||
            for (x = (int) xmin; x < (int) xmax; x++) {
 | 
					        for (x = xmin; x < xmax; x++) {
 | 
				
			||||||
            float w = filterp->filter((x - center + 0.5) * ss) * ss;
 | 
					            float w = filterp->filter((x - center + 0.5) * ss) * ss;
 | 
				
			||||||
                k[x - (int) xmin] = w;
 | 
					            k[x - xmin] = w;
 | 
				
			||||||
                ww = ww + w;
 | 
					            ww += w;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            if (ww == 0.0)
 | 
					        for (x = 0; x < xmax - xmin; x++) {
 | 
				
			||||||
                ww = 1.0;
 | 
					            if (ww != 0.0)
 | 
				
			||||||
            else
 | 
					                k[x] /= ww;
 | 
				
			||||||
                ww = 1.0 / ww;
 | 
					        }
 | 
				
			||||||
 | 
					        xbounds[xx * 2 + 0] = xmin;
 | 
				
			||||||
 | 
					        xbounds[xx * 2 + 1] = xmax;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    imOut = ImagingNew(imIn->mode, xsize, imIn->ysize);
 | 
				
			||||||
 | 
					    if ( ! imOut) {
 | 
				
			||||||
 | 
					        free(kk);
 | 
				
			||||||
 | 
					        free(xbounds);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ImagingSectionEnter(&cookie);
 | 
				
			||||||
 | 
					    /* horizontal stretch */
 | 
				
			||||||
 | 
					    for (yy = 0; yy < imOut->ysize; yy++) {
 | 
				
			||||||
        if (imIn->image8) {
 | 
					        if (imIn->image8) {
 | 
				
			||||||
            /* 8-bit grayscale */
 | 
					            /* 8-bit grayscale */
 | 
				
			||||||
                for (yy = 0; yy < imOut->ysize; yy++) {
 | 
					            for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
                    ss = 0.0;
 | 
					                xmin = xbounds[xx * 2 + 0];
 | 
				
			||||||
                    for (x = (int) xmin; x < (int) xmax; x++)
 | 
					                xmax = xbounds[xx * 2 + 1];
 | 
				
			||||||
                        ss = ss + imIn->image8[yy][x] * k[x - (int) xmin];
 | 
					                k = &kk[xx * kmax];
 | 
				
			||||||
                    ss = ss * ww + 0.5;
 | 
					                ss = 0.5;
 | 
				
			||||||
                    if (ss < 0.5)
 | 
					                for (x = xmin; x < xmax; x++)
 | 
				
			||||||
                        imOut->image8[yy][xx] = (UINT8) 0;
 | 
					                    ss += i2f(imIn->image8[yy][x]) * k[x - xmin];
 | 
				
			||||||
                    else if (ss >= 255.0)
 | 
					                imOut->image8[yy][xx] = clip8(ss);
 | 
				
			||||||
                        imOut->image8[yy][xx] = (UINT8) 255;
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                        imOut->image8[yy][xx] = (UINT8) ss;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else
 | 
					        } else
 | 
				
			||||||
            switch(imIn->type) {
 | 
					            switch(imIn->type) {
 | 
				
			||||||
            case IMAGING_TYPE_UINT8:
 | 
					            case IMAGING_TYPE_UINT8:
 | 
				
			||||||
                /* n-bit grayscale */
 | 
					                /* n-bit grayscale */
 | 
				
			||||||
                    for (yy = 0; yy < imOut->ysize; yy++) {
 | 
					                if (imIn->bands == 2) {
 | 
				
			||||||
                        for (b = 0; b < imIn->bands; b++) {
 | 
					                    for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
                            if (imIn->bands == 2 && b)
 | 
					                        xmin = xbounds[xx * 2 + 0];
 | 
				
			||||||
                                b = 3; /* hack to deal with LA images */
 | 
					                        xmax = xbounds[xx * 2 + 1];
 | 
				
			||||||
                            ss = 0.0;
 | 
					                        k = &kk[xx * kmax];
 | 
				
			||||||
                            for (x = (int) xmin; x < (int) xmax; x++)
 | 
					                        ss0 = ss1 = 0.5;
 | 
				
			||||||
                                ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin];
 | 
					                        for (x = xmin; x < xmax; x++) {
 | 
				
			||||||
                            ss = ss * ww + 0.5;
 | 
					                            ss0 += i2f((UINT8) imIn->image[yy][x*4 + 0]) * k[x - xmin];
 | 
				
			||||||
                            if (ss < 0.5)
 | 
					                            ss1 += i2f((UINT8) imIn->image[yy][x*4 + 3]) * k[x - xmin];
 | 
				
			||||||
                                imOut->image[yy][xx*4+b] = (UINT8) 0;
 | 
					                        }
 | 
				
			||||||
                            else if (ss >= 255.0)
 | 
					                        imOut->image[yy][xx*4 + 0] = clip8(ss0);
 | 
				
			||||||
                                imOut->image[yy][xx*4+b] = (UINT8) 255;
 | 
					                        imOut->image[yy][xx*4 + 3] = clip8(ss1);
 | 
				
			||||||
                            else
 | 
					                    }
 | 
				
			||||||
                                imOut->image[yy][xx*4+b] = (UINT8) ss;
 | 
					                } else if (imIn->bands == 3) {
 | 
				
			||||||
 | 
					                    for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
 | 
					                        xmin = xbounds[xx * 2 + 0];
 | 
				
			||||||
 | 
					                        xmax = xbounds[xx * 2 + 1];
 | 
				
			||||||
 | 
					                        k = &kk[xx * kmax];
 | 
				
			||||||
 | 
					                        ss0 = ss1 = ss2 = 0.5;
 | 
				
			||||||
 | 
					                        for (x = xmin; x < xmax; x++) {
 | 
				
			||||||
 | 
					                            ss0 += i2f((UINT8) imIn->image[yy][x*4 + 0]) * k[x - xmin];
 | 
				
			||||||
 | 
					                            ss1 += i2f((UINT8) imIn->image[yy][x*4 + 1]) * k[x - xmin];
 | 
				
			||||||
 | 
					                            ss2 += i2f((UINT8) imIn->image[yy][x*4 + 2]) * k[x - xmin];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 0] = clip8(ss0);
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 1] = clip8(ss1);
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 2] = clip8(ss2);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
 | 
					                        xmin = xbounds[xx * 2 + 0];
 | 
				
			||||||
 | 
					                        xmax = xbounds[xx * 2 + 1];
 | 
				
			||||||
 | 
					                        k = &kk[xx * kmax];
 | 
				
			||||||
 | 
					                        ss0 = ss1 = ss2 = ss3 = 0.5;
 | 
				
			||||||
 | 
					                        for (x = xmin; x < xmax; x++) {
 | 
				
			||||||
 | 
					                            ss0 += i2f((UINT8) imIn->image[yy][x*4 + 0]) * k[x - xmin];
 | 
				
			||||||
 | 
					                            ss1 += i2f((UINT8) imIn->image[yy][x*4 + 1]) * k[x - xmin];
 | 
				
			||||||
 | 
					                            ss2 += i2f((UINT8) imIn->image[yy][x*4 + 2]) * k[x - xmin];
 | 
				
			||||||
 | 
					                            ss3 += i2f((UINT8) imIn->image[yy][x*4 + 3]) * k[x - xmin];
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 0] = clip8(ss0);
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 1] = clip8(ss1);
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 2] = clip8(ss2);
 | 
				
			||||||
 | 
					                        imOut->image[yy][xx*4 + 3] = clip8(ss3);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case IMAGING_TYPE_INT32:
 | 
					            case IMAGING_TYPE_INT32:
 | 
				
			||||||
                /* 32-bit integer */
 | 
					                /* 32-bit integer */
 | 
				
			||||||
                    for (yy = 0; yy < imOut->ysize; yy++) {
 | 
					                for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
 | 
					                    xmin = xbounds[xx * 2 + 0];
 | 
				
			||||||
 | 
					                    xmax = xbounds[xx * 2 + 1];
 | 
				
			||||||
 | 
					                    k = &kk[xx * kmax];
 | 
				
			||||||
                    ss = 0.0;
 | 
					                    ss = 0.0;
 | 
				
			||||||
                        for (x = (int) xmin; x < (int) xmax; x++)
 | 
					                    for (x = xmin; x < xmax; x++)
 | 
				
			||||||
                            ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin];
 | 
					                        ss += i2f(IMAGING_PIXEL_I(imIn, x, yy)) * k[x - xmin];
 | 
				
			||||||
                        IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww;
 | 
					                    IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case IMAGING_TYPE_FLOAT32:
 | 
					            case IMAGING_TYPE_FLOAT32:
 | 
				
			||||||
                /* 32-bit float */
 | 
					                /* 32-bit float */
 | 
				
			||||||
                    for (yy = 0; yy < imOut->ysize; yy++) {
 | 
					                for (xx = 0; xx < xsize; xx++) {
 | 
				
			||||||
 | 
					                    xmin = xbounds[xx * 2 + 0];
 | 
				
			||||||
 | 
					                    xmax = xbounds[xx * 2 + 1];
 | 
				
			||||||
 | 
					                    k = &kk[xx * kmax];
 | 
				
			||||||
                    ss = 0.0;
 | 
					                    ss = 0.0;
 | 
				
			||||||
                        for (x = (int) xmin; x < (int) xmax; x++)
 | 
					                    for (x = xmin; x < xmax; x++)
 | 
				
			||||||
                            ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin];
 | 
					                        ss += IMAGING_PIXEL_F(imIn, x, yy) * k[x - xmin];
 | 
				
			||||||
                        IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww;
 | 
					                    IMAGING_PIXEL_F(imOut, xx, yy) = ss;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
                ImagingSectionLeave(&cookie);
 | 
					                ImagingSectionLeave(&cookie);
 | 
				
			||||||
 | 
					                ImagingDelete(imOut);
 | 
				
			||||||
 | 
					                free(kk);
 | 
				
			||||||
 | 
					                free(xbounds);
 | 
				
			||||||
                return (Imaging) ImagingError_ModeError();
 | 
					                return (Imaging) ImagingError_ModeError();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ImagingSectionLeave(&cookie);
 | 
					    ImagingSectionLeave(&cookie);
 | 
				
			||||||
 | 
					    free(kk);
 | 
				
			||||||
 | 
					    free(xbounds);
 | 
				
			||||||
 | 
					    return imOut;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    free(k);
 | 
					
 | 
				
			||||||
 | 
					Imaging
 | 
				
			||||||
 | 
					ImagingStretch(Imaging imIn, int xsize, int ysize, int filter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Imaging imTemp1, imTemp2, imTemp3;
 | 
				
			||||||
 | 
					    Imaging imOut;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
 | 
				
			||||||
 | 
					        return (Imaging) ImagingError_ModeError();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* two-pass resize, first pass */
 | 
				
			||||||
 | 
					    imTemp1 = ImagingStretchHorizontal(imIn, xsize, filter);
 | 
				
			||||||
 | 
					    if ( ! imTemp1)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* transpose image once */
 | 
				
			||||||
 | 
					    imTemp2 = ImagingTransposeToNew(imTemp1);
 | 
				
			||||||
 | 
					    ImagingDelete(imTemp1);
 | 
				
			||||||
 | 
					    if ( ! imTemp2)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* second pass */
 | 
				
			||||||
 | 
					    imTemp3 = ImagingStretchHorizontal(imTemp2, ysize, filter);
 | 
				
			||||||
 | 
					    ImagingDelete(imTemp2);
 | 
				
			||||||
 | 
					    if ( ! imTemp3)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* transpose result */
 | 
				
			||||||
 | 
					    imOut = ImagingTransposeToNew(imTemp3);
 | 
				
			||||||
 | 
					    ImagingDelete(imTemp3);
 | 
				
			||||||
 | 
					    if ( ! imOut)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return imOut;
 | 
					    return imOut;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -178,6 +178,21 @@ ImagingTranspose(Imaging imOut, Imaging imIn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,3 +72,9 @@
 | 
				
			||||||
#ifdef _MSC_VER
 | 
					#ifdef _MSC_VER
 | 
				
			||||||
typedef signed __int64       int64_t;
 | 
					typedef signed __int64       int64_t;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __GNUC__
 | 
				
			||||||
 | 
					    #define GCC_VERSION (__GNUC__ * 10000 \
 | 
				
			||||||
 | 
					                       + __GNUC_MINOR__ * 100 \
 | 
				
			||||||
 | 
					                       + __GNUC_PATCHLEVEL__)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -291,8 +291,9 @@ extern Imaging ImagingRotate(
 | 
				
			||||||
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 ImagingStretch(Imaging imOut, Imaging imIn, int filter);
 | 
					extern Imaging ImagingStretch(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(
 | 
					extern Imaging ImagingTransformPerspective(
 | 
				
			||||||
    Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
 | 
					    Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1,
 | 
				
			||||||
    double a[8], int filter, int fill);
 | 
					    double a[8], int filter, int fill);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user