aboutsummaryrefslogtreecommitdiffstats
path: root/src/jp2.c
diff options
context:
space:
mode:
authoryzrh <yzrh@noema.org>2022-12-29 00:18:07 +0000
committeryzrh <yzrh@noema.org>2022-12-29 00:40:14 +0000
commit8083b30530a37d3529d453515465a00aac74a154 (patch)
tree0390c6550f642c96ad0f4b40aab949d1e120ffd0 /src/jp2.c
parentabce2fd2e4f8089779fb9b1dce94133716b0bb39 (diff)
downloadmelon-8083b30530a37d3529d453515465a00aac74a154.tar.gz
melon-8083b30530a37d3529d453515465a00aac74a154.tar.zst
Add JPEG 2000 support.
Signed-off-by: yzrh <yzrh@noema.org>
Diffstat (limited to 'src/jp2.c')
-rw-r--r--src/jp2.c119
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(&param);
+
+ 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, &param)) {
+ 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;
+}