Imaging ImagingAllocateBlock(Imaging im) { Py_ssize_t y, i; /* overflow check for malloc */ if (im->linesize && im->ysize > INT_MAX / im->linesize) { return (Imaging) ImagingError_MemoryError(); } if (im->ysize * im->linesize <= 0) { /* some platforms return NULL for malloc(0); this fix prevents MemoryError on zero-sized images on such platforms */ im->block = (char *) malloc(1); } else { /* malloc check ok, overflow check above */ im->block = (char *) calloc(im->ysize, im->linesize); } if ( ! im->block) { return (Imaging) ImagingError_MemoryError(); } for (y = i = 0; y < im->ysize; y++) { im->image[y] = im->block + i; i += im->linesize; } im->destroy = ImagingDestroyBlock; return im; }
int ImagingPaletteCachePrepare(ImagingPalette palette) { /* Add a colour cache to a palette */ int i; int entries = 64*64*64; if (palette->cache == NULL) { /* The cache is 512k. It might be a good idea to break it up into a pointer array (e.g. an 8-bit image?) */ palette->cache = (INT16*) malloc(entries * sizeof(INT16)); if (!palette->cache) { (void) ImagingError_MemoryError(); return -1; } /* Mark all entries as empty */ for (i = 0; i < entries; i++) palette->cache[i] = 0x100; } return 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; }
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(); }
ImagingOutline ImagingOutlineNew(void) { ImagingOutline outline; outline = calloc(1, sizeof(struct ImagingOutlineInstance)); if (!outline) return (ImagingOutline) ImagingError_MemoryError(); outline->edges = NULL; outline->count = outline->size = 0; ImagingOutlineMove(outline, 0, 0); return outline; }
ImagingAccess ImagingAccessNew(Imaging im) { /* Create a standard access object */ ImagingAccess access; access = calloc(1, sizeof(struct ImagingAccessInstance)); if (!access) return (ImagingAccess) ImagingError_MemoryError(); access->im = im; access->getline = access_getline; access->destroy = access_destroy; return access; }
ImagingPalette ImagingPaletteDuplicate(ImagingPalette palette) { /* Duplicate palette descriptor */ ImagingPalette new_palette; if (!palette) return NULL; new_palette = malloc(sizeof(struct ImagingPaletteInstance)); if (!new_palette) return (ImagingPalette) ImagingError_MemoryError(); memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance)); /* Don't share the cache */ new_palette->cache = NULL; return new_palette; }
int ImagingDrawPolygon(Imaging im, int count, int* xy, const void* ink_, int fill, int op) { int i, n; DRAW* draw; INT32 ink; if (count <= 0) return 0; DRAWINIT(); if (fill) { /* Build edge list */ /* malloc check ok, using calloc */ Edge* e = calloc(count, sizeof(Edge)); if (!e) { (void) ImagingError_MemoryError(); return -1; } for (i = n = 0; i < count-1; i++) add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3]); if (xy[i+i] != xy[0] || xy[i+i+1] != xy[1]) add_edge(&e[n++], xy[i+i], xy[i+i+1], xy[0], xy[1]); draw->polygon(im, n, e, ink, 0); free(e); } else { /* Outline */ for (i = 0; i < count-1; i++) draw->line(im, xy[i+i], xy[i+i+1], xy[i+i+2], xy[i+i+3], ink); draw->line(im, xy[i+i], xy[i+i+1], xy[0], xy[1], ink); } return 0; }
Imaging ImagingAllocateArray(Imaging im, int dirty, int block_size) { int y, line_in_block, current_block; ImagingMemoryArena arena = &ImagingDefaultArena; ImagingMemoryBlock block = {NULL, 0}; int aligned_linesize, lines_per_block, blocks_count; char *aligned_ptr = NULL; /* 0-width or 0-height image. No need to do anything */ if ( ! im->linesize || ! im->ysize) { return im; } aligned_linesize = (im->linesize + arena->alignment - 1) & -arena->alignment; lines_per_block = (block_size - (arena->alignment - 1)) / aligned_linesize; if (lines_per_block == 0) lines_per_block = 1; blocks_count = (im->ysize + lines_per_block - 1) / lines_per_block; // printf("NEW size: %dx%d, ls: %d, lpb: %d, blocks: %d\n", // im->xsize, im->ysize, aligned_linesize, lines_per_block, blocks_count); /* One extra ponter is always NULL */ im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1); if ( ! im->blocks) { return (Imaging) ImagingError_MemoryError(); } /* Allocate image as an array of lines */ line_in_block = 0; current_block = 0; for (y = 0; y < im->ysize; y++) { if (line_in_block == 0) { int required; int lines_remaining = lines_per_block; if (lines_remaining > im->ysize - y) { lines_remaining = im->ysize - y; } required = lines_remaining * aligned_linesize + arena->alignment - 1; block = memory_get_block(arena, required, dirty); if ( ! block.ptr) { ImagingDestroyArray(im); return (Imaging) ImagingError_MemoryError(); } im->blocks[current_block] = block; /* Bulletproof code from libc _int_memalign */ aligned_ptr = (char *)( ((size_t) (block.ptr + arena->alignment - 1)) & -((Py_ssize_t) arena->alignment)); } im->image[y] = aligned_ptr + aligned_linesize * line_in_block; line_in_block += 1; if (line_in_block >= lines_per_block) { /* Reset counter and start new block */ line_in_block = 0; current_block += 1; } } im->destroy = ImagingDestroyArray; return im; }
static int ellipse(Imaging im, int x0, int y0, int x1, int y1, int start, int end, const void* ink_, int fill, int mode, int op) { int i, n; int cx, cy; int w, h; int x = 0, y = 0; int lx = 0, ly = 0; int sx = 0, sy = 0; DRAW* draw; INT32 ink; w = x1 - x0; h = y1 - y0; if (w < 0 || h < 0) return 0; DRAWINIT(); cx = (x0 + x1) / 2; cy = (y0 + y1) / 2; while (end < start) end += 360; if (mode != ARC && fill) { /* Build edge list */ Edge* e = malloc((end - start + 3) * sizeof(Edge)); if (!e) { ImagingError_MemoryError(); return -1; } n = 0; for (i = start; i <= end; i++) { x = FLOOR((cos(i*M_PI/180) * w/2) + cx + 0.5); y = FLOOR((sin(i*M_PI/180) * h/2) + cy + 0.5); if (i != start) add_edge(&e[n++], lx, ly, x, y); else sx = x, sy = y; lx = x, ly = y; } if (n > 0) { /* close and draw polygon */ if (mode == PIESLICE) { if (x != cx || y != cy) { add_edge(&e[n++], x, y, cx, cy); add_edge(&e[n++], cx, cy, sx, sy); } } else { if (x != sx || y != sy) add_edge(&e[n++], x, y, sx, sy); } draw->polygon(im, n, e, ink, 0); } free(e); } else { for (i = start; i <= end; i++) { x = FLOOR((cos(i*M_PI/180) * w/2) + cx + 0.5); y = FLOOR((sin(i*M_PI/180) * h/2) + cy + 0.5); if (i != start) draw->line(im, lx, ly, x, y, ink); else sx = x, sy = y; lx = x, ly = y; } if (i != start) { if (mode == PIESLICE) { if (x != cx || y != cy) { draw->line(im, x, y, cx, cy, ink); draw->line(im, cx, cy, sx, sy, ink); } } else if (mode == CHORD) { if (x != sx || y != sy) draw->line(im, x, y, sx, sy, ink); } } } return 0; }
static Imaging gblur(Imaging im, Imaging imOut, float floatRadius, int channels, int padding) { ImagingSectionCookie cookie; float *maskData = NULL; int y = 0; int x = 0; float z = 0; float sum = 0.0; float dev = 0.0; float *buffer = NULL; int *line = NULL; UINT8 *line8 = NULL; int pix = 0; float newPixel[4]; int channel = 0; int offset = 0; INT32 newPixelFinals; int radius = 0; float remainder = 0.0; int i; /* Do the gaussian blur */ /* For a symmetrical gaussian blur, instead of doing a radius*radius matrix lookup, you get the EXACT same results by doing a radius*1 transform, followed by a 1*radius transform. This reduces the number of lookups exponentially (10 lookups per pixel for a radius of 5 instead of 25 lookups). So, we blur the lines first, then we blur the resulting columns. */ /* first, round radius off to the next higher integer and hold the remainder this is used so we can support float radius values properly. */ remainder = floatRadius - ((int) floatRadius); floatRadius = ceil(floatRadius); /* Next, double the radius and offset by 2.0... that way "0" returns the original image instead of a black one. We multiply it by 2.0 so that it is a true "radius", not a diameter (the results match other paint programs closer that way too). */ radius = (int) ((floatRadius * 2.0) + 2.0); /* create the maskData for the gaussian curve */ maskData = malloc(radius * sizeof(float)); /* FIXME: error checking */ for (x = 0; x < radius; x++) { z = ((float) (x + 2) / ((float) radius)); dev = 0.5 + (((float) (radius * radius)) * 0.001); /* you can adjust this factor to change the shape/center-weighting of the gaussian */ maskData[x] = (float) pow((1.0 / sqrt(2.0 * 3.14159265359 * dev)), ((-(z - 1.0) * -(x - 1.0)) / (2.0 * dev))); } /* if there's any remainder, multiply the first/last values in MaskData it. this allows us to support float radius values. */ if (remainder > 0.0) { maskData[0] *= remainder; maskData[radius - 1] *= remainder; } for (x = 0; x < radius; x++) { /* this is done separately now due to the correction for float radius values above */ sum += maskData[x]; } for (i = 0; i < radius; i++) { maskData[i] *= (1.0 / sum); /* printf("%f\n", maskData[i]); */ } /* create a temporary memory buffer for the data for the first pass memset the buffer to 0 so we can use it directly with += */ /* don't bother about alpha/padding */ buffer = calloc((size_t) (im->xsize * im->ysize * channels), sizeof(float)); if (buffer == NULL) return ImagingError_MemoryError(); /* be nice to other threads while you go off to lala land */ ImagingSectionEnter(&cookie); /* memset(buffer, 0, sizeof(buffer)); */ newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; /* perform a blur on each line, and place in the temporary storage buffer */ for (y = 0; y < im->ysize; y++) { if (channels == 1 && im->image8 != NULL) { line8 = (UINT8 *) im->image8[y]; } else { line = im->image32[y]; } for (x = 0; x < im->xsize; x++) { newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; /* for each neighbor pixel, factor in its value/weighting to the current pixel */ for (pix = 0; pix < radius; pix++) { /* figure the offset of this neighbor pixel */ offset = (int) ((-((float) radius / 2.0) + (float) pix) + 0.5); if (x + offset < 0) offset = -x; else if (x + offset >= im->xsize) offset = im->xsize - x - 1; /* add (neighbor pixel value * maskData[pix]) to the current pixel value */ if (channels == 1) { buffer[(y * im->xsize) + x] += ((float) ((UINT8 *) & line8[x + offset])[0]) * (maskData[pix]); } else { for (channel = 0; channel < channels; channel++) { buffer[(y * im->xsize * channels) + (x * channels) + channel] += ((float) ((UINT8 *) & line[x + offset]) [channel]) * (maskData[pix]); } } } } } /* perform a blur on each column in the buffer, and place in the output image */ for (x = 0; x < im->xsize; x++) { for (y = 0; y < im->ysize; y++) { newPixel[0] = newPixel[1] = newPixel[2] = newPixel[3] = 0; /* for each neighbor pixel, factor in its value/weighting to the current pixel */ for (pix = 0; pix < radius; pix++) { /* figure the offset of this neighbor pixel */ offset = (int) (-((float) radius / 2.0) + (float) pix + 0.5); if (y + offset < 0) offset = -y; else if (y + offset >= im->ysize) offset = im->ysize - y - 1; /* add (neighbor pixel value * maskData[pix]) to the current pixel value */ for (channel = 0; channel < channels; channel++) { newPixel[channel] += (buffer [((y + offset) * im->xsize * channels) + (x * channels) + channel]) * (maskData[pix]); } } /* if the image is RGBX or RGBA, copy the 4th channel data to newPixel, so it gets put in imOut */ if (strcmp(im->mode, "RGBX") == 0 || strcmp(im->mode, "RGBA") == 0) { newPixel[3] = (float) ((UINT8 *) & line[x + offset])[3]; } /* pack the channels into an INT32 so we can put them back in the PIL image */ newPixelFinals = 0; if (channels == 1) { newPixelFinals = clip(newPixel[0]); } else { /* for RGB, the fourth channel isn't used anyways, so just pack a 0 in there, this saves checking the mode for each pixel. */ /* this doesn't work on little-endian machines... fix it! */ newPixelFinals = clip(newPixel[0]) | clip(newPixel[1]) << 8 | clip(newPixel[2]) << 16 | clip(newPixel[3]) << 24; } /* set the resulting pixel in imOut */ if (channels == 1) { imOut->image8[y][x] = (UINT8) newPixelFinals; } else { imOut->image32[y][x] = newPixelFinals; } } } /* free the buffer */ free(buffer); /* get the GIL back so Python knows who you are */ ImagingSectionLeave(&cookie); return imOut; }
int precompute_coeffs(int inSize, float in0, float in1, int outSize, struct filter *filterp, int **boundsp, double **kkp) { double support, scale, filterscale; double center, ww, ss; int xx, x, ksize, xmin, xmax; int *bounds; double *kk, *k; /* prepare for horizontal stretch */ filterscale = scale = (double) (in1 - in0) / outSize; if (filterscale < 1.0) { filterscale = 1.0; } /* determine support size (length of resampling filter) */ support = filterp->support * filterscale; /* maximum number of coeffs */ ksize = (int) ceil(support) * 2 + 1; // check for overflow if (outSize > INT_MAX / (ksize * sizeof(double))) { ImagingError_MemoryError(); return 0; } /* coefficient buffer */ /* malloc check ok, overflow checked above */ kk = malloc(outSize * ksize * sizeof(double)); if ( ! kk) { ImagingError_MemoryError(); return 0; } /* malloc check ok, ksize*sizeof(double) > 2*sizeof(int) */ bounds = malloc(outSize * 2 * sizeof(int)); if ( ! bounds) { free(kk); ImagingError_MemoryError(); return 0; } for (xx = 0; xx < outSize; xx++) { center = in0 + (xx + 0.5) * scale; ww = 0.0; ss = 1.0 / filterscale; // Round the value xmin = (int) (center - support + 0.5); if (xmin < 0) xmin = 0; // Round the value xmax = (int) (center + support + 0.5); if (xmax > inSize) xmax = inSize; xmax -= xmin; k = &kk[xx * ksize]; for (x = 0; x < xmax; x++) { double w = filterp->filter((x + xmin - center + 0.5) * ss); k[x] = w; ww += w; } for (x = 0; x < xmax; x++) { if (ww != 0.0) k[x] /= ww; } // Remaining values should stay empty if they are used despite of xmax. for (; x < ksize; x++) { k[x] = 0; } bounds[xx * 2 + 0] = xmin; bounds[xx * 2 + 1] = xmax; } *boundsp = bounds; *kkp = kk; return ksize; }
static int ellipse(Imaging im, int x0, int y0, int x1, int y1, float start, float end, const void* ink_, int fill, int width, int mode, int op) { float i; int j; int n; int cx, cy; int w, h; int x = 0, y = 0; int lx = 0, ly = 0; int sx = 0, sy = 0; DRAW* draw; INT32 ink; DRAWINIT(); if (width == 0) { width = 1; } for (j = 0; j < width; j++) { w = x1 - x0; h = y1 - y0; if (w < 0 || h < 0) return 0; cx = (x0 + x1) / 2; cy = (y0 + y1) / 2; while (end < start) end += 360; if (end - start > 360) { /* no need to go in loops */ end = start + 361; } if (mode != ARC && fill) { /* Build edge list */ /* malloc check UNDONE, FLOAT? */ Edge* e = calloc((end - start + 3), sizeof(Edge)); if (!e) { ImagingError_MemoryError(); return -1; } n = 0; for (i = start; i < end+1; i++) { if (i > end) { i = end; } ellipsePoint(cx, cy, w, h, i, &x, &y); if (i != start) add_edge(&e[n++], lx, ly, x, y); else sx = x, sy = y; lx = x, ly = y; } if (n > 0) { /* close and draw polygon */ if (mode == PIESLICE) { if (x != cx || y != cy) { add_edge(&e[n++], x, y, cx, cy); add_edge(&e[n++], cx, cy, sx, sy); } } else { if (x != sx || y != sy) add_edge(&e[n++], x, y, sx, sy); } draw->polygon(im, n, e, ink, 0); } free(e); } else { for (i = start; i < end+1; i++) { if (i > end) { i = end; } ellipsePoint(cx, cy, w, h, i, &x, &y); if (i != start) draw->line(im, lx, ly, x, y, ink); else sx = x, sy = y; lx = x, ly = y; } if (i != start) { if (mode == PIESLICE) { if (j == 0 && (x != cx || y != cy)) { if (width == 1) { draw->line(im, x, y, cx, cy, ink); draw->line(im, cx, cy, sx, sy, ink); } else { ImagingDrawWideLine(im, x, y, cx, cy, &ink, width, op); ImagingDrawWideLine(im, cx, cy, sx, sy, &ink, width, op); } } } else if (mode == CHORD) { if (x != sx || y != sy) draw->line(im, x, y, sx, sy, ink); } } } x0++; y0++; x1--; y1--; } return 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; }
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; }
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 ImagingOutlineTransform(ImagingOutline outline, double a[6]) { Edge *eIn; Edge *eOut; int i, n; int x0, y0, x1, y1; int X0, Y0, X1, Y1; double a0 = a[0]; double a1 = a[1]; double a2 = a[2]; double a3 = a[3]; double a4 = a[4]; double a5 = a[5]; eIn = outline->edges; n = outline->count; /* FIXME: ugly! */ outline->edges = NULL; outline->count = outline->size = 0; eOut = allocate(outline, n); if (!eOut) { outline->edges = eIn; outline->count = outline->size = n; ImagingError_MemoryError(); return -1; } for (i = 0; i < n; i++) { x0 = eIn->x0; y0 = eIn->y0; /* FIXME: ouch! */ if (eIn->x0 == eIn->xmin) x1 = eIn->xmax; else x1 = eIn->xmin; if (eIn->y0 == eIn->ymin) y1 = eIn->ymax; else y1 = eIn->ymin; /* full moon tonight! if this doesn't work, you may need to upgrade your compiler (make sure you have the right service pack) */ X0 = (int) (a0*x0 + a1*y0 + a2); Y0 = (int) (a3*x0 + a4*y0 + a5); X1 = (int) (a0*x1 + a1*y1 + a2); Y1 = (int) (a3*x1 + a4*y1 + a5); add_edge(eOut, X0, Y0, X1, Y1); eIn++; eOut++; } free(eIn); return 0; }