/* * The Python Imaging Library * $Id$ * * point (pixel) translation * * history: * 1995-11-27 fl Created * 1996-03-31 fl Fixed colour support * 1996-08-13 fl Support 8-bit to "1" thresholding * 1997-05-31 fl Added floating point transform * 1998-07-02 fl Added integer point transform * 1998-07-17 fl Support L to anything lookup * 2004-12-18 fl Refactored; added I to L lookup * * Copyright (c) 1997-2004 by Secret Labs AB. * Copyright (c) 1995-2004 by Fredrik Lundh. * * See the README file for information on usage and redistribution. */ #include "Imaging.h" typedef struct { const void *table; } im_point_context; static void im_point_8_8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 8-bit source, 8-bit destination */ UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = imIn->image8[y]; UINT8 *out = imOut->image8[y]; for (x = 0; x < imIn->xsize; x++) { out[x] = table[in[x]]; } } } static void im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 2x8-bit source, 2x8-bit destination */ UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = (UINT8 *)imIn->image[y]; UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++) { out[0] = table[in[0]]; out[3] = table[in[3] + 256]; in += 4; out += 4; } } } static void im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 3x8-bit source, 3x8-bit destination */ UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = (UINT8 *)imIn->image[y]; UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++) { out[0] = table[in[0]]; out[1] = table[in[1] + 256]; out[2] = table[in[2] + 512]; in += 4; out += 4; } } } static void im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 4x8-bit source, 4x8-bit destination */ UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = (UINT8 *)imIn->image[y]; UINT8 *out = (UINT8 *)imOut->image[y]; for (x = 0; x < imIn->xsize; x++) { out[0] = table[in[0]]; out[1] = table[in[1] + 256]; out[2] = table[in[2] + 512]; out[3] = table[in[3] + 768]; in += 4; out += 4; } } } static void im_point_8_32(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 8-bit source, 32-bit destination */ char *table = (char *)context->table; for (y = 0; y < imIn->ysize; y++) { UINT8 *in = imIn->image8[y]; INT32 *out = imOut->image32[y]; for (x = 0; x < imIn->xsize; x++) { memcpy(out + x, table + in[x] * sizeof(INT32), sizeof(INT32)); } } } static void im_point_32_8(Imaging imOut, Imaging imIn, im_point_context *context) { int x, y; /* 32-bit source, 8-bit destination */ UINT8 *table = (UINT8 *)context->table; for (y = 0; y < imIn->ysize; y++) { INT32 *in = imIn->image32[y]; UINT8 *out = imOut->image8[y]; for (x = 0; x < imIn->xsize; x++) { int v = in[x]; if (v < 0) { v = 0; } else if (v > 65535) { v = 65535; } out[x] = table[v]; } } } 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; } ImagingCopyPalette(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 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; } 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++) { char *in = (char *)imIn->image[y]; char *out = (char *)imOut->image[y]; /* FIXME: add clipping? */ for (x = 0; x < imIn->xsize; x++) { UINT16 v; memcpy(&v, in + x * sizeof(v), sizeof(v)); v = v * scale + offset; memcpy(out + x * sizeof(UINT16), &v, sizeof(v)); } } ImagingSectionLeave(&cookie); break; } /* FALL THROUGH */ default: ImagingDelete(imOut); return (Imaging)ImagingError_ValueError("internal error"); } return imOut; }