From d44212d650d9ae876170450dc6c0db508c0c305c Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sat, 24 Aug 2024 16:18:27 +0100 Subject: [PATCH] WIP - Non working struct encoding * structs can't be encoded this way, they need to have one child array per struct member. * i.e. struct of arrays, rather than an array of structs. --- src/PIL/Image.py | 2 + src/_imaging.c | 6 +-- src/libImaging/Arrow.c | 91 +++++++++++++++++++++++++++++++++++++++- src/libImaging/Imaging.h | 4 ++ src/libImaging/Storage.c | 60 ++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 5 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 963b00fe2..49bd19ae4 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -750,9 +750,11 @@ class Image: def __arrow_c_schema__(self) -> object: + self.load() return self.im.__arrow_c_schema__() def __arrow_c_array__(self, requested_schema: object | None = None) -> Tuple[object, object]: + self.load() return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__()) def __getstate__(self) -> list[Any]: diff --git a/src/_imaging.c b/src/_imaging.c index eccdcb9e8..eea719a5f 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -239,8 +239,8 @@ void ReleaseArrowSchemaPyCapsule(PyObject* capsule) { PyObject* ExportArrowSchemaPyCapsule(ImagingObject *self) { struct ArrowSchema* schema = - (struct ArrowSchema*)malloc(sizeof(struct ArrowSchema)); - export_uint32_type(schema); + (struct ArrowSchema*)calloc(1, sizeof(struct ArrowSchema)); + export_imaging_schema(self->image, schema); return PyCapsule_New(schema, "arrow_schema", ReleaseArrowSchemaPyCapsule); } @@ -255,7 +255,7 @@ void ReleaseArrowArrayPyCapsule(PyObject* capsule) { PyObject* ExportArrowArrayPyCapsule(ImagingObject *self) { struct ArrowArray* array = - (struct ArrowArray*)malloc(sizeof(struct ArrowArray)); + (struct ArrowArray*)calloc(1, sizeof(struct ArrowArray)); export_imaging_array(self->image, array); return PyCapsule_New(array, "arrow_array", ReleaseArrowArrayPyCapsule); } diff --git a/src/libImaging/Arrow.c b/src/libImaging/Arrow.c index 3a6d9dd60..550fb07d8 100644 --- a/src/libImaging/Arrow.c +++ b/src/libImaging/Arrow.c @@ -1,6 +1,7 @@ #include "Arrow.h" #include "Imaging.h" +#include /* struct ArrowSchema* */ /* _arrow_schema_channel(char* channel, char* format) { */ @@ -12,6 +13,18 @@ ReleaseExportedSchema(struct ArrowSchema* array) { // This should not be called on already released array //assert(array->release != NULL); + if (!array->release) { + return; + } + if (array->format) { + free((void*)array->format); + array->format = NULL; + } + if (array->name) { + free((void*)array->name); + array->name = NULL; + } + // Release children for (int64_t i = 0; i < array->n_children; ++i) { struct ArrowSchema* child = array->children[i]; @@ -36,7 +49,80 @@ ReleaseExportedSchema(struct ArrowSchema* array) { } -static void release_uint32_type(struct ArrowSchema* schema) { + +int export_named_type(struct ArrowSchema* schema, + char* format, + char* name) { + + char* formatp; + char* namep; + size_t format_len = strlen(format) + 1; + size_t name_len = strlen(name) + 1; + + formatp = calloc(format_len, 1); + + if (!formatp) { + return 1; + } + + namep = calloc(name_len, 1); + if (!namep){ + free(formatp); + return 1; + } + + strlcpy(formatp, format, format_len); + strlcpy(namep, name, name_len); + + *schema = (struct ArrowSchema) { + // Type description + .format = formatp, + .name = namep, + .metadata = NULL, + .flags = 0, + .n_children = 0, + .children = NULL, + .dictionary = NULL, + // Bookkeeping + .release = &ReleaseExportedSchema + }; + return 0; +} + +int export_imaging_schema(Imaging im, struct ArrowSchema* schema) { + int retval = 0; + + if (strcmp(im->arrow_band_format, "") == 0) { + return 1; + } + + if (im->bands == 1) { + return export_named_type(schema, im->arrow_band_format, im->band_names[0]); + } + + retval = export_named_type(schema, "+s", ""); + if (retval) { + return retval; + } + // if it's not 1 band, it's an int32 at the moment. 4 unint8 bands. + schema->n_children = 4; + schema->children = calloc(4, sizeof(struct ArrowSchema*)); + for (int i=0; i<4; i++) { + schema->children[i] = + (struct ArrowSchema*)calloc(1, sizeof(struct ArrowSchema)); + if (export_named_type(schema->children[i], im->arrow_band_format, im->band_names[i])) { + /* error recovery */ + for (int j=i-1; i>=0; i--) { + schema->children[j]->release(schema->children[j]); + free(schema->children[j]); + } + return 2; + } + } + return 0; +} + +static void release_simple_type(struct ArrowSchema* schema) { // Mark released schema->release = NULL; } @@ -52,10 +138,11 @@ void export_uint32_type(struct ArrowSchema* schema) { .children = NULL, .dictionary = NULL, // Bookkeeping - .release = &release_uint32_type + .release = &release_simple_type }; } + static void release_uint32_array(struct ArrowArray* array) { //assert(array->n_buffers == 2); // Free the buffers and the buffers array diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index a47ebedf0..79c24fd35 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -109,6 +109,9 @@ struct ImagingMemoryInstance { int arrow_borrow; /* Number of arrow arrays that have been allocated */ int blocks_count; /* Number of blocks that have been allocated */ int lines_per_block; /* Number of lines in a block have been allocated */ + + char band_names[4][3]; /* names of bands, max 2 char + null terminator */ + char arrow_band_format[2]; /* single character + null terminator */ }; #define IMAGING_PIXEL_1(im, x, y) ((im)->image8[(y)][(x)]) @@ -711,6 +714,7 @@ _imaging_tell_pyFd(PyObject *fd); #include "Arrow.h" extern void export_imaging_array(Imaging im, struct ArrowArray* array); +extern int export_imaging_schema(Imaging im, struct ArrowSchema* schema); extern void export_uint32_type(struct ArrowSchema* schema); /* Errcodes */ diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index 1e3d6fce0..49e545367 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -60,17 +60,20 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->ysize = ysize; im->type = IMAGING_TYPE_UINT8; + strcpy(im->arrow_band_format, "C"); if (strcmp(mode, "1") == 0) { /* 1-bit images */ im->bands = im->pixelsize = 1; im->linesize = xsize; + strcpy(im->band_names[0],"1"); } else if (strcmp(mode, "P") == 0) { /* 8-bit palette mapped images */ im->bands = im->pixelsize = 1; im->linesize = xsize; im->palette = ImagingPaletteNew("RGB"); + strcpy(im->band_names[0],"P"); } else if (strcmp(mode, "PA") == 0) { /* 8-bit palette with alpha */ @@ -78,23 +81,36 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 4; /* store in image32 memory */ im->linesize = xsize * 4; im->palette = ImagingPaletteNew("RGB"); + strcpy(im->band_names[0],"P"); + strcpy(im->band_names[1],"X"); + strcpy(im->band_names[2],"X"); + strcpy(im->band_names[3],"A"); } else if (strcmp(mode, "L") == 0) { /* 8-bit grayscale (luminance) images */ im->bands = im->pixelsize = 1; im->linesize = xsize; + strcpy(im->band_names[0],"L"); } else if (strcmp(mode, "LA") == 0) { /* 8-bit grayscale (luminance) with alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ im->linesize = xsize * 4; + strcpy(im->band_names[0],"L"); + strcpy(im->band_names[1],"X"); + strcpy(im->band_names[2],"X"); + strcpy(im->band_names[3],"A"); } else if (strcmp(mode, "La") == 0) { /* 8-bit grayscale (luminance) with premultiplied alpha */ im->bands = 2; im->pixelsize = 4; /* store in image32 memory */ im->linesize = xsize * 4; + strcpy(im->band_names[0],"L"); + strcpy(im->band_names[1],"X"); + strcpy(im->band_names[2],"X"); + strcpy(im->band_names[3],"a"); } else if (strcmp(mode, "F") == 0) { /* 32-bit floating point images */ @@ -102,6 +118,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 4; im->linesize = xsize * 4; im->type = IMAGING_TYPE_FLOAT32; + strcpy(im->arrow_band_format , "f"); + strcpy(im->band_names[0],"F"); } else if (strcmp(mode, "I") == 0) { /* 32-bit integer images */ @@ -109,6 +127,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 4; im->linesize = xsize * 4; im->type = IMAGING_TYPE_INT32; + strcpy(im->arrow_band_format , "i"); + strcpy(im->band_names[0],"I"); } else if (strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 || strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) { @@ -118,12 +138,18 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 2; im->linesize = xsize * 2; im->type = IMAGING_TYPE_SPECIAL; + strcpy(im->arrow_band_format , "s"); + strcpy(im->band_names[0],"I"); } else if (strcmp(mode, "RGB") == 0) { /* 24-bit true colour images */ im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"R"); + strcpy(im->band_names[1],"G"); + strcpy(im->band_names[2],"B"); + strcpy(im->band_names[3],"X"); } else if (strcmp(mode, "BGR;15") == 0) { /* EXPERIMENTAL */ @@ -132,6 +158,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 2; im->linesize = (xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; + /* not allowing arrow due to line length packing */ + strcpy(im->arrow_band_format , ""); } else if (strcmp(mode, "BGR;16") == 0) { /* EXPERIMENTAL */ @@ -140,6 +168,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 2; im->linesize = (xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; + /* not allowing arrow due to line length packing */ + strcpy(im->arrow_band_format , ""); } else if (strcmp(mode, "BGR;24") == 0) { /* EXPERIMENTAL */ @@ -148,32 +178,54 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->pixelsize = 3; im->linesize = (xsize * 3 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; + /* not allowing arrow due to line length packing */ + strcpy(im->arrow_band_format , ""); } else if (strcmp(mode, "RGBX") == 0) { /* 32-bit true colour images with padding */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"R"); + strcpy(im->band_names[1],"G"); + strcpy(im->band_names[2],"B"); + strcpy(im->band_names[3],"X"); } else if (strcmp(mode, "RGBA") == 0) { /* 32-bit true colour images with alpha */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"R"); + strcpy(im->band_names[1],"G"); + strcpy(im->band_names[2],"B"); + strcpy(im->band_names[3],"A"); } else if (strcmp(mode, "RGBa") == 0) { /* 32-bit true colour images with premultiplied alpha */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"R"); + strcpy(im->band_names[1],"G"); + strcpy(im->band_names[2],"B"); + strcpy(im->band_names[3],"a"); } else if (strcmp(mode, "CMYK") == 0) { /* 32-bit colour separation */ im->bands = im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"C"); + strcpy(im->band_names[1],"M"); + strcpy(im->band_names[2],"Y"); + strcpy(im->band_names[3],"K"); } else if (strcmp(mode, "YCbCr") == 0) { /* 24-bit video format */ im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"Y"); + strcpy(im->band_names[1],"Cb"); + strcpy(im->band_names[2],"Cr"); + strcpy(im->band_names[3],"X"); } else if (strcmp(mode, "LAB") == 0) { /* 24-bit color, luminance, + 2 color channels */ @@ -181,6 +233,10 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"L"); + strcpy(im->band_names[1],"a"); + strcpy(im->band_names[2],"b"); + strcpy(im->band_names[3],"X"); } else if (strcmp(mode, "HSV") == 0) { /* 24-bit color, luminance, + 2 color channels */ @@ -188,6 +244,10 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { im->bands = 3; im->pixelsize = 4; im->linesize = xsize * 4; + strcpy(im->band_names[0],"H"); + strcpy(im->band_names[1],"S"); + strcpy(im->band_names[2],"V"); + strcpy(im->band_names[3],"X"); } else { free(im);