/* * The Python Imaging Library * $Id$ * * helpers to bounding boxes, min/max values, number of colors, etc. * * history: * 1996-07-22 fl Created * 1996-12-30 fl Added projection stuff * 1998-07-12 fl Added extrema stuff * 2004-09-17 fl Added colors stuff * * Copyright (c) 1997-2004 by Secret Labs AB. * Copyright (c) 1996-2004 by Fredrik Lundh. * * See the README file for details on usage and redistribution. */ #include "Imaging.h" int ImagingGetBBox(Imaging im, int bbox[4]) { /* Get the bounding box for any non-zero data in the image.*/ int x, y; int has_data; /* Initialize bounding box to max values */ bbox[0] = im->xsize; bbox[1] = -1; bbox[2] = bbox[3] = 0; #define GETBBOX(image, mask)\ for (y = 0; y < im->ysize; y++) {\ has_data = 0;\ for (x = 0; x < im->xsize; x++) {\ if (im->image[y][x] & mask) {\ has_data = 1;\ if (x < bbox[0]) {\ bbox[0] = x;\ }\ if (x >= bbox[2]) {\ bbox[2] = x+1;\ }\ }\ }\ if (has_data) {\ if (bbox[1] < 0) {\ bbox[1] = y;\ }\ bbox[3] = y+1;\ }\ } if (im->image8) { GETBBOX(image8, 0xff); } else { INT32 mask = 0xffffffff; if (im->bands == 3) { ((UINT8*) &mask)[3] = 0; } else if (strcmp(im->mode, "RGBa") == 0 || strcmp(im->mode, "RGBA") == 0 || strcmp(im->mode, "La") == 0 || strcmp(im->mode, "LA") == 0 || strcmp(im->mode, "PA") == 0) { #ifdef WORDS_BIGENDIAN mask = 0x000000ff; #else mask = 0xff000000; #endif } GETBBOX(image32, mask); } /* Check that we got a box */ if (bbox[1] < 0) { return 0; /* no data */ } return 1; /* ok */ } int ImagingGetProjection(Imaging im, UINT8* xproj, UINT8* yproj) { /* Get projection arrays for non-zero data in the image.*/ int x, y; int has_data; /* Initialize projection arrays */ memset(xproj, 0, im->xsize); memset(yproj, 0, im->ysize); #define GETPROJ(image, mask)\ for (y = 0; y < im->ysize; y++) {\ has_data = 0;\ for (x = 0; x < im->xsize; x++) {\ if (im->image[y][x] & mask) {\ has_data = 1;\ xproj[x] = 1;\ }\ }\ if (has_data) {\ yproj[y] = 1;\ }\ } if (im->image8) { GETPROJ(image8, 0xff); } else { INT32 mask = 0xffffffff; if (im->bands == 3) { ((UINT8*) &mask)[3] = 0; } GETPROJ(image32, mask); } return 1; /* ok */ } int ImagingGetExtrema(Imaging im, void *extrema) { int x, y; INT32 imin, imax; FLOAT32 fmin, fmax; if (im->bands != 1) { (void) ImagingError_ModeError(); return -1; /* mismatch */ } if (!im->xsize || !im->ysize) { return 0; /* zero size */ } switch (im->type) { case IMAGING_TYPE_UINT8: imin = imax = im->image8[0][0]; for (y = 0; y < im->ysize; y++) { UINT8* in = im->image8[y]; for (x = 0; x < im->xsize; x++) { if (imin > in[x]) { imin = in[x]; } else if (imax < in[x]) { imax = in[x]; } } } ((UINT8*) extrema)[0] = (UINT8) imin; ((UINT8*) extrema)[1] = (UINT8) imax; break; case IMAGING_TYPE_INT32: imin = imax = im->image32[0][0]; for (y = 0; y < im->ysize; y++) { INT32* in = im->image32[y]; for (x = 0; x < im->xsize; x++) { if (imin > in[x]) { imin = in[x]; } else if (imax < in[x]) { imax = in[x]; } } } memcpy(extrema, &imin, sizeof(imin)); memcpy(((char*)extrema) + sizeof(imin), &imax, sizeof(imax)); break; case IMAGING_TYPE_FLOAT32: fmin = fmax = ((FLOAT32*) im->image32[0])[0]; for (y = 0; y < im->ysize; y++) { FLOAT32* in = (FLOAT32*) im->image32[y]; for (x = 0; x < im->xsize; x++) { if (fmin > in[x]) { fmin = in[x]; } else if (fmax < in[x]) { fmax = in[x]; } } } memcpy(extrema, &fmin, sizeof(fmin)); memcpy(((char*)extrema) + sizeof(fmin), &fmax, sizeof(fmax)); break; case IMAGING_TYPE_SPECIAL: if (strcmp(im->mode, "I;16") == 0) { UINT16 v; UINT8* pixel = *im->image8; #ifdef WORDS_BIGENDIAN v = pixel[0] + (pixel[1] << 8); #else memcpy(&v, pixel, sizeof(v)); #endif imin = imax = v; for (y = 0; y < im->ysize; y++) { for (x = 0; x < im->xsize; x++) { pixel = im->image[y] + x * sizeof(v); #ifdef WORDS_BIGENDIAN v = pixel[0] + (pixel[1] << 8); #else memcpy(&v, pixel, sizeof(v)); #endif if (imin > v) { imin = v; } else if (imax < v) { imax = v; } } } v = (UINT16) imin; memcpy(extrema, &v, sizeof(v)); v = (UINT16) imax; memcpy(((char*)extrema) + sizeof(v), &v, sizeof(v)); break; } /* FALL THROUGH */ default: (void) ImagingError_ModeError(); return -1; } return 1; /* ok */ } /* static ImagingColorItem* getcolors8(Imaging im, int maxcolors, int* size);*/ static ImagingColorItem* getcolors32(Imaging im, int maxcolors, int* size); ImagingColorItem* ImagingGetColors(Imaging im, int maxcolors, int* size) { /* FIXME: add support for 8-bit images */ return getcolors32(im, maxcolors, size); } static ImagingColorItem* getcolors32(Imaging im, int maxcolors, int* size) { unsigned int h; unsigned int i, incr; int colors; INT32 pixel_mask; int x, y; ImagingColorItem* table; ImagingColorItem* v; unsigned int code_size; unsigned int code_poly; unsigned int code_mask; /* note: the hash algorithm used here is based on the dictionary code in Python 2.1.3; the exact implementation is borrowed from Python's Unicode property database (written by yours truly) /F */ static int SIZES[] = { 4,3, 8,3, 16,3, 32,5, 64,3, 128,3, 256,29, 512,17, 1024,9, 2048,5, 4096,83, 8192,27, 16384,43, 32768,3, 65536,45, 131072,9, 262144,39, 524288,39, 1048576,9, 2097152,5, 4194304,3, 8388608,33, 16777216,27, 33554432,9, 67108864,71, 134217728,39, 268435456,9, 536870912,5, 1073741824,83, 0 }; code_size = code_poly = code_mask = 0; for (i = 0; SIZES[i]; i += 2) { if (SIZES[i] > maxcolors) { code_size = SIZES[i]; code_poly = SIZES[i+1]; code_mask = code_size - 1; break; } } /* printf("code_size=%d\n", code_size); */ /* printf("code_poly=%d\n", code_poly); */ if (!code_size) { return ImagingError_MemoryError(); /* just give up */ } if (!im->image32) { return ImagingError_ModeError(); } table = calloc(code_size + 1, sizeof(ImagingColorItem)); if (!table) { return ImagingError_MemoryError(); } pixel_mask = 0xffffffff; if (im->bands == 3) { ((UINT8*) &pixel_mask)[3] = 0; } colors = 0; for (y = 0; y < im->ysize; y++) { INT32* p = im->image32[y]; for (x = 0; x < im->xsize; x++) { INT32 pixel = p[x] & pixel_mask; h = (pixel); /* null hashing */ i = (~h) & code_mask; v = &table[i]; if (!v->count) { /* add to table */ if (colors++ == maxcolors) { goto overflow; } v->x = x; v->y = y; v->pixel = pixel; v->count = 1; continue; } else if (v->pixel == pixel) { v->count++; continue; } incr = (h ^ (h >> 3)) & code_mask; if (!incr) { incr = code_mask; } for (;;) { i = (i + incr) & code_mask; v = &table[i]; if (!v->count) { /* add to table */ if (colors++ == maxcolors) { goto overflow; } v->x = x; v->y = y; v->pixel = pixel; v->count = 1; break; } else if (v->pixel == pixel) { v->count++; break; } incr = incr << 1; if (incr > code_mask) { incr = incr ^ code_poly; } } } } overflow: /* pack the table */ for (x = y = 0; x < (int) code_size; x++) if (table[x].count) { if (x != y) { table[y] = table[x]; } y++; } table[y].count = 0; /* mark end of table */ *size = colors; return table; }