diff --git a/Tests/test_imageops_usm.py b/Tests/test_imageops_usm.py index d417772c8..f6eae640b 100644 --- a/Tests/test_imageops_usm.py +++ b/Tests/test_imageops_usm.py @@ -60,9 +60,10 @@ class TestImageOpsUsm(PillowTestCase): def test_usm_accuracy(self): - i = snakes._new(ImageOps.unsharp_mask(snakes, 5, 1024, 0)) + src = snakes.convert('RGB') + i = src._new(ImageOps.unsharp_mask(src, 5, 1024, 0)) # Image should not be changed because it have only 0 and 255 levels. - self.assertEqual(i.tobytes(), snakes.tobytes()) + self.assertEqual(i.tobytes(), src.tobytes()) def test_blur_accuracy(self): diff --git a/libImaging/UnsharpMask.c b/libImaging/UnsharpMask.c index 61526cca7..ec3bb23cc 100644 --- a/libImaging/UnsharpMask.c +++ b/libImaging/UnsharpMask.c @@ -10,13 +10,16 @@ #include "Imaging.h" -static inline UINT8 clip(double in) +typedef UINT8 pixel[4]; + + +static inline UINT8 clip8(int in) { - if (in >= 255.0) - return (UINT8) 255; - if (in <= 0.0) - return (UINT8) 0; - return (UINT8) (in + 0.5); + if (in >= 255) + return 255; + if (in <= 0) + return 0; + return (UINT8) in; } @@ -25,109 +28,64 @@ ImagingUnsharpMask(Imaging imOut, Imaging imIn, float radius, int percent, int threshold) { ImagingSectionCookie cookie; - Imaging result; - int channel = 0; - int channels = 0; - int hasAlpha = 0; - int x = 0; - int y = 0; + int x, y, diff; - int *lineIn = NULL; - int *lineOut = NULL; + pixel *lineIn = NULL; + pixel *lineOut = NULL; UINT8 *lineIn8 = NULL; UINT8 *lineOut8 = NULL; - int diff = 0; - - INT32 newPixel = 0; - - if (strcmp(imIn->mode, "RGB") == 0) { - channels = 3; - } else if (strcmp(imIn->mode, "RGBA") == 0) { - channels = 3; - } else if (strcmp(imIn->mode, "RGBX") == 0) { - channels = 3; - } else if (strcmp(imIn->mode, "CMYK") == 0) { - channels = 4; - } else if (strcmp(imIn->mode, "L") == 0) { - channels = 1; - } else - return ImagingError_ModeError(); - - /* first, do a gaussian blur on the image, putting results in imOut - temporarily */ + /* First, do a gaussian blur on the image, putting results in imOut + temporarily. All format checks are in gaussian blur. */ result = ImagingGaussianBlur(imOut, imIn, radius, 3); if (!result) return NULL; - /* now, go through each pixel, compare "normal" pixel to blurred - pixel. if the difference is more than threshold values, apply + /* Now, go through each pixel, compare "normal" pixel to blurred + pixel. If the difference is more than threshold values, apply the OPPOSITE correction to the amount of blur, multiplied by percent. */ ImagingSectionEnter(&cookie); - if (strcmp(imIn->mode, "RGBX") == 0 || strcmp(imIn->mode, "RGBA") == 0) { - hasAlpha = 1; - } - for (y = 0; y < imIn->ysize; y++) { - if (channels == 1) { + if (imIn->image8) + { lineIn8 = imIn->image8[y]; lineOut8 = imOut->image8[y]; - } else { - lineIn = imIn->image32[y]; - lineOut = imOut->image32[y]; - } - for (x = 0; x < imIn->xsize; x++) { - newPixel = 0; - /* compare in/out pixels, apply sharpening */ - if (channels == 1) { - diff = - ((UINT8 *) & lineIn8[x])[0] - - ((UINT8 *) & lineOut8[x])[0]; + for (x = 0; x < imIn->xsize; x++) { + /* compare in/out pixels, apply sharpening */ + diff = lineIn8[x] - lineOut8[x]; if (abs(diff) > threshold) { /* add the diff*percent to the original pixel */ - imOut->image8[y][x] = - clip((((UINT8 *) & lineIn8[x])[0]) + - (diff * ((float) percent) / 100.0)); + lineOut8[x] = clip8(lineIn8[x] + diff * percent / 100); } else { - /* newPixel is the same as imIn */ - imOut->image8[y][x] = ((UINT8 *) & lineIn8[x])[0]; + /* new pixel is the same as imIn */ + lineOut8[x] = lineIn8[x]; } } + } else { + lineIn = (pixel *)imIn->image32[y]; + lineOut = (pixel *)imOut->image32[y]; + for (x = 0; x < imIn->xsize; x++) { + /* compare in/out pixels, apply sharpening */ + diff = lineIn[x][0] - lineOut[x][0]; + lineOut[x][0] = abs(diff) > threshold ? + clip8(lineIn[x][0] + diff * percent / 100) : lineIn[x][0]; - else { - for (channel = 0; channel < channels; channel++) { - diff = (int) ((((UINT8 *) & lineIn[x])[channel]) - - (((UINT8 *) & lineOut[x])[channel])); - if (abs(diff) > threshold) { - /* add the diff*percent to the original pixel - this may not work for little-endian systems, fix it! */ - newPixel = - newPixel | - clip((float) (((UINT8 *) & lineIn[x])[channel]) - + - (diff * - (((float) percent / - 100.0)))) << (channel * 8); - } else { - /* newPixel is the same as imIn - this may not work for little-endian systems, fix it! */ - newPixel = - newPixel | ((UINT8 *) & lineIn[x])[channel] << - (channel * 8); - } - } - if (hasAlpha) { - /* preserve the alpha channel - this may not work for little-endian systems, fix it! */ - newPixel = - newPixel | ((UINT8 *) & lineIn[x])[channel] << 24; - } - imOut->image32[y][x] = newPixel; + diff = lineIn[x][1] - lineOut[x][1]; + lineOut[x][1] = abs(diff) > threshold ? + clip8(lineIn[x][1] + diff * percent / 100) : lineIn[x][1]; + + diff = lineIn[x][2] - lineOut[x][2]; + lineOut[x][2] = abs(diff) > threshold ? + clip8(lineIn[x][2] + diff * percent / 100) : lineIn[x][2]; + + diff = lineIn[x][3] - lineOut[x][3]; + lineOut[x][3] = abs(diff) > threshold ? + clip8(lineIn[x][3] + diff * percent / 100) : lineIn[x][3]; } } }