mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 17:54:32 +03:00
WIP - Initial Pillow->Arrow support
* Fixed format, only for 4 channel images
This commit is contained in:
parent
b14142462e
commit
cd31fa5bfe
1
setup.py
1
setup.py
|
@ -62,6 +62,7 @@ _IMAGING = ("decode", "encode", "map", "display", "outline", "path")
|
||||||
_LIB_IMAGING = (
|
_LIB_IMAGING = (
|
||||||
"Access",
|
"Access",
|
||||||
"AlphaComposite",
|
"AlphaComposite",
|
||||||
|
"Arrow",
|
||||||
"Resample",
|
"Resample",
|
||||||
"Reduce",
|
"Reduce",
|
||||||
"Bands",
|
"Bands",
|
||||||
|
|
|
@ -744,6 +744,13 @@ class Image:
|
||||||
new["shape"], new["typestr"] = _conv_type_shape(self)
|
new["shape"], new["typestr"] = _conv_type_shape(self)
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
|
||||||
|
def __arrow_c_schema__(self) -> object:
|
||||||
|
return self.im.__arrow_c_schema__()
|
||||||
|
|
||||||
|
def __arrow_c_array__(self, requested_schema: object | None = None) -> Tuple[object, object]:
|
||||||
|
return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__())
|
||||||
|
|
||||||
def __getstate__(self) -> list[Any]:
|
def __getstate__(self) -> list[Any]:
|
||||||
im_data = self.tobytes() # load image first
|
im_data = self.tobytes() # load image first
|
||||||
return [self.info, self.mode, self.size, self.getpalette(), im_data]
|
return [self.info, self.mode, self.size, self.getpalette(), im_data]
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libImaging/Imaging.h"
|
#include "libImaging/Imaging.h"
|
||||||
|
#include "libImaging/Arrow.h"
|
||||||
|
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -223,6 +224,43 @@ PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view) {
|
||||||
return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
|
return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* Arrow HANDLING */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void ReleaseArrowSchemaPyCapsule(PyObject* capsule) {
|
||||||
|
struct ArrowSchema* schema =
|
||||||
|
(struct ArrowSchema*)PyCapsule_GetPointer(capsule, "arrow_schema");
|
||||||
|
if (schema->release != NULL) {
|
||||||
|
schema->release(schema);
|
||||||
|
}
|
||||||
|
free(schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* ExportArrowSchemaPyCapsule(ImagingObject *self) {
|
||||||
|
struct ArrowSchema* schema =
|
||||||
|
(struct ArrowSchema*)malloc(sizeof(struct ArrowSchema));
|
||||||
|
export_uint32_type(schema);
|
||||||
|
return PyCapsule_New(schema, "arrow_schema", ReleaseArrowSchemaPyCapsule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseArrowArrayPyCapsule(PyObject* capsule) {
|
||||||
|
struct ArrowArray* array =
|
||||||
|
(struct ArrowArray*)PyCapsule_GetPointer(capsule, "arrow_array");
|
||||||
|
if (array->release != NULL) {
|
||||||
|
array->release(array);
|
||||||
|
}
|
||||||
|
free(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* ExportArrowArrayPyCapsule(ImagingObject *self) {
|
||||||
|
struct ArrowArray* array =
|
||||||
|
(struct ArrowArray*)malloc(sizeof(struct ArrowArray));
|
||||||
|
export_imaging_array(self->image, array);
|
||||||
|
return PyCapsule_New(array, "arrow_array", ReleaseArrowArrayPyCapsule);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* EXCEPTION REROUTING */
|
/* EXCEPTION REROUTING */
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@ -3685,6 +3723,10 @@ static struct PyMethodDef methods[] = {
|
||||||
|
|
||||||
{"save_ppm", (PyCFunction)_save_ppm, METH_VARARGS},
|
{"save_ppm", (PyCFunction)_save_ppm, METH_VARARGS},
|
||||||
|
|
||||||
|
/* arrow */
|
||||||
|
{"__arrow_c_schema__", (PyCFunction)ExportArrowSchemaPyCapsule, METH_VARARGS},
|
||||||
|
{"__arrow_c_array__", (PyCFunction)ExportArrowArrayPyCapsule, METH_VARARGS},
|
||||||
|
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
139
src/libImaging/Arrow.c
Normal file
139
src/libImaging/Arrow.c
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
|
||||||
|
#include "Arrow.h"
|
||||||
|
#include "Imaging.h"
|
||||||
|
|
||||||
|
/* struct ArrowSchema* */
|
||||||
|
/* _arrow_schema_channel(char* channel, char* format) { */
|
||||||
|
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
static void
|
||||||
|
ReleaseExportedSchema(struct ArrowSchema* array) {
|
||||||
|
// This should not be called on already released array
|
||||||
|
//assert(array->release != NULL);
|
||||||
|
|
||||||
|
// Release children
|
||||||
|
for (int64_t i = 0; i < array->n_children; ++i) {
|
||||||
|
struct ArrowSchema* child = array->children[i];
|
||||||
|
if (child->release != NULL) {
|
||||||
|
child->release(child);
|
||||||
|
//assert(child->release == NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release dictionary
|
||||||
|
struct ArrowSchema* dict = array->dictionary;
|
||||||
|
if (dict != NULL && dict->release != NULL) {
|
||||||
|
dict->release(dict);
|
||||||
|
//assert(dict->release == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO here: release and/or deallocate all data directly owned by
|
||||||
|
// the ArrowArray struct, such as the private_data.
|
||||||
|
|
||||||
|
// Mark array released
|
||||||
|
array->release = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void release_uint32_type(struct ArrowSchema* schema) {
|
||||||
|
// Mark released
|
||||||
|
schema->release = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_uint32_type(struct ArrowSchema* schema) {
|
||||||
|
*schema = (struct ArrowSchema) {
|
||||||
|
// Type description
|
||||||
|
.format = "I",
|
||||||
|
.name = "",
|
||||||
|
.metadata = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.n_children = 0,
|
||||||
|
.children = NULL,
|
||||||
|
.dictionary = NULL,
|
||||||
|
// Bookkeeping
|
||||||
|
.release = &release_uint32_type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_uint32_array(struct ArrowArray* array) {
|
||||||
|
//assert(array->n_buffers == 2);
|
||||||
|
// Free the buffers and the buffers array
|
||||||
|
free((void *) array->buffers[1]);
|
||||||
|
free(array->buffers);
|
||||||
|
// Mark released
|
||||||
|
array->release = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_uint32_array(const uint32_t* data, int64_t nitems,
|
||||||
|
struct ArrowArray* array) {
|
||||||
|
// Initialize primitive fields
|
||||||
|
*array = (struct ArrowArray) {
|
||||||
|
// Data description
|
||||||
|
.length = nitems,
|
||||||
|
.offset = 0,
|
||||||
|
.null_count = 0,
|
||||||
|
.n_buffers = 2,
|
||||||
|
.n_children = 0,
|
||||||
|
.children = NULL,
|
||||||
|
.dictionary = NULL,
|
||||||
|
// Bookkeeping
|
||||||
|
.release = &release_uint32_array
|
||||||
|
};
|
||||||
|
// Allocate list of buffers
|
||||||
|
array->buffers = (const void**) malloc(sizeof(void*) * array->n_buffers);
|
||||||
|
//assert(array->buffers != NULL);
|
||||||
|
array->buffers[0] = NULL; // no nulls, null bitmap can be omitted
|
||||||
|
array->buffers[1] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_const_array(struct ArrowArray* array) {
|
||||||
|
Imaging im = (Imaging)array->private_data;
|
||||||
|
im->arrow_borrow--;
|
||||||
|
ImagingDelete(im);
|
||||||
|
|
||||||
|
//assert(array->n_buffers == 2);
|
||||||
|
// Free the buffers and the buffers array
|
||||||
|
free(array->buffers);
|
||||||
|
// Mark released
|
||||||
|
array->release = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void export_imaging_array(Imaging im, struct ArrowArray* array) {
|
||||||
|
int length = im->xsize * im->ysize;
|
||||||
|
|
||||||
|
/* undone -- for now, single block images */
|
||||||
|
//assert (im->block_count = 0 || im->block_count = 1);
|
||||||
|
|
||||||
|
if (im->lines_per_block && im->lines_per_block < im->ysize) {
|
||||||
|
length = im->xsize * im->lines_per_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
im->arrow_borrow++;
|
||||||
|
// Initialize primitive fields
|
||||||
|
*array = (struct ArrowArray) {
|
||||||
|
// Data description
|
||||||
|
.length = length,
|
||||||
|
.offset = 0,
|
||||||
|
.null_count = 0,
|
||||||
|
.n_buffers = 2,
|
||||||
|
.n_children = 0,
|
||||||
|
.children = NULL,
|
||||||
|
.dictionary = NULL,
|
||||||
|
// Bookkeeping
|
||||||
|
.release = &release_const_array,
|
||||||
|
.private_data = im
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allocate list of buffers
|
||||||
|
array->buffers = (const void**) malloc(sizeof(void*) * array->n_buffers);
|
||||||
|
//assert(array->buffers != NULL);
|
||||||
|
array->buffers[0] = NULL; // no nulls, null bitmap can be omitted
|
||||||
|
|
||||||
|
if (im->block) {
|
||||||
|
array->buffers[1] = im->block;
|
||||||
|
} else {
|
||||||
|
array->buffers[1] = im->blocks[0].ptr;
|
||||||
|
}
|
||||||
|
}
|
48
src/libImaging/Arrow.h
Normal file
48
src/libImaging/Arrow.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// Apache License 2.0.
|
||||||
|
// Source apache arrow project
|
||||||
|
// https://arrow.apache.org/docs/format/CDataInterface.html
|
||||||
|
|
||||||
|
#ifndef ARROW_C_DATA_INTERFACE
|
||||||
|
#define ARROW_C_DATA_INTERFACE
|
||||||
|
|
||||||
|
#define ARROW_FLAG_DICTIONARY_ORDERED 1
|
||||||
|
#define ARROW_FLAG_NULLABLE 2
|
||||||
|
#define ARROW_FLAG_MAP_KEYS_SORTED 4
|
||||||
|
|
||||||
|
struct ArrowSchema {
|
||||||
|
// Array type description
|
||||||
|
const char* format;
|
||||||
|
const char* name;
|
||||||
|
const char* metadata;
|
||||||
|
int64_t flags;
|
||||||
|
int64_t n_children;
|
||||||
|
struct ArrowSchema** children;
|
||||||
|
struct ArrowSchema* dictionary;
|
||||||
|
|
||||||
|
// Release callback
|
||||||
|
void (*release)(struct ArrowSchema*);
|
||||||
|
// Opaque producer-specific data
|
||||||
|
void* private_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArrowArray {
|
||||||
|
// Array data description
|
||||||
|
int64_t length;
|
||||||
|
int64_t null_count;
|
||||||
|
int64_t offset;
|
||||||
|
int64_t n_buffers;
|
||||||
|
int64_t n_children;
|
||||||
|
const void** buffers;
|
||||||
|
struct ArrowArray** children;
|
||||||
|
struct ArrowArray* dictionary;
|
||||||
|
|
||||||
|
// Release callback
|
||||||
|
void (*release)(struct ArrowArray*);
|
||||||
|
// Opaque producer-specific data
|
||||||
|
void* private_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ARROW_C_DATA_INTERFACE
|
|
@ -104,6 +104,11 @@ struct ImagingMemoryInstance {
|
||||||
|
|
||||||
/* Virtual methods */
|
/* Virtual methods */
|
||||||
void (*destroy)(Imaging im);
|
void (*destroy)(Imaging im);
|
||||||
|
|
||||||
|
/* arrow */
|
||||||
|
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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IMAGING_PIXEL_1(im, x, y) ((im)->image8[(y)][(x)])
|
#define IMAGING_PIXEL_1(im, x, y) ((im)->image8[(y)][(x)])
|
||||||
|
@ -702,6 +707,12 @@ _imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence);
|
||||||
extern Py_ssize_t
|
extern Py_ssize_t
|
||||||
_imaging_tell_pyFd(PyObject *fd);
|
_imaging_tell_pyFd(PyObject *fd);
|
||||||
|
|
||||||
|
/* Arrow */
|
||||||
|
|
||||||
|
#include "Arrow.h"
|
||||||
|
extern void export_imaging_array(Imaging im, struct ArrowArray* array);
|
||||||
|
extern void export_uint32_type(struct ArrowSchema* schema);
|
||||||
|
|
||||||
/* Errcodes */
|
/* Errcodes */
|
||||||
#define IMAGING_CODEC_END 1
|
#define IMAGING_CODEC_END 1
|
||||||
#define IMAGING_CODEC_OVERRUN -1
|
#define IMAGING_CODEC_OVERRUN -1
|
||||||
|
|
|
@ -240,6 +240,11 @@ ImagingDelete(Imaging im) {
|
||||||
|
|
||||||
if (im->palette) {
|
if (im->palette) {
|
||||||
ImagingPaletteDelete(im->palette);
|
ImagingPaletteDelete(im->palette);
|
||||||
|
im->palette = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (im->arrow_borrow) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (im->destroy) {
|
if (im->destroy) {
|
||||||
|
@ -396,11 +401,13 @@ ImagingAllocateArray(Imaging im, ImagingMemoryArena arena, int dirty, int block_
|
||||||
if (lines_per_block == 0) {
|
if (lines_per_block == 0) {
|
||||||
lines_per_block = 1;
|
lines_per_block = 1;
|
||||||
}
|
}
|
||||||
|
im->lines_per_block = lines_per_block;
|
||||||
blocks_count = (im->ysize + lines_per_block - 1) / lines_per_block;
|
blocks_count = (im->ysize + lines_per_block - 1) / lines_per_block;
|
||||||
// printf("NEW size: %dx%d, ls: %d, lpb: %d, blocks: %d\n",
|
// printf("NEW size: %dx%d, ls: %d, lpb: %d, blocks: %d\n",
|
||||||
// im->xsize, im->ysize, aligned_linesize, lines_per_block, blocks_count);
|
// im->xsize, im->ysize, aligned_linesize, lines_per_block, blocks_count);
|
||||||
|
|
||||||
/* One extra pointer is always NULL */
|
/* One extra pointer is always NULL */
|
||||||
|
im->blocks_count = blocks_count;
|
||||||
im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1);
|
im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1);
|
||||||
if (!im->blocks) {
|
if (!im->blocks) {
|
||||||
return (Imaging)ImagingError_MemoryError();
|
return (Imaging)ImagingError_MemoryError();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user