Example #1
0
Imaging
ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4])
{
    struct filter *filterp;
    ResampleFunction ResampleHorizontal;
    ResampleFunction ResampleVertical;

    if (strcmp(imIn->mode, "P") == 0 || strcmp(imIn->mode, "1") == 0)
        return (Imaging) ImagingError_ModeError();

    if (imIn->type == IMAGING_TYPE_SPECIAL) {
        return (Imaging) ImagingError_ModeError();
    } else if (imIn->image8) {
        ResampleHorizontal = ImagingResampleHorizontal_8bpc;
        ResampleVertical = ImagingResampleVertical_8bpc;
    } else {
        switch(imIn->type) {
            case IMAGING_TYPE_UINT8:
                ResampleHorizontal = ImagingResampleHorizontal_8bpc;
                ResampleVertical = ImagingResampleVertical_8bpc;
                break;
            case IMAGING_TYPE_INT32:
            case IMAGING_TYPE_FLOAT32:
                ResampleHorizontal = ImagingResampleHorizontal_32bpc;
                ResampleVertical = ImagingResampleVertical_32bpc;
                break;
            default:
                return (Imaging) ImagingError_ModeError();
        }
    }

    /* check filter */
    switch (filter) {
    case IMAGING_TRANSFORM_BOX:
        filterp = &BOX;
        break;
    case IMAGING_TRANSFORM_BILINEAR:
        filterp = &BILINEAR;
        break;
    case IMAGING_TRANSFORM_HAMMING:
        filterp = &HAMMING;
        break;
    case IMAGING_TRANSFORM_BICUBIC:
        filterp = &BICUBIC;
        break;
    case IMAGING_TRANSFORM_LANCZOS:
        filterp = &LANCZOS;
        break;
    default:
        return (Imaging) ImagingError_ValueError(
            "unsupported resampling filter"
            );
    }

    return ImagingResampleInner(imIn, xsize, ysize, filterp, box,
                                ResampleHorizontal, ResampleVertical);
}
Example #2
0
Imaging
ImagingRankFilter(Imaging im, int size, int rank)
{
    Imaging imOut = NULL;
    int x, y;
    int i, margin, size2;

    if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL)
	return (Imaging) ImagingError_ModeError();

    if (!(size & 1))
	return (Imaging) ImagingError_ValueError("bad filter size");

    size2 = size * size;
    margin = (size-1) / 2;

    if (rank < 0 || rank >= size2)
	return (Imaging) ImagingError_ValueError("bad rank value");

    imOut = ImagingNew(im->mode, im->xsize - 2*margin, im->ysize - 2*margin);
    if (!imOut)
	return NULL;

#define RANK_BODY(type) do {\
    type* buf = malloc(size2 * sizeof(type));\
    if (!buf)\
        goto nomemory;\
    for (y = 0; y < imOut->ysize; y++)\
        for (x = 0; x < imOut->xsize; x++) {\
            for (i = 0; i < size; i++)\
                memcpy(buf + i*size, &IMAGING_PIXEL_##type(im, x, y+i),\
                       size * sizeof(type));\
            IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank);\
        }\
} while (0)

    if (im->image8)
        RANK_BODY(UINT8);
    else if (im->type == IMAGING_TYPE_INT32)
        RANK_BODY(INT32);
    else if (im->type == IMAGING_TYPE_FLOAT32)
        RANK_BODY(FLOAT32);
    else {
        /* safety net (we shouldn't end up here) */
        ImagingDelete(imOut);
        return (Imaging) ImagingError_ModeError();
    }
    
    ImagingCopyInfo(imOut, im);

    return imOut;

nomemory:
    ImagingDelete(imOut);
    return (Imaging) ImagingError_MemoryError();
}
Example #3
0
Imaging
ImagingConvertMatrix(Imaging im, const char *mode, float m[])
{
    Imaging imOut;
    int x, y;

    /* Assume there's enough data in the buffer */
    if (!im)
        return (Imaging) ImagingError_ModeError();

    if (strcmp(mode, "L") == 0 && im->bands == 3) {

        imOut = ImagingNew("L", im->xsize, im->ysize);
        if (!imOut)
            return NULL;

        for (y = 0; y < im->ysize; y++) {
            UINT8* in = (UINT8*) im->image[y];
            UINT8* out = (UINT8*) imOut->image[y];

            for (x = 0; x < im->xsize; x++) {
                float v = m[0]*in[0] + m[1]*in[1] + m[2]*in[2] + m[3] + 0.5;
                out[x] = CLIPF(v);
                in += 4;
            }
        }

    } else if (strlen(mode) == 3 && im->bands == 3) {

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

        for (y = 0; y < im->ysize; y++) {
            UINT8* in = (UINT8*) im->image[y];
            UINT8* out = (UINT8*) imOut->image[y];

            for (x = 0; x < im->xsize; x++) {
                float v0 = m[0]*in[0] + m[1]*in[1] +  m[2]*in[2] +  m[3] + 0.5;
                float v1 = m[4]*in[0] + m[5]*in[1] +  m[6]*in[2] +  m[7] + 0.5;
                float v2 = m[8]*in[0] + m[9]*in[1] + m[10]*in[2] + m[11] + 0.5;
                out[0] = CLIPF(v0);
                out[1] = CLIPF(v1);
                out[2] = CLIPF(v2);
                in += 4;
                out += 4;
            }
        }
    } else
        return (Imaging) ImagingError_ModeError();

    return imOut;
}
Example #4
0
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;
}
Example #5
0
Imaging
ImagingFillRadialGradient(const char *mode)
{
    Imaging im;
    int x, y;
    int d;

    if (strlen(mode) != 1)
	return (Imaging) ImagingError_ModeError();

    im = ImagingNew(mode, 256, 256);
    if (!im)
	return NULL;

    for (y = 0; y < 256; y++)
	for (x = 0; x < 256; x++) {
	    d = (int) sqrt((double) ((x-128)*(x-128) + (y-128)*(y-128)) * 2.0);
	    if (d >= 255)
		im->image8[y][x] = 255;
	    else
		im->image8[y][x] = d;
	}

    return im;
}
Example #6
0
Imaging
ImagingFillBand(Imaging imOut, int band, int color)
{
    int x, y;

    /* Check arguments */
    if (!imOut || imOut->type != IMAGING_TYPE_UINT8)
	return (Imaging) ImagingError_ModeError();

    if (band < 0 || band >= imOut->bands)
	return (Imaging) ImagingError_ValueError("band index out of range");

    /* Special case for LXXA etc */
    if (imOut->bands == 2 && band == 1)
        band = 3;

    color = CLIP(color);

    /* Insert color into image */
    for (y = 0; y < imOut->ysize; y++) {
	UINT8* out = (UINT8*) imOut->image[y] + band;
	for (x = 0; x < imOut->xsize; x++) {
	    *out = (UINT8) color;
	    out += 4;
	}
    }

    return imOut;
}
Example #7
0
ImagingPalette
ImagingPaletteNew(const char* mode)
{
    /* Create a palette object */

    int i;
    ImagingPalette palette;

    if (strcmp(mode, "RGB") && strcmp(mode, "RGBA"))
	return (ImagingPalette) ImagingError_ModeError();

    palette = calloc(1, sizeof(struct ImagingPaletteInstance));
    if (!palette)
	return (ImagingPalette) ImagingError_MemoryError();

    strncpy(palette->mode, mode, IMAGING_MODE_LENGTH);

    /* Initialize to ramp */
    for (i = 0; i < 256; i++) {
	palette->palette[i*4+0] =
	palette->palette[i*4+1] =
	palette->palette[i*4+2] = (UINT8) i;
	palette->palette[i*4+3] = 255; /* opaque */
    }

    return palette;
}
Example #8
0
Imaging ImagingGaussianBlur(Imaging im, Imaging imOut, float radius)
{
    int channels = 0;
    int padding = 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();

    return gblur(im, imOut, radius, channels, padding);
}
Example #9
0
Imaging
ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha)
{
    Imaging imOut;
    int x, y;

    /* Check arguments */
    if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8)
	return ImagingError_ModeError();
    if (imIn1->type  != imIn2->type  ||
	imIn1->bands != imIn2->bands ||
	imIn1->xsize != imIn2->xsize ||
	imIn1->ysize != imIn2->ysize)
	return ImagingError_Mismatch();

    /* Shortcuts */
    if (alpha == 0.0)
	return ImagingCopy(imIn1);
    else if (alpha == 1.0)
	return ImagingCopy(imIn2);

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

    ImagingCopyInfo(imOut, imIn1);

    if (alpha >= 0 && alpha <= 1.0) {
	/* Interpolate between bands */
	for (y = 0; y < imIn1->ysize; y++) {
	    UINT8* in1 = (UINT8*) imIn1->image[y];
	    UINT8* in2 = (UINT8*) imIn2->image[y];
	    UINT8* out = (UINT8*) imOut->image[y];
	    for (x = 0; x < imIn1->linesize; x++)
		out[x] = (UINT8)
		    ((int) in1[x] + alpha * ((int) in2[x] - (int) in1[x]));
	}
    } else {
	/* Extrapolation; must make sure to clip resulting values */
	for (y = 0; y < imIn1->ysize; y++) {
	    UINT8* in1 = (UINT8*) imIn1->image[y];
	    UINT8* in2 = (UINT8*) imIn2->image[y];
	    UINT8* out = (UINT8*) imOut->image[y];
	    for (x = 0; x < imIn1->linesize; x++) {
		float temp =
		    ((int) in1[x] + alpha * ((int) in2[x] - (int) in1[x]));
		if (temp <= 0.0)
		    out[x] = 0;
		else if (temp >= 255.0)
		    out[x] = 255;
		else
		    out[x] = (UINT8) temp;
	    }
	}
    }

    return imOut;
}
Example #10
0
Imaging
ImagingFillLinearGradient(const char *mode)
{
    Imaging im;
    int y;

    if (strlen(mode) != 1)
	return (Imaging) ImagingError_ModeError();

    im = ImagingNew(mode, 256, 256);
    if (!im)
	return NULL;

    for (y = 0; y < 256; y++)
	memset(im->image8[y], (unsigned char) y, 256);

    return im;
}
Example #11
0
Imaging
ImagingNegative(Imaging im)
{
    Imaging imOut;
    int x, y;

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

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

    for (y = 0; y < im->ysize; y++)
	for (x = 0; x < im->linesize; x++)
	     imOut->image[y][x] = ~im->image[y][x];

    return imOut;
}
Example #12
0
Imaging
ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1)
{
    Imaging imOut;
    int xsize, ysize;
    int dx0, dy0, dx1, dy1;
    INT32 zero = 0;
    
    if (!imIn)
	return (Imaging) ImagingError_ModeError();

    xsize = sx1 - sx0;
    if (xsize < 0)
        xsize = 0;
    ysize = sy1 - sy0;
    if (ysize < 0)
        ysize = 0;

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

    ImagingCopyInfo(imOut, imIn);

    if (sx0 < 0 || sy0 < 0 || sx1 > imIn->xsize || sy1 > imIn->ysize)
	(void) ImagingFill(imOut, &zero);

    dx0 = -sx0;
    dy0 = -sy0;
    dx1 = imIn->xsize - sx0;
    dy1 = imIn->ysize - sy0;

    /* paste the source image on top of the output image!!! */
    if (ImagingPaste(imOut, imIn, NULL, dx0, dy0, dx1, dy1) < 0) {
        ImagingDelete(imOut);
        return NULL;
    }

    return imOut;
}
Example #13
0
Imaging
ImagingGetBand(Imaging imIn, int band)
{
    Imaging imOut;
    int x, y;

    /* Check arguments */
    if (!imIn || imIn->type != IMAGING_TYPE_UINT8)
	return (Imaging) ImagingError_ModeError();

    if (band < 0 || band >= imIn->bands)
	return (Imaging) ImagingError_ValueError("band index out of range");

    /* Shortcuts */
    if (imIn->bands == 1)
	return ImagingCopy(imIn);

    /* Special case for LXXA etc */
    if (imIn->bands == 2 && band == 1)
        band = 3;

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

    /* Extract band from image */
    for (y = 0; y < imIn->ysize; y++) {
	UINT8* in = (UINT8*) imIn->image[y] + band;
	UINT8* out = imOut->image8[y];
	for (x = 0; x < imIn->xsize; x++) {
	    out[x] = *in;
	    in += 4;
	}
    }

    return imOut;
}
Example #14
0
Imaging
ImagingPutBand(Imaging imOut, Imaging imIn, int band)
{
    int x, y;

    /* Check arguments */
    if (!imIn || imIn->bands != 1 || !imOut)
	return (Imaging) ImagingError_ModeError();

    if (band < 0 || band >= imOut->bands)
	return (Imaging) ImagingError_ValueError("band index out of range");

    if (imIn->type  != imOut->type  ||
	imIn->xsize != imOut->xsize ||
	imIn->ysize != imOut->ysize)
	return (Imaging) ImagingError_Mismatch();

    /* Shortcuts */
    if (imOut->bands == 1)
	return ImagingCopy2(imOut, imIn);

    /* Special case for LXXA etc */
    if (imOut->bands == 2 && band == 1)
        band = 3;

    /* Insert band into image */
    for (y = 0; y < imIn->ysize; y++) {
	UINT8* in = imIn->image8[y];
	UINT8* out = (UINT8*) imOut->image[y] + band;
	for (x = 0; x < imIn->xsize; x++) {
	    *out = in[x];
	    out += 4;
	}
    }

    return imOut;
}
Example #15
0
Imaging
ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32* kernel,
              FLOAT32 offset, FLOAT32 divisor)
{
    Imaging imOut;
    int x, y;
    FLOAT32 sum;

    if (!im || strcmp(im->mode, "L") != 0)
	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 = ImagingNew(im->mode, im->xsize, im->ysize);
    if (!imOut)
	return NULL;

    /* brute force kernel implementations */
#define	KERNEL3x3(image, kernel, d) ( \
    (int) image[y+1][x-d] * kernel[0] + \
    (int) image[y+1][x]   * kernel[1] + \
    (int) image[y+1][x+d] * kernel[2] + \
    (int) image[y][x-d]   * kernel[3] + \
    (int) image[y][x]     * kernel[4] + \
    (int) image[y][x+d]   * kernel[5] + \
    (int) image[y-1][x-d] * kernel[6] + \
    (int) image[y-1][x]   * kernel[7] + \
    (int) image[y-1][x+d] * kernel[8])

#define	KERNEL5x5(image, kernel, d) ( \
    (int) image[y+2][x-d-d] * kernel[0] + \
    (int) image[y+2][x-d]   * kernel[1] + \
    (int) image[y+2][x]     * kernel[2] + \
    (int) image[y+2][x+d]   * kernel[3] + \
    (int) image[y+2][x+d+d] * kernel[4] + \
    (int) image[y+1][x-d-d] * kernel[5] + \
    (int) image[y+1][x-d]   * kernel[6] + \
    (int) image[y+1][x]     * kernel[7] + \
    (int) image[y+1][x+d]   * kernel[8] + \
    (int) image[y+1][x+d+d] * kernel[9] + \
    (int) image[y][x-d-d]   * kernel[10] + \
    (int) image[y][x-d]     * kernel[11] + \
    (int) image[y][x]       * kernel[12] + \
    (int) image[y][x+d]     * kernel[13] + \
    (int) image[y][x+d+d]   * kernel[14] + \
    (int) image[y-1][x-d-d] * kernel[15] + \
    (int) image[y-1][x-d]   * kernel[16] + \
    (int) image[y-1][x]     * kernel[17] + \
    (int) image[y-1][x+d]   * kernel[18] + \
    (int) image[y-1][x+d+d] * kernel[19] + \
    (int) image[y-2][x-d-d] * kernel[20] + \
    (int) image[y-2][x-d]   * kernel[21] + \
    (int) image[y-2][x]     * kernel[22] + \
    (int) image[y-2][x+d]   * kernel[23] + \
    (int) image[y-2][x+d+d] * kernel[24])

    if (xsize == 3) {
	/* 3x3 kernel. */
	for (x = 0; x < im->xsize; x++)
	    imOut->image[0][x] = im->image8[0][x];
	for (y = 1; y < im->ysize-1; y++) {
	    imOut->image[y][0] = im->image8[y][0];
	    for (x = 1; x < im->xsize-1; x++) {
		sum = KERNEL3x3(im->image8, kernel, 1) / divisor + offset;
		if (sum <= 0)
		    imOut->image8[y][x] = 0;
		else if (sum >= 255)
		    imOut->image8[y][x] = 255;
		else
		    imOut->image8[y][x] = (UINT8) sum;
	     }
	    imOut->image8[y][x] = im->image8[y][x];
	}
	for (x = 0; x < im->xsize; x++)
	    imOut->image8[y][x] = im->image8[y][x];
    } else {
	/* 5x5 kernel. */
	for (y = 0; y < 2; y++)
	    for (x = 0; x < im->xsize; x++)
		imOut->image8[y][x] = im->image8[y][x];
	for (; y < im->ysize-2; y++) {
	    for (x = 0; x < 2; x++)
		imOut->image8[y][x] = im->image8[y][x];
	    for (; x < im->xsize-2; x++) {
		sum = KERNEL5x5(im->image8, kernel, 1) / divisor + offset;
		if (sum <= 0)
		    imOut->image8[y][x] = 0;
		else if (sum >= 255)
		    imOut->image8[y][x] = 255;
		else
		    imOut->image8[y][x] = (UINT8) sum;
	    }
	    for (; x < im->xsize; x++)
		imOut->image8[y][x] = im->image8[y][x];
	}
	for (; y < im->ysize; y++)
	    for (x = 0; x < im->xsize; x++)
		imOut->image8[y][x] = im->image8[y][x];
    }
    return imOut;
}
Example #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;
}
Example #17
0
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;
}
Example #18
0
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;
}
Example #19
0
ImagingDIB
ImagingNewDIB(const char *mode, int xsize, int ysize)
{
    /* Create a Windows bitmap */

    ImagingDIB dib;
    RGBQUAD *palette;
    int i;

    /* Check mode */
    if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 &&
        strcmp(mode, "RGB") != 0)
        return (ImagingDIB) ImagingError_ModeError();

    /* Create DIB context and info header */
    /* malloc check ok, small constant allocation */
    dib = (ImagingDIB) malloc(sizeof(*dib));
    if (!dib)
        return (ImagingDIB) ImagingError_MemoryError();
    /* malloc check ok, small constant allocation */
    dib->info = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER) +
                                     256 * sizeof(RGBQUAD));
    if (!dib->info) {
        free(dib);
        return (ImagingDIB) ImagingError_MemoryError();
    }

    memset(dib->info, 0, sizeof(BITMAPINFOHEADER));
    dib->info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    dib->info->bmiHeader.biWidth = xsize;
    dib->info->bmiHeader.biHeight = ysize;
    dib->info->bmiHeader.biPlanes = 1;
    dib->info->bmiHeader.biBitCount = strlen(mode)*8;
    dib->info->bmiHeader.biCompression = BI_RGB;

    /* Create DIB */
    dib->dc = CreateCompatibleDC(NULL);
    if (!dib->dc) {
        free(dib->info);
        free(dib);
        return (ImagingDIB) ImagingError_MemoryError();
    }

    dib->bitmap = CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS,
                                   &dib->bits, NULL, 0);
    if (!dib->bitmap) {
        free(dib->info);
        free(dib);
        return (ImagingDIB) ImagingError_MemoryError();
    }

    strcpy(dib->mode, mode);
    dib->xsize = xsize;
    dib->ysize = ysize;

    dib->pixelsize = strlen(mode);
    dib->linesize = (xsize * dib->pixelsize + 3) & -4;

    if (dib->pixelsize == 1)
        dib->pack = dib->unpack = (ImagingShuffler) memcpy;
    else {
        dib->pack = ImagingPackBGR;
        dib->unpack = ImagingPackBGR;
    }

    /* Bind the DIB to the device context */
    dib->old_bitmap = SelectObject(dib->dc, dib->bitmap);

    palette = dib->info->bmiColors;

    /* Bind a palette to it as well (only required for 8-bit DIBs) */
    if (dib->pixelsize == 1) {
        for (i = 0; i < 256; i++) {
            palette[i].rgbRed =
            palette[i].rgbGreen =
            palette[i].rgbBlue = i;
            palette[i].rgbReserved = 0;
        }
        SetDIBColorTable(dib->dc, 0, 256, palette);
    }

    /* Create an associated palette (for 8-bit displays only) */
    if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) {

        char palbuf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
        LPLOGPALETTE pal = (LPLOGPALETTE) palbuf;
        int i, r, g, b;

        /* Load system palette */
        pal->palVersion = 0x300;
        pal->palNumEntries = 256;
        GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry);

        if (strcmp(mode, "L") == 0) {

            /* Greyscale DIB.  Fill all 236 slots with a greyscale ramp
             * (this is usually overkill on Windows since VGA only offers
             * 6 bits greyscale resolution).  Ignore the slots already
             * allocated by Windows */

            i = 10;
            for (r = 0; r < 236; r++) {
                pal->palPalEntry[i].peRed =
                pal->palPalEntry[i].peGreen =
                pal->palPalEntry[i].peBlue = i;
                i++;
            }

            dib->palette = CreatePalette(pal);

        } else if (strcmp(mode, "RGB") == 0) {

#ifdef CUBE216

            /* Colour DIB.  Create a 6x6x6 colour cube (216 entries) and
             * add 20 extra greylevels for best result with greyscale
             * images. */

            i = 10;
            for (r = 0; r < 256; r += 51)
                for (g = 0; g < 256; g += 51)
                    for (b = 0; b < 256; b += 51) {
                        pal->palPalEntry[i].peRed = r;
                        pal->palPalEntry[i].peGreen = g;
                        pal->palPalEntry[i].peBlue = b;
                        i++;
                    }
            for (r = 1; r < 22-1; r++) {
                /* Black and white are already provided by the cube. */
                pal->palPalEntry[i].peRed =
                pal->palPalEntry[i].peGreen =
                pal->palPalEntry[i].peBlue = r * 255 / (22-1);
                i++;
            }

#else

            /* Colour DIB.  Alternate palette. */

            i = 10;
            for (r = 0; r < 256; r += 37)
                for (g = 0; g < 256; g += 32)
                    for (b = 0; b < 256; b += 64) {
                        pal->palPalEntry[i].peRed = r;
                        pal->palPalEntry[i].peGreen = g;
                        pal->palPalEntry[i].peBlue = b;
                        i++;
                    }

#endif

            dib->palette = CreatePalette(pal);

        }

    }

    return dib;
}
Example #20
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"
           );
}
Example #21
0
Imaging
ImagingAlphaComposite(Imaging imDst, Imaging imSrc)
{
    Imaging imOut;
    int x, y;

    /* Check arguments */
    if (!imDst || !imSrc ||
        strcmp(imDst->mode, "RGBA") ||
        imDst->type != IMAGING_TYPE_UINT8 ||
        imDst->bands != 4)
        return ImagingError_ModeError();

    if (strcmp(imDst->mode, imSrc->mode) ||
        imDst->type  != imSrc->type  ||
        imDst->bands != imSrc->bands ||
        imDst->xsize != imSrc->xsize ||
        imDst->ysize != imSrc->ysize)
        return ImagingError_Mismatch();

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

    ImagingCopyInfo(imOut, imDst);

    for (y = 0; y < imDst->ysize; y++) {

        rgba8* dst = (rgba8*) imDst->image[y];
        rgba8* src = (rgba8*) imSrc->image[y];
        rgba8* out = (rgba8*) imOut->image[y];

        for (x = 0; x < imDst->xsize; x ++) {

            if (src->a == 0) {
                // Copy 4 bytes at once.
                *out = *dst;
            } else {
                // Integer implementation with increased precision.
                // Each variable has extra meaningful bits.
                // Divisions are rounded.

                // This code uses trick from Paste.c:
                // (a + (2 << (n-1)) - 1) / ((2 << n)-1)
                // almost equivalent to:
                // tmp = a + (2 << (n-1)), ((tmp >> n) + tmp) >> n

                UINT16 blend = dst->a * (255 - src->a);
                UINT16 outa255 = src->a * 255 + blend;
                // There we use 7 bits for precision.
                // We could use more, but we go beyond 32 bits.
                UINT16 coef1 = src->a * 255 * 255 * 128 / outa255;
                UINT16 coef2 = blend * 255 * 128 / outa255;

                #define SHIFTFORDIV255(a)\
                    ((a >> 8) + a >> 8)

                UINT32 tmpr = src->r * coef1 + dst->r * coef2 + (0x80 << 7);
                out->r = SHIFTFORDIV255(tmpr) >> 7;
                UINT32 tmpg = src->g * coef1 + dst->g * coef2 + (0x80 << 7);
                out->g = SHIFTFORDIV255(tmpg) >> 7;
                UINT32 tmpb = src->b * coef1 + dst->b * coef2 + (0x80 << 7);
                out->b = SHIFTFORDIV255(tmpb) >> 7;
                out->a = SHIFTFORDIV255(outa255 + 0x80);
            }

            dst++; src++; out++;
        }

    }

    return imOut;
}
Example #22
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;
}
Example #23
0
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;
}