From 62388199fa4caa150a8c952e875ee2b42238cf49 Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 2 Jul 2016 18:13:56 +0300 Subject: [PATCH 1/4] use lookups table instead of two conditions for each channel --- libImaging/Resample.c | 44 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/libImaging/Resample.c b/libImaging/Resample.c index 2c1a38a74..732d245dd 100644 --- a/libImaging/Resample.c +++ b/libImaging/Resample.c @@ -80,13 +80,47 @@ static struct filter LANCZOS = { lanczos_filter, 3.0 }; #define PRECISION_BITS (32 - 8 - 2) +UINT8 _lookups[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +UINT8 *lookups = &_lookups[128]; + + static inline UINT8 clip8(int in) { - if (in >= (1 << PRECISION_BITS << 8)) - return 255; - if (in <= 0) - return 0; - return (UINT8) (in >> PRECISION_BITS); + return lookups[in >> PRECISION_BITS]; } From 7d3db1f02a9e8ac61861b14d21f6d1ab288edaef Mon Sep 17 00:00:00 2001 From: homm Date: Sat, 2 Jul 2016 18:24:08 +0300 Subject: [PATCH 2/4] truncate zero coefficients --- libImaging/Resample.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libImaging/Resample.c b/libImaging/Resample.c index 732d245dd..ccd1d4d0a 100644 --- a/libImaging/Resample.c +++ b/libImaging/Resample.c @@ -176,6 +176,16 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp, k = &kk[xx * kmax]; for (x = 0; x < xmax; x++) { double w = filterp->filter((x + xmin - center + 0.5) * ss); + if (w == 0) { + if (x == 0) { + x -= 1; + xmin += 1; + xmax -= 1; + } else if (x == xmax - 1) { + xmax -= 1; + } + continue; + } k[x] = w; ww += w; } From 788810f313b923b739a67a5c7c95e17df18b0d4a Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 3 Jul 2016 02:06:54 +0300 Subject: [PATCH 3/4] =?UTF-8?q?ImagingPrecompute=20=E2=86=92=20precompute?= =?UTF-8?q?=5Fcoeffs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libImaging/Resample.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libImaging/Resample.c b/libImaging/Resample.c index ccd1d4d0a..f4d30f25f 100644 --- a/libImaging/Resample.c +++ b/libImaging/Resample.c @@ -125,7 +125,7 @@ static inline UINT8 clip8(int in) int -ImagingPrecompute(int inSize, int outSize, struct filter *filterp, +precompute_coeffs(int inSize, int outSize, struct filter *filterp, int **xboundsp, double **kkp) { double support, scale, filterscale; double center, ww, ss; @@ -217,8 +217,7 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp) int *k, *kk; double *prekk; - - kmax = ImagingPrecompute(imIn->xsize, xsize, filterp, &xbounds, &prekk); + kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &prekk); if ( ! kmax) { return (Imaging) ImagingError_MemoryError(); } @@ -329,8 +328,7 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp) int *k, *kk; double *prekk; - - kmax = ImagingPrecompute(imIn->ysize, ysize, filterp, &xbounds, &prekk); + kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &prekk); if ( ! kmax) { return (Imaging) ImagingError_MemoryError(); } @@ -440,7 +438,7 @@ ImagingResampleHorizontal_32bpc(Imaging imIn, int xsize, struct filter *filterp) int *xbounds; double *k, *kk; - kmax = ImagingPrecompute(imIn->xsize, xsize, filterp, &xbounds, &kk); + kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &kk); if ( ! kmax) { return (Imaging) ImagingError_MemoryError(); } @@ -500,7 +498,7 @@ ImagingResampleVertical_32bpc(Imaging imIn, int ysize, struct filter *filterp) int *xbounds; double *k, *kk; - kmax = ImagingPrecompute(imIn->ysize, ysize, filterp, &xbounds, &kk); + kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &kk); if ( ! kmax) { return (Imaging) ImagingError_MemoryError(); } From 5c0eb2c365ebd2afe767dedea6f1a679aff79e57 Mon Sep 17 00:00:00 2001 From: homm Date: Sun, 3 Jul 2016 02:09:39 +0300 Subject: [PATCH 4/4] normalize coefficients in normalize_coeffs_8bpc increase precision of negative filter lobes. Add test --- Tests/test_image_resample.py | 17 +++++++++++ libImaging/Resample.c | 58 ++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 464e127f8..edcf00c5e 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -320,5 +320,22 @@ class CoreResamplePassesTest(PillowTestCase): self.assertEqual(Image.core.getcount(), count + 2) +class CoreResampleCoefficientsTest(PillowTestCase): + def test_reduce(self): + test_color = 254 + # print '' + + for size in range(400000, 400010, 2): + # print '\r', size, + i = Image.new('L', (size, 1), 0) + draw = ImageDraw.Draw(i) + draw.rectangle((0, 0, i.size[0] // 2 - 1, 0), test_color) + + px = i.resize((5, i.size[1]), Image.BICUBIC).load() + if px[2, 0] != test_color // 2: + self.assertEqual(test_color // 2, px[2, 0]) + # print '\r>', size, test_color // 2, px[2, 0] + + if __name__ == '__main__': unittest.main() diff --git a/libImaging/Resample.c b/libImaging/Resample.c index f4d30f25f..9f03e40da 100644 --- a/libImaging/Resample.c +++ b/libImaging/Resample.c @@ -206,6 +206,32 @@ precompute_coeffs(int inSize, int outSize, struct filter *filterp, } +int +normalize_coeffs_8bpc(int outSize, int kmax, double *prekk, INT32 **kkp) +{ + int x; + INT32 *kk; + + /* malloc check ok, overflow checked in precompute_coeffs */ + kk = malloc(outSize * kmax * sizeof(INT32)); + if ( ! kk) { + return 0; + } + + for (x = 0; x < outSize * kmax; x++) { + if (prekk[x] < 0) { + kk[x] = (int) (-0.5 + prekk[x] * (1 << PRECISION_BITS)); + } else { + kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS)); + } + } + + *kkp = kk; + return kmax; +} + + + Imaging ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp) { @@ -214,27 +240,21 @@ ImagingResampleHorizontal_8bpc(Imaging imIn, int xsize, struct filter *filterp) int ss0, ss1, ss2, ss3; int xx, yy, x, kmax, xmin, xmax; int *xbounds; - int *k, *kk; + INT32 *k, *kk; double *prekk; kmax = precompute_coeffs(imIn->xsize, xsize, filterp, &xbounds, &prekk); if ( ! kmax) { return (Imaging) ImagingError_MemoryError(); } - - kk = malloc(xsize * kmax * sizeof(int)); - if ( ! kk) { + + kmax = normalize_coeffs_8bpc(xsize, kmax, prekk, &kk); + free(prekk); + if ( ! kmax) { free(xbounds); - free(prekk); return (Imaging) ImagingError_MemoryError(); } - for (x = 0; x < xsize * kmax; x++) { - kk[x] = (int) (0.5 + prekk[x] * (1 << PRECISION_BITS)); - } - - free(prekk); - imOut = ImagingNew(imIn->mode, xsize, imIn->ysize); if ( ! imOut) { free(kk); @@ -325,27 +345,21 @@ ImagingResampleVertical_8bpc(Imaging imIn, int ysize, struct filter *filterp) int ss0, ss1, ss2, ss3; int xx, yy, y, kmax, ymin, ymax; int *xbounds; - int *k, *kk; + INT32 *k, *kk; double *prekk; kmax = precompute_coeffs(imIn->ysize, ysize, filterp, &xbounds, &prekk); if ( ! kmax) { return (Imaging) ImagingError_MemoryError(); } - - kk = malloc(ysize * kmax * sizeof(int)); - if ( ! kk) { + + kmax = normalize_coeffs_8bpc(ysize, kmax, prekk, &kk); + free(prekk); + if ( ! kmax) { free(xbounds); - free(prekk); return (Imaging) ImagingError_MemoryError(); } - for (y = 0; y < ysize * kmax; y++) { - kk[y] = (int) (0.5 + prekk[y] * (1 << PRECISION_BITS)); - } - - free(prekk); - imOut = ImagingNew(imIn->mode, imIn->xsize, ysize); if ( ! imOut) { free(kk);