From 81c72bd2975c365bdb5d3213f041516abbdf956a Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 31 Aug 2017 19:18:48 +0300 Subject: [PATCH 1/4] Crop if box size matches requested size --- _imaging.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_imaging.c b/_imaging.c index af28ffa2a..0ed848ed8 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1529,8 +1529,10 @@ _resize(ImagingObject* self, PyObject* args) return ImagingError_ValueError("box can't be empty"); } - if (box[0] == 0 && box[1] == 0 && box[2] == xsize && box[3] == ysize) { - imOut = ImagingCopy(imIn); + // If box's coordinates are int and box size matches requested size + if (box[0] - (int) box[0] == 0 && box[1] - (int) box[1] == 0 + && box[2] - box[0] == xsize && box[3] - box[1] == ysize) { + imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]); } else if (filter == IMAGING_TRANSFORM_NEAREST) { double a[6]; From 1e1f773f8a2b5d8785d4c03a0acd063612c59cf2 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 31 Aug 2017 19:25:25 +0300 Subject: [PATCH 2/4] Rename variables --- libImaging/Resample.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libImaging/Resample.c b/libImaging/Resample.c index 47d2274b6..db7a41b8f 100644 --- a/libImaging/Resample.c +++ b/libImaging/Resample.c @@ -554,7 +554,7 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, Imaging imOut = NULL; int i; - int yroi_min, yroi_max; + int ybox_first, ybox_last; int ksize_horiz, ksize_vert; int *bounds_horiz, *bounds_vert; double *kk_horiz, *kk_vert; @@ -574,21 +574,21 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, } // First used row in the source image - yroi_min = bounds_vert[0]; + ybox_first = bounds_vert[0]; // Last used row in the source image - yroi_max = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1]; + ybox_last = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1]; /* two-pass resize, first pass */ if (box[0] || box[2] != xsize) { // Shift bounds for vertical pass for (i = 0; i < ysize; i++) { - bounds_vert[i * 2] -= yroi_min; + bounds_vert[i * 2] -= ybox_first; } - imTemp = ImagingNewDirty(imIn->mode, xsize, yroi_max - yroi_min); + imTemp = ImagingNewDirty(imIn->mode, xsize, ybox_last - ybox_first); if (imTemp) { - ResampleHorizontal(imTemp, imIn, yroi_min, + ResampleHorizontal(imTemp, imIn, ybox_first, ksize_horiz, bounds_horiz, kk_horiz); } free(bounds_horiz); From edcbd3f67d354564436d065c7f52384deda80239 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 31 Aug 2017 22:28:43 +0300 Subject: [PATCH 3/4] Tests for skipping passes (are passed if disable the passes skipping) --- Tests/test_image_resample.py | 81 ++++++++++++++++++++++++++++++++++++ _imaging.c | 4 +- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index a7739c884..556a4c4d6 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -344,6 +344,7 @@ class CoreResamplePassesTest(PillowTestCase): cropped = im.crop(box).resize(im.size, Image.BILINEAR) self.assert_image_similar(with_box, cropped, 0.1) + class CoreResampleCoefficientsTest(PillowTestCase): def test_reduce(self): test_color = 254 @@ -458,6 +459,86 @@ class CoreResampleBoxTest(PillowTestCase): cropped = im.crop(box).resize((32, 32), resample) self.assert_image_similar(cropped, with_box, 0.4) + def test_passthrough(self): + "When no resize is required" + im = hopper() + + for size, box in [ + ((40, 50), (0, 0, 40, 50)), + ((40, 50), (0, 10, 40, 60)), + ((40, 50), (10, 0, 50, 50)), + ((40, 50), (10, 20, 50, 70)), + ]: + try: + res = im.resize(size, Image.LANCZOS, box) + self.assertEqual(res.size, size) + self.assert_image_equal(res, im.crop(box)) + except AssertionError: + print('>>>', size, box) + raise + + def test_no_passthrough(self): + "When resize is required" + im = hopper() + + for size, box in [ + ((40, 50), (0.4, 0.4, 40.4, 50.4)), + ((40, 50), (0.4, 10.4, 40.4, 60.4)), + ((40, 50), (10.4, 0.4, 50.4, 50.4)), + ((40, 50), (10.4, 20.4, 50.4, 70.4)), + ]: + try: + res = im.resize(size, Image.LANCZOS, box) + self.assertEqual(res.size, size) + with self.assertRaisesRegexp(AssertionError, "difference \d"): + # check that the difference at least that much + self.assert_image_similar(res, im.crop(box), 20) + except AssertionError: + print('>>>', size, box) + raise + + def test_skip_horizontal(self): + "Can skip resize in one dimension" + im = hopper() + + for flt in [Image.NEAREST, Image.BICUBIC]: + for size, box in [ + ((40, 50), (0, 0, 40, 90)), + ((40, 50), (0, 20, 40, 90)), + ((40, 50), (10, 0, 50, 90)), + ((40, 50), (10, 20, 50, 90)), + ]: + try: + res = im.resize(size, flt, box) + self.assertEqual(res.size, size) + # Borders should be slightly different + self.assert_image_similar( + res, im.crop(box).resize(size, flt), 0.4) + except AssertionError: + print('>>>', size, box, flt) + raise + + def test_skip_vertical(self): + "Can skip resize in one dimension" + im = hopper() + + for flt in [Image.NEAREST, Image.BICUBIC]: + for size, box in [ + ((40, 50), (0, 0, 90, 50)), + ((40, 50), (20, 0, 90, 50)), + ((40, 50), (0, 10, 90, 60)), + ((40, 50), (20, 10, 90, 60)), + ]: + try: + res = im.resize(size, flt, box) + self.assertEqual(res.size, size) + # Borders should be slightly different + self.assert_image_similar( + res, im.crop(box).resize(size, flt), 0.4) + except AssertionError: + print('>>>', size, box, flt) + raise + if __name__ == '__main__': unittest.main() diff --git a/_imaging.c b/_imaging.c index 0ed848ed8..b7726a2cc 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1530,8 +1530,8 @@ _resize(ImagingObject* self, PyObject* args) } // If box's coordinates are int and box size matches requested size - if (box[0] - (int) box[0] == 0 && box[1] - (int) box[1] == 0 - && box[2] - box[0] == xsize && box[3] - box[1] == ysize) { + if (box[0] - (int) box[0] == 0 && box[2] - box[0] == xsize + && box[1] - (int) box[1] == 0 && box[3] - box[1] == ysize) { imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]); } else if (filter == IMAGING_TRANSFORM_NEAREST) { From 0acc2cea9c5a29ca79750b4e5259de3b785cd160 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 1 Sep 2017 00:23:02 +0300 Subject: [PATCH 4/4] Fix need_horizontal and need_vertical conditions in resample --- libImaging/Resample.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libImaging/Resample.c b/libImaging/Resample.c index db7a41b8f..877f25a94 100644 --- a/libImaging/Resample.c +++ b/libImaging/Resample.c @@ -553,12 +553,15 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, Imaging imTemp = NULL; Imaging imOut = NULL; - int i; + int i, need_horizontal, need_vertical; int ybox_first, ybox_last; int ksize_horiz, ksize_vert; int *bounds_horiz, *bounds_vert; double *kk_horiz, *kk_vert; + need_horizontal = xsize != imIn->xsize || box[0] || box[2] != xsize; + need_vertical = ysize != imIn->ysize || box[1] || box[3] != ysize; + ksize_horiz = precompute_coeffs(imIn->xsize, box[0], box[2], xsize, filterp, &bounds_horiz, &kk_horiz); if ( ! ksize_horiz) { @@ -579,8 +582,8 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, ybox_last = bounds_vert[ysize*2 - 2] + bounds_vert[ysize*2 - 1]; - /* two-pass resize, first pass */ - if (box[0] || box[2] != xsize) { + /* two-pass resize, horizontal pass */ + if (need_horizontal) { // Shift bounds for vertical pass for (i = 0; i < ysize; i++) { bounds_vert[i * 2] -= ybox_first; @@ -605,8 +608,8 @@ ImagingResampleInner(Imaging imIn, int xsize, int ysize, free(kk_horiz); } - /* second pass */ - if (box[1] || box[3] != ysize) { + /* vertical pass */ + if (need_vertical) { imOut = ImagingNewDirty(imIn->mode, imIn->xsize, ysize); if (imOut) { /* imIn can be the original image or horizontally resampled one */