diff --git a/Tests/test_image_reduce.py b/Tests/test_image_reduce.py index 8036db847..d36dbd609 100644 --- a/Tests/test_image_reduce.py +++ b/Tests/test_image_reduce.py @@ -18,7 +18,7 @@ class TestImageReduce(PillowTestCase): cls.gradients_image = Image.open("Tests/images/radial_gradients.png") cls.gradients_image.load() - def test_args(self): + def test_args_factor(self): im = Image.new("L", (10, 10)) self.assertEqual((4, 4), im.reduce(3).size) @@ -62,6 +62,12 @@ class TestImageReduce(PillowTestCase): assert len(mode_info.bands) == 1 return self.gradients_image.convert(mode) + def compare_reduce_with_box(self, im, factor): + box = (11, 13, 146, 164) + reduced = im.reduce(factor, box=box) + reference = im.crop(box).reduce(factor) + self.assertEqual(reduced, reference) + def compare_reduce_with_reference(self, im, factor, average_diff=0.4, max_diff=1): """Image.reduce() should look very similar to Image.resize(BOX). @@ -136,6 +142,7 @@ class TestImageReduce(PillowTestCase): im = self.get_image("L") for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_LA(self): im = self.get_image("LA") @@ -146,16 +153,19 @@ class TestImageReduce(PillowTestCase): im.putalpha(Image.new('L', im.size, 255)) for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_La(self): im = self.get_image("La") for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_RGB(self): im = self.get_image("RGB") for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_RGBA(self): im = self.get_image("RGBA") @@ -166,18 +176,22 @@ class TestImageReduce(PillowTestCase): im.putalpha(Image.new('L', im.size, 255)) for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_RGBa(self): im = self.get_image("RGBa") for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_I(self): im = self.get_image("I") for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) + self.compare_reduce_with_box(im, factor) def test_mode_F(self): im = self.get_image("F") for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor, 0, 0) + self.compare_reduce_with_box(im, factor) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 9df67ff39..e4ec78b53 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1887,7 +1887,7 @@ class Image(object): return self._new(self.im.resize(size, resample, box)) - def reduce(self, factor): + def reduce(self, factor, box=None): """ Returns reduced in `factor` times copy of the image. If the size of the image is not dividable by the `factor`, @@ -1895,21 +1895,30 @@ class Image(object): :param factor: A greater than 0 integer or tuple of two integers for width and height separately. + :param box: An optional 4-tuple of ints giving the region + of the source image which should be reduced. + The values should be within (0, 0, width, height) rectangle. + If omitted or None, the entire source is used. """ if not isinstance(factor, (list, tuple)): factor = (factor, factor) - if factor == (1, 1): + if box is None: + box = (0, 0) + self.size + else: + box = tuple(box) + + if factor == (1, 1) and box == (0, 0) + self.size: return self.copy() if self.mode in ["LA", "RGBA"]: im = self.convert(self.mode[:-1] + "a") - im = im.reduce(factor) + im = im.reduce(factor, box) return im.convert(self.mode) self.load() - return self._new(self.im.reduce(factor)) + return self._new(self.im.reduce(factor, box)) def rotate( self, diff --git a/src/_imaging.c b/src/_imaging.c index c36b2e818..48240fda2 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -1836,20 +1836,39 @@ _reduce(ImagingObject* self, PyObject* args) Imaging imOut; int xscale, yscale; + int box[4] = {0, 0, 0, 0}; imIn = self->image; + box[2] = imIn->xsize; + box[3] = imIn->ysize; - if (!PyArg_ParseTuple(args, "(ii)", &xscale, &yscale)) + if (!PyArg_ParseTuple(args, "(ii)|(iiii)", &xscale, &yscale, + &box[0], &box[1], &box[2], &box[3])) return NULL; if (xscale < 1 || yscale < 1) { return ImagingError_ValueError("scale must be > 0"); } + if (box[0] < 0 || box[1] < 0) { + return ImagingError_ValueError("box offset can't be negative"); + } + + if (box[2] > imIn->xsize || box[3] > imIn->ysize) { + return ImagingError_ValueError("box can't exceed original image size"); + } + + if (box[2] < box[0] || box[3] < box[1]) { + return ImagingError_ValueError("box can't be empty"); + } + if (xscale == 1 && yscale == 1) { - imOut = ImagingCopy(imIn); + imOut = ImagingCrop(imIn, box[0], box[1], box[2], box[3]); } else { - imOut = ImagingReduce(imIn, xscale, yscale); + // Change box format: (left, top, width, height) + box[2] -= box[0]; + box[3] -= box[1]; + imOut = ImagingReduce(imIn, xscale, yscale, box); } return PyImagingNew(imOut); diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index eee20cf6e..71dc9c003 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -313,7 +313,7 @@ extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); extern Imaging ImagingTransverse(Imaging imOut, Imaging imIn); extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]); -extern Imaging ImagingReduce(Imaging imIn, int xscale, int yscale); +extern Imaging ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]); extern Imaging ImagingTransform( Imaging imOut, Imaging imIn, int method, int x0, int y0, int x1, int y1, double *a, int filter, int fill); diff --git a/src/libImaging/Reduce.c b/src/libImaging/Reduce.c index 237d450dc..bad9d1623 100644 --- a/src/libImaging/Reduce.c +++ b/src/libImaging/Reduce.c @@ -15,39 +15,37 @@ division_UINT32(int divider, int result_bits) void -ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) +ImagingReduceNxN(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* The most general implementation for any xscale and yscale */ - int x, y, xx, yy, xi; + int x, y, xx, yy; UINT32 multiplier = division_UINT32(yscale * xscale, 8); UINT32 amend = yscale * xscale / 2; if (imIn->image8) { - for (y = 0; y < imIn->ysize / yscale; y++) { - for (x = 0; x < imIn->xsize / xscale; x++) { + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; UINT32 ss = amend; - for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) { + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image8[yy]; UINT8 *line1 = (UINT8 *)imIn->image8[yy + 1]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + line1[xx + 1]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss += line0[xx + 0] + line1[xx + 0]; } } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image8[yy]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line[xx + 0] + line[xx + 1]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss += line[xx + 0]; } } @@ -55,36 +53,34 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) } } } else { - for (y = 0; y < imIn->ysize / yscale; y++) { + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; if (imIn->bands == 2) { - for (x = 0; x < imIn->xsize / xscale; x++) { + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; UINT32 v; UINT32 ss0 = amend, ss3 = amend; - for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) { + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss0 += line0[xx*4 + 0] + line0[xx*4 + 4] + line1[xx*4 + 0] + line1[xx*4 + 4]; ss3 += line0[xx*4 + 3] + line0[xx*4 + 7] + line1[xx*4 + 3] + line1[xx*4 + 7]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; ss3 += line0[xx*4 + 3] + line1[xx*4 + 3]; } } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss0 += line[xx*4 + 0] + line[xx*4 + 4]; ss3 += line[xx*4 + 3] + line[xx*4 + 7]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss0 += line[xx*4 + 0]; ss3 += line[xx*4 + 3]; } @@ -95,14 +91,14 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else if (imIn->bands == 3) { - for (x = 0; x < imIn->xsize / xscale; x++) { + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend; - for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) { + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss0 += line0[xx*4 + 0] + line0[xx*4 + 4] + line1[xx*4 + 0] + line1[xx*4 + 4]; ss1 += line0[xx*4 + 1] + line0[xx*4 + 5] + @@ -111,7 +107,6 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) line1[xx*4 + 2] + line1[xx*4 + 6]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; ss1 += line0[xx*4 + 1] + line1[xx*4 + 1]; ss2 += line0[xx*4 + 2] + line1[xx*4 + 2]; @@ -119,14 +114,12 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss0 += line[xx*4 + 0] + line[xx*4 + 4]; ss1 += line[xx*4 + 1] + line[xx*4 + 5]; ss2 += line[xx*4 + 2] + line[xx*4 + 6]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss0 += line[xx*4 + 0]; ss1 += line[xx*4 + 1]; ss2 += line[xx*4 + 2]; @@ -138,14 +131,14 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } else { // bands == 4 - for (x = 0; x < imIn->xsize / xscale; x++) { + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; - for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) { + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { UINT8 *line0 = (UINT8 *)imIn->image[yy]; UINT8 *line1 = (UINT8 *)imIn->image[yy + 1]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss0 += line0[xx*4 + 0] + line0[xx*4 + 4] + line1[xx*4 + 0] + line1[xx*4 + 4]; ss1 += line0[xx*4 + 1] + line0[xx*4 + 5] + @@ -156,7 +149,6 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) line1[xx*4 + 3] + line1[xx*4 + 7]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss0 += line0[xx*4 + 0] + line1[xx*4 + 0]; ss1 += line0[xx*4 + 1] + line1[xx*4 + 1]; ss2 += line0[xx*4 + 2] + line1[xx*4 + 2]; @@ -165,15 +157,13 @@ ImagingReduceNxN(Imaging imOut, Imaging imIn, int xscale, int yscale) } if (yscale & 0x01) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss0 += line[xx*4 + 0] + line[xx*4 + 4]; ss1 += line[xx*4 + 1] + line[xx*4 + 5]; ss2 += line[xx*4 + 2] + line[xx*4 + 6]; ss3 += line[xx*4 + 3] + line[xx*4 + 7]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss0 += line[xx*4 + 0]; ss1 += line[xx*4 + 1]; ss2 += line[xx*4 + 2]; @@ -1025,74 +1015,77 @@ ImagingReduce5x5(Imaging imOut, Imaging imIn) void -ImagingReduceCorners(Imaging imOut, Imaging imIn, int xscale, int yscale) +ImagingReduceCorners(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* Fill the last row and the last column for any xscale and yscale. */ int x, y, xx, yy; if (imIn->image8) { - if (imIn->xsize % xscale) { - int scale = (imIn->xsize % xscale) * yscale; + if (box[2] % xscale) { + int scale = (box[2] % xscale) * yscale; UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; - for (y = 0; y < imIn->ysize / yscale; y++) { + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; UINT32 ss = amend; - x = imIn->xsize / xscale; + x = box[2] / xscale; - for (yy = y*yscale; yy < y*yscale + yscale; yy++) { + for (yy = yy_from; yy < yy_from + yscale; yy++) { UINT8 *line = (UINT8 *)imIn->image8[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } imOut->image8[y][x] = (ss * multiplier) >> 24; } } - if (imIn->ysize % yscale) { - int scale = xscale * (imIn->ysize % yscale); + if (box[3] % yscale) { + int scale = xscale * (box[3] % yscale); UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; - y = imIn->ysize / yscale; - for (x = 0; x < imIn->xsize / xscale; x++) { + y = box[3] / yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; UINT32 ss = amend; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image8[yy]; - for (xx = x*xscale; xx < x*xscale + xscale; xx++) { + for (xx = xx_from; xx < xx_from + xscale; xx++) { ss += line[xx + 0]; } } imOut->image8[y][x] = (ss * multiplier) >> 24; } } - if (imIn->xsize % xscale && imIn->ysize % yscale) { - int scale = (imIn->xsize % xscale) * (imIn->ysize % yscale); + if (box[2] % xscale && box[3] % yscale) { + int scale = (box[2] % xscale) * (box[3] % yscale); UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; UINT32 ss = amend; - x = imIn->xsize / xscale; - y = imIn->ysize / yscale; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + x = box[2] / xscale; + y = box[3] / yscale; + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image8[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } imOut->image8[y][x] = (ss * multiplier) >> 24; } } else { - if (imIn->xsize % xscale) { - int scale = (imIn->xsize % xscale) * yscale; + if (box[2] % xscale) { + int scale = (box[2] % xscale) * yscale; UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; - for (y = 0; y < imIn->ysize / yscale; y++) { + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; - x = imIn->xsize / xscale; + x = box[2] / xscale; - for (yy = y*yscale; yy < y*yscale + yscale; yy++) { + for (yy = yy_from; yy < yy_from + yscale; yy++) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss0 += line[xx*4 + 0]; ss1 += line[xx*4 + 1]; ss2 += line[xx*4 + 2]; @@ -1105,17 +1098,18 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int xscale, int yscale) memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } - if (imIn->ysize % yscale) { - int scale = xscale * (imIn->ysize % yscale); + if (box[3] % yscale) { + int scale = xscale * (box[3] % yscale); UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; - y = imIn->ysize / yscale; - for (x = 0; x < imIn->xsize / xscale; x++) { + y = box[3] / yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xx = x*xscale; xx < x*xscale + xscale; xx++) { + for (xx = xx_from; xx < xx_from + xscale; xx++) { ss0 += line[xx*4 + 0]; ss1 += line[xx*4 + 1]; ss2 += line[xx*4 + 2]; @@ -1128,17 +1122,17 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int xscale, int yscale) memcpy(imOut->image[y] + x * sizeof(v), &v, sizeof(v)); } } - if (imIn->xsize % xscale && imIn->ysize % yscale) { - int scale = (imIn->xsize % xscale) * (imIn->ysize % yscale); + if (box[2] % xscale && box[3] % yscale) { + int scale = (box[2] % xscale) * (box[3] % yscale); UINT32 multiplier = division_UINT32(scale, 8); UINT32 amend = scale / 2; UINT32 v; UINT32 ss0 = amend, ss1 = amend, ss2 = amend, ss3 = amend; - x = imIn->xsize / xscale; - y = imIn->ysize / yscale; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + x = box[2] / xscale; + y = box[3] / yscale; + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { UINT8 *line = (UINT8 *)imIn->image[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss0 += line[xx*4 + 0]; ss1 += line[xx*4 + 1]; ss2 += line[xx*4 + 2]; @@ -1155,39 +1149,37 @@ ImagingReduceCorners(Imaging imOut, Imaging imIn, int xscale, int yscale) void -ImagingReduceNxN_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) +ImagingReduceNxN_32bpc(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* The most general implementation for any xscale and yscale */ - int x, y, xx, yy, xi; + int x, y, xx, yy; double multiplier = 1.0 / (yscale * xscale); switch(imIn->type) { case IMAGING_TYPE_INT32: - for (y = 0; y < imIn->ysize / yscale; y++) { - for (x = 0; x < imIn->xsize / xscale; x++) { + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; double ss = 0; - for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) { + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { INT32 *line0 = (INT32 *)imIn->image32[yy]; INT32 *line1 = (INT32 *)imIn->image32[yy + 1]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + line1[xx + 1]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss += line0[xx + 0] + line1[xx + 0]; } } if (yscale & 0x01) { INT32 *line = (INT32 *)imIn->image32[yy]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line[xx + 0] + line[xx + 1]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss += line[xx + 0]; } } @@ -1197,30 +1189,28 @@ ImagingReduceNxN_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) break; case IMAGING_TYPE_FLOAT32: - for (y = 0; y < imIn->ysize / yscale; y++) { - for (x = 0; x < imIn->xsize / xscale; x++) { + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; double ss = 0; - for (yy = y*yscale; yy < y*yscale + yscale - 1; yy += 2) { + for (yy = yy_from; yy < yy_from + yscale - 1; yy += 2) { FLOAT32 *line0 = (FLOAT32 *)imIn->image32[yy]; FLOAT32 *line1 = (FLOAT32 *)imIn->image32[yy + 1]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line0[xx + 0] + line0[xx + 1] + line1[xx + 0] + line1[xx + 1]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss += line0[xx + 0] + line1[xx + 0]; } } if (yscale & 0x01) { FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xi = 0; xi < xscale - 1; xi += 2) { - xx = x*xscale + xi; + for (xx = xx_from; xx < xx_from + xscale - 1; xx += 2) { ss += line[xx + 0] + line[xx + 1]; } if (xscale & 0x01) { - xx = x*xscale + xi; ss += line[xx + 0]; } } @@ -1233,7 +1223,7 @@ ImagingReduceNxN_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) void -ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) +ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int box[4], int xscale, int yscale) { /* Fill the last row and the last column for any xscale and yscale. */ @@ -1241,42 +1231,44 @@ ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) switch(imIn->type) { case IMAGING_TYPE_INT32: - if (imIn->xsize % xscale) { - double multiplier = 1.0 / ((imIn->xsize % xscale) * yscale); - for (y = 0; y < imIn->ysize / yscale; y++) { + if (box[2] % xscale) { + double multiplier = 1.0 / ((box[2] % xscale) * yscale); + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; double ss = 0; - x = imIn->xsize / xscale; - for (yy = y*yscale; yy < y*yscale + yscale; yy++) { + x = box[2] / xscale; + for (yy = yy_from; yy < yy_from + yscale; yy++) { INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); } } - if (imIn->ysize % yscale) { - double multiplier = 1.0 / (xscale * (imIn->ysize % yscale)); - y = imIn->ysize / yscale; - for (x = 0; x < imIn->xsize / xscale; x++) { + if (box[3] % yscale) { + double multiplier = 1.0 / (xscale * (box[3] % yscale)); + y = box[3] / yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; double ss = 0; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = x*xscale; xx < x*xscale + xscale; xx++) { + for (xx = xx_from; xx < xx_from + xscale; xx++) { ss += line[xx + 0]; } } IMAGING_PIXEL_I(imOut, x, y) = ROUND_UP(ss * multiplier); } } - if (imIn->xsize % xscale && imIn->ysize % yscale) { - double multiplier = 1.0 / ((imIn->xsize % xscale) * (imIn->ysize % yscale)); + if (box[2] % xscale && box[3] % yscale) { + double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale)); double ss = 0; - x = imIn->xsize / xscale; - y = imIn->ysize / yscale; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + x = box[2] / xscale; + y = box[3] / yscale; + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { INT32 *line = (INT32 *)imIn->image32[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } @@ -1285,42 +1277,44 @@ ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) break; case IMAGING_TYPE_FLOAT32: - if (imIn->xsize % xscale) { - double multiplier = 1.0 / ((imIn->xsize % xscale) * yscale); - for (y = 0; y < imIn->ysize / yscale; y++) { + if (box[2] % xscale) { + double multiplier = 1.0 / ((box[2] % xscale) * yscale); + for (y = 0; y < box[3] / yscale; y++) { + int yy_from = box[1] + y*yscale; double ss = 0; - x = imIn->xsize / xscale; - for (yy = y*yscale; yy < y*yscale + yscale; yy++) { + x = box[2] / xscale; + for (yy = yy_from; yy < yy_from + yscale; yy++) { FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; } } - if (imIn->ysize % yscale) { - double multiplier = 1.0 / (xscale * (imIn->ysize % yscale)); - y = imIn->ysize / yscale; - for (x = 0; x < imIn->xsize / xscale; x++) { + if (box[3] % yscale) { + double multiplier = 1.0 / (xscale * (box[3] % yscale)); + y = box[3] / yscale; + for (x = 0; x < box[2] / xscale; x++) { + int xx_from = box[0] + x*xscale; double ss = 0; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = x*xscale; xx < x*xscale + xscale; xx++) { + for (xx = xx_from; xx < xx_from + xscale; xx++) { ss += line[xx + 0]; } } IMAGING_PIXEL_F(imOut, x, y) = ss * multiplier; } } - if (imIn->xsize % xscale && imIn->ysize % yscale) { - double multiplier = 1.0 / ((imIn->xsize % xscale) * (imIn->ysize % yscale)); + if (box[2] % xscale && box[3] % yscale) { + double multiplier = 1.0 / ((box[2] % xscale) * (box[3] % yscale)); double ss = 0; - x = imIn->xsize / xscale; - y = imIn->ysize / yscale; - for (yy = y*yscale; yy < imIn->ysize; yy++) { + x = box[2] / xscale; + y = box[3] / yscale; + for (yy = box[1] + y*yscale; yy < box[1] + box[3]; yy++) { FLOAT32 *line = (FLOAT32 *)imIn->image32[yy]; - for (xx = x*xscale; xx < imIn->xsize; xx++) { + for (xx = box[0] + x*xscale; xx < box[0] + box[2]; xx++) { ss += line[xx + 0]; } } @@ -1332,7 +1326,7 @@ ImagingReduceCorners_32bpc(Imaging imOut, Imaging imIn, int xscale, int yscale) Imaging -ImagingReduce(Imaging imIn, int xscale, int yscale) +ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) { ImagingSectionCookie cookie; Imaging imOut = NULL; @@ -1344,8 +1338,8 @@ ImagingReduce(Imaging imIn, int xscale, int yscale) return (Imaging) ImagingError_ModeError(); imOut = ImagingNewDirty(imIn->mode, - (imIn->xsize + xscale - 1) / xscale, - (imIn->ysize + yscale - 1) / yscale); + (box[2] + xscale - 1) / xscale, + (box[3] + yscale - 1) / yscale); if ( ! imOut) { return NULL; } @@ -1354,44 +1348,44 @@ ImagingReduce(Imaging imIn, int xscale, int yscale) switch(imIn->type) { case IMAGING_TYPE_UINT8: - if (xscale == 1) { - if (yscale == 2) { - ImagingReduce1x2(imOut, imIn); - } else if (yscale == 3) { - ImagingReduce1x3(imOut, imIn); - } else { - ImagingReduce1xN(imOut, imIn, yscale); - } - } else if (yscale == 1) { - if (xscale == 2) { - ImagingReduce2x1(imOut, imIn); - } else if (xscale == 3) { - ImagingReduce3x1(imOut, imIn); - } else { - ImagingReduceNx1(imOut, imIn, xscale); - } - } else if (xscale == yscale && xscale <= 5) { - if (xscale == 2) { - ImagingReduce2x2(imOut, imIn); - } else if (xscale == 3) { - ImagingReduce3x3(imOut, imIn); - } else if (xscale == 4) { - ImagingReduce4x4(imOut, imIn); - } else { - ImagingReduce5x5(imOut, imIn); - } - } else { - ImagingReduceNxN(imOut, imIn, xscale, yscale); - } + // if (xscale == 1) { + // if (yscale == 2) { + // ImagingReduce1x2(imOut, imIn); + // } else if (yscale == 3) { + // ImagingReduce1x3(imOut, imIn); + // } else { + // ImagingReduce1xN(imOut, imIn, yscale); + // } + // } else if (yscale == 1) { + // if (xscale == 2) { + // ImagingReduce2x1(imOut, imIn); + // } else if (xscale == 3) { + // ImagingReduce3x1(imOut, imIn); + // } else { + // ImagingReduceNx1(imOut, imIn, xscale); + // } + // } else if (xscale == yscale && xscale <= 5) { + // if (xscale == 2) { + // ImagingReduce2x2(imOut, imIn); + // } else if (xscale == 3) { + // ImagingReduce3x3(imOut, imIn); + // } else if (xscale == 4) { + // ImagingReduce4x4(imOut, imIn); + // } else { + // ImagingReduce5x5(imOut, imIn); + // } + // } else { + ImagingReduceNxN(imOut, imIn, box, xscale, yscale); + // } - ImagingReduceCorners(imOut, imIn, xscale, yscale); + ImagingReduceCorners(imOut, imIn, box, xscale, yscale); break; case IMAGING_TYPE_INT32: case IMAGING_TYPE_FLOAT32: - ImagingReduceNxN_32bpc(imOut, imIn, xscale, yscale); + ImagingReduceNxN_32bpc(imOut, imIn, box, xscale, yscale); - ImagingReduceCorners_32bpc(imOut, imIn, xscale, yscale); + ImagingReduceCorners_32bpc(imOut, imIn, box, xscale, yscale); break; }