Example #1
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 #2
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 #3
0
Imaging
ImagingEffectSpread(Imaging imIn, int distance)
{
    /* Randomly spread pixels in an image */

    Imaging imOut;
    int x, y;

    imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);

    if (!imOut)
	return NULL;

#define	SPREAD(type, image)\
    for (y = 0; y < imIn->ysize; y++)\
	for (x = 0; x < imIn->xsize; x++) {\
            int xx = x + (rand() % distance) - distance/2;\
            int yy = y + (rand() % distance) - distance/2;\
            if (xx >= 0 && xx < imIn->xsize && yy >= 0 && yy < imIn->ysize) {\
                imOut->image[yy][xx] = imIn->image[y][x];\
                imOut->image[y][x]   = imIn->image[yy][xx];\
            } else\
                imOut->image[y][x]   = imIn->image[y][x];\
        }

    if (imIn->image8) {
	SPREAD(UINT8, image8);
    } else {
	SPREAD(INT32, image32);
    }

    ImagingCopyInfo(imOut, imIn);

    return imOut;
}
Example #4
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 #5
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 #6
0
Imaging
ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality)
{
    /* Generate a Mandelbrot set covering the given extent */

    Imaging im;
    int x, y, k;
    double width, height;
    double x1, y1, xi2, yi2, cr, ci, radius;
    double dr, di;

    /* Check arguments */
    width  = extent[2] - extent[0];
    height = extent[3] - extent[1];
    if (width < 0.0 || height < 0.0 || quality < 2)
        return (Imaging) ImagingError_ValueError(NULL);

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

    dr = width/(xsize-1);
    di = height/(ysize-1);

    radius = 100.0;

    for (y = 0; y < ysize; y++) {
        UINT8* buf = im->image8[y];
	for (x = 0; x < xsize; x++) {
	    x1 = y1 = xi2 = yi2 = 0.0;
	    cr = x*dr + extent[0];
	    ci = y*di + extent[1];
	    for (k = 1;; k++) {
		y1 = 2*x1*y1 + ci;
		x1 = xi2 - yi2 + cr;
		xi2 = x1*x1;
		yi2 = y1*y1;
		if ((xi2 + yi2) > radius) {
		    buf[x] = k*255/quality;
		    break;
		}
		if (k > quality) {
		    buf[x] = 0;
		    break;
		}
	    }
	}
    }
    return im;
}
Example #7
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 #8
0
Imaging
ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode)
{
    Imaging imOut;
    int x, y;

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

    imOut = ImagingNew(
        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);\
    }

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

    ImagingCopyInfo(imOut, imIn);

    return imOut;
}
Example #9
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 #10
0
Imaging
ImagingEffectNoise(int xsize, int ysize, float sigma)
{
    /* Generate gaussian noise centered around 128 */

    Imaging imOut;
    int x, y;
    int nextok;
    double this, next;

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

    next = 0.0;
    nextok = 0;

    for (y = 0; y < imOut->ysize; y++) {
        UINT8* out = imOut->image8[y];
	for (x = 0; x < imOut->xsize; x++) {
            if (nextok) {
                this = next;
                nextok = 0;
            } else {
                /* after numerical recepies */
                double v1, v2, radius, factor;
                do {
                    v1 = rand()*(2.0/32767.0) - 1.0;
                    v2 = rand()*(2.0/32767.0) - 1.0;
                    radius= v1*v1 + v2*v2;
                } while (radius >= 1.0);
                factor = sqrt(-2.0*log(radius)/radius);
                this = factor * v1;
                next = factor * v2;
            }
            out[x] = (unsigned char) (128 + sigma * this);
        }
    }

    return imOut;
}
Example #11
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 #12
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 #13
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 #14
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 #15
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 #16
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"
           );
}