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(); }
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; }
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; }
Imaging ImagingNewInternal(const char* mode, int xsize, int ysize, int dirty) { Imaging im; if (xsize < 0 || ysize < 0) { return (Imaging) ImagingError_ValueError("bad image size"); } im = ImagingNewPrologue(mode, xsize, ysize); if ( ! im) return NULL; if (ImagingAllocateArray(im, dirty, ImagingDefaultArena.block_size)) { return im; } ImagingError_Clear(); // Try to allocate the image once more with smallest possible block size if (ImagingAllocateArray(im, dirty, IMAGING_PAGE_SIZE)) { return im; } ImagingDelete(im); return NULL; }
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); }
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; }
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; }
Imaging ImagingNewBlock(const char* mode, int xsize, int ysize) { Imaging im; if (xsize < 0 || ysize < 0) { return (Imaging) ImagingError_ValueError("bad image size"); } im = ImagingNewPrologue(mode, xsize, ysize); if ( ! im) return NULL; if (ImagingAllocateBlock(im)) { return im; } ImagingDelete(im); return NULL; }
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; }
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; }
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; }
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; }
Imaging ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { Imaging im; /* linesize overflow check, roughly the current largest space req'd */ if (xsize > (INT_MAX / 4) - 1) { return (Imaging) ImagingError_MemoryError(); } im = (Imaging) calloc(1, size); if (!im) { return (Imaging) ImagingError_MemoryError(); } /* Setup image descriptor */ im->xsize = xsize; im->ysize = ysize; im->type = IMAGING_TYPE_UINT8; if (strcmp(mode, "1") == 0) { /* 1-bit images */ im->bands = im->pixelsize = 1; im->linesize = xsize; } else if (strcmp(mode, "P") == 0) { /* 8-bit palette mapped images */ im->bands = im->pixelsize = 1; im->linesize = xsize; im->palette = ImagingPaletteNew("RGB"); } else if (strcmp(mode, "PA") == 0) { /* 8-bit palette with alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ im->linesize = xsize * 4; im->palette = ImagingPaletteNew("RGB"); } else if (strcmp(mode, "L") == 0) { /* 8-bit greyscale (luminance) images */ im->bands = im->pixelsize = 1; im->linesize = xsize; } else if (strcmp(mode, "LA") == 0) { /* 8-bit greyscale (luminance) with alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ im->linesize = xsize * 4; } else if (strcmp(mode, "La") == 0) { /* 8-bit greyscale (luminance) with premultiplied alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ im->linesize = xsize * 4; } else if (strcmp(mode, "F") == 0) { /* 32-bit floating point images */ im->bands = 1; im->pixelsize = 4; im->linesize = xsize * 4; im->type = IMAGING_TYPE_FLOAT32; } else if (strcmp(mode, "I") == 0) { /* 32-bit integer images */ im->bands = 1; im->pixelsize = 4; im->linesize = xsize * 4; im->type = IMAGING_TYPE_INT32; } else if (strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 \ || strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) { /* EXPERIMENTAL */ /* 16-bit raw integer images */ im->bands = 1; im->pixelsize = 2; im->linesize = xsize * 2; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "RGB") == 0) { /* 24-bit true colour images */ im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "BGR;15") == 0) { /* EXPERIMENTAL */ /* 15-bit true colour */ im->bands = 1; im->pixelsize = 2; im->linesize = (xsize*2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;16") == 0) { /* EXPERIMENTAL */ /* 16-bit reversed true colour */ im->bands = 1; im->pixelsize = 2; im->linesize = (xsize*2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;24") == 0) { /* EXPERIMENTAL */ /* 24-bit reversed true colour */ im->bands = 1; im->pixelsize = 3; im->linesize = (xsize*3 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "BGR;32") == 0) { /* EXPERIMENTAL */ /* 32-bit reversed true colour */ im->bands = 1; im->pixelsize = 4; im->linesize = (xsize*4 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; } else if (strcmp(mode, "RGBX") == 0) { /* 32-bit true colour images with padding */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "RGBA") == 0) { /* 32-bit true colour images with alpha */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "RGBa") == 0) { /* 32-bit true colour images with premultiplied alpha */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "CMYK") == 0) { /* 32-bit colour separation */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "YCbCr") == 0) { /* 24-bit video format */ im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "LAB") == 0) { /* 24-bit color, luminance, + 2 color channels */ /* L is uint8, a,b are int8 */ im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; } else if (strcmp(mode, "HSV") == 0) { /* 24-bit color, luminance, + 2 color channels */ /* L is uint8, a,b are int8 */ im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; } else { free(im); return (Imaging) ImagingError_ValueError("unrecognized image mode"); } /* Setup image descriptor */ strcpy(im->mode, mode); /* Pointer array (allocate at least one line, to avoid MemoryError exceptions on platforms where calloc(0, x) returns NULL) */ im->image = (char **) calloc((ysize > 0) ? ysize : 1, sizeof(void *)); if ( ! im->image) { free(im); return (Imaging) ImagingError_MemoryError(); } /* Initialize alias pointers to pixel data. */ switch (im->pixelsize) { case 1: case 2: case 3: im->image8 = (UINT8 **) im->image; break; case 4: im->image32 = (INT32 **) im->image; break; } ImagingDefaultArena.stats_new_count += 1; return im; }
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; }
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" ); }
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; }
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; }