Pillow/libImaging/UnsharpMask.c
2014-10-25 17:17:53 +04:00

139 lines
4.3 KiB
C

/* PILusm, a gaussian blur and unsharp masking library for PIL
By Kevin Cazabon, copyright 2003
kevin_cazabon@hotmail.com
kevin@cazabon.com */
/* Originally released under LGPL. Graciously donated to PIL
for distribution under the standard PIL license in 2009." */
#include "Python.h"
#include "Imaging.h"
static inline UINT8 clip(double in)
{
if (in >= 255.0)
return (UINT8) 255;
if (in <= 0.0)
return (UINT8) 0;
return (UINT8) (in + 0.5);
}
Imaging
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 *lineIn = NULL;
int *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 */
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
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) {
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];
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));
} else {
/* newPixel is the same as imIn */
imOut->image8[y][x] = ((UINT8 *) & lineIn8[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;
}
}
}
ImagingSectionLeave(&cookie);
return imOut;
}