aboutsummaryrefslogblamecommitdiffstats
path: root/src/jp2.c
blob: a9d4429e4defece8ef8ba8a21eb470e8ef2396fc (plain) (tree)
1
2
3
4
5
6
7
8
9







                                            
                     









































































































                                                                               
/*
 * Copyright (c) 2022, yzrh <yzrh@noema.org>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>

#include <openjpeg.h>

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;
}