summaryrefslogtreecommitdiffstats
path: root/contrib/python/Pillow/py3/libImaging/Storage.c
diff options
context:
space:
mode:
authorshumkovnd <[email protected]>2023-11-10 14:39:34 +0300
committershumkovnd <[email protected]>2023-11-10 16:42:24 +0300
commit77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch)
treec51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/Pillow/py3/libImaging/Storage.c
parentdd6d20cadb65582270ac23f4b3b14ae189704b9d (diff)
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/Pillow/py3/libImaging/Storage.c')
-rw-r--r--contrib/python/Pillow/py3/libImaging/Storage.c577
1 files changed, 577 insertions, 0 deletions
diff --git a/contrib/python/Pillow/py3/libImaging/Storage.c b/contrib/python/Pillow/py3/libImaging/Storage.c
new file mode 100644
index 00000000000..128595f6547
--- /dev/null
+++ b/contrib/python/Pillow/py3/libImaging/Storage.c
@@ -0,0 +1,577 @@
+/*
+ * 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 ImagingCopyPalette
+ * 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"
+#include <string.h>
+
+/* --------------------------------------------------------------------
+ * Standard image object.
+ */
+
+Imaging
+ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) {
+ Imaging im;
+
+ /* linesize overflow check, roughly the current largest space req'd */
+ if (xsize > (INT_MAX / 4) - 1) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ 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, "La") == 0) {
+ /* 8-bit greyscale (luminance) with premultiplied 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 || strcmp(mode, "I;16N") == 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 reversed true colour */
+ im->bands = 3;
+ 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 = 3;
+ 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 = 3;
+ im->pixelsize = 3;
+ im->linesize = (xsize * 3 + 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) {
+ /* 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 if (strcmp(mode, "LAB") == 0) {
+ /* 24-bit color, luminance, + 2 color channels */
+ /* L is uint8, a,b are int8 */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else if (strcmp(mode, "HSV") == 0) {
+ /* 24-bit color, luminance, + 2 color channels */
+ /* L is uint8, a,b are int8 */
+ im->bands = 3;
+ im->pixelsize = 4;
+ im->linesize = xsize * 4;
+
+ } else {
+ free(im);
+ return (Imaging)ImagingError_ValueError("unrecognized image mode");
+ }
+
+ /* Setup image descriptor */
+ strcpy(im->mode, mode);
+
+ /* 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 *));
+
+ if (!im->image) {
+ free(im);
+ 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;
+ }
+
+ ImagingDefaultArena.stats_new_count += 1;
+
+ return im;
+}
+
+Imaging
+ImagingNewPrologue(const char *mode, int xsize, int ysize) {
+ return ImagingNewPrologueSubtype(
+ mode, xsize, ysize, sizeof(struct ImagingMemoryInstance));
+}
+
+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. */
+
+#define IMAGING_PAGE_SIZE (4096)
+
+struct ImagingMemoryArena ImagingDefaultArena = {
+ 1, // alignment
+ 16 * 1024 * 1024, // block_size
+ 0, // blocks_max
+ 0, // blocks_cached
+ NULL, // blocks_pool
+ 0,
+ 0,
+ 0,
+ 0,
+ 0 // Stats
+};
+
+int
+ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) {
+ void *p;
+ /* Free already cached blocks */
+ ImagingMemoryClearCache(arena, blocks_max);
+
+ if (blocks_max == 0 && arena->blocks_pool != NULL) {
+ free(arena->blocks_pool);
+ arena->blocks_pool = NULL;
+ } else if (arena->blocks_pool != NULL) {
+ p = realloc(arena->blocks_pool, sizeof(*arena->blocks_pool) * blocks_max);
+ if (!p) {
+ // Leave previous blocks_max value
+ return 0;
+ }
+ arena->blocks_pool = p;
+ } else {
+ arena->blocks_pool = calloc(sizeof(*arena->blocks_pool), blocks_max);
+ if (!arena->blocks_pool) {
+ return 0;
+ }
+ }
+ arena->blocks_max = blocks_max;
+
+ return 1;
+}
+
+void
+ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size) {
+ while (arena->blocks_cached > new_size) {
+ arena->blocks_cached -= 1;
+ free(arena->blocks_pool[arena->blocks_cached].ptr);
+ arena->stats_freed_blocks += 1;
+ }
+}
+
+ImagingMemoryBlock
+memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) {
+ ImagingMemoryBlock block = {NULL, 0};
+
+ if (arena->blocks_cached > 0) {
+ // Get block from cache
+ arena->blocks_cached -= 1;
+ block = arena->blocks_pool[arena->blocks_cached];
+ // Reallocate if needed
+ if (block.size != requested_size) {
+ block.ptr = realloc(block.ptr, requested_size);
+ }
+ if (!block.ptr) {
+ // Can't allocate, free previous pointer (it is still valid)
+ free(arena->blocks_pool[arena->blocks_cached].ptr);
+ arena->stats_freed_blocks += 1;
+ return block;
+ }
+ if (!dirty) {
+ memset(block.ptr, 0, requested_size);
+ }
+ arena->stats_reused_blocks += 1;
+ if (block.ptr != arena->blocks_pool[arena->blocks_cached].ptr) {
+ arena->stats_reallocated_blocks += 1;
+ }
+ } else {
+ if (dirty) {
+ block.ptr = malloc(requested_size);
+ } else {
+ block.ptr = calloc(1, requested_size);
+ }
+ arena->stats_allocated_blocks += 1;
+ }
+ block.size = requested_size;
+ return block;
+}
+
+void
+memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block) {
+ if (arena->blocks_cached < arena->blocks_max) {
+ // Reduce block size
+ if (block.size > arena->block_size) {
+ block.size = arena->block_size;
+ block.ptr = realloc(block.ptr, arena->block_size);
+ }
+ arena->blocks_pool[arena->blocks_cached] = block;
+ arena->blocks_cached += 1;
+ } else {
+ free(block.ptr);
+ arena->stats_freed_blocks += 1;
+ }
+}
+
+static void
+ImagingDestroyArray(Imaging im) {
+ int y = 0;
+
+ if (im->blocks) {
+ while (im->blocks[y].ptr) {
+ memory_return_block(&ImagingDefaultArena, im->blocks[y]);
+ y += 1;
+ }
+ free(im->blocks);
+ }
+}
+
+Imaging
+ImagingAllocateArray(Imaging im, int dirty, int block_size) {
+ int y, line_in_block, current_block;
+ ImagingMemoryArena arena = &ImagingDefaultArena;
+ ImagingMemoryBlock block = {NULL, 0};
+ int aligned_linesize, lines_per_block, blocks_count;
+ char *aligned_ptr = NULL;
+
+ /* 0-width or 0-height image. No need to do anything */
+ if (!im->linesize || !im->ysize) {
+ return im;
+ }
+
+ aligned_linesize = (im->linesize + arena->alignment - 1) & -arena->alignment;
+ lines_per_block = (block_size - (arena->alignment - 1)) / aligned_linesize;
+ if (lines_per_block == 0) {
+ lines_per_block = 1;
+ }
+ blocks_count = (im->ysize + lines_per_block - 1) / lines_per_block;
+ // printf("NEW size: %dx%d, ls: %d, lpb: %d, blocks: %d\n",
+ // im->xsize, im->ysize, aligned_linesize, lines_per_block, blocks_count);
+
+ /* One extra pointer is always NULL */
+ im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1);
+ if (!im->blocks) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ /* Allocate image as an array of lines */
+ line_in_block = 0;
+ current_block = 0;
+ for (y = 0; y < im->ysize; y++) {
+ if (line_in_block == 0) {
+ int required;
+ int lines_remaining = lines_per_block;
+ if (lines_remaining > im->ysize - y) {
+ lines_remaining = im->ysize - y;
+ }
+ required = lines_remaining * aligned_linesize + arena->alignment - 1;
+ block = memory_get_block(arena, required, dirty);
+ if (!block.ptr) {
+ ImagingDestroyArray(im);
+ return (Imaging)ImagingError_MemoryError();
+ }
+ im->blocks[current_block] = block;
+ /* Bulletproof code from libc _int_memalign */
+ aligned_ptr = (char *)(
+ ((size_t) (block.ptr + arena->alignment - 1)) &
+ -((Py_ssize_t) arena->alignment));
+ }
+
+ im->image[y] = aligned_ptr + aligned_linesize * line_in_block;
+
+ line_in_block += 1;
+ if (line_in_block >= lines_per_block) {
+ /* Reset counter and start new block */
+ line_in_block = 0;
+ current_block += 1;
+ }
+ }
+
+ im->destroy = ImagingDestroyArray;
+
+ return im;
+}
+
+/* Block Storage Type */
+/* ------------------ */
+/* Allocate image as a single block. */
+
+static void
+ImagingDestroyBlock(Imaging im) {
+ if (im->block) {
+ free(im->block);
+ }
+}
+
+Imaging
+ImagingAllocateBlock(Imaging im) {
+ Py_ssize_t y, i;
+
+ /* overflow check for malloc */
+ if (im->linesize && im->ysize > INT_MAX / im->linesize) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ if (im->ysize * im->linesize <= 0) {
+ /* some platforms return NULL for malloc(0); this fix
+ prevents MemoryError on zero-sized images on such
+ platforms */
+ im->block = (char *)malloc(1);
+ } else {
+ /* malloc check ok, overflow check above */
+ im->block = (char *)calloc(im->ysize, im->linesize);
+ }
+
+ if (!im->block) {
+ return (Imaging)ImagingError_MemoryError();
+ }
+
+ for (y = i = 0; y < im->ysize; y++) {
+ im->image[y] = im->block + i;
+ i += im->linesize;
+ }
+
+ im->destroy = ImagingDestroyBlock;
+
+ return im;
+}
+
+/* --------------------------------------------------------------------
+ * Create a new, internally allocated, image.
+ */
+
+Imaging
+ImagingNewInternal(const char *mode, int xsize, int ysize, int dirty) {
+ Imaging im;
+
+ if (xsize < 0 || ysize < 0) {
+ return (Imaging)ImagingError_ValueError("bad image size");
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if (!im) {
+ return NULL;
+ }
+
+ if (ImagingAllocateArray(im, dirty, ImagingDefaultArena.block_size)) {
+ return im;
+ }
+
+ ImagingError_Clear();
+
+ // Try to allocate the image once more with smallest possible block size
+ if (ImagingAllocateArray(im, dirty, IMAGING_PAGE_SIZE)) {
+ return im;
+ }
+
+ ImagingDelete(im);
+ return NULL;
+}
+
+Imaging
+ImagingNew(const char *mode, int xsize, int ysize) {
+ return ImagingNewInternal(mode, xsize, ysize, 0);
+}
+
+Imaging
+ImagingNewDirty(const char *mode, int xsize, int ysize) {
+ return ImagingNewInternal(mode, xsize, ysize, 1);
+}
+
+Imaging
+ImagingNewBlock(const char *mode, int xsize, int ysize) {
+ Imaging im;
+
+ if (xsize < 0 || ysize < 0) {
+ return (Imaging)ImagingError_ValueError("bad image size");
+ }
+
+ im = ImagingNewPrologue(mode, xsize, ysize);
+ if (!im) {
+ return NULL;
+ }
+
+ if (ImagingAllocateBlock(im)) {
+ return im;
+ }
+
+ ImagingDelete(im);
+ return NULL;
+}
+
+Imaging
+ImagingNew2Dirty(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 = ImagingNewDirty(mode, imIn->xsize, imIn->ysize);
+ if (!imOut) {
+ return NULL;
+ }
+ }
+
+ return imOut;
+}
+
+void
+ImagingCopyPalette(Imaging destination, Imaging source) {
+ if (source->palette) {
+ if (destination->palette) {
+ ImagingPaletteDelete(destination->palette);
+ }
+ destination->palette = ImagingPaletteDuplicate(source->palette);
+ }
+}