sharp alpha channel

resolve sharp endianness issues
This commit is contained in:
homm 2014-11-22 01:00:04 +03:00
parent d0c419632e
commit 107b4a8b07
2 changed files with 46 additions and 87 deletions

View File

@ -60,9 +60,10 @@ class TestImageOpsUsm(PillowTestCase):
def test_usm_accuracy(self): 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. # 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): def test_blur_accuracy(self):

View File

@ -10,13 +10,16 @@
#include "Imaging.h" #include "Imaging.h"
static inline UINT8 clip(double in) typedef UINT8 pixel[4];
static inline UINT8 clip8(int in)
{ {
if (in >= 255.0) if (in >= 255)
return (UINT8) 255; return 255;
if (in <= 0.0) if (in <= 0)
return (UINT8) 0; return 0;
return (UINT8) (in + 0.5); return (UINT8) in;
} }
@ -25,109 +28,64 @@ ImagingUnsharpMask(Imaging imOut, Imaging imIn, float radius, int percent,
int threshold) int threshold)
{ {
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
Imaging result; Imaging result;
int channel = 0;
int channels = 0;
int hasAlpha = 0;
int x = 0; int x, y, diff;
int y = 0;
int *lineIn = NULL; pixel *lineIn = NULL;
int *lineOut = NULL; pixel *lineOut = NULL;
UINT8 *lineIn8 = NULL; UINT8 *lineIn8 = NULL;
UINT8 *lineOut8 = NULL; UINT8 *lineOut8 = NULL;
int diff = 0; /* First, do a gaussian blur on the image, putting results in imOut
temporarily. All format checks are in gaussian blur. */
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 */
result = ImagingGaussianBlur(imOut, imIn, radius, 3); result = ImagingGaussianBlur(imOut, imIn, radius, 3);
if (!result) if (!result)
return NULL; return NULL;
/* now, go through each pixel, compare "normal" pixel to blurred /* Now, go through each pixel, compare "normal" pixel to blurred
pixel. if the difference is more than threshold values, apply pixel. If the difference is more than threshold values, apply
the OPPOSITE correction to the amount of blur, multiplied by the OPPOSITE correction to the amount of blur, multiplied by
percent. */ percent. */
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
if (strcmp(imIn->mode, "RGBX") == 0 || strcmp(imIn->mode, "RGBA") == 0) {
hasAlpha = 1;
}
for (y = 0; y < imIn->ysize; y++) { for (y = 0; y < imIn->ysize; y++) {
if (channels == 1) { if (imIn->image8)
{
lineIn8 = imIn->image8[y]; lineIn8 = imIn->image8[y];
lineOut8 = imOut->image8[y]; lineOut8 = imOut->image8[y];
} else { for (x = 0; x < imIn->xsize; x++) {
lineIn = imIn->image32[y]; /* compare in/out pixels, apply sharpening */
lineOut = imOut->image32[y]; diff = lineIn8[x] - lineOut8[x];
}
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];
if (abs(diff) > threshold) { if (abs(diff) > threshold) {
/* add the diff*percent to the original pixel */ /* add the diff*percent to the original pixel */
imOut->image8[y][x] = lineOut8[x] = clip8(lineIn8[x] + diff * percent / 100);
clip((((UINT8 *) & lineIn8[x])[0]) +
(diff * ((float) percent) / 100.0));
} else { } else {
/* newPixel is the same as imIn */ /* new pixel is the same as imIn */
imOut->image8[y][x] = ((UINT8 *) & lineIn8[x])[0]; 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 { diff = lineIn[x][1] - lineOut[x][1];
for (channel = 0; channel < channels; channel++) { lineOut[x][1] = abs(diff) > threshold ?
diff = (int) ((((UINT8 *) & lineIn[x])[channel]) - clip8(lineIn[x][1] + diff * percent / 100) : lineIn[x][1];
(((UINT8 *) & lineOut[x])[channel]));
if (abs(diff) > threshold) { diff = lineIn[x][2] - lineOut[x][2];
/* add the diff*percent to the original pixel lineOut[x][2] = abs(diff) > threshold ?
this may not work for little-endian systems, fix it! */ clip8(lineIn[x][2] + diff * percent / 100) : lineIn[x][2];
newPixel =
newPixel | diff = lineIn[x][3] - lineOut[x][3];
clip((float) (((UINT8 *) & lineIn[x])[channel]) lineOut[x][3] = abs(diff) > threshold ?
+ clip8(lineIn[x][3] + diff * percent / 100) : lineIn[x][3];
(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;
} }
} }
} }