diff options
Diffstat (limited to 'Imaging/libImaging/Storage.c')
-rw-r--r-- | Imaging/libImaging/Storage.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/Imaging/libImaging/Storage.c b/Imaging/libImaging/Storage.c new file mode 100644 index 0000000..5f2ae90 --- /dev/null +++ b/Imaging/libImaging/Storage.c @@ -0,0 +1,399 @@ +/* + * The Python Imaging Library + * $Id: Storage.c 2542 2005-10-02 21:37:20Z Fredrik $ + * + * imaging storage object + * + * This baseline implementation is designed to efficiently handle + * large images, provided they fit into the available memory. + * + * history: + * 1995-06-15 fl Created + * 1995-09-12 fl Updated API, compiles silently under ANSI C++ + * 1995-11-26 fl Compiles silently under Borland 4.5 as well + * 1996-05-05 fl Correctly test status from Prologue + * 1997-05-12 fl Increased THRESHOLD (to speed up Tk interface) + * 1997-05-30 fl Added support for floating point images + * 1997-11-17 fl Added support for "RGBX" images + * 1998-01-11 fl Added support for integer images + * 1998-03-05 fl Exported Prologue/Epilogue functions + * 1998-07-01 fl Added basic "YCrCb" support + * 1998-07-03 fl Attach palette in prologue for "P" images + * 1998-07-09 hk Don't report MemoryError on zero-size images + * 1998-07-12 fl Change "YCrCb" to "YCbCr" (!) + * 1998-10-26 fl Added "I;16" and "I;16B" storage modes (experimental) + * 1998-12-29 fl Fixed allocation bug caused by previous fix + * 1999-02-03 fl Added "RGBa" and "BGR" modes (experimental) + * 2001-04-22 fl Fixed potential memory leak in ImagingCopyInfo + * 2003-09-26 fl Added "LA" and "PA" modes (experimental) + * 2005-10-02 fl Added image counter + * + * Copyright (c) 1998-2005 by Secret Labs AB + * Copyright (c) 1995-2005 by Fredrik Lundh + * + * See the README file for information on usage and redistribution. + */ + + +#include "Imaging.h" + + +int ImagingNewCount = 0; + +/* -------------------------------------------------------------------- + * Standard image object. + */ + +Imaging +ImagingNewPrologueSubtype(const char *mode, unsigned xsize, unsigned ysize, + int size) +{ + Imaging im; + ImagingSectionCookie cookie; + + 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, "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;16B") == 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) { + /* EXPERIMENTAL */ + /* 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 { + free(im); + return (Imaging) ImagingError_ValueError("unrecognized mode"); + } + + /* Setup image descriptor */ + strcpy(im->mode, mode); + + ImagingSectionEnter(&cookie); + + /* 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 *)); + + ImagingSectionLeave(&cookie); + + if (!im->image) { + free(im); + return (Imaging) ImagingError_MemoryError(); + } + + ImagingNewCount++; + + return im; +} + +Imaging +ImagingNewPrologue(const char *mode, unsigned xsize, unsigned ysize) +{ + return ImagingNewPrologueSubtype( + mode, xsize, ysize, sizeof(struct ImagingMemoryInstance) + ); +} + +Imaging +ImagingNewEpilogue(Imaging im) +{ + /* If the raster data allocator didn't setup a destructor, + assume that it couldn't allocate the required amount of + memory. */ + if (!im->destroy) + 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; + } + + return im; +} + +void +ImagingDelete(Imaging im) +{ + if (!im) + return; + + if (im->palette) + ImagingPaletteDelete(im->palette); + + if (im->destroy) + im->destroy(im); + + if (im->image) + free(im->image); + + free(im); +} + + +/* Array Storage Type */ +/* ------------------ */ +/* Allocate image as an array of line buffers. */ + +static void +ImagingDestroyArray(Imaging im) +{ + int y; + + if (im->image) + for (y = 0; y < im->ysize; y++) + if (im->image[y]) + free(im->image[y]); +} + +Imaging +ImagingNewArray(const char *mode, int xsize, int ysize) +{ + Imaging im; + ImagingSectionCookie cookie; + + int y; + char* p; + + im = ImagingNewPrologue(mode, xsize, ysize); + if (!im) + return NULL; + + ImagingSectionEnter(&cookie); + + /* Allocate image as an array of lines */ + for (y = 0; y < im->ysize; y++) { + p = (char *) malloc(im->linesize); + if (!p) { + ImagingDestroyArray(im); + break; + } + im->image[y] = p; + } + + ImagingSectionLeave(&cookie); + + if (y == im->ysize) + im->destroy = ImagingDestroyArray; + + return ImagingNewEpilogue(im); +} + + +/* Block Storage Type */ +/* ------------------ */ +/* Allocate image as a single block. */ + +static void +ImagingDestroyBlock(Imaging im) +{ + if (im->block) + free(im->block); +} + +Imaging +ImagingNewBlock(const char *mode, int xsize, int ysize) +{ + Imaging im; + int y, i; + int bytes; + + im = ImagingNewPrologue(mode, xsize, ysize); + if (!im) + return NULL; + + /* Use a single block */ + bytes = im->ysize * im->linesize; + if (bytes <= 0) + /* some platforms return NULL for malloc(0); this fix + prevents MemoryError on zero-sized images on such + platforms */ + bytes = 1; + im->block = (char *) malloc(bytes); + + if (im->block) { + + for (y = i = 0; y < im->ysize; y++) { + im->image[y] = im->block + i; + i += im->linesize; + } + + im->destroy = ImagingDestroyBlock; + + } + + return ImagingNewEpilogue(im); +} + +/* -------------------------------------------------------------------- + * Create a new, internally allocated, image. + */ +#if defined(IMAGING_SMALL_MODEL) +#define THRESHOLD 16384L +#else +#define THRESHOLD 1048576L +#endif + +Imaging +ImagingNew(const char* mode, int xsize, int ysize) +{ + /* FIXME: strlen(mode) is no longer accurate */ + if ((long) xsize * ysize * strlen(mode) <= THRESHOLD) + return ImagingNewBlock(mode, xsize, ysize); + else + return ImagingNewArray(mode, xsize, ysize); +} + +Imaging +ImagingNew2(const char* mode, Imaging imOut, Imaging imIn) +{ + /* allocate or validate output image */ + + if (imOut) { + /* make sure images match */ + if (strcmp(imOut->mode, mode) != 0 + || imOut->xsize != imIn->xsize + || imOut->ysize != imIn->ysize) { + ImagingError_Mismatch(); + return NULL; + } + } else { + /* create new image */ + imOut = ImagingNew(mode, imIn->xsize, imIn->ysize); + if (!imOut) + return NULL; + } + + return imOut; +} + +void +ImagingCopyInfo(Imaging destination, Imaging source) +{ + if (source->palette) { + if (destination->palette) + ImagingPaletteDelete(destination->palette); + destination->palette = ImagingPaletteDuplicate(source->palette); + } +} |