Pillow/src/libImaging/GetBBox.c
2024-08-14 15:28:34 +04:00

386 lines
13 KiB
C

/*
* 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], int alpha_only) {
/* 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) \
/* first stage: looking for any pixels from top */ \
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; \
bbox[0] = x; \
bbox[1] = y; \
break; \
} \
} \
if (has_data) { \
break; \
} \
} \
/* Check that we have a box */ \
if (bbox[1] < 0) { \
return 0; /* no data */ \
} \
/* second stage: looking for any pixels from bottom */ \
for (y = im->ysize - 1; y >= bbox[1]; 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; \
} \
bbox[3] = y + 1; \
break; \
} \
} \
if (has_data) { \
break; \
} \
} \
/* third stage: looking for left and right boundaries */ \
for (y = bbox[1]; y < bbox[3]; y++) { \
for (x = 0; x < bbox[0]; x++) { \
if (im->image[y][x] & mask) { \
bbox[0] = x; \
break; \
} \
} \
for (x = im->xsize - 1; x >= bbox[2]; x--) { \
if (im->image[y][x] & mask) { \
bbox[2] = x + 1; \
break; \
} \
} \
}
if (im->image8) {
GETBBOX(image8, 0xff);
} else {
INT32 mask = 0xffffffff;
if (im->bands == 3) {
((UINT8 *)&mask)[3] = 0;
} else if (alpha_only &&
(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);
}
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];
}
}
if (imin == 0 && imax == 255) {
break;
}
}
((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 = (UINT8 *)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;
}