コード例 #1
0
ファイル: Filter.c プロジェクト: Dormouse759/Pillow
Imaging
ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
              FLOAT32 offset)
{
    Imaging imOut;
    ImagingSectionCookie cookie;

    if ( ! im || im->type != IMAGING_TYPE_UINT8)
        return (Imaging) ImagingError_ModeError();

    if (im->xsize < xsize || im->ysize < ysize)
        return ImagingCopy(im);

    if ((xsize != 3 && xsize != 5) || xsize != ysize)
        return (Imaging) ImagingError_ValueError("bad kernel size");

    imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize);
    if (!imOut)
        return NULL;

    ImagingSectionEnter(&cookie);
    if (xsize == 3) {
        /* 3x3 kernel. */
        ImagingFilter3x3(imOut, im, kernel, offset);
    } else {
        /* 5x5 kernel. */
        ImagingFilter5x5(imOut, im, kernel, offset);
    }
    ImagingSectionLeave(&cookie);
    return imOut;
}
コード例 #2
0
ファイル: encode.c プロジェクト: AnubhabB/Pillow
static PyObject*
_encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
{
    UINT8* buf;
    int status;
    ImagingSectionCookie cookie;

    /* Encode to a file handle */

    int fh;
    int bufsize = 16384;

    if (!PyArg_ParseTuple(args, "i|i", &fh, &bufsize))
        return NULL;

    /* Allocate an encoder buffer */
    buf = (UINT8*) malloc(bufsize);
    if (!buf)
        return PyErr_NoMemory();

    ImagingSectionEnter(&cookie);

    do {

        /* This replaces the inner loop in the ImageFile _save
           function. */

        status = encoder->encode(encoder->im, &encoder->state, buf, bufsize);

        if (status > 0)
            if (write(fh, buf, status) < 0) {
                ImagingSectionLeave(&cookie);
                free(buf);
                return PyErr_SetFromErrno(PyExc_IOError);
            }

    } while (encoder->state.errcode == 0);

    ImagingSectionLeave(&cookie);

    free(buf);

    return Py_BuildValue("i", encoder->state.errcode);
}
コード例 #3
0
ファイル: Filter.c プロジェクト: Dormouse759/Pillow
Imaging
ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
{
    Imaging imOut;
    int x, y;
    ImagingSectionCookie cookie;

    if (xmargin < 0 && ymargin < 0)
        return (Imaging) ImagingError_ValueError("bad kernel size");

    imOut = ImagingNewDirty(
        imIn->mode, imIn->xsize+2*xmargin, imIn->ysize+2*ymargin);
    if (!imOut)
        return NULL;

#define EXPAND_LINE(type, image, yin, yout) {\
    for (x = 0; x < xmargin; x++)\
        imOut->image[yout][x] = imIn->image[yin][0];\
    for (x = 0; x < imIn->xsize; x++)\
        imOut->image[yout][x+xmargin] = imIn->image[yin][x];\
    for (x = 0; x < xmargin; x++)\
        imOut->image[yout][xmargin+imIn->xsize+x] =\
            imIn->image[yin][imIn->xsize-1];\
    }

#define EXPAND(type, image) {\
    for (y = 0; y < ymargin; y++)\
        EXPAND_LINE(type, image, 0, y);\
    for (y = 0; y < imIn->ysize; y++)\
        EXPAND_LINE(type, image, y, y+ymargin);\
    for (y = 0; y < ymargin; y++)\
        EXPAND_LINE(type, image, imIn->ysize-1, ymargin+imIn->ysize+y);\
    }

    ImagingSectionEnter(&cookie);
    if (imIn->image8) {
        EXPAND(UINT8, image8);
    } else {
        EXPAND(INT32, image32);
    }
    ImagingSectionLeave(&cookie);

    ImagingCopyPalette(imOut, imIn);

    return imOut;
}
コード例 #4
0
ファイル: Resample.c プロジェクト: wiredfool/Pillow
void
ImagingResampleVertical_32bpc(Imaging imOut, Imaging imIn, int offset,
                              int ksize, int *bounds, double *kk)
{
    ImagingSectionCookie cookie;
    double ss;
    int xx, yy, y, ymin, ymax;
    double *k;

    ImagingSectionEnter(&cookie);
    switch(imIn->type) {
        case IMAGING_TYPE_INT32:
            for (yy = 0; yy < imOut->ysize; yy++) {
                ymin = bounds[yy * 2 + 0];
                ymax = bounds[yy * 2 + 1];
                k = &kk[yy * ksize];
                for (xx = 0; xx < imOut->xsize; xx++) {
                    ss = 0.0;
                    for (y = 0; y < ymax; y++)
                        ss += IMAGING_PIXEL_I(imIn, xx, y + ymin) * k[y];
                    IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
                }
            }
            break;

        case IMAGING_TYPE_FLOAT32:
            for (yy = 0; yy < imOut->ysize; yy++) {
                ymin = bounds[yy * 2 + 0];
                ymax = bounds[yy * 2 + 1];
                k = &kk[yy * ksize];
                for (xx = 0; xx < imOut->xsize; xx++) {
                    ss = 0.0;
                    for (y = 0; y < ymax; y++)
                        ss += IMAGING_PIXEL_F(imIn, xx, y + ymin) * k[y];
                    IMAGING_PIXEL_F(imOut, xx, yy) = ss;
                }
            }
            break;
    }
    ImagingSectionLeave(&cookie);
}
コード例 #5
0
ファイル: Resample.c プロジェクト: wiredfool/Pillow
void
ImagingResampleHorizontal_32bpc(Imaging imOut, Imaging imIn, int offset,
                                int ksize, int *bounds, double *kk)
{
    ImagingSectionCookie cookie;
    double ss;
    int xx, yy, x, xmin, xmax;
    double *k;

    ImagingSectionEnter(&cookie);
    switch(imIn->type) {
        case IMAGING_TYPE_INT32:
            for (yy = 0; yy < imOut->ysize; yy++) {
                for (xx = 0; xx < imOut->xsize; xx++) {
                    xmin = bounds[xx * 2 + 0];
                    xmax = bounds[xx * 2 + 1];
                    k = &kk[xx * ksize];
                    ss = 0.0;
                    for (x = 0; x < xmax; x++)
                        ss += IMAGING_PIXEL_I(imIn, x + xmin, yy + offset) * k[x];
                    IMAGING_PIXEL_I(imOut, xx, yy) = ROUND_UP(ss);
                }
            }
            break;

        case IMAGING_TYPE_FLOAT32:
            for (yy = 0; yy < imOut->ysize; yy++) {
                for (xx = 0; xx < imOut->xsize; xx++) {
                    xmin = bounds[xx * 2 + 0];
                    xmax = bounds[xx * 2 + 1];
                    k = &kk[xx * ksize];
                    ss = 0.0;
                    for (x = 0; x < xmax; x++)
                        ss += IMAGING_PIXEL_F(imIn, x + xmin, yy + offset) * k[x];
                    IMAGING_PIXEL_F(imOut, xx, yy) = ss;
                }
            }
            break;
    }
    ImagingSectionLeave(&cookie);
}
コード例 #6
0
ファイル: decode.c プロジェクト: olt/Pillow
static PyObject*
_decode(ImagingDecoderObject* decoder, PyObject* args)
{
    UINT8* buffer;
    int bufsize, status;
    ImagingSectionCookie cookie;

    if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH, &buffer, &bufsize))
        return NULL;

    if (!decoder->pulls_fd) {
        ImagingSectionEnter(&cookie);
    }

    status = decoder->decode(decoder->im, &decoder->state, buffer, bufsize);

    if (!decoder->pulls_fd) {
        ImagingSectionLeave(&cookie);
    }

    return Py_BuildValue("ii", status, decoder->state.errcode);
}
コード例 #7
0
ファイル: Fill.c プロジェクト: 10printhello/gitpil
Imaging
ImagingFill(Imaging im, const void* colour)
{
    int x, y;
    ImagingSectionCookie cookie;

    if (im->type == IMAGING_TYPE_SPECIAL) {
        /* use generic API */
        ImagingAccess access = ImagingAccessNew(im);
        if (access) {
            for (y = 0; y < im->ysize; y++)
                for (x = 0; x < im->xsize; x++)
                    access->put_pixel(im, x, y, colour);
            ImagingAccessDelete(im, access);
        } else {
            /* wipe the image */
            for (y = 0; y < im->ysize; y++)
                memset(im->image[y], 0, im->linesize);
        }
    } else {
        ImagingSectionEnter(&cookie);
        INT32 c = 0L;
        memcpy(&c, colour, im->pixelsize);
        if (im->image32 && c != 0L) {
            for (y = 0; y < im->ysize; y++)
                for (x = 0; x < im->xsize; x++)
                    im->image32[y][x] = c;
        } else {
            unsigned char cc = (unsigned char) *(UINT8*) colour;
            for (y = 0; y < im->ysize; y++)
                memset(im->image[y], cc, im->linesize);
        }
        ImagingSectionLeave(&cookie);
    }

    return im;
}
コード例 #8
0
ファイル: Paste.c プロジェクト: 0xD34DC0DE/PIL
int
ImagingFill2(Imaging imOut, const void* ink, Imaging imMask,
             int dx0, int dy0, int dx1, int dy1)
{
    ImagingSectionCookie cookie;
    int xsize, ysize;
    int pixelsize;
    int sx0, sy0;

    if (!imOut || !ink) {
	(void) ImagingError_ModeError();
	return -1;
    }

    pixelsize = imOut->pixelsize;

    xsize = dx1 - dx0;
    ysize = dy1 - dy0;

    if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) {
	(void) ImagingError_Mismatch();
	return -1;
    }

    /* Determine which region to fill */
    sx0 = sy0 = 0;
    if (dx0 < 0)
	xsize += dx0, sx0 = -dx0, dx0 = 0;
    if (dx0 + xsize > imOut->xsize)
	xsize = imOut->xsize - dx0;
    if (dy0 < 0)
	ysize += dy0, sy0 = -dy0, dy0 = 0;
    if (dy0 + ysize > imOut->ysize)
	ysize = imOut->ysize - dy0;

    if (xsize <= 0 || ysize <= 0)
	return 0;

    if (!imMask) {
        ImagingSectionEnter(&cookie);
        fill(imOut, ink, dx0, dy0, xsize, ysize, pixelsize);
        ImagingSectionLeave(&cookie);

    } else if (strcmp(imMask->mode, "1") == 0) {
        ImagingSectionEnter(&cookie);
        fill_mask_1(imOut, ink, imMask, dx0, dy0, sx0, sy0,
                    xsize, ysize, pixelsize);
        ImagingSectionLeave(&cookie);

    } else if (strcmp(imMask->mode, "L") == 0) {
        ImagingSectionEnter(&cookie);
        fill_mask_L(imOut, ink, imMask, dx0, dy0, sx0, sy0,
                    xsize, ysize, pixelsize);
        ImagingSectionLeave(&cookie);

    } else if (strcmp(imMask->mode, "RGBA") == 0) {
        ImagingSectionEnter(&cookie);
        fill_mask_RGBA(imOut, ink, imMask, dx0, dy0, sx0, sy0,
                       xsize, ysize, pixelsize);
        ImagingSectionLeave(&cookie);

    } else if (strcmp(imMask->mode, "RGBa") == 0) {
        ImagingSectionEnter(&cookie);
        fill_mask_RGBa(imOut, ink, imMask, dx0, dy0, sx0, sy0,
                       xsize, ysize, pixelsize);
        ImagingSectionLeave(&cookie);

    } else {
	(void) ImagingError_ValueError("bad transparency mask");
	return -1;
    }

    return 0;
}
コード例 #9
0
ファイル: Resample.c プロジェクト: wiredfool/Pillow
void
ImagingResampleVertical_8bpc(Imaging imOut, Imaging imIn, int offset,
                             int ksize, int *bounds, double *prekk)
{
    ImagingSectionCookie cookie;
    int ss0, ss1, ss2, ss3;
    int xx, yy, y, ymin, ymax;
    INT32 *k, *kk;

    // use the same buffer for normalized coefficients
    kk = (INT32 *) prekk;
    normalize_coeffs_8bpc(imOut->ysize, ksize, prekk);

    ImagingSectionEnter(&cookie);
    if (imIn->image8) {
        for (yy = 0; yy < imOut->ysize; yy++) {
            k = &kk[yy * ksize];
            ymin = bounds[yy * 2 + 0];
            ymax = bounds[yy * 2 + 1];
            for (xx = 0; xx < imOut->xsize; xx++) {
                ss0 = 1 << (PRECISION_BITS -1);
                for (y = 0; y < ymax; y++)
                    ss0 += ((UINT8) imIn->image8[y + ymin][xx]) * k[y];
                imOut->image8[yy][xx] = clip8(ss0);
            }
        }
    } else if (imIn->type == IMAGING_TYPE_UINT8) {
        if (imIn->bands == 2) {
            for (yy = 0; yy < imOut->ysize; yy++) {
                k = &kk[yy * ksize];
                ymin = bounds[yy * 2 + 0];
                ymax = bounds[yy * 2 + 1];
                for (xx = 0; xx < imOut->xsize; xx++) {
                    ss0 = ss3 = 1 << (PRECISION_BITS -1);
                    for (y = 0; y < ymax; y++) {
                        ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
                        ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
                    }
                    ((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
                        clip8(ss0), 0, 0, clip8(ss3));
                }
            }
        } else if (imIn->bands == 3) {
            for (yy = 0; yy < imOut->ysize; yy++) {
                k = &kk[yy * ksize];
                ymin = bounds[yy * 2 + 0];
                ymax = bounds[yy * 2 + 1];
                for (xx = 0; xx < imOut->xsize; xx++) {
                    ss0 = ss1 = ss2 = 1 << (PRECISION_BITS -1);
                    for (y = 0; y < ymax; y++) {
                        ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
                        ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
                        ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
                    }
                    ((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
                        clip8(ss0), clip8(ss1), clip8(ss2), 0);
                }
            }
        } else {
            for (yy = 0; yy < imOut->ysize; yy++) {
                k = &kk[yy * ksize];
                ymin = bounds[yy * 2 + 0];
                ymax = bounds[yy * 2 + 1];
                for (xx = 0; xx < imOut->xsize; xx++) {
                    ss0 = ss1 = ss2 = ss3 = 1 << (PRECISION_BITS -1);
                    for (y = 0; y < ymax; y++) {
                        ss0 += ((UINT8) imIn->image[y + ymin][xx*4 + 0]) * k[y];
                        ss1 += ((UINT8) imIn->image[y + ymin][xx*4 + 1]) * k[y];
                        ss2 += ((UINT8) imIn->image[y + ymin][xx*4 + 2]) * k[y];
                        ss3 += ((UINT8) imIn->image[y + ymin][xx*4 + 3]) * k[y];
                    }
                    ((UINT32 *) imOut->image[yy])[xx] = MAKE_UINT32(
                        clip8(ss0), clip8(ss1), clip8(ss2), clip8(ss3));
                }
            }
        }
    }
    ImagingSectionLeave(&cookie);
}
コード例 #10
0
ファイル: Antialias.c プロジェクト: 1060460048/Pillow
Imaging
ImagingStretch(Imaging imOut, Imaging imIn, int filter)
{
    /* FIXME: this is a quick and straightforward translation from a
       python prototype.  might need some further C-ification... */

    ImagingSectionCookie cookie;
    struct filter *filterp;
    float support, scale, filterscale;
    float center, ww, ss, ymin, ymax, xmin, xmax;
    int xx, yy, x, y, b;
    float *k;

    /* check modes */
    if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0)
	return (Imaging) ImagingError_ModeError();

    /* check filter */
    switch (filter) {
    case IMAGING_TRANSFORM_NEAREST:
        filterp = &NEAREST;
        break;
    case IMAGING_TRANSFORM_ANTIALIAS:
        filterp = &ANTIALIAS;
        break;
    case IMAGING_TRANSFORM_BILINEAR:
        filterp = &BILINEAR;
        break;
    case IMAGING_TRANSFORM_BICUBIC:
        filterp = &BICUBIC;
        break;
    default:
        return (Imaging) ImagingError_ValueError(
            "unsupported resampling filter"
            );
    }

    if (imIn->ysize == imOut->ysize) {
        /* prepare for horizontal stretch */
        filterscale = scale = (float) imIn->xsize / imOut->xsize;
    } else if (imIn->xsize == imOut->xsize) {
        /* prepare for vertical stretch */
        filterscale = scale = (float) imIn->ysize / imOut->ysize;
    } else
	return (Imaging) ImagingError_Mismatch();

    /* determine support size (length of resampling filter) */
    support = filterp->support;

    if (filterscale < 1.0) {
        filterscale = 1.0;
        support = 0.5;
    }

    support = support * filterscale;

    /* coefficient buffer (with rounding safety margin) */
    k = malloc(((int) support * 2 + 10) * sizeof(float));
    if (!k)
        return (Imaging) ImagingError_MemoryError();

    ImagingSectionEnter(&cookie);
    if (imIn->xsize == imOut->xsize) {
        /* vertical stretch */
        for (yy = 0; yy < imOut->ysize; yy++) {
            center = (yy + 0.5) * scale;
            ww = 0.0;
            ss = 1.0 / filterscale;
            /* calculate filter weights */
            ymin = floor(center - support);
            if (ymin < 0.0)
                ymin = 0.0;
            ymax = ceil(center + support);
            if (ymax > (float) imIn->ysize)
		ymax = (float) imIn->ysize;
            for (y = (int) ymin; y < (int) ymax; y++) {
                float w = filterp->filter((y - center + 0.5) * ss) * ss;
                k[y - (int) ymin] = w;
                ww = ww + w;
            }
            if (ww == 0.0)
                ww = 1.0;
            else
                ww = 1.0 / ww;
            if (imIn->image8) {
                /* 8-bit grayscale */
                for (xx = 0; xx < imOut->xsize; xx++) {
                    ss = 0.0;
                    for (y = (int) ymin; y < (int) ymax; y++)
                        ss = ss + imIn->image8[y][xx] * k[y - (int) ymin];
                    ss = ss * ww + 0.5;
                    if (ss < 0.5)
                        imOut->image8[yy][xx] = 0;
                    else if (ss >= 255.0)
                        imOut->image8[yy][xx] = 255;
                    else
                        imOut->image8[yy][xx] = (UINT8) ss;
                }
            } else
                switch(imIn->type) {
                case IMAGING_TYPE_UINT8:
                    /* n-bit grayscale */
                    for (xx = 0; xx < imOut->xsize*4; xx++) {
                        /* FIXME: skip over unused pixels */
                        ss = 0.0;
                        for (y = (int) ymin; y < (int) ymax; y++)
                            ss = ss + (UINT8) imIn->image[y][xx] * k[y-(int) ymin];
                        ss = ss * ww + 0.5;
                        if (ss < 0.5)
                            imOut->image[yy][xx] = (UINT8) 0;
                        else if (ss >= 255.0)
                            imOut->image[yy][xx] = (UINT8) 255;
                        else
                            imOut->image[yy][xx] = (UINT8) ss;
                    }
                    break;
                case IMAGING_TYPE_INT32:
                    /* 32-bit integer */
                    for (xx = 0; xx < imOut->xsize; xx++) {
                        ss = 0.0;
                        for (y = (int) ymin; y < (int) ymax; y++)
                            ss = ss + IMAGING_PIXEL_I(imIn, xx, y) * k[y - (int) ymin];
                        IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww;
                    }
                    break;
                case IMAGING_TYPE_FLOAT32:
                    /* 32-bit float */
                    for (xx = 0; xx < imOut->xsize; xx++) {
                        ss = 0.0;
                        for (y = (int) ymin; y < (int) ymax; y++)
                            ss = ss + IMAGING_PIXEL_F(imIn, xx, y) * k[y - (int) ymin];
                        IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww;
                    }
                    break;
                default:
                    ImagingSectionLeave(&cookie);
                    return (Imaging) ImagingError_ModeError();
                }
        }
    } else {
        /* horizontal stretch */
        for (xx = 0; xx < imOut->xsize; xx++) {
            center = (xx + 0.5) * scale;
            ww = 0.0;
            ss = 1.0 / filterscale;
            xmin = floor(center - support);
            if (xmin < 0.0)
                xmin = 0.0;
            xmax = ceil(center + support);
            if (xmax > (float) imIn->xsize)
		xmax = (float) imIn->xsize;
            for (x = (int) xmin; x < (int) xmax; x++) {
                float w = filterp->filter((x - center + 0.5) * ss) * ss;
                k[x - (int) xmin] = w;
                ww = ww + w;
            }
            if (ww == 0.0)
                ww = 1.0;
            else
                ww = 1.0 / ww;
            if (imIn->image8) {
                /* 8-bit grayscale */
                for (yy = 0; yy < imOut->ysize; yy++) {
                    ss = 0.0;
                    for (x = (int) xmin; x < (int) xmax; x++)
                        ss = ss + imIn->image8[yy][x] * k[x - (int) xmin];
                    ss = ss * ww + 0.5;
                    if (ss < 0.5)
                        imOut->image8[yy][xx] = (UINT8) 0;
                    else if (ss >= 255.0)
                        imOut->image8[yy][xx] = (UINT8) 255;
                    else
                        imOut->image8[yy][xx] = (UINT8) ss;
                }
            } else
                switch(imIn->type) {
                case IMAGING_TYPE_UINT8:
                    /* n-bit grayscale */
                    for (yy = 0; yy < imOut->ysize; yy++) {
                        for (b = 0; b < imIn->bands; b++) {
                            if (imIn->bands == 2 && b)
                                b = 3; /* hack to deal with LA images */
                            ss = 0.0;
                            for (x = (int) xmin; x < (int) xmax; x++)
                                ss = ss + (UINT8) imIn->image[yy][x*4+b] * k[x - (int) xmin];
                            ss = ss * ww + 0.5;
                            if (ss < 0.5)
                                imOut->image[yy][xx*4+b] = (UINT8) 0;
                            else if (ss >= 255.0)
                                imOut->image[yy][xx*4+b] = (UINT8) 255;
                            else
                                imOut->image[yy][xx*4+b] = (UINT8) ss;
                        }
                    }
                    break;
                case IMAGING_TYPE_INT32:
                    /* 32-bit integer */
                    for (yy = 0; yy < imOut->ysize; yy++) {
                        ss = 0.0;
                        for (x = (int) xmin; x < (int) xmax; x++)
                            ss = ss + IMAGING_PIXEL_I(imIn, x, yy) * k[x - (int) xmin];
                        IMAGING_PIXEL_I(imOut, xx, yy) = (int) ss * ww;
                    }
                    break;
                case IMAGING_TYPE_FLOAT32:
                    /* 32-bit float */
                    for (yy = 0; yy < imOut->ysize; yy++) {
                        ss = 0.0;
                        for (x = (int) xmin; x < (int) xmax; x++)
                            ss = ss + IMAGING_PIXEL_F(imIn, x, yy) * k[x - (int) xmin];
                        IMAGING_PIXEL_F(imOut, xx, yy) = ss * ww;
                    }
                    break;
                default:
                    ImagingSectionLeave(&cookie);
                    return (Imaging) ImagingError_ModeError();
                }
        }
    }
    ImagingSectionLeave(&cookie);

    free(k);

    return imOut;
}
コード例 #11
0
Imaging
ImagingPointTransform(Imaging imIn, double scale, double offset)
{
    /* scale/offset transform */

    ImagingSectionCookie cookie;
    Imaging imOut;
    int x, y;

    if (!imIn || (strcmp(imIn->mode, "I") != 0 &&
                  strcmp(imIn->mode, "I;16") != 0 &&
                  strcmp(imIn->mode, "F") != 0))
        return (Imaging) ImagingError_ModeError();

    imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
    if (!imOut)
        return NULL;

    ImagingCopyInfo(imOut, imIn);

    switch (imIn->type) {
    case IMAGING_TYPE_INT32:
        ImagingSectionEnter(&cookie);
        for (y = 0; y < imIn->ysize; y++) {
            INT32* in  = imIn->image32[y];
            INT32* out = imOut->image32[y];
            /* FIXME: add clipping? */
            for (x = 0; x < imIn->xsize; x++)
                out[x] = in[x] * scale + offset;
        }
        ImagingSectionLeave(&cookie);
        break;
    case IMAGING_TYPE_FLOAT32:
        ImagingSectionEnter(&cookie);
        for (y = 0; y < imIn->ysize; y++) {
            FLOAT32* in  = (FLOAT32*) imIn->image32[y];
            FLOAT32* out = (FLOAT32*) imOut->image32[y];
            for (x = 0; x < imIn->xsize; x++)
                out[x] = in[x] * scale + offset;
        }
        ImagingSectionLeave(&cookie);
        break;
    case IMAGING_TYPE_SPECIAL:
        if (strcmp(imIn->mode,"I;16") == 0) {
            ImagingSectionEnter(&cookie);
            for (y = 0; y < imIn->ysize; y++) {
                UINT16* in  = (UINT16 *)imIn->image[y];
                UINT16* out = (UINT16 *)imOut->image[y];
                /* FIXME: add clipping? */
                for (x = 0; x < imIn->xsize; x++)
                    out[x] = in[x] * scale + offset;
            }
            ImagingSectionLeave(&cookie);
            break;
        }
    /* FALL THROUGH */
    default:
        ImagingDelete(imOut);
        return (Imaging) ImagingError_ValueError("internal error");
    }

    return imOut;
}
コード例 #12
0
Imaging
ImagingPoint(Imaging imIn, const char* mode, const void* table)
{
    /* lookup table transform */

    ImagingSectionCookie cookie;
    Imaging imOut;
    im_point_context context;
    void (*point)(Imaging imIn, Imaging imOut, im_point_context* context);

    if (!imIn)
        return (Imaging) ImagingError_ModeError();

    if (!mode)
        mode = imIn->mode;

    if (imIn->type != IMAGING_TYPE_UINT8) {
        if (imIn->type != IMAGING_TYPE_INT32 || strcmp(mode, "L") != 0)
            goto mode_mismatch;
    } else if (!imIn->image8 && strcmp(imIn->mode, mode) != 0)
        goto mode_mismatch;

    imOut = ImagingNew(mode, imIn->xsize, imIn->ysize);
    if (!imOut)
        return NULL;

    /* find appropriate handler */
    if (imIn->type == IMAGING_TYPE_UINT8) {
        if (imIn->bands == imOut->bands && imIn->type == imOut->type) {
            switch (imIn->bands) {
            case 1:
                point = im_point_8_8;
                break;
            case 2:
                point = im_point_2x8_2x8;
                break;
            case 3:
                point = im_point_3x8_3x8;
                break;
            case 4:
                point = im_point_4x8_4x8;
                break;
            default:
                /* this cannot really happen */
                point = im_point_8_8;
                break;
            }
        } else
            point = im_point_8_32;
    } else
        point = im_point_32_8;

    ImagingCopyInfo(imOut, imIn);

    ImagingSectionEnter(&cookie);

    context.table = table;
    point(imOut, imIn, &context);

    ImagingSectionLeave(&cookie);

    return imOut;

mode_mismatch:
    return (Imaging) ImagingError_ValueError(
               "point operation not supported for this mode"
           );
}
コード例 #13
0
ファイル: Histo.c プロジェクト: 0xD34DC0DE/PIL
ImagingHistogram
ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
{
    ImagingSectionCookie cookie;
    int x, y, i;
    ImagingHistogram h;
    INT32 imin, imax;
    FLOAT32 fmin, fmax, scale;

    if (!im)
	return ImagingError_ModeError();

    if (imMask) {
	/* Validate mask */
	if (im->xsize != imMask->xsize || im->ysize != imMask->ysize)
	    return ImagingError_Mismatch();
	if (strcmp(imMask->mode, "1") != 0 && strcmp(imMask->mode, "L") != 0)
	    return ImagingError_ValueError("bad transparency mask");
    }

    h = ImagingHistogramNew(im);

    if (imMask) {
	/* mask */
	if (im->image8) {
            ImagingSectionEnter(&cookie);
	    for (y = 0; y < im->ysize; y++)
		for (x = 0; x < im->xsize; x++)
		    if (imMask->image8[y][x] != 0)
			h->histogram[im->image8[y][x]]++;
            ImagingSectionLeave(&cookie);
	} else { /* yes, we need the braces. C isn't Python! */
            if (im->type != IMAGING_TYPE_UINT8)
                return ImagingError_ModeError();
            ImagingSectionEnter(&cookie);
	    for (y = 0; y < im->ysize; y++) {
		UINT8* in = (UINT8*) im->image32[y];
		for (x = 0; x < im->xsize; x++)
		    if (imMask->image8[y][x] != 0) {
			h->histogram[(*in++)]++;
			h->histogram[(*in++)+256]++;
			h->histogram[(*in++)+512]++;
			h->histogram[(*in++)+768]++;
		    } else
			in += 4;
	    }
            ImagingSectionLeave(&cookie);
	}
    } else {
	/* mask not given; process pixels in image */
	if (im->image8) {
            ImagingSectionEnter(&cookie);
	    for (y = 0; y < im->ysize; y++)
		for (x = 0; x < im->xsize; x++)
		    h->histogram[im->image8[y][x]]++;
            ImagingSectionLeave(&cookie);
	} else {
            switch (im->type) {
            case IMAGING_TYPE_UINT8:
                ImagingSectionEnter(&cookie);
                for (y = 0; y < im->ysize; y++) {
                    UINT8* in = (UINT8*) im->image[y];
                    for (x = 0; x < im->xsize; x++) {
                        h->histogram[(*in++)]++;
                        h->histogram[(*in++)+256]++;
                        h->histogram[(*in++)+512]++;
                        h->histogram[(*in++)+768]++;
                    }
                }
                ImagingSectionLeave(&cookie);
                break;
            case IMAGING_TYPE_INT32:
                if (!minmax)
                    return ImagingError_ValueError("min/max not given");
                if (!im->xsize || !im->ysize)
                    break;
                imin = ((INT32*) minmax)[0];
                imax = ((INT32*) minmax)[1];
                if (imin >= imax)
                    break;
                ImagingSectionEnter(&cookie);
                scale = 255.0F / (imax - imin);
                for (y = 0; y < im->ysize; y++) {
                    INT32* in = im->image32[y];
                    for (x = 0; x < im->xsize; x++) {
                        i = (int) (((*in++)-imin)*scale);
                        if (i >= 0 && i < 256)
                            h->histogram[i]++;
                    }
                }
                ImagingSectionLeave(&cookie);
                break;
            case IMAGING_TYPE_FLOAT32:
                if (!minmax)
                    return ImagingError_ValueError("min/max not given");
                if (!im->xsize || !im->ysize)
                    break;
                fmin = ((FLOAT32*) minmax)[0];
                fmax = ((FLOAT32*) minmax)[1];
                if (fmin >= fmax)
                    break;
                ImagingSectionEnter(&cookie);
                scale = 255.0F / (fmax - fmin);
                for (y = 0; y < im->ysize; y++) {
                    FLOAT32* in = (FLOAT32*) im->image32[y];
                    for (x = 0; x < im->xsize; x++) {
                        i = (int) (((*in++)-fmin)*scale);
                        if (i >= 0 && i < 256)
                            h->histogram[i]++;
                    }
                }
                ImagingSectionLeave(&cookie);
                break;
            }
        }
    }

    return h;
}
コード例 #14
0
ファイル: ZipEncode.c プロジェクト: Dormouse759/Pillow
int
ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
{
    ZIPSTATE* context = (ZIPSTATE*) state->context;
    int err;
    int compress_level, compress_type;
    UINT8* ptr;
    int i, bpp, s, sum;
    ImagingSectionCookie cookie;

    if (!state->state) {

        /* Initialization */

        /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */

        /* overflow check for malloc */
        if (state->bytes > INT_MAX - 1) {
            state->errcode = IMAGING_CODEC_MEMORY;
            return -1;
        }

        /* Expand standard buffer to make room for the filter selector,
           and allocate filter buffers */
        free(state->buffer);
        /* malloc check ok, overflow checked above */
        state->buffer = (UINT8*) malloc(state->bytes+1);
        context->previous = (UINT8*) malloc(state->bytes+1);
        context->prior = (UINT8*) malloc(state->bytes+1);
        context->up = (UINT8*) malloc(state->bytes+1);
        context->average = (UINT8*) malloc(state->bytes+1);
        context->paeth = (UINT8*) malloc(state->bytes+1);
        if (!state->buffer || !context->previous || !context->prior ||
            !context->up || !context->average || !context->paeth) {
            free(context->paeth);
            free(context->average);
            free(context->up);
            free(context->prior);
            free(context->previous);
            state->errcode = IMAGING_CODEC_MEMORY;
            return -1;
        }

        /* Initialise filter buffers */
        state->buffer[0] = 0;
        context->prior[0] = 1;
        context->up[0] = 2;
        context->average[0] = 3;
        context->paeth[0] = 4;

        /* Initialise previous buffer to black */
        memset(context->previous, 0, state->bytes+1);

        /* Setup compression context */
        context->z_stream.zalloc = (alloc_func)0;
        context->z_stream.zfree = (free_func)0;
        context->z_stream.opaque = (voidpf)0;
        context->z_stream.next_in = 0;
        context->z_stream.avail_in = 0;

        compress_level = (context->optimize) ? Z_BEST_COMPRESSION
                                             : context->compress_level;

        if (context->compress_type == -1) {
            compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED
                                                       : Z_DEFAULT_STRATEGY;
        } else {
            compress_type = context->compress_type;
        }

        err = deflateInit2(&context->z_stream,
                           /* compression level */
                           compress_level,
                           /* compression method */
                           Z_DEFLATED,
                           /* compression memory resources */
                           15, 9,
                           /* compression strategy (image data are filtered)*/
                           compress_type);
        if (err < 0) {
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
        }

        if (context->dictionary && context->dictionary_size > 0) {
            err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary,
                                       context->dictionary_size);
            if (err < 0) {
                state->errcode = IMAGING_CODEC_CONFIG;
                return -1;
            }
        }

        /* Ready to decode */
        state->state = 1;

    }

    /* Setup the destination buffer */
    context->z_stream.next_out = buf;
    context->z_stream.avail_out = bytes;
    if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
        /* We have some data from previous round, deflate it first */
        err = deflate(&context->z_stream, Z_NO_FLUSH);

        if (err < 0) {
            /* Something went wrong inside the compression library */
            if (err == Z_DATA_ERROR)
                state->errcode = IMAGING_CODEC_BROKEN;
            else if (err == Z_MEM_ERROR)
                state->errcode = IMAGING_CODEC_MEMORY;
            else
                state->errcode = IMAGING_CODEC_CONFIG;
            free(context->paeth);
            free(context->average);
            free(context->up);
            free(context->prior);
            free(context->previous);
            deflateEnd(&context->z_stream);
            return -1;
        }
    }

    ImagingSectionEnter(&cookie);
    for (;;) {

        switch (state->state) {

        case 1:

            /* Compress image data */
            while (context->z_stream.avail_out > 0) {

                if (state->y >= state->ysize) {
                    /* End of image; now flush compressor buffers */
                    state->state = 2;
                    break;

                }

                /* Stuff image data into the compressor */
                state->shuffle(state->buffer+1,
                               (UINT8*) im->image[state->y + state->yoff] +
                               state->xoff * im->pixelsize,
                               state->xsize);

                state->y++;

                context->output = state->buffer;

                if (context->mode == ZIP_PNG) {

                    /* Filter the image data.  For each line, select
                       the filter that gives the least total distance
                       from zero for the filtered data (taken from
                       LIBPNG) */

                    bpp = (state->bits + 7) / 8;

                    /* 0. No filter */
                    for (i = 1, sum = 0; i <= state->bytes; i++) {
                        UINT8 v = state->buffer[i];
                        sum += (v < 128) ? v : 256 - v;
                    }

                    /* 2. Up.  We'll test this first to save time when
                       an image line is identical to the one above. */
                    if (sum > 0) {
                        for (i = 1, s = 0; i <= state->bytes; i++) {
                            UINT8 v = state->buffer[i] - context->previous[i];
                            context->up[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->up;
                            sum = s; /* 0 if line was duplicated */
                        }
                    }

                    /* 1. Prior */
                    if (sum > 0) {
                        for (i = 1, s = 0; i <= bpp; i++) {
                            UINT8 v = state->buffer[i];
                            context->prior[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        for (; i <= state->bytes; i++) {
                            UINT8 v = state->buffer[i] - state->buffer[i-bpp];
                            context->prior[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->prior;
                            sum = s; /* 0 if line is solid */
                        }
                    }

                    /* 3. Average (not very common in real-life images,
                       so its only used with the optimize option) */
                    if (context->optimize && sum > 0) {
                        for (i = 1, s = 0; i <= bpp; i++) {
                            UINT8 v = state->buffer[i] - context->previous[i]/2;
                            context->average[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        for (; i <= state->bytes; i++) {
                            UINT8 v = state->buffer[i] -
                                      (state->buffer[i-bpp] + context->previous[i])/2;
                            context->average[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->average;
                            sum = s;
                        }
                    }

                    /* 4. Paeth */
                    if (sum > 0) {
                        for (i = 1, s = 0; i <= bpp; i++) {
                            UINT8 v = state->buffer[i] - context->previous[i];
                            context->paeth[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        for (; i <= state->bytes; i++) {
                            UINT8 v;
                            int a, b, c;
                            int pa, pb, pc;

                            /* fetch pixels */
                            a = state->buffer[i-bpp];
                            b = context->previous[i];
                            c = context->previous[i-bpp];

                            /* distances to surrounding pixels */
                            pa = abs(b - c);
                            pb = abs(a - c);
                            pc = abs(a + b - 2*c);

                            /* pick predictor with the shortest distance */
                            v = state->buffer[i] -
                                ((pa <= pb && pa <= pc) ? a :
                                 (pb <= pc) ? b : c);
                            context->paeth[i] = v;
                            s += (v < 128) ? v : 256 - v;
                        }
                        if (s < sum) {
                            context->output = context->paeth;
                            sum = s;
                        }
                    }
                }

                /* Compress this line */
                context->z_stream.next_in = context->output;
                context->z_stream.avail_in = state->bytes+1;

                err = deflate(&context->z_stream, Z_NO_FLUSH);

                if (err < 0) {
                    /* Something went wrong inside the compression library */
                    if (err == Z_DATA_ERROR)
                        state->errcode = IMAGING_CODEC_BROKEN;
                    else if (err == Z_MEM_ERROR)
                        state->errcode = IMAGING_CODEC_MEMORY;
                    else
                        state->errcode = IMAGING_CODEC_CONFIG;
                    free(context->paeth);
                    free(context->average);
                    free(context->up);
                    free(context->prior);
                    free(context->previous);
                    deflateEnd(&context->z_stream);
                    ImagingSectionLeave(&cookie);
                    return -1;
                }

                /* Swap buffer pointers */
                ptr = state->buffer;
                state->buffer = context->previous;
                context->previous = ptr;

            }

            if (context->z_stream.avail_out == 0)
                break; /* Buffer full */

        case 2:

            /* End of image data; flush compressor buffers */

            while (context->z_stream.avail_out > 0) {

                err = deflate(&context->z_stream, Z_FINISH);

                if (err == Z_STREAM_END) {

                    free(context->paeth);
                    free(context->average);
                    free(context->up);
                    free(context->prior);
                    free(context->previous);

                    deflateEnd(&context->z_stream);

                    state->errcode = IMAGING_CODEC_END;

                    break;
                }

                if (context->z_stream.avail_out == 0)
                    break; /* Buffer full */

            }

        }
        ImagingSectionLeave(&cookie);
        return bytes - context->z_stream.avail_out;

    }

    /* Should never ever arrive here... */
    state->errcode = IMAGING_CODEC_CONFIG;
    ImagingSectionLeave(&cookie);
    return -1;
}
コード例 #15
0
static Imaging
gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding)
{
    ImagingSectionCookie cookie;

    float *maskData = NULL;
    int y = 0;
    int x = 0;
    float z = 0;
    float sum = 0.0;
    float dev = 0.0;

    float *buffer = NULL;

    int *line = NULL;
    UINT8 *line8 = NULL;

    int pix = 0;
    float newPixel[4];
    int channel = 0;
    int offset = 0;
    INT32 newPixelFinals;

    int radius = 0;
    float remainder = 0.0;

    int i;

    /* Do the gaussian blur */

    /* For a symmetrical gaussian blur, instead of doing a radius*radius
       matrix lookup, you get the EXACT same results by doing a radius*1
       transform, followed by a 1*radius transform.  This reduces the
       number of lookups exponentially (10 lookups per pixel for a
       radius of 5 instead of 25 lookups).  So, we blur the lines first,
       then we blur the resulting columns. */

    /* first, round radius off to the next higher integer and hold the
       remainder this is used so we can support float radius values
       properly. */

    remainder = floatRadius - ((int) floatRadius);
    floatRadius = ceil(floatRadius);

    /* Next, double the radius and offset by 2.0... that way "0" returns
       the original image instead of a black one.  We multiply it by 2.0
       so that it is a true "radius", not a diameter (the results match
       other paint programs closer that way too). */
    radius = (int) ((floatRadius * 2.0) + 2.0);

    /* create the maskData for the gaussian curve */
    maskData = malloc(radius * sizeof(float));
    /* FIXME: error checking */
    for (x = 0; x < radius; x++) {
	z = ((float) (x + 2) / ((float) radius));
	dev = 0.5 + (((float) (radius * radius)) * 0.001);
	/* you can adjust this factor to change the shape/center-weighting
	   of the gaussian */
	maskData[x] = (float) pow((1.0 / sqrt(2.0 * 3.14159265359 * dev)),
				  ((-(z - 1.0) * -(x - 1.0)) /
				   (2.0 * dev)));
    }

    /* if there's any remainder, multiply the first/last values in
       MaskData it.  this allows us to support float radius values. */
    if (remainder > 0.0) {
	maskData[0] *= remainder;
	maskData[radius - 1] *= remainder;
    }

    for (x = 0; x < radius; x++) {
	/* this is done separately now due to the correction for float
	   radius values above */
	sum += maskData[x];
    }

    for (i = 0; i < radius; i++) {
	maskData[i] *= (1.0 / sum);
	/* printf("%f\n", maskData[i]); */
    }

    /* create a temporary memory buffer for the data for the first pass
       memset the buffer to 0 so we can use it directly with += */

    /* don't bother about alpha/padding */
    buffer = calloc((size_t) (im->xsize * im->ysize * channels),
		    sizeof(float));
    if (buffer == NULL)
	return ImagingError_MemoryError();

    /* be nice to other threads while you go off to lala land */
    ImagingSectionEnter(&cookie);

    /* memset(buffer, 0, sizeof(buffer)); */

    newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;

    /* perform a blur on each line, and place in the temporary storage buffer */
    for (y = 0; y < im->ysize; y++) {
	if (channels == 1 && im->image8 != NULL) {
	    line8 = (UINT8 *) im->image8[y];
	} else {
	    line = im->image32[y];
	}
	for (x = 0; x < im->xsize; x++) {
	    newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;
	    /* for each neighbor pixel, factor in its value/weighting to the
	       current pixel */
	    for (pix = 0; pix < radius; pix++) {
		/* figure the offset of this neighbor pixel */
		offset =
		    (int) ((-((float) radius / 2.0) + (float) pix) + 0.5);
		if (x + offset < 0)
		    offset = -x;
		else if (x + offset >= im->xsize)
		    offset = im->xsize - x - 1;

		/* add (neighbor pixel value * maskData[pix]) to the current
		   pixel value */
		if (channels == 1) {
		    buffer[(y * im->xsize) + x] +=
			((float) ((UINT8 *) & line8[x + offset])[0]) *
			(maskData[pix]);
		} else {
		    for (channel = 0; channel < channels; channel++) {
			buffer[(y * im->xsize * channels) +
			       (x * channels) + channel] +=
			    ((float) ((UINT8 *) & line[x + offset])
			     [channel]) * (maskData[pix]);
		    }
		}
	    }
	}
    }

    /* perform a blur on each column in the buffer, and place in the
       output image */
    for (x = 0; x < im->xsize; x++) {
	for (y = 0; y < im->ysize; y++) {
	    newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0;
	    /* for each neighbor pixel, factor in its value/weighting to the
	       current pixel */
	    for (pix = 0; pix < radius; pix++) {
		/* figure the offset of this neighbor pixel */
		offset =
		    (int) (-((float) radius / 2.0) + (float) pix + 0.5);
		if (y + offset < 0)
		    offset = -y;
		else if (y + offset >= im->ysize)
		    offset = im->ysize - y - 1;
		/* add (neighbor pixel value * maskData[pix]) to the current
		   pixel value */
		for (channel = 0; channel < channels; channel++) {
		    newPixel[channel] +=
			(buffer
			 [((y + offset) * im->xsize * channels) +
			  (x * channels) + channel]) * (maskData[pix]);
		}
	    }
	    /* if the image is RGBX or RGBA, copy the 4th channel data to
	       newPixel, so it gets put in imOut */
	    if (strcmp(im->mode, "RGBX") == 0
		|| strcmp(im->mode, "RGBA") == 0) {
	      newPixel[3] = (float) ((UINT8 *) & line[x + offset])[3];
	    }

	    /* pack the channels into an INT32 so we can put them back in
	       the PIL image */
	    newPixelFinals = 0;
	    if (channels == 1) {
		newPixelFinals = clip(newPixel[0]);
	    } else {
		/* for RGB, the fourth channel isn't used anyways, so just
		   pack a 0 in there, this saves checking the mode for each
		   pixel. */
		/* this doesn't work on little-endian machines... fix it! */
		newPixelFinals =
		    clip(newPixel[0]) | clip(newPixel[1]) << 8 |
		    clip(newPixel[2]) << 16 | clip(newPixel[3]) << 24;
	    }
	    /* set the resulting pixel in imOut */
	    if (channels == 1) {
		imOut->image8[y][x] = (UINT8) newPixelFinals;
	    } else {
		imOut->image32[y][x] = newPixelFinals;
	    }
	}
    }

    /* free the buffer */
    free(buffer);

    /* get the GIL back so Python knows who you are */
    ImagingSectionLeave(&cookie);

    return imOut;
}
コード例 #16
0
Imaging
ImagingUnsharpMask(Imaging im, Imaging imOut, float radius, int percent,
		   int threshold)
{
    ImagingSectionCookie cookie;

    Imaging result;
    int channel = 0;
    int channels = 0;
    int padding = 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(im->mode, "RGB") == 0) {
	channels = 3;
	padding = 1;
    } else if (strcmp(im->mode, "RGBA") == 0) {
	channels = 3;
	padding = 1;
    } else if (strcmp(im->mode, "RGBX") == 0) {
	channels = 3;
	padding = 1;
    } else if (strcmp(im->mode, "CMYK") == 0) {
	channels = 4;
	padding = 0;
    } else if (strcmp(im->mode, "L") == 0) {
	channels = 1;
	padding = 0;
    } else
	return ImagingError_ModeError();

    /* first, do a gaussian blur on the image, putting results in imOut
       temporarily */
    result = gblur(im, imOut, radius, channels, padding);
    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);

    for (y = 0; y < im->ysize; y++) {
	if (channels == 1) {
	    lineIn8 = im->image8[y];
	    lineOut8 = imOut->image8[y];
	} else {
	    lineIn = im->image32[y];
	    lineOut = imOut->image32[y];
	}
	for (x = 0; x < im->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 (strcmp(im->mode, "RGBX") == 0
		    || strcmp(im->mode, "RGBA") == 0) {
		    /* 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;
}