Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch to read GML geo metadata and other associated data for inclusio… #1110

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
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