mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-22 23:00:36 +03:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
9313587fec
commit
4256b2a8c5
252
src/_jpegxl.c
252
src/_jpegxl.c
|
@ -8,15 +8,18 @@
|
||||||
#include <jxl/types.h>
|
#include <jxl/types.h>
|
||||||
#include <jxl/thread_parallel_runner.h>
|
#include <jxl/thread_parallel_runner.h>
|
||||||
|
|
||||||
#define _PIL_JXL_CHECK(call_name) if (decp->status != JXL_DEC_SUCCESS) { jxl_call_name = call_name; goto end; }
|
#define _PIL_JXL_CHECK(call_name) \
|
||||||
|
if (decp->status != JXL_DEC_SUCCESS) { \
|
||||||
|
jxl_call_name = call_name; \
|
||||||
void _pil_jxl_get_pixel_format(JxlPixelFormat *pf, const JxlBasicInfo *bi) {
|
goto end; \
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_pil_jxl_get_pixel_format(JxlPixelFormat *pf, const JxlBasicInfo *bi) {
|
||||||
pf->num_channels = bi->num_color_channels + bi->num_extra_channels;
|
pf->num_channels = bi->num_color_channels + bi->num_extra_channels;
|
||||||
|
|
||||||
if (bi->exponent_bits_per_sample > 0 || bi->alpha_exponent_bits > 0) {
|
if (bi->exponent_bits_per_sample > 0 || bi->alpha_exponent_bits > 0) {
|
||||||
pf->data_type = JXL_TYPE_FLOAT; // not yet supported
|
pf->data_type = JXL_TYPE_FLOAT; // not yet supported
|
||||||
} else if (bi->bits_per_sample > 8) {
|
} else if (bi->bits_per_sample > 8) {
|
||||||
pf->data_type = JXL_TYPE_UINT16; // not yet supported
|
pf->data_type = JXL_TYPE_UINT16; // not yet supported
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,40 +30,44 @@ void _pil_jxl_get_pixel_format(JxlPixelFormat *pf, const JxlBasicInfo *bi) {
|
||||||
// would be great to test it
|
// would be great to test it
|
||||||
pf->endianness = JXL_NATIVE_ENDIAN;
|
pf->endianness = JXL_NATIVE_ENDIAN;
|
||||||
pf->align = 0;
|
pf->align = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: floating point mode
|
// TODO: floating point mode
|
||||||
char* _pil_jxl_get_mode(const JxlBasicInfo *bi) {
|
char *
|
||||||
|
_pil_jxl_get_mode(const JxlBasicInfo *bi) {
|
||||||
// 16-bit single channel images are supported
|
// 16-bit single channel images are supported
|
||||||
if (bi->bits_per_sample == 16 && bi->num_color_channels == 1 &&
|
if (bi->bits_per_sample == 16 && bi->num_color_channels == 1 &&
|
||||||
bi->alpha_bits == 0 && !bi->alpha_premultiplied
|
bi->alpha_bits == 0 && !bi->alpha_premultiplied)
|
||||||
) return "I;16";
|
return "I;16";
|
||||||
|
|
||||||
// PIL doesn't support high bit depth images
|
// PIL doesn't support high bit depth images
|
||||||
// it will throw an exception but that's for your own good
|
// it will throw an exception but that's for your own good
|
||||||
// you wouldn't want to see distorted image
|
// you wouldn't want to see distorted image
|
||||||
if (bi->bits_per_sample != 8) return "uns";
|
if (bi->bits_per_sample != 8)
|
||||||
|
return "uns";
|
||||||
|
|
||||||
// image has transparency
|
// image has transparency
|
||||||
if (bi->alpha_bits > 0) {
|
if (bi->alpha_bits > 0) {
|
||||||
if (bi->num_color_channels == 3) {
|
if (bi->num_color_channels == 3) {
|
||||||
if (bi->alpha_premultiplied) return "RGBa";
|
if (bi->alpha_premultiplied)
|
||||||
|
return "RGBa";
|
||||||
return "RGBA";
|
return "RGBA";
|
||||||
} if (bi->num_color_channels == 1) {
|
}
|
||||||
if (bi->alpha_premultiplied) return "La";
|
if (bi->num_color_channels == 1) {
|
||||||
|
if (bi->alpha_premultiplied)
|
||||||
|
return "La";
|
||||||
return "LA";
|
return "LA";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// image has no transparency
|
// image has no transparency
|
||||||
if (bi->num_color_channels == 3) return "RGB";
|
if (bi->num_color_channels == 3)
|
||||||
if (bi->num_color_channels == 1) return "L";
|
return "RGB";
|
||||||
|
if (bi->num_color_channels == 1)
|
||||||
|
return "L";
|
||||||
|
|
||||||
// could not recognize mode
|
// could not recognize mode
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoder type
|
// Decoder type
|
||||||
|
@ -68,8 +75,8 @@ typedef struct {
|
||||||
PyObject_HEAD JxlDecoder *decoder;
|
PyObject_HEAD JxlDecoder *decoder;
|
||||||
void *runner;
|
void *runner;
|
||||||
|
|
||||||
uint8_t *jxl_data; // input jxl bitstream
|
uint8_t *jxl_data; // input jxl bitstream
|
||||||
Py_ssize_t jxl_data_len; // length of input jxl bitstream
|
Py_ssize_t jxl_data_len; // length of input jxl bitstream
|
||||||
|
|
||||||
uint8_t *outbuf;
|
uint8_t *outbuf;
|
||||||
Py_ssize_t outbuf_len;
|
Py_ssize_t outbuf_len;
|
||||||
|
@ -135,24 +142,22 @@ _jxl_decoder_dealloc(PyObject *self) {
|
||||||
|
|
||||||
// sets input jxl bitstream loaded into jxl_data
|
// sets input jxl bitstream loaded into jxl_data
|
||||||
// has to be called after every rewind
|
// has to be called after every rewind
|
||||||
void _jxl_decoder_set_input(PyObject *self) {
|
void
|
||||||
|
_jxl_decoder_set_input(PyObject *self) {
|
||||||
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
||||||
|
|
||||||
decp->status = JxlDecoderSetInput(decp->decoder, decp->jxl_data,
|
decp->status =
|
||||||
decp->jxl_data_len);
|
JxlDecoderSetInput(decp->decoder, decp->jxl_data, decp->jxl_data_len);
|
||||||
|
|
||||||
// the input contains the whole jxl bitstream so it can be closed
|
// the input contains the whole jxl bitstream so it can be closed
|
||||||
JxlDecoderCloseInput(decp->decoder);
|
JxlDecoderCloseInput(decp->decoder);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_jxl_decoder_rewind(PyObject *self) {
|
_jxl_decoder_rewind(PyObject *self) {
|
||||||
|
|
||||||
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
||||||
JxlDecoderRewind(decp->decoder);
|
JxlDecoderRewind(decp->decoder);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -163,7 +168,7 @@ _jxl_decoder_count_frames(PyObject *self) {
|
||||||
|
|
||||||
// count all JXL_DEC_NEED_IMAGE_OUT_BUFFER events
|
// count all JXL_DEC_NEED_IMAGE_OUT_BUFFER events
|
||||||
while (decp->status != JXL_DEC_SUCCESS) {
|
while (decp->status != JXL_DEC_SUCCESS) {
|
||||||
//printf("fetch_frame_count status: %u\n", decp->status);
|
// printf("fetch_frame_count status: %u\n", decp->status);
|
||||||
decp->status = JxlDecoderProcessInput(decp->decoder);
|
decp->status = JxlDecoderProcessInput(decp->decoder);
|
||||||
|
|
||||||
if (decp->status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
if (decp->status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
||||||
|
@ -177,7 +182,6 @@ _jxl_decoder_count_frames(PyObject *self) {
|
||||||
_jxl_decoder_rewind((PyObject *)decp);
|
_jxl_decoder_rewind((PyObject *)decp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -200,7 +204,7 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
decp->n_frames = 0;
|
decp->n_frames = 0;
|
||||||
|
|
||||||
// used for printing more detailed error messages
|
// used for printing more detailed error messages
|
||||||
char* jxl_call_name;
|
char *jxl_call_name;
|
||||||
|
|
||||||
// parse one argument which is a string with jxl data
|
// parse one argument which is a string with jxl data
|
||||||
if (!PyArg_ParseTuple(args, "S", &jxl_string)) {
|
if (!PyArg_ParseTuple(args, "S", &jxl_string)) {
|
||||||
|
@ -213,28 +217,28 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
Py_ssize_t _tmp_jxl_data_len;
|
Py_ssize_t _tmp_jxl_data_len;
|
||||||
|
|
||||||
// convert jxl data string to C uint8_t pointer
|
// convert jxl data string to C uint8_t pointer
|
||||||
PyBytes_AsStringAndSize((PyObject *)jxl_string, (char **)&_tmp_jxl_data, &_tmp_jxl_data_len);
|
PyBytes_AsStringAndSize(
|
||||||
|
(PyObject *)jxl_string, (char **)&_tmp_jxl_data, &_tmp_jxl_data_len);
|
||||||
|
|
||||||
// here occurs this copying (inefficiency)
|
// here occurs this copying (inefficiency)
|
||||||
decp->jxl_data = malloc(_tmp_jxl_data_len);
|
decp->jxl_data = malloc(_tmp_jxl_data_len);
|
||||||
memcpy(decp->jxl_data, _tmp_jxl_data, _tmp_jxl_data_len);
|
memcpy(decp->jxl_data, _tmp_jxl_data, _tmp_jxl_data_len);
|
||||||
decp->jxl_data_len = _tmp_jxl_data_len;
|
decp->jxl_data_len = _tmp_jxl_data_len;
|
||||||
|
|
||||||
//printf("%zu\n", decp->jxl_data_len);
|
// printf("%zu\n", decp->jxl_data_len);
|
||||||
|
|
||||||
size_t suggested_num_threads = JxlThreadParallelRunnerDefaultNumWorkerThreads();
|
size_t suggested_num_threads = JxlThreadParallelRunnerDefaultNumWorkerThreads();
|
||||||
decp->runner = JxlThreadParallelRunnerCreate(NULL, suggested_num_threads);
|
decp->runner = JxlThreadParallelRunnerCreate(NULL, suggested_num_threads);
|
||||||
decp->decoder = JxlDecoderCreate(NULL);
|
decp->decoder = JxlDecoderCreate(NULL);
|
||||||
|
|
||||||
decp->status = JxlDecoderSetParallelRunner(decp->decoder,
|
decp->status = JxlDecoderSetParallelRunner(
|
||||||
JxlThreadParallelRunner, decp->runner);
|
decp->decoder, JxlThreadParallelRunner, decp->runner);
|
||||||
_PIL_JXL_CHECK("JxlDecoderSetParallelRunner")
|
_PIL_JXL_CHECK("JxlDecoderSetParallelRunner")
|
||||||
|
|
||||||
decp->status = JxlDecoderSubscribeEvents(decp->decoder,
|
decp->status = JxlDecoderSubscribeEvents(
|
||||||
JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING
|
decp->decoder,
|
||||||
| JXL_DEC_FRAME | JXL_DEC_BOX
|
JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME | JXL_DEC_BOX |
|
||||||
| JXL_DEC_FULL_IMAGE
|
JXL_DEC_FULL_IMAGE);
|
||||||
);
|
|
||||||
_PIL_JXL_CHECK("JxlDecoderSubscribeEvents")
|
_PIL_JXL_CHECK("JxlDecoderSubscribeEvents")
|
||||||
|
|
||||||
// tell libjxl to decompress boxes (for example Exif is usually compressed)
|
// tell libjxl to decompress boxes (for example Exif is usually compressed)
|
||||||
|
@ -246,11 +250,10 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
|
|
||||||
// decode everything up to the first frame
|
// decode everything up to the first frame
|
||||||
do {
|
do {
|
||||||
|
|
||||||
decp->status = JxlDecoderProcessInput(decp->decoder);
|
decp->status = JxlDecoderProcessInput(decp->decoder);
|
||||||
//printf("Status: %d\n", decp->status);
|
// printf("Status: %d\n", decp->status);
|
||||||
|
|
||||||
decoder_loop_skip_process:
|
decoder_loop_skip_process:
|
||||||
|
|
||||||
// there was an error at JxlDecoderProcessInput stage
|
// there was an error at JxlDecoderProcessInput stage
|
||||||
if (decp->status == JXL_DEC_ERROR) {
|
if (decp->status == JXL_DEC_ERROR) {
|
||||||
|
@ -260,18 +263,15 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
|
|
||||||
// got basic info
|
// got basic info
|
||||||
if (decp->status == JXL_DEC_BASIC_INFO) {
|
if (decp->status == JXL_DEC_BASIC_INFO) {
|
||||||
|
decp->status = JxlDecoderGetBasicInfo(decp->decoder, &decp->basic_info);
|
||||||
decp->status = JxlDecoderGetBasicInfo(decp->decoder,
|
|
||||||
&decp->basic_info);
|
|
||||||
_PIL_JXL_CHECK("JxlDecoderGetBasicInfo");
|
_PIL_JXL_CHECK("JxlDecoderGetBasicInfo");
|
||||||
|
|
||||||
_pil_jxl_get_pixel_format(&decp->pixel_format, &decp->basic_info);
|
_pil_jxl_get_pixel_format(&decp->pixel_format, &decp->basic_info);
|
||||||
if (decp->pixel_format.data_type != JXL_TYPE_UINT8 &&
|
if (decp->pixel_format.data_type != JXL_TYPE_UINT8 &&
|
||||||
decp->pixel_format.data_type != JXL_TYPE_UINT16) {
|
decp->pixel_format.data_type != JXL_TYPE_UINT16) {
|
||||||
|
|
||||||
// only 8 bit integer value images are supported for now
|
// only 8 bit integer value images are supported for now
|
||||||
PyErr_SetString(PyExc_NotImplementedError,
|
PyErr_SetString(
|
||||||
"unsupported pixel data type");
|
PyExc_NotImplementedError, "unsupported pixel data type");
|
||||||
goto end_with_custom_error;
|
goto end_with_custom_error;
|
||||||
}
|
}
|
||||||
decp->mode = _pil_jxl_get_mode(&decp->basic_info);
|
decp->mode = _pil_jxl_get_mode(&decp->basic_info);
|
||||||
|
@ -281,9 +281,8 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
|
|
||||||
// got color encoding
|
// got color encoding
|
||||||
if (decp->status == JXL_DEC_COLOR_ENCODING) {
|
if (decp->status == JXL_DEC_COLOR_ENCODING) {
|
||||||
|
decp->status = JxlDecoderGetICCProfileSize(
|
||||||
decp->status = JxlDecoderGetICCProfileSize(decp->decoder,
|
decp->decoder, JXL_COLOR_PROFILE_TARGET_DATA, &decp->jxl_icc_len);
|
||||||
JXL_COLOR_PROFILE_TARGET_DATA, &decp->jxl_icc_len);
|
|
||||||
_PIL_JXL_CHECK("JxlDecoderGetICCProfileSize");
|
_PIL_JXL_CHECK("JxlDecoderGetICCProfileSize");
|
||||||
|
|
||||||
decp->jxl_icc = malloc(decp->jxl_icc_len);
|
decp->jxl_icc = malloc(decp->jxl_icc_len);
|
||||||
|
@ -292,21 +291,23 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
goto end_with_custom_error;
|
goto end_with_custom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
decp->status = JxlDecoderGetColorAsICCProfile(decp->decoder,
|
decp->status = JxlDecoderGetColorAsICCProfile(
|
||||||
|
decp->decoder,
|
||||||
JXL_COLOR_PROFILE_TARGET_DATA,
|
JXL_COLOR_PROFILE_TARGET_DATA,
|
||||||
decp->jxl_icc, decp->jxl_icc_len);
|
decp->jxl_icc,
|
||||||
|
decp->jxl_icc_len);
|
||||||
_PIL_JXL_CHECK("JxlDecoderGetColorAsICCProfile");
|
_PIL_JXL_CHECK("JxlDecoderGetColorAsICCProfile");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decp->status == JXL_DEC_BOX) {
|
if (decp->status == JXL_DEC_BOX) {
|
||||||
|
|
||||||
char btype[4];
|
char btype[4];
|
||||||
decp->status = JxlDecoderGetBoxType(decp->decoder, btype, JXL_TRUE);
|
decp->status = JxlDecoderGetBoxType(decp->decoder, btype, JXL_TRUE);
|
||||||
_PIL_JXL_CHECK("JxlDecoderGetBoxType");
|
_PIL_JXL_CHECK("JxlDecoderGetBoxType");
|
||||||
|
|
||||||
//printf("found box type: %c%c%c%c\n", btype[0], btype[1], btype[2], btype[3]);
|
// printf("found box type: %c%c%c%c\n", btype[0], btype[1], btype[2],
|
||||||
|
// btype[3]);
|
||||||
|
|
||||||
bool is_box_exif, is_box_xmp;
|
bool is_box_exif, is_box_xmp;
|
||||||
is_box_exif = !memcmp(btype, "Exif", 4);
|
is_box_exif = !memcmp(btype, "Exif", 4);
|
||||||
|
@ -319,31 +320,35 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
size_t cur_compr_box_size;
|
size_t cur_compr_box_size;
|
||||||
decp->status = JxlDecoderGetBoxSizeRaw(decp->decoder, &cur_compr_box_size);
|
decp->status = JxlDecoderGetBoxSizeRaw(decp->decoder, &cur_compr_box_size);
|
||||||
_PIL_JXL_CHECK("JxlDecoderGetBoxSizeRaw");
|
_PIL_JXL_CHECK("JxlDecoderGetBoxSizeRaw");
|
||||||
//printf("Exif/xmp box size: %zu\n", cur_compr_box_size);
|
// printf("Exif/xmp box size: %zu\n", cur_compr_box_size);
|
||||||
|
|
||||||
uint8_t* final_jxl_buf = NULL;
|
uint8_t *final_jxl_buf = NULL;
|
||||||
Py_ssize_t final_jxl_buf_len = 0;
|
Py_ssize_t final_jxl_buf_len = 0;
|
||||||
|
|
||||||
// cur_box_size is actually compressed box size
|
// cur_box_size is actually compressed box size
|
||||||
// it will also serve as our chunk size
|
// it will also serve as our chunk size
|
||||||
do {
|
do {
|
||||||
uint8_t* _new_jxl_buf = realloc(final_jxl_buf, final_jxl_buf_len + cur_compr_box_size);
|
uint8_t *_new_jxl_buf =
|
||||||
|
realloc(final_jxl_buf, final_jxl_buf_len + cur_compr_box_size);
|
||||||
if (!_new_jxl_buf) {
|
if (!_new_jxl_buf) {
|
||||||
PyErr_SetString(PyExc_OSError, "failed to allocate final_jxl_buf");
|
PyErr_SetString(PyExc_OSError, "failed to allocate final_jxl_buf");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
final_jxl_buf = _new_jxl_buf;
|
final_jxl_buf = _new_jxl_buf;
|
||||||
|
|
||||||
decp->status = JxlDecoderSetBoxBuffer(decp->decoder, final_jxl_buf + final_jxl_buf_len, cur_compr_box_size);
|
decp->status = JxlDecoderSetBoxBuffer(
|
||||||
|
decp->decoder,
|
||||||
|
final_jxl_buf + final_jxl_buf_len,
|
||||||
|
cur_compr_box_size);
|
||||||
_PIL_JXL_CHECK("JxlDecoderSetBoxBuffer");
|
_PIL_JXL_CHECK("JxlDecoderSetBoxBuffer");
|
||||||
|
|
||||||
decp->status = JxlDecoderProcessInput(decp->decoder);
|
decp->status = JxlDecoderProcessInput(decp->decoder);
|
||||||
|
|
||||||
size_t remaining = JxlDecoderReleaseBoxBuffer(decp->decoder);
|
size_t remaining = JxlDecoderReleaseBoxBuffer(decp->decoder);
|
||||||
//printf("boxes status: %d, remaining: %zu\n", decp->status, remaining);
|
// printf("boxes status: %d, remaining: %zu\n", decp->status,
|
||||||
|
// remaining);
|
||||||
final_jxl_buf_len += (cur_compr_box_size - remaining);
|
final_jxl_buf_len += (cur_compr_box_size - remaining);
|
||||||
}
|
} while (decp->status == JXL_DEC_BOX_NEED_MORE_OUTPUT);
|
||||||
while (decp->status == JXL_DEC_BOX_NEED_MORE_OUTPUT);
|
|
||||||
|
|
||||||
if (is_box_exif) {
|
if (is_box_exif) {
|
||||||
decp->jxl_exif = final_jxl_buf;
|
decp->jxl_exif = final_jxl_buf;
|
||||||
|
@ -356,7 +361,6 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
// dirty hack: skip first step of decoding loop since
|
// dirty hack: skip first step of decoding loop since
|
||||||
// we already did it in do...while above
|
// we already did it in do...while above
|
||||||
goto decoder_loop_skip_process;
|
goto decoder_loop_skip_process;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (decp->status != JXL_DEC_FRAME);
|
} while (decp->status != JXL_DEC_FRAME);
|
||||||
|
@ -376,20 +380,23 @@ _jxl_decoder_new(PyObject *self, PyObject *args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (PyObject *)decp;
|
return (PyObject *)decp;
|
||||||
//Py_RETURN_NONE;
|
// Py_RETURN_NONE;
|
||||||
|
|
||||||
// on success we should never reach here
|
// on success we should never reach here
|
||||||
|
|
||||||
// set error message
|
// set error message
|
||||||
char err_msg[128];
|
char err_msg[128];
|
||||||
|
|
||||||
end:
|
end:
|
||||||
snprintf(err_msg, 128,
|
snprintf(
|
||||||
|
err_msg,
|
||||||
|
128,
|
||||||
"could not create decoder object. libjxl call: %s returned: %d",
|
"could not create decoder object. libjxl call: %s returned: %d",
|
||||||
jxl_call_name, decp->status);
|
jxl_call_name,
|
||||||
|
decp->status);
|
||||||
PyErr_SetString(PyExc_OSError, err_msg);
|
PyErr_SetString(PyExc_OSError, err_msg);
|
||||||
|
|
||||||
end_with_custom_error:
|
end_with_custom_error:
|
||||||
|
|
||||||
// deallocate
|
// deallocate
|
||||||
_jxl_decoder_dealloc((PyObject *)decp);
|
_jxl_decoder_dealloc((PyObject *)decp);
|
||||||
|
@ -411,19 +418,17 @@ _jxl_decoder_get_info(PyObject *self) {
|
||||||
decp->basic_info.animation.tps_numerator,
|
decp->basic_info.animation.tps_numerator,
|
||||||
decp->basic_info.animation.tps_denominator,
|
decp->basic_info.animation.tps_denominator,
|
||||||
decp->basic_info.animation.num_loops,
|
decp->basic_info.animation.num_loops,
|
||||||
decp->n_frames
|
decp->n_frames);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_jxl_decoder_get_next(PyObject *self) {
|
_jxl_decoder_get_next(PyObject *self) {
|
||||||
|
|
||||||
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
||||||
PyObject *bytes;
|
PyObject *bytes;
|
||||||
PyObject *ret;
|
PyObject *ret;
|
||||||
JxlFrameHeader fhdr = {};
|
JxlFrameHeader fhdr = {};
|
||||||
|
|
||||||
char* jxl_call_name;
|
char *jxl_call_name;
|
||||||
|
|
||||||
// process events until next frame output is ready
|
// process events until next frame output is ready
|
||||||
while (decp->status != JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
while (decp->status != JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
||||||
|
@ -450,23 +455,23 @@ _jxl_decoder_get_next(PyObject *self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t new_outbuf_len;
|
size_t new_outbuf_len;
|
||||||
decp->status = JxlDecoderImageOutBufferSize(decp->decoder, &decp->pixel_format, &new_outbuf_len);
|
decp->status = JxlDecoderImageOutBufferSize(
|
||||||
|
decp->decoder, &decp->pixel_format, &new_outbuf_len);
|
||||||
_PIL_JXL_CHECK("JxlDecoderImageOutBufferSize");
|
_PIL_JXL_CHECK("JxlDecoderImageOutBufferSize");
|
||||||
|
|
||||||
// only allocate memory when current buffer is too small
|
// only allocate memory when current buffer is too small
|
||||||
if (decp->outbuf_len < new_outbuf_len) {
|
if (decp->outbuf_len < new_outbuf_len) {
|
||||||
|
|
||||||
decp->outbuf_len = new_outbuf_len;
|
decp->outbuf_len = new_outbuf_len;
|
||||||
uint8_t* _new_outbuf = realloc(decp->outbuf, decp->outbuf_len);
|
uint8_t *_new_outbuf = realloc(decp->outbuf, decp->outbuf_len);
|
||||||
if (!_new_outbuf) {
|
if (!_new_outbuf) {
|
||||||
PyErr_SetString(PyExc_OSError, "failed to allocate outbuf");
|
PyErr_SetString(PyExc_OSError, "failed to allocate outbuf");
|
||||||
goto end_with_custom_error;
|
goto end_with_custom_error;
|
||||||
}
|
}
|
||||||
decp->outbuf = _new_outbuf;
|
decp->outbuf = _new_outbuf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decp->status = JxlDecoderSetImageOutBuffer(decp->decoder, &decp->pixel_format, decp->outbuf, decp->outbuf_len);
|
decp->status = JxlDecoderSetImageOutBuffer(
|
||||||
|
decp->decoder, &decp->pixel_format, decp->outbuf, decp->outbuf_len);
|
||||||
_PIL_JXL_CHECK("JxlDecoderSetImageOutBuffer");
|
_PIL_JXL_CHECK("JxlDecoderSetImageOutBuffer");
|
||||||
|
|
||||||
// decode image into output_buffer
|
// decode image into output_buffer
|
||||||
|
@ -477,8 +482,7 @@ _jxl_decoder_get_next(PyObject *self) {
|
||||||
goto end_with_custom_error;
|
goto end_with_custom_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = PyBytes_FromStringAndSize(
|
bytes = PyBytes_FromStringAndSize((char *)(decp->outbuf), decp->outbuf_len);
|
||||||
(char *)(decp->outbuf), decp->outbuf_len);
|
|
||||||
|
|
||||||
ret = Py_BuildValue("SIi", bytes, fhdr.duration, fhdr.is_last);
|
ret = Py_BuildValue("SIi", bytes, fhdr.duration, fhdr.is_last);
|
||||||
|
|
||||||
|
@ -490,26 +494,29 @@ _jxl_decoder_get_next(PyObject *self) {
|
||||||
// set error message
|
// set error message
|
||||||
char err_msg[128];
|
char err_msg[128];
|
||||||
|
|
||||||
end:
|
end:
|
||||||
snprintf(err_msg, 128,
|
snprintf(
|
||||||
|
err_msg,
|
||||||
|
128,
|
||||||
"could not read frame. libjxl call: %s returned: %d",
|
"could not read frame. libjxl call: %s returned: %d",
|
||||||
jxl_call_name, decp->status);
|
jxl_call_name,
|
||||||
|
decp->status);
|
||||||
PyErr_SetString(PyExc_OSError, err_msg);
|
PyErr_SetString(PyExc_OSError, err_msg);
|
||||||
|
|
||||||
end_with_custom_error:
|
end_with_custom_error:
|
||||||
|
|
||||||
// no need to deallocate anything here
|
// no need to deallocate anything here
|
||||||
// user can just ignore error
|
// user can just ignore error
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_jxl_decoder_get_icc(PyObject *self) {
|
_jxl_decoder_get_icc(PyObject *self) {
|
||||||
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
||||||
|
|
||||||
if (!decp->jxl_icc) Py_RETURN_NONE;
|
if (!decp->jxl_icc)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return PyBytes_FromStringAndSize((const char *)decp->jxl_icc, decp->jxl_icc_len);
|
return PyBytes_FromStringAndSize((const char *)decp->jxl_icc, decp->jxl_icc_len);
|
||||||
}
|
}
|
||||||
|
@ -518,7 +525,8 @@ PyObject *
|
||||||
_jxl_decoder_get_exif(PyObject *self) {
|
_jxl_decoder_get_exif(PyObject *self) {
|
||||||
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
||||||
|
|
||||||
if (!decp->jxl_exif) Py_RETURN_NONE;
|
if (!decp->jxl_exif)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return PyBytes_FromStringAndSize((const char *)decp->jxl_exif, decp->jxl_exif_len);
|
return PyBytes_FromStringAndSize((const char *)decp->jxl_exif, decp->jxl_exif_len);
|
||||||
}
|
}
|
||||||
|
@ -527,7 +535,8 @@ PyObject *
|
||||||
_jxl_decoder_get_xmp(PyObject *self) {
|
_jxl_decoder_get_xmp(PyObject *self) {
|
||||||
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
PILJpegXlDecoderObject *decp = (PILJpegXlDecoderObject *)self;
|
||||||
|
|
||||||
if (!decp->jxl_xmp) Py_RETURN_NONE;
|
if (!decp->jxl_xmp)
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return PyBytes_FromStringAndSize((const char *)decp->jxl_xmp, decp->jxl_xmp_len);
|
return PyBytes_FromStringAndSize((const char *)decp->jxl_xmp, decp->jxl_xmp_len);
|
||||||
}
|
}
|
||||||
|
@ -547,34 +556,34 @@ static struct PyMethodDef _jpegxl_decoder_methods[] = {
|
||||||
static PyTypeObject PILJpegXlDecoder_Type = {
|
static PyTypeObject PILJpegXlDecoder_Type = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0) "PILJpegXlDecoder", /*tp_name */
|
PyVarObject_HEAD_INIT(NULL, 0) "PILJpegXlDecoder", /*tp_name */
|
||||||
sizeof(PILJpegXlDecoderObject), /*tp_basicsize */
|
sizeof(PILJpegXlDecoderObject), /*tp_basicsize */
|
||||||
0, /*tp_itemsize */
|
0, /*tp_itemsize */
|
||||||
/* methods */
|
/* methods */
|
||||||
(destructor)_jxl_decoder_dealloc, /*tp_dealloc*/
|
(destructor)_jxl_decoder_dealloc, /*tp_dealloc*/
|
||||||
0, /*tp_vectorcall_offset*/
|
0, /*tp_vectorcall_offset*/
|
||||||
0, /*tp_getattr*/
|
0, /*tp_getattr*/
|
||||||
0, /*tp_setattr*/
|
0, /*tp_setattr*/
|
||||||
0, /*tp_as_async*/
|
0, /*tp_as_async*/
|
||||||
0, /*tp_repr*/
|
0, /*tp_repr*/
|
||||||
0, /*tp_as_number*/
|
0, /*tp_as_number*/
|
||||||
0, /*tp_as_sequence*/
|
0, /*tp_as_sequence*/
|
||||||
0, /*tp_as_mapping*/
|
0, /*tp_as_mapping*/
|
||||||
0, /*tp_hash*/
|
0, /*tp_hash*/
|
||||||
0, /*tp_call*/
|
0, /*tp_call*/
|
||||||
0, /*tp_str*/
|
0, /*tp_str*/
|
||||||
0, /*tp_getattro*/
|
0, /*tp_getattro*/
|
||||||
0, /*tp_setattro*/
|
0, /*tp_setattro*/
|
||||||
0, /*tp_as_buffer*/
|
0, /*tp_as_buffer*/
|
||||||
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||||
0, /*tp_doc*/
|
0, /*tp_doc*/
|
||||||
0, /*tp_traverse*/
|
0, /*tp_traverse*/
|
||||||
0, /*tp_clear*/
|
0, /*tp_clear*/
|
||||||
0, /*tp_richcompare*/
|
0, /*tp_richcompare*/
|
||||||
0, /*tp_weaklistoffset*/
|
0, /*tp_weaklistoffset*/
|
||||||
0, /*tp_iter*/
|
0, /*tp_iter*/
|
||||||
0, /*tp_iternext*/
|
0, /*tp_iternext*/
|
||||||
_jpegxl_decoder_methods, /*tp_methods*/
|
_jpegxl_decoder_methods, /*tp_methods*/
|
||||||
0, /*tp_members*/
|
0, /*tp_members*/
|
||||||
0, /*tp_getset*/
|
0, /*tp_getset*/
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return libjxl decoder version available as integer:
|
// Return libjxl decoder version available as integer:
|
||||||
|
@ -594,16 +603,17 @@ JpegXlDecoderVersion_str(void) {
|
||||||
"%d.%d.%d",
|
"%d.%d.%d",
|
||||||
version_number / 1000000,
|
version_number / 1000000,
|
||||||
(version_number % 1000000) / 1000,
|
(version_number % 1000000) / 1000,
|
||||||
(version_number % 1000)
|
(version_number % 1000));
|
||||||
);
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef jpegxlMethods[] = {
|
static PyMethodDef jpegxlMethods[] = {
|
||||||
{"JpegXlDecoderVersion", JpegXlDecoderVersion_wrapper, METH_NOARGS, "JpegXlVersion"},
|
{"JpegXlDecoderVersion",
|
||||||
|
JpegXlDecoderVersion_wrapper,
|
||||||
|
METH_NOARGS,
|
||||||
|
"JpegXlVersion"},
|
||||||
{"PILJpegXlDecoder", _jxl_decoder_new, METH_VARARGS, "PILJpegXlDecoder"},
|
{"PILJpegXlDecoder", _jxl_decoder_new, METH_VARARGS, "PILJpegXlDecoder"},
|
||||||
{NULL, NULL}
|
{NULL, NULL}};
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup_module(PyObject *m) {
|
setup_module(PyObject *m) {
|
||||||
|
@ -627,10 +637,10 @@ PyInit__jpegxl(void) {
|
||||||
|
|
||||||
static PyModuleDef module_def = {
|
static PyModuleDef module_def = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_jpegxl", /* m_name */
|
"_jpegxl", /* m_name */
|
||||||
NULL, /* m_doc */
|
NULL, /* m_doc */
|
||||||
-1, /* m_size */
|
-1, /* m_size */
|
||||||
jpegxlMethods, /* m_methods */
|
jpegxlMethods, /* m_methods */
|
||||||
};
|
};
|
||||||
|
|
||||||
m = PyModule_Create(&module_def);
|
m = PyModule_Create(&module_def);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user