diff options
Diffstat (limited to 'src/jp2.c')
-rw-r--r-- | src/jp2.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/jp2.c b/src/jp2.c new file mode 100644 index 0000000..9420b48 --- /dev/null +++ b/src/jp2.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022, yzrh <yzrh@noema.org> + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <string.h> + +#ifdef __linux__ +#include <openjpeg.h> +#else +#include <openjpeg-2.5/openjpeg.h> +#endif + +typedef struct _stream_user_data { + OPJ_SIZE_T pos; + OPJ_SIZE_T size; + const unsigned char *data; +} stream_user_data; + +static OPJ_SIZE_T +_opj_stream_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) +{ + stream_user_data *d = (stream_user_data *) p_user_data; + + if (d->pos >= d->size) + return (OPJ_SIZE_T) - 1; + + OPJ_SIZE_T ret_size = p_nb_bytes; + + if (d->pos + ret_size > d->size) + ret_size = d->size - d->pos; + + memcpy(p_buffer, d->data + d->pos, ret_size); + + d->pos += ret_size; + + return ret_size; +} + +static OPJ_OFF_T +_opj_stream_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data) +{ + stream_user_data *d = (stream_user_data *) p_user_data; + + if (d->pos + p_nb_bytes <= d->size) + d->pos += p_nb_bytes; + else + d->pos = d->size; + + return d->pos; +} + +static OPJ_BOOL +_opj_stream_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data) +{ + stream_user_data *d = (stream_user_data *) p_user_data; + + if (p_nb_bytes <= (OPJ_OFF_T) d->size) { + d->pos = p_nb_bytes; + return OPJ_TRUE; + } + + return OPJ_FALSE; +} + +int +strinfo_jp2_dim(int *jp2_width, int *jp2_height, + const char * restrict data, int data_size) +{ + opj_codec_t *codec; + opj_dparameters_t param; + opj_stream_t *stream; + opj_image_t *image; + stream_user_data d; + + if (data_size < 2) + return 1; + + opj_set_default_decoder_parameters(¶m); + + if ((unsigned char) data[0] == 0xff && (unsigned char) data[1] == 0x4f) + codec = opj_create_decompress(OPJ_CODEC_J2K); + else + codec = opj_create_decompress(OPJ_CODEC_JP2); + + if (!opj_setup_decoder(codec, ¶m)) { + opj_destroy_codec(codec); + return 1; + } + + stream = opj_stream_default_create(OPJ_TRUE); + + d.pos = 0; + d.size = data_size; + d.data = (unsigned char *) data; + + opj_stream_set_read_function(stream, _opj_stream_read); + opj_stream_set_skip_function(stream, _opj_stream_skip); + opj_stream_set_seek_function(stream, _opj_stream_seek); + opj_stream_set_user_data(stream, &d, NULL); + opj_stream_set_user_data_length(stream, data_size); + + if (!opj_read_header(stream, codec, &image)) { + opj_destroy_codec(codec); + opj_stream_destroy(stream); + return 1; + } + + opj_destroy_codec(codec); + opj_stream_destroy(stream); + + *jp2_width = image->x1 - image->x0; + *jp2_height = image->y1 - image->y0; + + opj_image_destroy(image); + + return 0; +} |