Skip to content
Open
6 changes: 6 additions & 0 deletions src/bin/jp2/opj_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ int main(int argc, char *argv[])
opj_stream_t *l_stream = NULL; /* Stream */
opj_codestream_info_v2_t* cstr_info = NULL;
opj_codestream_index_t* cstr_index = NULL;
opj_jp2_metadata_t *jp2_metadata = NULL;

OPJ_INT32 num_images, imageno;
img_fol_t img_fol;
Expand Down Expand Up @@ -602,6 +603,11 @@ int main(int argc, char *argv[])

cstr_info = opj_get_cstr_info(l_codec);

/* Dump associated data if there is any */
jp2_metadata = opj_get_jp2_metadata(l_codec);
opj_dump_associated_data(jp2_metadata, stdout);
opj_destroy_jp2_metadata(&jp2_metadata);

cstr_index = opj_get_cstr_index(l_codec);

/* close the byte stream */
Expand Down
11 changes: 11 additions & 0 deletions src/lib/openjp2/j2k.c
Original file line number Diff line number Diff line change
Expand Up @@ -10508,6 +10508,17 @@ opj_codestream_info_v2_t* j2k_get_cstr_info(opj_j2k_t* p_j2k)
return cstr_info;
}

opj_jp2_metadata_t* j2k_get_metadata( opj_j2k_t* p_j2k )
{
opj_jp2_metadata_t* p_metadata = opj_malloc(sizeof(opj_jp2_metadata_t));

/* A J2K stream can not contain ASOC boxes */
p_metadata->nbasoc = 0;
p_metadata->asoc_info = 00;

return p_metadata;
}

opj_codestream_index_t* j2k_get_cstr_index(opj_j2k_t* p_j2k)
{
opj_codestream_index_t* l_cstr_index = (opj_codestream_index_t*)
Expand Down
9 changes: 9 additions & 0 deletions src/lib/openjp2/j2k.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,15 @@ void j2k_dump_image_comp_header(opj_image_comp_t* comp, OPJ_BOOL dev_dump_flag,
*/
opj_codestream_info_v2_t* j2k_get_cstr_info(opj_j2k_t* p_j2k);

/**
* Get the metadata from a JPEG2000 codec.
*
*@param p_j2k the component image header to dump.
*
*@return The metadata extract from the jpg2000 codec
*/
opj_jp2_metadata_t* j2k_get_metadata( opj_j2k_t* p_j2k );

/**
* Get the codestream index from a JPEG2000 codec.
*
Expand Down
200 changes: 197 additions & 3 deletions src/lib/openjp2/jp2.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ static OPJ_BOOL opj_jp2_read_cdef(opj_jp2_t * jp2,
static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color,
opj_event_mgr_t *);

/**
* Destroy list of ASOC entities
*/
static void opj_jp2_asoc_destroy(opj_jp2_asoc_t *p_asoc, OPJ_UINT32 num);

/**
* Writes the Channel Definition box.
*
Expand Down Expand Up @@ -161,6 +166,22 @@ static OPJ_BOOL opj_jp2_read_ftyp(opj_jp2_t *jp2,
OPJ_UINT32 p_header_size,
opj_event_mgr_t * p_manager);

/**
* Reads a ASOC box - Associated data box.
* Also reads contained label (LBL) and XML boxes
*
* @param p_header_data the data contained in the ASOC box.
* @param jp2 the jpeg2000 file codec.
* @param p_header_size the size of the data contained in the ASOC box.
* @param p_manager the user event manager.
*
* @return true if the ASOC box is valid.
*/
static OPJ_BOOL opj_jp2_read_asoc(opj_jp2_t *jp2,
OPJ_BYTE * p_header_data,
OPJ_UINT32 p_header_size,
opj_event_mgr_t * p_manager);

static OPJ_BOOL opj_jp2_skip_jp2c(opj_jp2_t *jp2,
opj_stream_private_t *stream,
opj_event_mgr_t * p_manager);
Expand Down Expand Up @@ -425,7 +446,8 @@ static const opj_jp2_header_handler_t * opj_jp2_find_handler(OPJ_UINT32 p_id);
static const opj_jp2_header_handler_t jp2_header [] = {
{JP2_JP, opj_jp2_read_jp},
{JP2_FTYP, opj_jp2_read_ftyp},
{JP2_JP2H, opj_jp2_read_jp2h}
{JP2_JP2H, opj_jp2_read_jp2h},
{JP2_ASOC, opj_jp2_read_asoc}
};

static const opj_jp2_header_handler_t jp2_img_header [] = {
Expand Down Expand Up @@ -960,7 +982,7 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color,
for (i = 0; i < nr_channels; i++) {
OPJ_BYTE mtyp = cmap[i].mtyp;
OPJ_BYTE pcol = cmap[i].pcol;
/* See ISO 15444-1 Table I.14 MTYPi field values */
/* See ISO 15444-1 Table I.14 MTYPi field values */
if (mtyp != 0 && mtyp != 1) {
opj_event_msg(p_manager, EVT_ERROR,
"Invalid value for cmap[%d].mtyp = %d.\n", i,
Expand Down Expand Up @@ -2638,6 +2660,129 @@ static OPJ_BOOL opj_jp2_read_ftyp(opj_jp2_t *jp2,
return OPJ_TRUE;
}

static OPJ_BOOL opj_jp2_read_asoc(opj_jp2_t *jp2,
OPJ_BYTE * p_header_data,
OPJ_UINT32 p_header_size,
opj_event_mgr_t * p_manager)
{
OPJ_UINT32 label_tag;
OPJ_UINT32 asoc_tag;
OPJ_UINT32 asoc_size;
opj_jp2_asoc_t *asoc;

/* preconditions */
assert(jp2 != 00);
assert(p_header_data != 00);
assert(p_manager != 00);

if (p_header_size < 8) {
opj_event_msg(p_manager, EVT_ERROR,
"Cannot handle ASOC box of less than 8 bytes\n");
return OPJ_FALSE;
}

opj_read_bytes(p_header_data, &asoc_size, 4);
p_header_data += 4;
p_header_size -= 4;

if (p_header_size < asoc_size) {
opj_event_msg(p_manager, EVT_ERROR,
"ASOC super box is smaller than containing sub box\n");
return OPJ_FALSE;
}

opj_read_bytes(p_header_data, &label_tag, 4);
p_header_data += 4;
p_header_size -= 4;
asoc_size -= 4;

if (label_tag != JP2_LBL) {
/* TODO: Verify that ASOC must have a following label ? */
opj_event_msg(p_manager, EVT_WARNING,
"ASOC data does not have a label (LBL)\n");
return OPJ_TRUE; // No error if we could not parse
}

if (jp2->numasoc == 0) {
/* Create a first asoc */
jp2->numasoc = 1;
jp2->asoc = opj_malloc(sizeof(opj_jp2_asoc_t));
} else {
/* Add an asoc to existing ones */
(jp2->numasoc)++;
jp2->asoc = opj_realloc(jp2->asoc, jp2->numasoc * sizeof(opj_jp2_asoc_t));
}

asoc = &(jp2->asoc[jp2->numasoc - 1]);

/* TODO: This is not correct if a parent asoc contains multiple child asocs! */
asoc->level = jp2->numasoc - 1;
asoc->label_length = asoc_size + 1;
asoc->label = opj_malloc(asoc->label_length);
memcpy(asoc->label, p_header_data, asoc_size);
asoc->label[asoc->label_length - 1] = '\0'; /* NULL terminated label string */
asoc->xml_buf = 00;
asoc->xml_len = 0;

p_header_data += asoc_size;
p_header_size -= asoc_size;

if (p_header_size < 4) {
opj_event_msg(p_manager, EVT_ERROR,
"Cannot handle ASOC sub box of less than 4 bytes\n");
return OPJ_FALSE;
}

opj_read_bytes(p_header_data, &asoc_tag, 4);
p_header_data += 4;
p_header_size -= 4;

switch (asoc_tag) {
case JP2_ASOC: {
/* Start of nested ASOC tags. Parse this level. */
if (!opj_jp2_read_asoc(jp2, p_header_data, p_header_size, p_manager)) {
return OPJ_FALSE;
}
}
break;

case JP2_XML: {
asoc->xml_len = p_header_size + 1;
asoc->xml_buf = opj_malloc(asoc->xml_len);
memcpy(asoc->xml_buf, p_header_data, p_header_size);
asoc->xml_buf[asoc->xml_len - 1] = '\0';
}
break;

default: {
/* Copy the unknown data for external handling.
NOTE: This is not tested, but does the same as if an XML tag was found.*/
asoc->xml_len = p_header_size + 1;
asoc->xml_buf = opj_malloc(asoc->xml_len);
memcpy(asoc->xml_buf, p_header_data, p_header_size);
asoc->xml_buf[asoc->xml_len - 1] = '\0';
}
}

return OPJ_TRUE;
}

static void opj_jp2_asoc_destroy(opj_jp2_asoc_t *p_asoc, OPJ_UINT32 num)
{
OPJ_UINT32 i;
opj_jp2_asoc_t *asoc;
for (i = 0; i < num; i++) {
asoc = &(p_asoc[i]);
opj_free(asoc->label);
asoc->label = 00;
asoc->label_length = 0;

opj_free(asoc->xml_buf);
asoc->xml_buf = 00;
asoc->xml_len = 0;
}
}

static OPJ_BOOL opj_jp2_skip_jp2c(opj_jp2_t *jp2,
opj_stream_private_t *stream,
opj_event_mgr_t * p_manager)
Expand Down Expand Up @@ -3070,6 +3215,12 @@ void opj_jp2_destroy(opj_jp2_t *jp2)
jp2->m_procedure_list = 00;
}

if (jp2->numasoc) {
opj_jp2_asoc_destroy(jp2->asoc, jp2->numasoc);
jp2->asoc = 00;
jp2->numasoc = 0;
}

opj_free(jp2);
}
}
Expand Down Expand Up @@ -3205,6 +3356,11 @@ opj_jp2_t* opj_jp2_create(OPJ_BOOL p_is_decoder)
opj_jp2_destroy(jp2);
return 00;
}

/* Association data */
jp2->asoc = 00;
jp2->numasoc = 0;

}

return jp2;
Expand All @@ -3227,7 +3383,45 @@ opj_codestream_index_t* jp2_get_cstr_index(opj_jp2_t* p_jp2)

opj_codestream_info_v2_t* jp2_get_cstr_info(opj_jp2_t* p_jp2)
{
return j2k_get_cstr_info(p_jp2->j2k);
opj_codestream_info_v2_t* p_info = j2k_get_cstr_info(p_jp2->j2k);
return p_info;
}

opj_jp2_metadata_t* jp2_get_metadata( opj_jp2_t* p_jp2 )
{
opj_jp2_metadata_t* p_metadata = opj_malloc(sizeof(opj_jp2_metadata_t));
jp2_copy_asoc_data(p_jp2, p_metadata);
return p_metadata;
}

OPJ_BOOL jp2_copy_asoc_data( opj_jp2_t* p_jp2, opj_jp2_metadata_t* p_jp2_metadata )
{
OPJ_UINT32 i;
opj_jp2_asoc_t *asoc, *to_asoc;

p_jp2_metadata->nbasoc = p_jp2->numasoc;
p_jp2_metadata->asoc_info = opj_malloc(p_jp2_metadata->nbasoc * sizeof(opj_jp2_asoc_t));
for (i=0; i<p_jp2_metadata->nbasoc; i++) {
asoc = &(p_jp2->asoc[i]);
to_asoc = &(p_jp2_metadata->asoc_info[i]);
to_asoc->level = asoc->level;
to_asoc->label_length = asoc->label_length;
to_asoc->xml_len = asoc->xml_len;
if (asoc->label_length && asoc->label) {
to_asoc->label = opj_malloc(to_asoc->label_length);
memcpy(to_asoc->label, asoc->label, to_asoc->label_length);
} else {
to_asoc->label = 00;
}
if (asoc->xml_len && asoc->xml_buf) {
to_asoc->xml_buf = opj_malloc( to_asoc->xml_len);
memcpy(to_asoc->xml_buf, asoc->xml_buf, to_asoc->xml_len);
} else {
to_asoc->xml_buf = 00;
}
}

return OPJ_TRUE;
}

OPJ_BOOL opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2,
Expand Down
20 changes: 20 additions & 0 deletions src/lib/openjp2/jp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
#define JP2_DTBL 0x6474626c /**< Data Reference box */
#define JP2_BPCC 0x62706363 /**< Bits per component box */
#define JP2_JP2 0x6a703220 /**< File type fields */
#define JP2_ASOC 0x61736f63 /**< Associated data */
#define JP2_LBL 0x6c626c20 /**< Association label */
#define JP2_XML 0x786d6c20 /**< XML data */

/* For the future */
/* #define JP2_RES 0x72657320 */ /**< Resolution box (super-box) */
Expand Down Expand Up @@ -186,6 +189,9 @@ typedef struct opj_jp2 {

opj_jp2_color_t color;

opj_jp2_asoc_t *asoc;
OPJ_UINT32 numasoc;

OPJ_BOOL ignore_pclr_cmap_cdef;
OPJ_BYTE has_jp2h;
OPJ_BYTE has_ihdr;
Expand Down Expand Up @@ -480,6 +486,20 @@ void jp2_dump(opj_jp2_t* p_jp2, OPJ_INT32 flag, FILE* out_stream);
*/
opj_codestream_info_v2_t* jp2_get_cstr_info(opj_jp2_t* p_jp2);

/**
* Get the metadata from a JPEG2000 codec.
*
*@param p_jp2 jp2 codec.
*
*@return the metadata extract from the jpg2000 codec
*/
opj_jp2_metadata_t* jp2_get_metadata( opj_jp2_t* p_jp2 );

/**
* Copy associated data
*/
OPJ_BOOL jp2_copy_asoc_data(opj_jp2_t* p_jp2, opj_jp2_metadata_t* p_jp2_metadata);

/**
* Get the codestream index from a JPEG2000 codec.
*
Expand Down
Loading