From c8471bcbda68b7d7bd4542bce1da9c21e1aec07d Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 05:03:27 +0400 Subject: [PATCH 01/18] Hide stretch implementation detail in Antialias.c --- _imaging.c | 25 ++----------------------- libImaging/Antialias.c | 41 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/_imaging.c b/_imaging.c index 4eb878cf7..6cddd913b 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1613,7 +1613,6 @@ static PyObject* _stretch(ImagingObject* self, PyObject* args) { Imaging imIn; - Imaging imTemp; Imaging imOut; int xsize, ysize; @@ -1623,35 +1622,15 @@ _stretch(ImagingObject* self, PyObject* args) imIn = self->image; - /* two-pass resize: minimize size of intermediate image */ - if ((Py_ssize_t) imIn->xsize * ysize < (Py_ssize_t) xsize * imIn->ysize) - 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; - } - imOut = ImagingNew(imIn->mode, xsize, ysize); - if (!imOut) { - ImagingDelete(imTemp); + if ( ! imOut) return NULL; - } - /* second pass */ - if (!ImagingStretch(imOut, imTemp, filter)) { + if (!ImagingStretch(imOut, imIn, filter)) { ImagingDelete(imOut); - ImagingDelete(imTemp); return NULL; } - ImagingDelete(imTemp); - return PyImagingNew(imOut); } diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index be49bc827..fc084e952 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -79,7 +79,7 @@ static inline float bicubic_filter(float x) static struct filter BICUBIC = { bicubic_filter, 2.0 }; Imaging -ImagingStretch(Imaging imOut, Imaging imIn, int filter) +ImagingStretchPass(Imaging imOut, Imaging imIn, int filter) { /* FIXME: this is a quick and straightforward translation from a python prototype. might need some further C-ification... */ @@ -95,9 +95,6 @@ ImagingStretch(Imaging imOut, Imaging imIn, int filter) 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 */ switch (filter) { case IMAGING_TRANSFORM_NEAREST: @@ -305,3 +302,39 @@ ImagingStretch(Imaging imOut, Imaging imIn, int filter) return imOut; } + + +Imaging +ImagingStretch(Imaging imOut, Imaging imIn, int filter) +{ + Imaging imTemp; + int xsize = imOut->xsize; + int ysize = imOut->ysize; + + if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) + return (Imaging) ImagingError_ModeError(); + + /* two-pass resize: minimize size of intermediate image */ + if ((Py_ssize_t) imIn->xsize * ysize < (Py_ssize_t) xsize * imIn->ysize) + imTemp = ImagingNew(imIn->mode, imIn->xsize, ysize); + else + imTemp = ImagingNew(imIn->mode, xsize, imIn->ysize); + if ( ! imTemp) + return NULL; + + /* first pass */ + if ( ! ImagingStretchPass(imTemp, imIn, filter)) { + ImagingDelete(imTemp); + return NULL; + } + + /* second pass */ + if ( ! ImagingStretchPass(imOut, imTemp, filter)) { + ImagingDelete(imTemp); + return NULL; + } + + ImagingDelete(imTemp); + + return imOut; +} From 40f9f48680d4c3228c33521d458580d5c552b0e2 Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 05:20:37 +0400 Subject: [PATCH 02/18] two ImagingStretchHorizaontal pass with two transposes --- libImaging/Antialias.c | 276 ++++++++++++++++------------------------- 1 file changed, 110 insertions(+), 166 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index fc084e952..5193e6877 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -79,7 +79,7 @@ static inline float bicubic_filter(float x) static struct filter BICUBIC = { bicubic_filter, 2.0 }; Imaging -ImagingStretchPass(Imaging imOut, Imaging imIn, int filter) +ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) { /* FIXME: this is a quick and straightforward translation from a python prototype. might need some further C-ification... */ @@ -87,14 +87,19 @@ ImagingStretchPass(Imaging imOut, Imaging imIn, int filter) ImagingSectionCookie cookie; struct filter *filterp; float support, scale, filterscale; - float center, ww, ss, ymin, ymax, xmin, xmax; - int xx, yy, x, y, b; + float center, ww, ss, xmin, xmax; + int xx, yy, x, b; float *k; /* check modes */ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) return (Imaging) ImagingError_ModeError(); + if (imOut->ysize != imIn->ysize) + return (Imaging) ImagingError_ValueError( + "ImagingStretchHorizaontal requires equal heights" + ); + /* check filter */ switch (filter) { case IMAGING_TRANSFORM_NEAREST: @@ -115,14 +120,8 @@ ImagingStretchPass(Imaging imOut, Imaging imIn, int filter) ); } - if (imIn->ysize == imOut->ysize) { - /* prepare for horizontal stretch */ - filterscale = scale = (float) imIn->xsize / imOut->xsize; - } else if (imIn->xsize == imOut->xsize) { - /* prepare for vertical stretch */ - filterscale = scale = (float) imIn->ysize / imOut->ysize; - } else - return (Imaging) ImagingError_Mismatch(); + /* prepare for horizontal stretch */ + filterscale = scale = (float) imIn->xsize / imOut->xsize; /* determine support size (length of resampling filter) */ support = filterp->support; @@ -139,162 +138,83 @@ ImagingStretchPass(Imaging imOut, Imaging imIn, int filter) return (Imaging) ImagingError_MemoryError(); ImagingSectionEnter(&cookie); - if (imIn->xsize == imOut->xsize) { - /* vertical stretch */ - for (yy = 0; yy < imOut->ysize; yy++) { - 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; + /* horizontal stretch */ + for (xx = 0; xx < imOut->xsize; xx++) { + center = (xx + 0.5) * scale; + ww = 0.0; + ss = 1.0 / filterscale; + xmin = floor(center - support); + if (xmin < 0.0) + xmin = 0.0; + xmax = ceil(center + support); + if (xmax > (float) imIn->xsize) + xmax = (float) imIn->xsize; + for (x = (int) xmin; x < (int) xmax; x++) { + float w = filterp->filter((x - center + 0.5) * ss) * ss; + k[x - (int) xmin] = w; + ww = ww + w; + } + if (ww == 0.0) + ww = 1.0; + else + ww = 1.0 / ww; + if (imIn->image8) { + /* 8-bit grayscale */ + for (yy = 0; yy < imOut->ysize; yy++) { + ss = 0.0; + for (x = (int) xmin; x < (int) xmax; x++) + ss = ss + imIn->image8[yy][x] * k[x - (int) xmin]; + ss = ss * ww + 0.5; + if (ss < 0.5) + imOut->image8[yy][xx] = (UINT8) 0; + else if (ss >= 255.0) + imOut->image8[yy][xx] = (UINT8) 255; + else + imOut->image8[yy][xx] = (UINT8) ss; } - if (ww == 0.0) - ww = 1.0; - else - 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 */ + } else + switch(imIn->type) { + case IMAGING_TYPE_UINT8: + /* n-bit grayscale */ + for (yy = 0; yy < imOut->ysize; yy++) { + for (b = 0; b < imIn->bands; b++) { + if (imIn->bands == 2 && b) + b = 3; /* hack to deal with LA images */ ss = 0.0; - for (y = (int) ymin; y < (int) ymax; y++) - ss = ss + (UINT8) imIn->image[y][xx] * k[y-(int) ymin]; + for (x = (int) xmin; x < (int) xmax; x++) + ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin]; ss = ss * ww + 0.5; if (ss < 0.5) - imOut->image[yy][xx] = (UINT8) 0; + imOut->image[yy][xx*4+b] = (UINT8) 0; else if (ss >= 255.0) - imOut->image[yy][xx] = (UINT8) 255; + imOut->image[yy][xx*4+b] = (UINT8) 255; else - imOut->image[yy][xx] = (UINT8) ss; + imOut->image[yy][xx*4+b] = (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; - ww = 0.0; - ss = 1.0 / filterscale; - xmin = floor(center - support); - if (xmin < 0.0) - xmin = 0.0; - xmax = ceil(center + support); - if (xmax > (float) imIn->xsize) - xmax = (float) imIn->xsize; - for (x = (int) xmin; x < (int) xmax; x++) { - float w = filterp->filter((x - center + 0.5) * ss) * ss; - k[x - (int) xmin] = w; - ww = ww + w; - } - if (ww == 0.0) - ww = 1.0; - else - ww = 1.0 / ww; - if (imIn->image8) { - /* 8-bit grayscale */ + break; + case IMAGING_TYPE_INT32: + /* 32-bit integer */ for (yy = 0; yy < imOut->ysize; yy++) { ss = 0.0; for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + imIn->image8[yy][x] * k[x - (int) xmin]; - ss = ss * ww + 0.5; - if (ss < 0.5) - imOut->image8[yy][xx] = (UINT8) 0; - else if (ss >= 255.0) - imOut->image8[yy][xx] = (UINT8) 255; - else - imOut->image8[yy][xx] = (UINT8) ss; + ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin]; + IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww; } - } else - switch(imIn->type) { - case IMAGING_TYPE_UINT8: - /* n-bit grayscale */ - for (yy = 0; yy < imOut->ysize; yy++) { - for (b = 0; b < imIn->bands; b++) { - if (imIn->bands == 2 && b) - b = 3; /* hack to deal with LA images */ - ss = 0.0; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin]; - ss = ss * ww + 0.5; - if (ss < 0.5) - imOut->image[yy][xx*4+b] = (UINT8) 0; - else if (ss >= 255.0) - imOut->image[yy][xx*4+b] = (UINT8) 255; - else - imOut->image[yy][xx*4+b] = (UINT8) ss; - } - } - break; - case IMAGING_TYPE_INT32: - /* 32-bit integer */ - for (yy = 0; yy < imOut->ysize; yy++) { - ss = 0.0; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin]; - IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww; - } - break; - case IMAGING_TYPE_FLOAT32: - /* 32-bit float */ - for (yy = 0; yy < imOut->ysize; yy++) { - ss = 0.0; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin]; - IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww; - } - break; - default: - ImagingSectionLeave(&cookie); - return (Imaging) ImagingError_ModeError(); + break; + case IMAGING_TYPE_FLOAT32: + /* 32-bit float */ + for (yy = 0; yy < imOut->ysize; yy++) { + ss = 0.0; + for (x = (int) xmin; x < (int) xmax; x++) + ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin]; + IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww; } - } + break; + default: + ImagingSectionLeave(&cookie); + return (Imaging) ImagingError_ModeError(); + } } ImagingSectionLeave(&cookie); @@ -307,34 +227,58 @@ ImagingStretchPass(Imaging imOut, Imaging imIn, int filter) Imaging ImagingStretch(Imaging imOut, Imaging imIn, int filter) { - Imaging imTemp; + Imaging imTemp1, imTemp2, imTemp3; int xsize = imOut->xsize; int ysize = imOut->ysize; if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) return (Imaging) ImagingError_ModeError(); - /* two-pass resize: minimize size of intermediate image */ - if ((Py_ssize_t) imIn->xsize * ysize < (Py_ssize_t) xsize * imIn->ysize) - imTemp = ImagingNew(imIn->mode, imIn->xsize, ysize); - else - imTemp = ImagingNew(imIn->mode, xsize, imIn->ysize); - if ( ! imTemp) + /* two-pass resize */ + imTemp1 = ImagingNew(imIn->mode, xsize, imIn->ysize); + if ( ! imTemp1) return NULL; /* first pass */ - if ( ! ImagingStretchPass(imTemp, imIn, filter)) { - ImagingDelete(imTemp); + if ( ! ImagingStretchHorizaontal(imTemp1, imIn, filter)) { + ImagingDelete(imTemp1); + return NULL; + } + + imTemp2 = ImagingNew(imIn->mode, imIn->ysize, xsize); + if ( ! imTemp2) { + ImagingDelete(imTemp1); + return NULL; + } + + /* transpose image once */ + if ( ! ImagingTranspose(imTemp2, imTemp1)) { + ImagingDelete(imTemp1); + ImagingDelete(imTemp2); + return NULL; + } + ImagingDelete(imTemp1); + + imTemp3 = ImagingNew(imIn->mode, ysize, xsize); + if ( ! imTemp3) { + ImagingDelete(imTemp2); return NULL; } /* second pass */ - if ( ! ImagingStretchPass(imOut, imTemp, filter)) { - ImagingDelete(imTemp); + if ( ! ImagingStretchHorizaontal(imTemp3, imTemp2, filter)) { + ImagingDelete(imTemp2); + ImagingDelete(imTemp3); return NULL; } + ImagingDelete(imTemp2); - ImagingDelete(imTemp); + /* transpose result */ + if ( ! ImagingTranspose(imOut, imTemp3)) { + ImagingDelete(imTemp3); + return NULL; + } + ImagingDelete(imTemp3); return imOut; } From b77521bd6cacc3c620a0d3bbd246f9136f3d9246 Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 05:37:33 +0400 Subject: [PATCH 03/18] Precompute coefficients for all x --- libImaging/Antialias.c | 45 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 5193e6877..aeb9581d4 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -88,8 +88,8 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) struct filter *filterp; float support, scale, filterscale; float center, ww, ss, xmin, xmax; - int xx, yy, x, b; - float *k; + int xx, yy, x, b, kmax; + float *k, *kk, *xbounds; /* check modes */ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) @@ -132,11 +132,45 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) support = support * filterscale; + /* maximum number of coofs */ + kmax = (int) ceil(support) * 2 + 1; + /* coefficient buffer (with rounding safety margin) */ - k = malloc(((int) support * 2 + 10) * sizeof(float)); - if (!k) + kk = malloc(imOut->xsize * kmax * sizeof(float)); + if ( ! kk) return (Imaging) ImagingError_MemoryError(); + xbounds = malloc(imOut->xsize * 3 * sizeof(float)); + if ( ! xbounds) { + free(kk); + return (Imaging) ImagingError_MemoryError(); + } + + for (xx = 0; xx < imOut->xsize; xx++) { + k = &kk[xx * kmax]; + center = (xx + 0.5) * scale; + ww = 0.0; + ss = 1.0 / filterscale; + xmin = floor(center - support); + if (xmin < 0.0) + xmin = 0.0; + xmax = ceil(center + support); + if (xmax > (float) imIn->xsize) + xmax = (float) imIn->xsize; + for (x = (int) xmin; x < (int) xmax; x++) { + float w = filterp->filter((x - center + 0.5) * ss) * ss; + k[x - (int) xmin] = w; + ww = ww + w; + } + if (ww == 0.0) + ww = 1.0; + else + ww = 1.0 / ww; + xbounds[xx * 3 + 0] = xmin; + xbounds[xx * 3 + 1] = xmax; + xbounds[xx * 3 + 2] = ww; + } + ImagingSectionEnter(&cookie); /* horizontal stretch */ for (xx = 0; xx < imOut->xsize; xx++) { @@ -218,7 +252,8 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) } ImagingSectionLeave(&cookie); - free(k); + free(kk); + free(xbounds); return imOut; } From 01b947c602f53a994d8f61f37ec8649cbfe133fd Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 05:41:38 +0400 Subject: [PATCH 04/18] Iterate pixels in native order --- libImaging/Antialias.c | 44 ++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index aeb9581d4..fc45e0ded 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -173,28 +173,14 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) ImagingSectionEnter(&cookie); /* horizontal stretch */ - for (xx = 0; xx < imOut->xsize; xx++) { - center = (xx + 0.5) * scale; - ww = 0.0; - ss = 1.0 / filterscale; - xmin = floor(center - support); - if (xmin < 0.0) - xmin = 0.0; - xmax = ceil(center + support); - if (xmax > (float) imIn->xsize) - xmax = (float) imIn->xsize; - for (x = (int) xmin; x < (int) xmax; x++) { - float w = filterp->filter((x - center + 0.5) * ss) * ss; - k[x - (int) xmin] = w; - ww = ww + w; - } - if (ww == 0.0) - ww = 1.0; - else - ww = 1.0 / ww; + for (yy = 0; yy < imOut->ysize; yy++) { if (imIn->image8) { /* 8-bit grayscale */ - for (yy = 0; yy < imOut->ysize; yy++) { + for (xx = 0; xx < imOut->xsize; xx++) { + xmin = xbounds[xx * 3 + 0]; + xmax = xbounds[xx * 3 + 1]; + ww = xbounds[xx * 3 + 2]; + k = &kk[xx * kmax]; ss = 0.0; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + imIn->image8[yy][x] * k[x - (int) xmin]; @@ -210,7 +196,11 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) switch(imIn->type) { case IMAGING_TYPE_UINT8: /* n-bit grayscale */ - for (yy = 0; yy < imOut->ysize; yy++) { + for (xx = 0; xx < imOut->xsize; xx++) { + xmin = xbounds[xx * 3 + 0]; + xmax = xbounds[xx * 3 + 1]; + ww = xbounds[xx * 3 + 2]; + k = &kk[xx * kmax]; for (b = 0; b < imIn->bands; b++) { if (imIn->bands == 2 && b) b = 3; /* hack to deal with LA images */ @@ -229,7 +219,11 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) break; case IMAGING_TYPE_INT32: /* 32-bit integer */ - for (yy = 0; yy < imOut->ysize; yy++) { + for (xx = 0; xx < imOut->xsize; xx++) { + xmin = xbounds[xx * 3 + 0]; + xmax = xbounds[xx * 3 + 1]; + ww = xbounds[xx * 3 + 2]; + k = &kk[xx * kmax]; ss = 0.0; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin]; @@ -238,7 +232,11 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) break; case IMAGING_TYPE_FLOAT32: /* 32-bit float */ - for (yy = 0; yy < imOut->ysize; yy++) { + for (xx = 0; xx < imOut->xsize; xx++) { + xmin = xbounds[xx * 3 + 0]; + xmax = xbounds[xx * 3 + 1]; + ww = xbounds[xx * 3 + 2]; + k = &kk[xx * kmax]; ss = 0.0; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin]; From e276e6a535abe64e48b4eb1b29eff2183348257e Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 05:50:54 +0400 Subject: [PATCH 05/18] move ww into coefficients --- libImaging/Antialias.c | 47 ++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index fc45e0ded..95e854dd6 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -140,7 +140,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) if ( ! kk) return (Imaging) ImagingError_MemoryError(); - xbounds = malloc(imOut->xsize * 3 * sizeof(float)); + xbounds = malloc(imOut->xsize * 2 * sizeof(float)); if ( ! xbounds) { free(kk); return (Imaging) ImagingError_MemoryError(); @@ -160,15 +160,14 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) for (x = (int) xmin; x < (int) xmax; x++) { float w = filterp->filter((x - center + 0.5) * ss) * ss; k[x - (int) xmin] = w; - ww = ww + w; + ww += w; } - if (ww == 0.0) - ww = 1.0; - else - ww = 1.0 / ww; - xbounds[xx * 3 + 0] = xmin; - xbounds[xx * 3 + 1] = xmax; - xbounds[xx * 3 + 2] = ww; + for (x = 0; x < (int) xmax - (int) xmin; x++) { + if (ww != 0.0) + k[x] /= ww; + } + xbounds[xx * 2 + 0] = xmin; + xbounds[xx * 2 + 1] = xmax; } ImagingSectionEnter(&cookie); @@ -177,14 +176,12 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) if (imIn->image8) { /* 8-bit grayscale */ for (xx = 0; xx < imOut->xsize; xx++) { - xmin = xbounds[xx * 3 + 0]; - xmax = xbounds[xx * 3 + 1]; - ww = xbounds[xx * 3 + 2]; + xmin = xbounds[xx * 2 + 0]; + xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; - ss = 0.0; + ss = 0.5; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + imIn->image8[yy][x] * k[x - (int) xmin]; - ss = ss * ww + 0.5; if (ss < 0.5) imOut->image8[yy][xx] = (UINT8) 0; else if (ss >= 255.0) @@ -197,17 +194,15 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) case IMAGING_TYPE_UINT8: /* n-bit grayscale */ for (xx = 0; xx < imOut->xsize; xx++) { - xmin = xbounds[xx * 3 + 0]; - xmax = xbounds[xx * 3 + 1]; - ww = xbounds[xx * 3 + 2]; + xmin = xbounds[xx * 2 + 0]; + xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; for (b = 0; b < imIn->bands; b++) { if (imIn->bands == 2 && b) b = 3; /* hack to deal with LA images */ - ss = 0.0; + ss = 0.5; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin]; - ss = ss * ww + 0.5; if (ss < 0.5) imOut->image[yy][xx*4+b] = (UINT8) 0; else if (ss >= 255.0) @@ -220,27 +215,25 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) case IMAGING_TYPE_INT32: /* 32-bit integer */ for (xx = 0; xx < imOut->xsize; xx++) { - xmin = xbounds[xx * 3 + 0]; - xmax = xbounds[xx * 3 + 1]; - ww = xbounds[xx * 3 + 2]; + xmin = xbounds[xx * 2 + 0]; + xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; ss = 0.0; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin]; - IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww; + IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss; } break; case IMAGING_TYPE_FLOAT32: /* 32-bit float */ for (xx = 0; xx < imOut->xsize; xx++) { - xmin = xbounds[xx * 3 + 0]; - xmax = xbounds[xx * 3 + 1]; - ww = xbounds[xx * 3 + 2]; + xmin = xbounds[xx * 2 + 0]; + xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; ss = 0.0; for (x = (int) xmin; x < (int) xmax; x++) ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin]; - IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww; + IMAGING_PIXEL_F(imOut, xx, yy) = ss; } break; default: From a484d28d1f902742edac0ccd2aabfdd8371dc020 Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 05:57:08 +0400 Subject: [PATCH 06/18] make x indexes int --- libImaging/Antialias.c | 43 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 95e854dd6..3ecb35936 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -87,9 +87,10 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) ImagingSectionCookie cookie; struct filter *filterp; float support, scale, filterscale; - float center, ww, ss, xmin, xmax; - int xx, yy, x, b, kmax; - float *k, *kk, *xbounds; + float center, ww, ss; + int xx, yy, x, b, kmax, xmin, xmax; + int *xbounds; + float *k, *kk; /* check modes */ if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) @@ -140,7 +141,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) if ( ! kk) return (Imaging) ImagingError_MemoryError(); - xbounds = malloc(imOut->xsize * 2 * sizeof(float)); + xbounds = malloc(imOut->xsize * 2 * sizeof(int)); if ( ! xbounds) { free(kk); return (Imaging) ImagingError_MemoryError(); @@ -151,18 +152,18 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) center = (xx + 0.5) * scale; ww = 0.0; ss = 1.0 / filterscale; - xmin = floor(center - support); - if (xmin < 0.0) - xmin = 0.0; - xmax = ceil(center + support); - if (xmax > (float) imIn->xsize) - xmax = (float) imIn->xsize; - for (x = (int) xmin; x < (int) xmax; x++) { + xmin = (int) floor(center - support); + if (xmin < 0) + xmin = 0; + xmax = (int) ceil(center + support); + if (xmax > imIn->xsize) + xmax = imIn->xsize; + for (x = xmin; x < xmax; x++) { float w = filterp->filter((x - center + 0.5) * ss) * ss; - k[x - (int) xmin] = w; + k[x - xmin] = w; ww += w; } - for (x = 0; x < (int) xmax - (int) xmin; x++) { + for (x = 0; x < xmax - xmin; x++) { if (ww != 0.0) k[x] /= ww; } @@ -180,8 +181,8 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; ss = 0.5; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + imIn->image8[yy][x] * k[x - (int) xmin]; + for (x = xmin; x < xmax; x++) + ss = ss + imIn->image8[yy][x] * k[x - xmin]; if (ss < 0.5) imOut->image8[yy][xx] = (UINT8) 0; else if (ss >= 255.0) @@ -201,8 +202,8 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) if (imIn->bands == 2 && b) b = 3; /* hack to deal with LA images */ ss = 0.5; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin]; + for (x = xmin; x < xmax; x++) + ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - xmin]; if (ss < 0.5) imOut->image[yy][xx*4+b] = (UINT8) 0; else if (ss >= 255.0) @@ -219,8 +220,8 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; ss = 0.0; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin]; + for (x = xmin; x < xmax; x++) + ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - xmin]; IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss; } break; @@ -231,8 +232,8 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; ss = 0.0; - for (x = (int) xmin; x < (int) xmax; x++) - ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin]; + for (x = xmin; x < xmax; x++) + ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - xmin]; IMAGING_PIXEL_F(imOut, xx, yy) = ss; } break; From e9fc720709f635f9ed0564a6c4f1243badebed0d Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 25 Oct 2014 06:04:04 +0400 Subject: [PATCH 07/18] faster float to 8bit convertion --- libImaging/Antialias.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 3ecb35936..1b940914d 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -78,6 +78,18 @@ static inline float bicubic_filter(float x) static struct filter BICUBIC = { bicubic_filter, 2.0 }; + +static inline UINT8 clip8(float in) +{ + int out = (int) in; + if (out >= 255) + return 255; + if (out <= 0) + return 0; + return (UINT8) out; +} + + Imaging ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) { @@ -183,12 +195,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) ss = 0.5; for (x = xmin; x < xmax; x++) ss = ss + imIn->image8[yy][x] * k[x - xmin]; - if (ss < 0.5) - imOut->image8[yy][xx] = (UINT8) 0; - else if (ss >= 255.0) - imOut->image8[yy][xx] = (UINT8) 255; - else - imOut->image8[yy][xx] = (UINT8) ss; + imOut->image8[yy][xx] = clip8(ss); } } else switch(imIn->type) { @@ -204,12 +211,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) ss = 0.5; for (x = xmin; x < xmax; x++) ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - xmin]; - if (ss < 0.5) - imOut->image[yy][xx*4+b] = (UINT8) 0; - else if (ss >= 255.0) - imOut->image[yy][xx*4+b] = (UINT8) 255; - else - imOut->image[yy][xx*4+b] = (UINT8) ss; + imOut->image[yy][xx*4+b] = clip8(ss); } } break; From c22af89ef0fee353b8f5b496147845e79b2dec26 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 26 Oct 2014 00:11:39 +0400 Subject: [PATCH 08/18] optimize memory usage --- _imaging.c | 13 ++---- libImaging/Antialias.c | 98 +++++++++++++++++++----------------------- libImaging/Imaging.h | 2 +- 3 files changed, 49 insertions(+), 64 deletions(-) diff --git a/_imaging.c b/_imaging.c index 6cddd913b..f7ea510bc 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1612,22 +1612,17 @@ im_setmode(ImagingObject* self, PyObject* args) static PyObject* _stretch(ImagingObject* self, PyObject* args) { - Imaging imIn; - Imaging imOut; + Imaging imIn, imOut; int xsize, ysize; int filter = IMAGING_TRANSFORM_NEAREST; if (!PyArg_ParseTuple(args, "(ii)|i", &xsize, &ysize, &filter)) - return NULL; + return NULL; imIn = self->image; - imOut = ImagingNew(imIn->mode, xsize, ysize); - if ( ! imOut) - return NULL; - - if (!ImagingStretch(imOut, imIn, filter)) { - ImagingDelete(imOut); + imOut = ImagingStretch(imIn, xsize, ysize, filter); + if ( ! imOut) { return NULL; } diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 1b940914d..de991290b 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -91,12 +91,13 @@ static inline UINT8 clip8(float in) Imaging -ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) +ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) { /* FIXME: this is a quick and straightforward translation from a python prototype. might need some further C-ification... */ ImagingSectionCookie cookie; + Imaging imOut; struct filter *filterp; float support, scale, filterscale; float center, ww, ss; @@ -104,15 +105,6 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) int *xbounds; float *k, *kk; - /* check modes */ - if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) - return (Imaging) ImagingError_ModeError(); - - if (imOut->ysize != imIn->ysize) - return (Imaging) ImagingError_ValueError( - "ImagingStretchHorizaontal requires equal heights" - ); - /* check filter */ switch (filter) { case IMAGING_TRANSFORM_NEAREST: @@ -134,7 +126,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) } /* prepare for horizontal stretch */ - filterscale = scale = (float) imIn->xsize / imOut->xsize; + filterscale = scale = (float) imIn->xsize / xsize; /* determine support size (length of resampling filter) */ support = filterp->support; @@ -149,17 +141,17 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) kmax = (int) ceil(support) * 2 + 1; /* coefficient buffer (with rounding safety margin) */ - kk = malloc(imOut->xsize * kmax * sizeof(float)); + kk = malloc(xsize * kmax * sizeof(float)); if ( ! kk) return (Imaging) ImagingError_MemoryError(); - xbounds = malloc(imOut->xsize * 2 * sizeof(int)); + xbounds = malloc(xsize * 2 * sizeof(int)); if ( ! xbounds) { free(kk); return (Imaging) ImagingError_MemoryError(); } - for (xx = 0; xx < imOut->xsize; xx++) { + for (xx = 0; xx < xsize; xx++) { k = &kk[xx * kmax]; center = (xx + 0.5) * scale; ww = 0.0; @@ -183,12 +175,19 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) 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) { /* 8-bit grayscale */ - for (xx = 0; xx < imOut->xsize; xx++) { + for (xx = 0; xx < xsize; xx++) { xmin = xbounds[xx * 2 + 0]; xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; @@ -201,7 +200,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) switch(imIn->type) { case IMAGING_TYPE_UINT8: /* n-bit grayscale */ - for (xx = 0; xx < imOut->xsize; xx++) { + for (xx = 0; xx < xsize; xx++) { xmin = xbounds[xx * 2 + 0]; xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; @@ -217,7 +216,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) break; case IMAGING_TYPE_INT32: /* 32-bit integer */ - for (xx = 0; xx < imOut->xsize; xx++) { + for (xx = 0; xx < xsize; xx++) { xmin = xbounds[xx * 2 + 0]; xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; @@ -229,7 +228,7 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) break; case IMAGING_TYPE_FLOAT32: /* 32-bit float */ - for (xx = 0; xx < imOut->xsize; xx++) { + for (xx = 0; xx < xsize; xx++) { xmin = xbounds[xx * 2 + 0]; xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; @@ -254,60 +253,51 @@ ImagingStretchHorizaontal(Imaging imOut, Imaging imIn, int filter) Imaging -ImagingStretch(Imaging imOut, Imaging imIn, int filter) +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 +ImagingStretch(Imaging imIn, int xsize, int ysize, int filter) { Imaging imTemp1, imTemp2, imTemp3; - int xsize = imOut->xsize; - int ysize = imOut->ysize; + Imaging imOut; if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0) return (Imaging) ImagingError_ModeError(); - /* two-pass resize */ - imTemp1 = ImagingNew(imIn->mode, xsize, imIn->ysize); + /* two-pass resize, first pass */ + imTemp1 = ImagingStretchHorizaontal(imIn, xsize, filter); if ( ! imTemp1) return NULL; - /* first pass */ - if ( ! ImagingStretchHorizaontal(imTemp1, imIn, filter)) { - ImagingDelete(imTemp1); - return NULL; - } - - imTemp2 = ImagingNew(imIn->mode, imIn->ysize, xsize); - if ( ! imTemp2) { - ImagingDelete(imTemp1); - return NULL; - } - /* transpose image once */ - if ( ! ImagingTranspose(imTemp2, imTemp1)) { - ImagingDelete(imTemp1); - ImagingDelete(imTemp2); - return NULL; - } + imTemp2 = ImagingTransposeToNew(imTemp1); ImagingDelete(imTemp1); - - imTemp3 = ImagingNew(imIn->mode, ysize, xsize); - if ( ! imTemp3) { - ImagingDelete(imTemp2); + if ( ! imTemp2) return NULL; - } /* second pass */ - if ( ! ImagingStretchHorizaontal(imTemp3, imTemp2, filter)) { - ImagingDelete(imTemp2); - ImagingDelete(imTemp3); - return NULL; - } + imTemp3 = ImagingStretchHorizaontal(imTemp2, ysize, filter); ImagingDelete(imTemp2); + if ( ! imTemp3) + return NULL; /* transpose result */ - if ( ! ImagingTranspose(imOut, imTemp3)) { - ImagingDelete(imTemp3); - return NULL; - } + imOut = ImagingTransposeToNew(imTemp3); ImagingDelete(imTemp3); + if ( ! imOut) + return NULL; return imOut; } diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index f014bc0aa..d5aa6e27a 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -291,7 +291,7 @@ extern Imaging ImagingRotate( extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate180(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 ImagingTransformPerspective( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, From 42967dd1a62a8d32f279f6623b6760f8c15d94f6 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 26 Oct 2014 01:20:24 +0400 Subject: [PATCH 09/18] speedup by unrolling loops --- libImaging/Antialias.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index de991290b..f67053c09 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -100,8 +100,8 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) Imaging imOut; struct filter *filterp; float support, scale, filterscale; - float center, ww, ss; - int xx, yy, x, b, kmax, xmin, xmax; + float center, ww, ss, ss4[4]; + int xx, yy, x, kmax, xmin, xmax; int *xbounds; float *k, *kk; @@ -204,13 +204,27 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) xmin = xbounds[xx * 2 + 0]; xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; - for (b = 0; b < imIn->bands; b++) { - if (imIn->bands == 2 && b) - b = 3; /* hack to deal with LA images */ - ss = 0.5; - for (x = xmin; x < xmax; x++) - ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - xmin]; - imOut->image[yy][xx*4+b] = clip8(ss); + if (imIn->bands == 3) { + ss4[0] = ss4[1] = ss4[2] = 0.5; + for (x = xmin; x < xmax; x++) { + ss4[0] += (UINT8) imIn->image[yy][x*4 + 0] * k[x - xmin]; + ss4[1] += (UINT8) imIn->image[yy][x*4 + 1] * k[x - xmin]; + ss4[2] += (UINT8) imIn->image[yy][x*4 + 2] * k[x - xmin]; + } + imOut->image32[yy][xx] = + clip8(ss4[0]) | clip8(ss4[1]) << 8 | + clip8(ss4[2]) << 16; + } else { + ss4[0] = ss4[1] = ss4[2] = ss4[3] = 0.5; + for (x = xmin; x < xmax; x++) { + ss4[0] += (UINT8) imIn->image[yy][x*4 + 0] * k[x - xmin]; + ss4[1] += (UINT8) imIn->image[yy][x*4 + 1] * k[x - xmin]; + ss4[2] += (UINT8) imIn->image[yy][x*4 + 2] * k[x - xmin]; + ss4[3] += (UINT8) imIn->image[yy][x*4 + 3] * k[x - xmin]; + } + imOut->image32[yy][xx] = + clip8(ss4[0]) | clip8(ss4[1]) << 8 | + clip8(ss4[2]) << 16 | clip8(ss4[3]) << 24; } } break; From 1cd6da4a4924aa0a5af4eda7d012a1e10177c34a Mon Sep 17 00:00:00 2001 From: homm Date: Mon, 27 Oct 2014 18:09:45 +0300 Subject: [PATCH 10/18] fix performance regression on 64 bit GCC 4.8. --- libImaging/Antialias.c | 48 ++++++++++++++++++++++++++--------------- libImaging/ImPlatform.h | 6 ++++++ 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index f67053c09..03b6767bf 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -90,6 +90,21 @@ static inline UINT8 clip8(float in) } +/* 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 ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) { @@ -100,7 +115,7 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) Imaging imOut; struct filter *filterp; float support, scale, filterscale; - float center, ww, ss, ss4[4]; + float center, ww, ss, ss0, ss1, ss2, ss3; int xx, yy, x, kmax, xmin, xmax; int *xbounds; float *k, *kk; @@ -193,7 +208,7 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) k = &kk[xx * kmax]; ss = 0.5; for (x = xmin; x < xmax; x++) - ss = ss + imIn->image8[yy][x] * k[x - xmin]; + ss += i2f(imIn->image8[yy][x]) * k[x - xmin]; imOut->image8[yy][xx] = clip8(ss); } } else @@ -205,26 +220,25 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; if (imIn->bands == 3) { - ss4[0] = ss4[1] = ss4[2] = 0.5; + ss0 = ss1 = ss2 = 0.5; for (x = xmin; x < xmax; x++) { - ss4[0] += (UINT8) imIn->image[yy][x*4 + 0] * k[x - xmin]; - ss4[1] += (UINT8) imIn->image[yy][x*4 + 1] * k[x - xmin]; - ss4[2] += (UINT8) imIn->image[yy][x*4 + 2] * k[x - xmin]; + 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->image32[yy][xx] = - clip8(ss4[0]) | clip8(ss4[1]) << 8 | - clip8(ss4[2]) << 16; + clip8(ss0) | clip8(ss1) << 8 | clip8(ss2) << 16; } else { - ss4[0] = ss4[1] = ss4[2] = ss4[3] = 0.5; + ss0 = ss1 = ss2 = ss3 = 0.5; for (x = xmin; x < xmax; x++) { - ss4[0] += (UINT8) imIn->image[yy][x*4 + 0] * k[x - xmin]; - ss4[1] += (UINT8) imIn->image[yy][x*4 + 1] * k[x - xmin]; - ss4[2] += (UINT8) imIn->image[yy][x*4 + 2] * k[x - xmin]; - ss4[3] += (UINT8) imIn->image[yy][x*4 + 3] * k[x - xmin]; + 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->image32[yy][xx] = - clip8(ss4[0]) | clip8(ss4[1]) << 8 | - clip8(ss4[2]) << 16 | clip8(ss4[3]) << 24; + clip8(ss0) | clip8(ss1) << 8 | + clip8(ss2) << 16 | clip8(ss3) << 24; } } break; @@ -236,7 +250,7 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) k = &kk[xx * kmax]; ss = 0.0; for (x = xmin; x < xmax; x++) - ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - xmin]; + ss += i2f(IMAGING_PIXEL_I(imIn, x, yy)) * k[x - xmin]; IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss; } break; @@ -248,7 +262,7 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) k = &kk[xx * kmax]; ss = 0.0; for (x = xmin; x < xmax; x++) - ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - xmin]; + ss += IMAGING_PIXEL_F(imIn, x, yy) * k[x - xmin]; IMAGING_PIXEL_F(imOut, xx, yy) = ss; } break; diff --git a/libImaging/ImPlatform.h b/libImaging/ImPlatform.h index 70ee63119..43c17cc85 100644 --- a/libImaging/ImPlatform.h +++ b/libImaging/ImPlatform.h @@ -72,3 +72,9 @@ #ifdef _MSC_VER typedef signed __int64 int64_t; #endif + +#ifdef __GNUC__ + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#endif From b8a2b5b907d149453bb9e1f8d1a66372ab6c9519 Mon Sep 17 00:00:00 2001 From: homm Date: Mon, 3 Nov 2014 03:09:38 +0300 Subject: [PATCH 11/18] typo. Free mem after ModeError. --- libImaging/Antialias.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 03b6767bf..25d2461cc 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -106,11 +106,8 @@ static float inline i2f(int v) { return (float) v; } Imaging -ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) +ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) { - /* FIXME: this is a quick and straightforward translation from a - python prototype. might need some further C-ification... */ - ImagingSectionCookie cookie; Imaging imOut; struct filter *filterp; @@ -268,14 +265,15 @@ ImagingStretchHorizaontal(Imaging imIn, int xsize, int filter) break; default: ImagingSectionLeave(&cookie); + ImagingDelete(imOut); + free(kk); + free(xbounds); return (Imaging) ImagingError_ModeError(); } } ImagingSectionLeave(&cookie); - free(kk); free(xbounds); - return imOut; } @@ -305,7 +303,7 @@ ImagingStretch(Imaging imIn, int xsize, int ysize, int filter) return (Imaging) ImagingError_ModeError(); /* two-pass resize, first pass */ - imTemp1 = ImagingStretchHorizaontal(imIn, xsize, filter); + imTemp1 = ImagingStretchHorizontal(imIn, xsize, filter); if ( ! imTemp1) return NULL; @@ -316,7 +314,7 @@ ImagingStretch(Imaging imIn, int xsize, int ysize, int filter) return NULL; /* second pass */ - imTemp3 = ImagingStretchHorizaontal(imTemp2, ysize, filter); + imTemp3 = ImagingStretchHorizontal(imTemp2, ysize, filter); ImagingDelete(imTemp2); if ( ! imTemp3) return NULL; From 2657c0dec0ffb8fad660949be4714572211c4148 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 7 Nov 2014 14:47:23 -0800 Subject: [PATCH 12/18] Test for endianness issues in stretch --- Tests/test_imaging_stretch.py | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/Tests/test_imaging_stretch.py b/Tests/test_imaging_stretch.py index a9858eff5..52548e3dc 100644 --- a/Tests/test_imaging_stretch.py +++ b/Tests/test_imaging_stretch.py @@ -39,6 +39,73 @@ class TestImagingStretch(PillowTestCase): self.assertEqual(r.mode, "RGB") self.assertEqual(r.size, (764, 414)) + def test_endianess(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 endianess issues + + im = Image.new('L', (2,2), 0) + im.putpixel((1,1),128) + + blank = Image.new('L', (4,4), 0) + alpha = Image.new('L', (4,4), 255) + + for f in [Image.BILINEAR, Image.BICUBIC, Image.ANTIALIAS]: + + im_r = Image.new('RGBA', (2,2), (0,0,0,255)) + im_r.putpixel((1,1),(128,0,0,255)) + + target = im._new(im.im.stretch((4,4), f)) + stretched = im_r._new(im_r.im.stretch((4,4),f)) + + self.assert_image_equal(stretched.split()[0],target) + self.assert_image_equal(stretched.split()[1],blank) + self.assert_image_equal(stretched.split()[2],blank) + self.assert_image_equal(stretched.split()[3],alpha) + + + im_r = Image.new('RGB', (2,2), (0,0,0)) + im_r.putpixel((1,1),(128,0,0)) + + target = im._new(im.im.stretch((4,4), f)) + stretched = im_r._new(im_r.im.stretch((4,4),f)) + + #print " ".join(hex(ord(s)) for s in stretched.split()[0].tobytes()) + #print " ".join(hex(ord(s)) for s in stretched.split()[1].tobytes()) + #print " ".join(hex(ord(s)) for s in stretched.split()[2].tobytes()) + + #print " ".join(hex(ord(s)) for s in target.tobytes()) + + #print + + self.assert_image_equal(stretched.split()[0],target, 'rxRGB R channel fail') + self.assert_image_equal(stretched.split()[1],blank, 'rxRGB G channel fail') + self.assert_image_equal(stretched.split()[2],blank, 'rxRGB B channel fail') + + + im_g = Image.new('RGBA', (2,2), (0,0,0,255)) + im_g.putpixel((1,1),(0,128,0,255)) + + stretched = im_g._new(im_g.im.stretch((4,4),f)) + + self.assert_image_equal(stretched.split()[0],blank) + self.assert_image_equal(stretched.split()[1],target) + self.assert_image_equal(stretched.split()[2],blank) + self.assert_image_equal(stretched.split()[3],alpha) + + + im_g = Image.new('RGB', (2,2), (0,0,0)) + im_g.putpixel((1,1),(0,128,0)) + + target = im._new(im.im.stretch((4,4), f)) + stretched = im_g._new(im_g.im.stretch((4,4),f)) + + self.assert_image_equal(stretched.split()[0],blank, 'gxRGB R channel fail') + self.assert_image_equal(stretched.split()[1],target, 'gxRGB G channel fail') + self.assert_image_equal(stretched.split()[2],blank, 'gxRGB B channel fail') + if __name__ == '__main__': unittest.main() From af02f2b29ed4c2721649f786c69f81dc637ed0fe Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 7 Nov 2014 15:49:04 -0800 Subject: [PATCH 13/18] Fix for endianness issues in stretch --- libImaging/Antialias.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 25d2461cc..0cf51b521 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -223,8 +223,13 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) ss1 += i2f((UINT8) imIn->image[yy][x*4 + 1]) * k[x - xmin]; ss2 += i2f((UINT8) imIn->image[yy][x*4 + 2]) * k[x - xmin]; } +#ifdef WORDS_BIGENDIAN + imOut->image32[yy][xx] = + clip8(ss2) << 8 | clip8(ss1) << 16 | clip8(ss0) << 24; +#else imOut->image32[yy][xx] = clip8(ss0) | clip8(ss1) << 8 | clip8(ss2) << 16; +#endif } else { ss0 = ss1 = ss2 = ss3 = 0.5; for (x = xmin; x < xmax; x++) { @@ -233,9 +238,15 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) ss2 += i2f((UINT8) imIn->image[yy][x*4 + 2]) * k[x - xmin]; ss3 += i2f((UINT8) imIn->image[yy][x*4 + 3]) * k[x - xmin]; } +#ifdef WORDS_BIGENDIAN + imOut->image32[yy][xx] = + clip8(ss3) | clip8(ss2) << 8 | + clip8(ss1) << 16 | clip8(ss0) << 24; +#else imOut->image32[yy][xx] = clip8(ss0) | clip8(ss1) << 8 | clip8(ss2) << 16 | clip8(ss3) << 24; +#endif } } break; From 1a7c9b72ab617d947ee1a12f79cbe8a5b731ff47 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 9 Nov 2014 01:00:01 +0300 Subject: [PATCH 14/18] generalize endianess test --- Tests/test_imaging_stretch.py | 83 ++++++++++++----------------------- 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/Tests/test_imaging_stretch.py b/Tests/test_imaging_stretch.py index 52548e3dc..b5336bac2 100644 --- a/Tests/test_imaging_stretch.py +++ b/Tests/test_imaging_stretch.py @@ -1,6 +1,7 @@ """ Tests for ImagingCore.stretch functionality. """ +from itertools import permutations from helper import unittest, PillowTestCase @@ -12,6 +13,9 @@ im = Image.open("Tests/images/hopper.ppm").copy() class TestImagingStretch(PillowTestCase): + def stretch(self, im, size, f): + return im._new(im.im.stretch(size, f)) + def test_modes(self): self.assertRaises(ValueError, im.convert("1").im.stretch, (15, 12), Image.ANTIALIAS) @@ -46,65 +50,34 @@ class TestImagingStretch(PillowTestCase): # The R and A channels should not swap, which is indicitive of # an endianess issues - im = Image.new('L', (2,2), 0) - im.putpixel((1,1),128) - - blank = Image.new('L', (4,4), 0) - alpha = Image.new('L', (4,4), 255) + 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() + ) - im_r = Image.new('RGBA', (2,2), (0,0,0,255)) - im_r.putpixel((1,1),(128,0,0,255)) + 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) - target = im._new(im.im.stretch((4,4), f)) - stretched = im_r._new(im_r.im.stretch((4,4),f)) - - self.assert_image_equal(stretched.split()[0],target) - self.assert_image_equal(stretched.split()[1],blank) - self.assert_image_equal(stretched.split()[2],blank) - self.assert_image_equal(stretched.split()[3],alpha) - - - im_r = Image.new('RGB', (2,2), (0,0,0)) - im_r.putpixel((1,1),(128,0,0)) - - target = im._new(im.im.stretch((4,4), f)) - stretched = im_r._new(im_r.im.stretch((4,4),f)) - - #print " ".join(hex(ord(s)) for s in stretched.split()[0].tobytes()) - #print " ".join(hex(ord(s)) for s in stretched.split()[1].tobytes()) - #print " ".join(hex(ord(s)) for s in stretched.split()[2].tobytes()) - - #print " ".join(hex(ord(s)) for s in target.tobytes()) - - #print - - self.assert_image_equal(stretched.split()[0],target, 'rxRGB R channel fail') - self.assert_image_equal(stretched.split()[1],blank, 'rxRGB G channel fail') - self.assert_image_equal(stretched.split()[2],blank, 'rxRGB B channel fail') - - - im_g = Image.new('RGBA', (2,2), (0,0,0,255)) - im_g.putpixel((1,1),(0,128,0,255)) - - stretched = im_g._new(im_g.im.stretch((4,4),f)) - - self.assert_image_equal(stretched.split()[0],blank) - self.assert_image_equal(stretched.split()[1],target) - self.assert_image_equal(stretched.split()[2],blank) - self.assert_image_equal(stretched.split()[3],alpha) - - - im_g = Image.new('RGB', (2,2), (0,0,0)) - im_g.putpixel((1,1),(0,128,0)) - - target = im._new(im.im.stretch((4,4), f)) - stretched = im_g._new(im_g.im.stretch((4,4),f)) - - self.assert_image_equal(stretched.split()[0],blank, 'gxRGB R channel fail') - self.assert_image_equal(stretched.split()[1],target, 'gxRGB G channel fail') - self.assert_image_equal(stretched.split()[2],blank, 'gxRGB B channel fail') + 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__': From abc5e113716897aab33237da800d745b99db3e41 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 9 Nov 2014 01:05:50 +0300 Subject: [PATCH 15/18] two bands case --- libImaging/Antialias.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 0cf51b521..fd2ec51be 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -216,7 +216,18 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) xmin = xbounds[xx * 2 + 0]; xmax = xbounds[xx * 2 + 1]; k = &kk[xx * kmax]; - if (imIn->bands == 3) { + if (imIn->bands == 2) { + ss0 = ss1 = 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 + 3]) * k[x - xmin]; + } +#ifdef WORDS_BIGENDIAN + imOut->image32[yy][xx] = clip8(ss1) | clip8(ss0) << 24; +#else + imOut->image32[yy][xx] = clip8(ss0) | clip8(ss1) << 24; +#endif + } else if (imIn->bands == 3) { ss0 = ss1 = ss2 = 0.5; for (x = xmin; x < xmax; x++) { ss0 += i2f((UINT8) imIn->image[yy][x*4 + 0]) * k[x - xmin]; From 7a64f7be80ac675b2eec079f8430de964afbc408 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 9 Nov 2014 02:27:43 +0300 Subject: [PATCH 16/18] Replace UINT32 assignment with per-channel UINT8 assignment --- libImaging/Antialias.c | 54 ++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index fd2ec51be..4b997eaa9 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -212,36 +212,39 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) switch(imIn->type) { case IMAGING_TYPE_UINT8: /* n-bit grayscale */ - for (xx = 0; xx < xsize; xx++) { - xmin = xbounds[xx * 2 + 0]; - xmax = xbounds[xx * 2 + 1]; - k = &kk[xx * kmax]; - if (imIn->bands == 2) { + if (imIn->bands == 2) { + for (xx = 0; xx < xsize; xx++) { + xmin = xbounds[xx * 2 + 0]; + xmax = xbounds[xx * 2 + 1]; + k = &kk[xx * kmax]; ss0 = ss1 = 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 + 3]) * k[x - xmin]; } -#ifdef WORDS_BIGENDIAN - imOut->image32[yy][xx] = clip8(ss1) | clip8(ss0) << 24; -#else - imOut->image32[yy][xx] = clip8(ss0) | clip8(ss1) << 24; -#endif - } else if (imIn->bands == 3) { + imOut->image[yy][xx*4 + 0] = clip8(ss0); + imOut->image[yy][xx*4 + 3] = clip8(ss1); + } + } 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]; } -#ifdef WORDS_BIGENDIAN - imOut->image32[yy][xx] = - clip8(ss2) << 8 | clip8(ss1) << 16 | clip8(ss0) << 24; -#else - imOut->image32[yy][xx] = - clip8(ss0) | clip8(ss1) << 8 | clip8(ss2) << 16; -#endif - } else { + 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]; @@ -249,15 +252,10 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) ss2 += i2f((UINT8) imIn->image[yy][x*4 + 2]) * k[x - xmin]; ss3 += i2f((UINT8) imIn->image[yy][x*4 + 3]) * k[x - xmin]; } -#ifdef WORDS_BIGENDIAN - imOut->image32[yy][xx] = - clip8(ss3) | clip8(ss2) << 8 | - clip8(ss1) << 16 | clip8(ss0) << 24; -#else - imOut->image32[yy][xx] = - clip8(ss0) | clip8(ss1) << 8 | - clip8(ss2) << 16 | clip8(ss3) << 24; -#endif + 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; From 3894dbe7542ced66fdbe27e98c27ff773fc09da3 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 9 Nov 2014 02:33:14 +0300 Subject: [PATCH 17/18] fix typo --- Tests/test_imaging_stretch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_imaging_stretch.py b/Tests/test_imaging_stretch.py index b5336bac2..aaf1a4d1d 100644 --- a/Tests/test_imaging_stretch.py +++ b/Tests/test_imaging_stretch.py @@ -43,12 +43,12 @@ class TestImagingStretch(PillowTestCase): self.assertEqual(r.mode, "RGB") self.assertEqual(r.size, (764, 414)) - def test_endianess(self): + 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 endianess issues + # an endianness issues. samples = { 'blank': Image.new('L', (2, 2), 0), From 90ee223305baef8c7f2d8923849fe39cd9c255f4 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 9 Nov 2014 03:15:54 +0300 Subject: [PATCH 18/18] Move ImagingTransposeToNew from Antialias.c to Geometry.c --- libImaging/Antialias.c | 15 --------------- libImaging/Geometry.c | 15 +++++++++++++++ libImaging/Imaging.h | 1 + 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/libImaging/Antialias.c b/libImaging/Antialias.c index 4b997eaa9..5c9514103 100644 --- a/libImaging/Antialias.c +++ b/libImaging/Antialias.c @@ -298,21 +298,6 @@ ImagingStretchHorizontal(Imaging imIn, int xsize, int filter) } -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 ImagingStretch(Imaging imIn, int xsize, int ysize, int filter) { diff --git a/libImaging/Geometry.c b/libImaging/Geometry.c index afd162dad..b987a5616 100644 --- a/libImaging/Geometry.c +++ b/libImaging/Geometry.c @@ -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 ImagingRotate180(Imaging imOut, Imaging imIn) { diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index d5aa6e27a..6c91958ec 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -293,6 +293,7 @@ extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); extern Imaging ImagingStretch(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);