Patch to read GML geo metadata and other associated data for inclusion in openjpeg

This commit is contained in:
hw 2018-03-22 13:33:24 +01:00
parent 2c7eb4fed9
commit 53df2bf860
5 changed files with 265 additions and 16 deletions

View File

@ -10442,6 +10442,9 @@ opj_codestream_info_v2_t* j2k_get_cstr_info(opj_j2k_t* p_j2k)
if (!cstr_info) {
return NULL;
}
cstr_info->nbasoc = 0;
cstr_info->asoc_info = 00;
cstr_info->nbcomps = p_j2k->m_private_image->numcomps;

View File

@ -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.
*
@ -159,7 +164,23 @@ static OPJ_BOOL opj_jp2_write_ftyp(opj_jp2_t *jp2,
static OPJ_BOOL opj_jp2_read_ftyp(opj_jp2_t *jp2,
OPJ_BYTE * p_header_data,
OPJ_UINT32 p_header_size,
opj_event_mgr_t * p_manager);
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,
@ -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 [] = {
@ -2636,6 +2658,104 @@ static OPJ_BOOL opj_jp2_read_ftyp(opj_jp2_t *jp2,
jp2->jp2_state |= JP2_STATE_FILE_TYPE;
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);
opj_read_bytes(p_header_data,&asoc_size,4);
p_header_data += 4;
p_header_size -= 4;
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 ) {
jp2->numasoc = 1;
jp2->asoc = opj_malloc(sizeof(opj_jp2_asoc_t));
}
else {
(jp2->numasoc)++;
jp2->asoc = opj_realloc(jp2->asoc, jp2->numasoc * sizeof(opj_jp2_asoc_t));
}
asoc = &(jp2->asoc[jp2->numasoc-1]);
asoc->level = jp2->numasoc-1; /* TODO: This is not correct if a parent asoc contains multiple child asocs! */
asoc->label_length = asoc_size;
asoc->label = opj_malloc(asoc_size);
memcpy(asoc->label, p_header_data, asoc_size);
asoc->xml_buf = 00;
asoc->xml_len = 0;
p_header_data += asoc_size;
p_header_size -= asoc_size;
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;
asoc->xml_buf = opj_malloc(p_header_size);
memcpy( asoc->xml_buf, p_header_data, p_header_size );
}
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;
asoc->xml_buf = opj_malloc(p_header_size);
memcpy( asoc->xml_buf, p_header_data, p_header_size );
}
}
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,
@ -3068,6 +3188,12 @@ void opj_jp2_destroy(opj_jp2_t *jp2)
if (jp2->m_procedure_list) {
opj_procedure_list_destroy(jp2->m_procedure_list);
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);
@ -3204,7 +3330,12 @@ opj_jp2_t* opj_jp2_create(OPJ_BOOL p_is_decoder)
if (! jp2->m_procedure_list) {
opj_jp2_destroy(jp2);
return 00;
}
}
/* Association data */
jp2->asoc = 00;
jp2->numasoc = 0;
}
return jp2;
@ -3226,8 +3357,31 @@ 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);
jp2_copy_asoc_data( p_jp2, p_info );
return p_info;
}
OPJ_BOOL jp2_copy_asoc_data( opj_jp2_t* p_jp2, opj_codestream_info_v2_t* p_info )
{
OPJ_UINT32 i;
opj_jp2_asoc_t *asoc, *to_asoc;
p_info->nbasoc = p_jp2->numasoc;
p_info->asoc_info = opj_malloc(p_info->nbasoc * sizeof(opj_jp2_asoc_t));
for (i=0; i<p_info->nbasoc; i++) {
asoc = &(p_jp2->asoc[i]);
to_asoc = &(p_info->asoc_info[i]);
to_asoc->level = asoc->level;
to_asoc->label_length = asoc->label_length;
to_asoc->xml_len = asoc->xml_len;
to_asoc->label = opj_malloc( to_asoc->label_length );
memcpy(to_asoc->label, asoc->label, to_asoc->label_length);
to_asoc->xml_buf = opj_malloc( to_asoc->xml_len);
memcpy(to_asoc->xml_buf, asoc->xml_buf, to_asoc->xml_len);
}
return OPJ_TRUE;
}
OPJ_BOOL opj_jp2_set_decoded_resolution_factor(opj_jp2_t *p_jp2,

View File

@ -58,7 +58,10 @@
#define JP2_CDEF 0x63646566 /**< Channel Definition box */
#define JP2_DTBL 0x6474626c /**< Data Reference box */
#define JP2_BPCC 0x62706363 /**< Bits per component box */
#define JP2_JP2 0x6a703220 /**< File type fields */
#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) */
@ -184,7 +187,10 @@ typedef struct opj_jp2 {
OPJ_UINT32 jp2_state;
OPJ_UINT32 jp2_img_state;
opj_jp2_color_t color;
opj_jp2_color_t color;
opj_jp2_asoc_t *asoc;
OPJ_UINT32 numasoc;
OPJ_BOOL ignore_pclr_cmap_cdef;
OPJ_BYTE has_jp2h;
@ -478,7 +484,12 @@ void jp2_dump(opj_jp2_t* p_jp2, OPJ_INT32 flag, FILE* out_stream);
*
*@return the codestream information extract from the jpg2000 codec
*/
opj_codestream_info_v2_t* jp2_get_cstr_info(opj_jp2_t* p_jp2);
opj_codestream_info_v2_t* jp2_get_cstr_info(opj_jp2_t* p_jp2);
/**
* Copy associated data
*/
OPJ_BOOL jp2_copy_asoc_data( opj_jp2_t* p_jp2, opj_codestream_info_v2_t* p_info );
/**
* Get the codestream index from a JPEG2000 codec.

View File

@ -37,6 +37,7 @@
#include "opj_includes.h"
static void opj_asoc_destroy( opj_jp2_asoc_t *p_asoc, OPJ_UINT32 num );
/* ---------------------------------------------------------------------- */
/* Functions to set the message handlers */
@ -950,6 +951,26 @@ void OPJ_CALLCONV opj_dump_codec(opj_codec_t *p_codec,
/* TODO return error */
/* fprintf(stderr, "[ERROR] Input parameter of the dump_codec function are incorrect.\n"); */
return;
}
void OPJ_CALLCONV opj_dump_associated_data(
opj_codestream_info_v2_t* cstr_info,
FILE* output_stream )
{
OPJ_UINT32 i;
if ( cstr_info->asoc_info ) {
fprintf(output_stream, "\n\nAssociated data: {\n");
for (i=0; i<cstr_info->nbasoc; i++) {
fprintf(output_stream, "\tlabel=%s, xml/data=", (char*) cstr_info->asoc_info[i].label);
if (cstr_info->asoc_info[i].xml_buf) {
fprintf(output_stream, "%s\n", (char*) cstr_info->asoc_info[i].xml_buf);
}
else {
fprintf(output_stream, "NULL\n");
}
}
fprintf(output_stream, "}\n");
}
}
opj_codestream_info_v2_t* OPJ_CALLCONV opj_get_cstr_info(opj_codec_t *p_codec)
@ -963,6 +984,23 @@ opj_codestream_info_v2_t* OPJ_CALLCONV opj_get_cstr_info(opj_codec_t *p_codec)
return NULL;
}
void opj_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;
}
}
void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_v2_t **cstr_info)
{
if (cstr_info) {
@ -975,6 +1013,12 @@ void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_v2_t **cstr_info)
/* FIXME not used for the moment*/
}
if ((*cstr_info)->nbasoc) {
opj_asoc_destroy((*cstr_info)->asoc_info, (*cstr_info)->nbasoc);
(*cstr_info)->asoc_info = 00;
(*cstr_info)->nbasoc = 0;
}
opj_free((*cstr_info));
(*cstr_info) = NULL;
}
@ -1049,7 +1093,12 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream(
return l_stream;
}
OPJ_OFF_T opj_stream_skip_api(opj_stream_t * p_stream, OPJ_OFF_T p_size)
{
opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream;
return l_stream->m_opj_skip(l_stream, p_size, NULL);
}
void* OPJ_CALLCONV opj_image_data_alloc(OPJ_SIZE_T size)
{

View File

@ -916,6 +916,22 @@ typedef struct opj_tile_v2_info {
} opj_tile_info_v2_t;
/**
Collector for association box (ASOC data), defined by a level, label and optionally XML data.
E.g. georeferencing with GML uses this (http://docs.opengeospatial.org/is/08-085r4/08-085r4.html).
In this case the first asoc is labelled 'gml.data' and has no XML data. The second asoc is named
'gml.root-instance' and contains XML formatted geo-information.
*/
typedef struct opj_jp2_asoc
{
OPJ_UINT32 level;
OPJ_BYTE *label;
OPJ_UINT32 label_length;
OPJ_BYTE *xml_buf;
OPJ_UINT32 xml_len;
} opj_jp2_asoc_t;
/**
* Information structure about the codestream (FIXME should be expand and enhance)
*/
@ -943,6 +959,12 @@ typedef struct opj_codestream_info_v2 {
/** information regarding tiles inside image */
opj_tile_info_v2_t *tile_info; /* FIXME not used for the moment */
/** Number of associated data boxes*/
OPJ_UINT32 nbasoc;
/** Associated data, e.g. GML geoinformation */
opj_jp2_asoc_t *asoc_info;
} opj_codestream_info_v2_t;
@ -1178,13 +1200,22 @@ OPJ_API void OPJ_CALLCONV opj_stream_set_skip_function(opj_stream_t* p_stream,
opj_stream_skip_fn p_function);
/**
* Sets the given function to be used as a seek function, the stream is then seekable,
* using SEEK_SET behavior.
* Sets the given function to be used as a seek function, the stream is then seekable.
* @param p_stream the stream to modify
* @param p_function the function to use a skip function.
*/
OPJ_API void OPJ_CALLCONV opj_stream_set_seek_function(opj_stream_t* p_stream,
opj_stream_seek_fn p_function);
opj_stream_seek_fn p_function);
/**
* Skips a number of bytes from the stream.
* @param p_stream the stream to skip data from.
* @param p_size the number of bytes to skip.
* @param p_event_mgr the user event manager to be notified of special events.
* @return the number of bytes skipped, or -1 if an error occurred.
*/
OPJ_API OPJ_OFF_T OPJ_CALLCONV opj_stream_skip_api(opj_stream_t * p_stream, OPJ_OFF_T p_size);
/**
* Sets the given data to be used as a user data for the stream.
@ -1314,9 +1345,6 @@ OPJ_API OPJ_BOOL OPJ_CALLCONV opj_setup_decoder(opj_codec_t *p_codec,
* number, or "ALL_CPUS". If OPJ_NUM_THREADS is set and this function is called,
* this function will override the behaviour of the environment variable.
*
* Currently this function must be called after opj_setup_decoder() and
* before opj_read_header().
*
* Note: currently only has effect on the decompressor.
*
* @param p_codec decompressor handler
@ -1609,7 +1637,11 @@ OPJ_API void OPJ_CALLCONV opj_dump_codec(opj_codec_t *p_codec,
*
*/
OPJ_API opj_codestream_info_v2_t* OPJ_CALLCONV opj_get_cstr_info(
opj_codec_t *p_codec);
opj_codec_t *p_codec);
OPJ_API void OPJ_CALLCONV opj_dump_associated_data(
opj_codestream_info_v2_t* cstr_info,
FILE* output_stream );
/**
* Get the codestream index from the codec