mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-01 00:17:27 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			414 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			414 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * The Python Imaging Library
 | |
|  * $Id$
 | |
|  *
 | |
|  * 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;16L") == 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	(2048*2048*4L)
 | |
| #endif
 | |
| 
 | |
| Imaging
 | |
| ImagingNew(const char* mode, int xsize, int ysize)
 | |
| {
 | |
|     int bytes;
 | |
|     Imaging im;
 | |
| 
 | |
|     if (strlen(mode) == 1) {
 | |
|         if (mode[0] == 'F' || mode[0] == 'I')
 | |
|             bytes = 4;
 | |
|         else
 | |
|             bytes = 1;
 | |
|     } else
 | |
|         bytes = strlen(mode); /* close enough */
 | |
| 
 | |
|     if ((Py_ssize_t) xsize * ysize * bytes <= THRESHOLD) {
 | |
|         im = ImagingNewBlock(mode, xsize, ysize);
 | |
|         if (im)
 | |
|             return im;
 | |
|         /* assume memory error; try allocating in array mode instead */
 | |
|         ImagingError_Clear();
 | |
|     }
 | |
| 
 | |
|     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) {
 | |
|             return ImagingError_Mismatch();
 | |
|         }
 | |
|     } 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);
 | |
|     }
 | |
| }
 |