X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libopenjpeg%2Fjp2.c;h=ad5527bb19b117922c41c9c030ca1c885874a2d6;hb=aaf6e84373014df770e838e0e423e764d3f8e1c1;hp=1029746cc686a6badea42f52419df90b81c0e15f;hpb=fa720c1858c5bccc70d9b0a8413c944c64d73b04;p=openjpeg.git diff --git a/libopenjpeg/jp2.c b/libopenjpeg/jp2.c index 1029746c..ad5527bb 100644 --- a/libopenjpeg/jp2.c +++ b/libopenjpeg/jp2.c @@ -34,6 +34,8 @@ /** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */ /*@{*/ +#define BOX_SIZE 1024 + /** @name Local static functions */ /*@{*/ @@ -53,9 +55,51 @@ Read the IHDR box - Image Header box @return Returns true if successful, returns false otherwise */ static opj_bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); + +/** + * Reads a IHDR box - Image Header box + * + * @param p_image_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_image_header_size the size of the image header + * @param p_manager the user event manager. + * + * @return true if the image header is valid, fale else. + */ +static opj_bool jp2_read_ihdr_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_image_header_data, + unsigned int p_image_header_size, + struct opj_event_mgr * p_manager + ); + static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); + +/** + * Reads a Bit per Component box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size the size of the bpc header + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +static opj_bool jp2_read_bpcc_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_bpc_header_data, + unsigned int p_bpc_header_size, + struct opj_event_mgr * p_manager + ); + +static opj_bool jp2_read_cdef_v2( opj_jp2_v2_t * jp2, + unsigned char * p_cdef_header_data, + OPJ_UINT32 p_cdef_header_size, + opj_event_mgr_t * p_manager + ); + static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio); /** Write the FTYP box - File type box @@ -70,6 +114,41 @@ Read the FTYP box - File type box @return Returns true if successful, returns false otherwise */ static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); + +/** + * Reads a a FTYP box - File type box + * + * @param p_header_data the data contained in the FTYP box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the FTYP box. + * @param p_manager the user event manager. + * + * @return true if the FTYP box is valid. + */ +static opj_bool jp2_read_ftyp_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + +/** + * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param p_header_data the data contained in the file header box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the file header box. + * @param p_manager the user event manager. + * + * @return true if the JP2 Header box was successfully reconized. +*/ +static opj_bool jp2_read_jp2h_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + static int jp2_write_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info); static opj_bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_codestream_length, unsigned int *j2k_codestream_offset); static void jp2_write_jp(opj_cio_t *cio); @@ -80,6 +159,24 @@ Read the JP box - JPEG 2000 signature @return Returns true if successful, returns false otherwise */ static opj_bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio); + +/** + * Reads a jpeg2000 file signature box. + * + * @param p_header_data the data contained in the signature box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the signature box. + * @param p_manager the user event manager. + * + * @return true if the file signature box is valid. + */ +static opj_bool jp2_read_jp_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + struct opj_event_mgr * p_manager + ); + /** Decode the structure of a JP2 file @param jp2 JP2 handle @@ -94,7 +191,7 @@ Apply collected palette data @param color Collector for profile, cdef and pclr data @param image */ -static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image); +static void jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color); /** Collect palette data @param jp2 JP2 handle @@ -105,6 +202,13 @@ Collect palette data */ static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_box_t *box, opj_jp2_color_t *color); + +static opj_bool jp2_read_pclr_v2( opj_jp2_v2_t *jp2, + unsigned char * p_pclr_header_data, + OPJ_UINT32 p_pclr_header_size, + opj_event_mgr_t * p_manager + ); + /** Collect component mapping data @param jp2 JP2 handle @@ -115,6 +219,14 @@ Collect component mapping data */ static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_box_t *box, opj_jp2_color_t *color); + + +static opj_bool jp2_read_cmap_v2( opj_jp2_v2_t * jp2, + unsigned char * p_cmap_header_data, + OPJ_UINT32 p_cmap_header_size, + opj_event_mgr_t * p_manager + ); + /** Collect colour specification data @param jp2 JP2 handle @@ -125,6 +237,24 @@ Collect colour specification data */ static opj_bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_box_t *box, opj_jp2_color_t *color); + +/** + * Reads the Color Specification box. + * + * @param p_colr_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_colr_header_size the size of the color header + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. +*/ +static opj_bool jp2_read_colr_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_colr_header_data, + OPJ_UINT32 p_colr_header_size, + struct opj_event_mgr * p_manager + ); + /** Write file Index (superbox) @param[in] offset_jp2c offset of jp2c box @@ -143,6 +273,7 @@ Write index Finder box */ static void write_iptr( int offset, int length, opj_cio_t *cio); /** + Write proxy box @param[in] offset_jp2c offset of jp2c box @param[in] length_jp2c length of jp2c box @@ -155,6 +286,129 @@ static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int le /*@}*/ +/** + * Sets up the procedures to do on reading header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_end_header_reading (opj_jp2_v2_t *jp2); + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +opj_bool jp2_read_header_procedure( + opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param jp2 the jpeg2000 file codec to execute the procedures on. + * @param cio the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +static opj_bool jp2_exec ( + opj_jp2_v2_t * jp2, + struct opj_procedure_list * p_procedure_list, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. + * + * @param cio the input stream to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_manager user event manager. + * + * @return true if the box is reconized, false otherwise +*/ +static opj_bool jp2_read_boxhdr_v2( + opj_jp2_box_t *box, + OPJ_UINT32 * p_number_bytes_read, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager + ); + +/** + * Finds the execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_find_handler (int p_id ); + +/** + * Finds the image execution function related to the given box id. + * + * @param p_id the id of the handler to fetch. + * + * @return the given handler or NULL if it could not be found. + */ +static const opj_jp2_header_handler_t * jp2_img_find_handler (int p_id); + +const opj_jp2_header_handler_t jp2_header [] = +{ + {JP2_JP,jp2_read_jp_v2}, + {JP2_FTYP,jp2_read_ftyp_v2}, + {JP2_JP2H,jp2_read_jp2h_v2} +}; + +const opj_jp2_header_handler_t jp2_img_header [] = +{ + {JP2_IHDR,jp2_read_ihdr_v2}, + {JP2_COLR,jp2_read_colr_v2}, + {JP2_BPCC,jp2_read_bpcc_v2}, + {JP2_PCLR,jp2_read_pclr_v2}, + {JP2_CMAP,jp2_read_cmap_v2}, + {JP2_CDEF,jp2_read_cdef_v2} + +}; + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. Data is read from a character string + * + * @param p_data the character string to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_box_max_size the maximum number of bytes in the box. + * + * @return true if the box is reconized, false otherwise +*/ +static opj_bool jp2_read_boxhdr_char( + opj_jp2_box_t *box, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_number_bytes_read, + OPJ_UINT32 p_box_max_size, + struct opj_event_mgr * p_manager + ); + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +static void jp2_setup_decoding_validation (opj_jp2_v2_t *jp2); + +/** + * Sets up the procedures to do on reading header. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_header_reading (opj_jp2_v2_t *jp2); + + + /* ----------------------------------------------------------------------- */ static opj_bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_box_t *box) { @@ -177,6 +431,60 @@ static opj_bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_bo return OPJ_TRUE; } +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. + * + * @param cio the input stream to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (should usually be 8). + * @param p_manager user event manager. + * + * @return true if the box is reconized, false otherwise +*/ +opj_bool jp2_read_boxhdr_v2(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + /* read header from file */ + unsigned char l_data_header [8]; + + // preconditions + assert(cio != 00); + assert(box != 00); + assert(p_number_bytes_read != 00); + assert(p_manager != 00); + + *p_number_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + if (*p_number_bytes_read != 8) { + return OPJ_FALSE; + } + + /* process read data */ + opj_read_bytes(l_data_header,&(box->length), 4); + opj_read_bytes(l_data_header+4,&(box->type), 4); + + // do we have a "special very large box ?" + // read then the XLBox + if (box->length == 1) { + OPJ_UINT32 l_xl_part_size; + + OPJ_UINT32 l_nb_bytes_read = opj_stream_read_data(cio,l_data_header,8,p_manager); + if (l_nb_bytes_read != 8) { + if (l_nb_bytes_read > 0) { + *p_number_bytes_read += l_nb_bytes_read; + } + + return OPJ_FALSE; + } + + opj_read_bytes(l_data_header,&l_xl_part_size, 4); + if (l_xl_part_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return OPJ_FALSE; + } + opj_read_bytes(l_data_header,&(box->length), 4); + } + return OPJ_TRUE; +} + #if 0 static void jp2_write_url(opj_cio_t *cio, char *Idx_file) { unsigned int i; @@ -231,6 +539,73 @@ static opj_bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { return OPJ_TRUE; } +/** + * Reads a IHDR box - Image Header box + * + * @param p_image_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_image_header_size the size of the image header + * @param p_image_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the image header is valid, fale else. + */ +opj_bool jp2_read_ihdr_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_image_header_data, + unsigned int p_image_header_size, + opj_event_mgr_t * p_manager + ) +{ + // preconditions + assert(p_image_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if (p_image_header_size != 14) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Bad image header box (bad size)\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_image_header_data,&(jp2->h),4); /* HEIGHT */ + p_image_header_data += 4; + opj_read_bytes(p_image_header_data,&(jp2->w),4); /* WIDTH */ + p_image_header_data += 4; + opj_read_bytes(p_image_header_data,&(jp2->numcomps),2); /* NC */ + p_image_header_data += 2; + + /* allocate memory for components */ + jp2->comps = (opj_jp2_comps_t*) opj_malloc(jp2->numcomps * sizeof(opj_jp2_comps_t)); + if (jp2->comps == 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to handle image header (ihdr)\n"); + return OPJ_FALSE; + } + memset(jp2->comps,0,jp2->numcomps * sizeof(opj_jp2_comps_t)); + + opj_read_bytes(p_image_header_data,&(jp2->bpc),1); /* BPC */ + ++ p_image_header_data; + + // if equal to 0 then need a BPC box (cf. chapter about image header box of the norm) + /*if (jp2->bpc == 0){ + // indicate with a flag that we will wait a BPC box + }*/ + + opj_read_bytes(p_image_header_data,&(jp2->C),1); /* C */ + ++ p_image_header_data; + + // Should be equal to 7 cf. chapter about image header box of the norm + if (jp2->C != 7){ + opj_event_msg_v2(p_manager, EVT_INFO, "JP2 IHDR box: compression type indicate that the file is not a conforming JP2 file (%d) \n", jp2->C); + } + + opj_read_bytes(p_image_header_data,&(jp2->UnkC),1); /* UnkC */ + ++ p_image_header_data; + opj_read_bytes(p_image_header_data,&(jp2->IPR),1); /* IPR */ + ++ p_image_header_data; + + return OPJ_TRUE; +} + static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { opj_jp2_box_t box; @@ -297,6 +672,50 @@ static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { return OPJ_TRUE; } +/** + * Reads a Bit per Component box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size pointer that will hold the size of the bpc header + * @param p_bpc_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +opj_bool jp2_read_bpcc_v2( opj_jp2_v2_t *jp2, + unsigned char * p_bpc_header_data, + unsigned int p_bpc_header_size, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 i; + + // preconditions + assert(p_bpc_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + // TODO MSD + /*if (jp2->bpc != 0 ){ + opj_event_msg_v2(p_manager, EVT_WARNING, "A BPCC header box is available although BPC is different to zero (%d)\n",jp2->bpc); + }*/ + + // and length is relevant + if (p_bpc_header_size != jp2->numcomps) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return OPJ_FALSE; + } + + // read info for each component + for (i = 0; i < jp2->numcomps; ++i) { + opj_read_bytes(p_bpc_header_data,&jp2->comps[i].bpcc ,1); /* read each BPCC component */ + ++p_bpc_header_data; + } + + return OPJ_TRUE; +} + static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio) { opj_jp2_box_t box; @@ -344,16 +763,17 @@ static void free_color_data(opj_jp2_color_t *color) if(color->icc_profile_buf) opj_free(color->icc_profile_buf); } -static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image) + +static void jp2_apply_pclr(opj_image_t *image, opj_jp2_color_t *color) { opj_image_comp_t *old_comps, *new_comps; - unsigned char *channel_size, *channel_sign; - unsigned int *entries; + OPJ_BYTE *channel_size, *channel_sign; + OPJ_UINT32 *entries; opj_jp2_cmap_comp_t *cmap; - int *src, *dst; - unsigned int j, max; - unsigned short i, nr_channels, cmp, pcol; - int k, top_k; + OPJ_INT32 *src, *dst; + OPJ_UINT32 j, max; + OPJ_UINT16 i, nr_channels, cmp, pcol; + OPJ_INT32 k, top_k; channel_size = color->jp2_pclr->channel_size; channel_sign = color->jp2_pclr->channel_sign; @@ -363,50 +783,52 @@ static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image) old_comps = image->comps; new_comps = (opj_image_comp_t*) - opj_malloc(nr_channels * sizeof(opj_image_comp_t)); + opj_malloc(nr_channels * sizeof(opj_image_comp_t)); - for(i = 0; i < nr_channels; ++i) - { - pcol = cmap[i].pcol; cmp = cmap[i].cmp; + for(i = 0; i < nr_channels; ++i) { + pcol = cmap[i].pcol; cmp = cmap[i].cmp; - new_comps[pcol] = old_comps[cmp]; + new_comps[pcol] = old_comps[cmp]; + + /* Direct use */ + if(cmap[i].mtyp == 0){ + old_comps[cmp].data = NULL; continue; + } + + /* Palette mapping: */ + new_comps[pcol].data = (int*) + opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(int)); + new_comps[pcol].prec = channel_size[i]; + new_comps[pcol].sgnd = channel_sign[i]; + } - if(cmap[i].mtyp == 0) /* Direct use */ - { - old_comps[cmp].data = NULL; continue; - } -/* Palette mapping: */ - new_comps[pcol].data = (int*) - opj_malloc(old_comps[cmp].w * old_comps[cmp].h * sizeof(int)); - new_comps[pcol].prec = channel_size[i]; - new_comps[pcol].sgnd = channel_sign[i]; - } top_k = color->jp2_pclr->nr_entries - 1; - for(i = 0; i < nr_channels; ++i) - { -/* Direct use: */ - if(cmap[i].mtyp == 0) continue; + for(i = 0; i < nr_channels; ++i) { + /* Direct use: */ + if(cmap[i].mtyp == 0) continue; -/* Palette mapping: */ - cmp = cmap[i].cmp; pcol = cmap[i].pcol; - src = old_comps[cmp].data; - dst = new_comps[pcol].data; - max = new_comps[pcol].w * new_comps[pcol].h; + /* Palette mapping: */ + cmp = cmap[i].cmp; pcol = cmap[i].pcol; + src = old_comps[cmp].data; + dst = new_comps[pcol].data; + max = new_comps[pcol].w * new_comps[pcol].h; + + for(j = 0; j < max; ++j) + { + /* The index */ + if((k = src[j]) < 0) k = 0; else if(k > top_k) k = top_k; + + /* The colour */ + dst[j] = entries[k * nr_channels + pcol]; + } + } - for(j = 0; j < max; ++j) - { -/* The index */ - if((k = src[j]) < 0) k = 0; else if(k > top_k) k = top_k; -/* The colour */ - dst[j] = entries[k * nr_channels + pcol]; - } - } max = image->numcomps; - for(i = 0; i < max; ++i) - { - if(old_comps[i].data) opj_free(old_comps[i].data); - } + for(i = 0; i < max; ++i) { + if(old_comps[i].data) opj_free(old_comps[i].data); + } + opj_free(old_comps); image->comps = new_comps; image->numcomps = nr_channels; @@ -415,6 +837,7 @@ static void jp2_apply_pclr(opj_jp2_color_t *color, opj_image_t *image) }/* apply_pclr() */ + static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_box_t *box, opj_jp2_color_t *color) { @@ -470,6 +893,81 @@ static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, return OPJ_TRUE; }/* jp2_read_pclr() */ +/** + * Reads a palette box. + * + * @param p_bpc_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_bpc_header_size pointer that will hold the size of the bpc header + * @param p_bpc_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. + */ +opj_bool jp2_read_pclr_v2( opj_jp2_v2_t *jp2, + unsigned char * p_pclr_header_data, + OPJ_UINT32 p_pclr_header_size, + opj_event_mgr_t * p_manager + ){ + opj_jp2_pclr_t *jp2_pclr; + OPJ_BYTE *channel_size, *channel_sign; + OPJ_UINT32 *entries; + OPJ_UINT16 nr_entries,nr_channels; + OPJ_UINT16 i, j; + OPJ_UINT32 l_value; + + // preconditions + assert(p_pclr_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if(jp2->color.jp2_pclr) + return OPJ_FALSE; + + opj_read_bytes(p_pclr_header_data, &l_value , 2); /* NE */ + p_pclr_header_data += 2; + nr_entries = (OPJ_UINT16) l_value; + + opj_read_bytes(p_pclr_header_data, &l_value , 1); /* NPC */ + ++p_pclr_header_data; + nr_channels = (OPJ_UINT16) l_value; + + entries = (OPJ_UINT32*) opj_malloc(nr_channels * nr_entries * sizeof(OPJ_UINT32)); + channel_size = (OPJ_BYTE*) opj_malloc(nr_channels); + channel_sign = (OPJ_BYTE*) opj_malloc(nr_channels); + + jp2_pclr = (opj_jp2_pclr_t*)opj_malloc(sizeof(opj_jp2_pclr_t)); + jp2_pclr->channel_sign = channel_sign; + jp2_pclr->channel_size = channel_size; + jp2_pclr->entries = entries; + jp2_pclr->nr_entries = nr_entries; + jp2_pclr->nr_channels = nr_channels; + jp2_pclr->cmap = NULL; + + jp2->color.jp2_pclr = jp2_pclr; + + for(i = 0; i < nr_channels; ++i) { + opj_read_bytes(p_pclr_header_data, &l_value , 1); /* Bi */ + ++p_pclr_header_data; + + channel_size[i] = (l_value & 0x7f) + 1; + channel_sign[i] = (l_value & 0x80)? 1 : 0; + } + + for(j = 0; j < nr_entries; ++j) { + for(i = 0; i < nr_channels; ++i) { + //*entries++ = cio_read(cio, channel_size[i]>>3); + opj_read_bytes(p_pclr_header_data, &l_value , channel_size[i]>>3); /* Cji */ + p_pclr_header_data += channel_size[i]>>3; + *entries = (OPJ_UINT32) l_value; + entries++; + } + } + + return OPJ_TRUE; +} + + static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_box_t *box, opj_jp2_color_t *color) { @@ -501,37 +999,100 @@ static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio, color->jp2_pclr->cmap = cmap; return OPJ_TRUE; + }/* jp2_read_cmap() */ +/** + * Reads the Component Mapping box. + * + * @param p_cmap_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_cmap_header_size pointer that will hold the size of the color header + * @param p_manager the user event manager. + * + * @return true if the cdef header is valid, false else. +*/ +static opj_bool jp2_read_cmap_v2( opj_jp2_v2_t * jp2, + unsigned char * p_cmap_header_data, + OPJ_UINT32 p_cmap_header_size, + opj_event_mgr_t * p_manager + ) +{ + opj_jp2_cmap_comp_t *cmap; + OPJ_BYTE i, nr_channels; + OPJ_UINT32 l_value; + + // preconditions + assert(jp2 != 00); + assert(p_cmap_header_data != 00); + assert(p_manager != 00); + + /* Need nr_channels: */ + if(jp2->color.jp2_pclr == NULL) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Need to read a PCLR box before the CMAP box.\n"); + return OPJ_FALSE; + } + + /* Part 1, I.5.3.5: 'There shall be at most one Component Mapping box + * inside a JP2 Header box' : + */ + if(jp2->color.jp2_pclr->cmap) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Only one CMAP box is allowed.\n"); + return OPJ_FALSE; + } + + nr_channels = jp2->color.jp2_pclr->nr_channels; + cmap = (opj_jp2_cmap_comp_t*) opj_malloc(nr_channels * sizeof(opj_jp2_cmap_comp_t)); + + for(i = 0; i < nr_channels; ++i) { + opj_read_bytes(p_cmap_header_data, &l_value, 2); /* CMP^i */ + p_cmap_header_data +=2; + cmap[i].cmp = (OPJ_UINT16) l_value; + + opj_read_bytes(p_cmap_header_data, &l_value, 1); /* MTYP^i */ + ++p_cmap_header_data; + cmap[i].mtyp = (OPJ_BYTE) l_value; + + opj_read_bytes(p_cmap_header_data, &l_value, 1); /* PCOL^i */ + ++p_cmap_header_data; + cmap[i].pcol = (OPJ_BYTE) l_value; + } + + jp2->color.jp2_pclr->cmap = cmap; + + return OPJ_TRUE; +} + static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color) { opj_jp2_cdef_info_t *info; - int color_space; - unsigned short i, n, cn, typ, asoc, acn; + OPJ_INT32 color_space; + OPJ_UINT16 i, n, cn, typ, asoc, acn; color_space = image->color_space; info = color->jp2_cdef->info; n = color->jp2_cdef->n; for(i = 0; i < n; ++i) - { -/* WATCH: acn = asoc - 1 ! */ - if((asoc = info[i].asoc) == 0) continue; + { + /* WATCH: acn = asoc - 1 ! */ + if((asoc = info[i].asoc) == 0) continue; - cn = info[i].cn; typ = info[i].typ; acn = asoc - 1; + cn = info[i].cn; typ = info[i].typ; acn = asoc - 1; - if(cn != acn) - { - opj_image_comp_t saved; + if(cn != acn) + { + opj_image_comp_t saved; - memcpy(&saved, &image->comps[cn], sizeof(opj_image_comp_t)); - memcpy(&image->comps[cn], &image->comps[acn], sizeof(opj_image_comp_t)); - memcpy(&image->comps[acn], &saved, sizeof(opj_image_comp_t)); + memcpy(&saved, &image->comps[cn], sizeof(opj_image_comp_t)); + memcpy(&image->comps[cn], &image->comps[acn], sizeof(opj_image_comp_t)); + memcpy(&image->comps[acn], &saved, sizeof(opj_image_comp_t)); + + info[i].asoc = cn + 1; + info[acn].asoc = info[acn].cn + 1; + } + } - info[i].asoc = cn + 1; - info[acn].asoc = info[acn].cn + 1; - } - } if(color->jp2_cdef->info) opj_free(color->jp2_cdef->info); opj_free(color->jp2_cdef); color->jp2_cdef = NULL; @@ -571,27 +1132,88 @@ static opj_bool jp2_read_cdef(opj_jp2_t *jp2, opj_cio_t *cio, return OPJ_TRUE; }/* jp2_read_cdef() */ -static opj_bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, - opj_jp2_box_t *box, opj_jp2_color_t *color) +/** + * Reads the Component Definition box. + * + * @param p_cdef_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_cdef_header_size pointer that will hold the size of the color header + * @param p_manager the user event manager. + * + * @return true if the cdef header is valid, false else. +*/ +static opj_bool jp2_read_cdef_v2( opj_jp2_v2_t * jp2, + unsigned char * p_cdef_header_data, + OPJ_UINT32 p_cdef_header_size, + opj_event_mgr_t * p_manager + ) { - int skip_len; - opj_common_ptr cinfo; + opj_jp2_cdef_info_t *cdef_info; + unsigned short i; + OPJ_UINT32 l_value; -/* Part 1, I.5.3.3 : 'A conforming JP2 reader shall ignore all Colour - * Specification boxes after the first.' -*/ - if(color->jp2_has_colr) return OPJ_FALSE; + // preconditions + assert(jp2 != 00); + assert(p_cdef_header_data != 00); + assert(p_manager != 00); - cinfo = jp2->cinfo; + /* Part 1, I.5.3.6: 'The shall be at most one Channel Definition box + * inside a JP2 Header box.'*/ + if(jp2->color.jp2_cdef) return OPJ_FALSE; - jp2->meth = cio_read(cio, 1); /* METH */ - jp2->precedence = cio_read(cio, 1); /* PRECEDENCE */ - jp2->approx = cio_read(cio, 1); /* APPROX */ + opj_read_bytes(p_cdef_header_data,&l_value ,2); /* N */ + p_cdef_header_data+= 2; - if (jp2->meth == 1) - { - jp2->enumcs = cio_read(cio, 4); /* EnumCS */ - } + if ( (OPJ_UINT16)l_value == 0){ /* szukw000: FIXME */ + opj_event_msg_v2(p_manager, EVT_ERROR, "Number of channel description is equal to zero in CDEF box.\n"); + return OPJ_FALSE; + } + + cdef_info = (opj_jp2_cdef_info_t*) opj_malloc(l_value * sizeof(opj_jp2_cdef_info_t)); + + jp2->color.jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); + jp2->color.jp2_cdef->info = cdef_info; + jp2->color.jp2_cdef->n = (OPJ_UINT16) l_value; + + for(i = 0; i < jp2->color.jp2_cdef->n; ++i) { + opj_read_bytes(p_cdef_header_data, &l_value, 2); /* Cn^i */ + p_cdef_header_data +=2; + cdef_info[i].cn = (OPJ_UINT16) l_value; + + opj_read_bytes(p_cdef_header_data, &l_value, 2); /* Typ^i */ + p_cdef_header_data +=2; + cdef_info[i].typ = (OPJ_UINT16) l_value; + + opj_read_bytes(p_cdef_header_data, &l_value, 2); /* Asoc^i */ + p_cdef_header_data +=2; + cdef_info[i].asoc = (OPJ_UINT16) l_value; + } + + return OPJ_TRUE; +} + + +static opj_bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, + opj_jp2_box_t *box, opj_jp2_color_t *color) +{ + int skip_len; + opj_common_ptr cinfo; + +/* Part 1, I.5.3.3 : 'A conforming JP2 reader shall ignore all Colour + * Specification boxes after the first.' +*/ + if(color->jp2_has_colr) return OPJ_FALSE; + + cinfo = jp2->cinfo; + + jp2->meth = cio_read(cio, 1); /* METH */ + jp2->precedence = cio_read(cio, 1); /* PRECEDENCE */ + jp2->approx = cio_read(cio, 1); /* APPROX */ + + if (jp2->meth == 1) + { + jp2->enumcs = cio_read(cio, 4); /* EnumCS */ + } else if (jp2->meth == 2) { @@ -626,6 +1248,87 @@ static opj_bool jp2_read_colr(opj_jp2_t *jp2, opj_cio_t *cio, return OPJ_TRUE; }/* jp2_read_colr() */ +/** + * Reads the Colour Specification box. + * + * @param p_colr_header_data pointer to actual data (already read from file) + * @param jp2 the jpeg2000 file codec. + * @param p_colr_header_size pointer that will hold the size of the color header + * @param p_colr_header_max_size maximum size of the header, any size bigger than this value should result the function to output false. + * @param p_manager the user event manager. + * + * @return true if the bpc header is valid, fale else. +*/ +static opj_bool jp2_read_colr_v2( opj_jp2_v2_t * jp2, + unsigned char * p_colr_header_data, + OPJ_UINT32 p_colr_header_size, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 l_value; + + // preconditions + assert(jp2 != 00); + assert(p_colr_header_data != 00); + assert(p_manager != 00); + + if (p_colr_header_size < 3) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Bad COLR header box (bad size)\n"); + return OPJ_FALSE; + } + + /* Part 1, I.5.3.3 : 'A conforming JP2 reader shall ignore all Colour + * Specification boxes after the first.' + */ + if(jp2->color.jp2_has_colr) { + opj_event_msg_v2(p_manager, EVT_INFO, "A conforming JP2 reader shall ignore all Colour Specification boxes after the first, so we ignore this one.\n"); + p_colr_header_data += p_colr_header_size; + return OPJ_TRUE; + } + + opj_read_bytes(p_colr_header_data,&jp2->meth ,1); /* METH */ + ++p_colr_header_data; + + opj_read_bytes(p_colr_header_data,&jp2->precedence ,1); /* PRECEDENCE */ + ++p_colr_header_data; + + opj_read_bytes(p_colr_header_data,&jp2->approx ,1); /* APPROX */ + ++p_colr_header_data; + + if (jp2->meth == 1) { + if (p_colr_header_size != 7) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Bad BPCC header box (bad size)\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_colr_header_data,&jp2->enumcs ,4); /* EnumCS */ + } + else if (jp2->meth == 2) { + // ICC profile + int it_icc_value = 0; + int icc_len = p_colr_header_size - 3; + + jp2->color.icc_profile_len = icc_len; + jp2->color.icc_profile_buf = (unsigned char*) opj_malloc(icc_len); + + memset(jp2->color.icc_profile_buf, 0, icc_len * sizeof(unsigned char)); + + for (it_icc_value = 0; it_icc_value < icc_len; ++it_icc_value) + { + opj_read_bytes(p_colr_header_data,&l_value,1); /* icc values */ + ++p_colr_header_data; + jp2->color.icc_profile_buf[it_icc_value] = (OPJ_BYTE) l_value; + } + + } + else // TODO MSD + opj_event_msg_v2(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), so we will skip the fields following the approx field.\n", jp2->meth); + + jp2->color.jp2_has_colr = 1; + + return OPJ_TRUE; +} + opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color) { opj_jp2_box_t box; @@ -769,7 +1472,7 @@ opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, if( !color.jp2_pclr->cmap) jp2_free_pclr(&color); else - jp2_apply_pclr(&color, image); + jp2_apply_pclr(image, &color); } if(color.icc_profile_buf) { @@ -781,6 +1484,52 @@ opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, }/* opj_jp2_decode() */ +opj_bool jp2_decode_v2( opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + opj_image_t* p_image, + struct opj_event_mgr * p_manager) +{ + if (!p_image) + return OPJ_FALSE; + + /* J2K decoding */ + if( ! j2k_decode_v2(jp2->j2k, cio, p_image, p_manager) ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Failed to decode the codestream in the JP2 file\n"); + return OPJ_FALSE; + } + + /* Set Image Color Space */ + if (jp2->enumcs == 16) + p_image->color_space = CLRSPC_SRGB; + else if (jp2->enumcs == 17) + p_image->color_space = CLRSPC_GRAY; + else if (jp2->enumcs == 18) + p_image->color_space = CLRSPC_SYCC; + else + p_image->color_space = CLRSPC_UNKNOWN; + + /* Apply the color space if needed */ + if(jp2->color.jp2_cdef) { + jp2_apply_cdef(p_image, &(jp2->color)); + } + + if(jp2->color.jp2_pclr) { + /* Part 1, I.5.3.4: Either both or none : */ + if( !jp2->color.jp2_pclr->cmap) + jp2_free_pclr(&(jp2->color)); + else + jp2_apply_pclr(p_image, &(jp2->color)); + } + + if(jp2->color.icc_profile_buf) { + p_image->icc_profile_buf = jp2->color.icc_profile_buf; + p_image->icc_profile_len = jp2->color.icc_profile_len; + jp2->color.icc_profile_buf = NULL; + } + + return OPJ_TRUE; +} + void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio) { opj_jp2_box_t box; @@ -961,7 +1710,7 @@ static int write_fidx( int offset_jp2c, int length_jp2c, int offset_idx, int len cio_skip( cio, 4); /* L [at the end] */ cio_write( cio, JPIP_FIDX, 4); /* IPTR */ - write_prxy( offset_jp2c, length_jp2c, offset_idx, offset_jp2c, cio); + write_prxy( offset_jp2c, length_jp2c, offset_idx, length_idx, cio); len = cio_tell( cio)-lenp; cio_seek( cio, lenp); @@ -1052,6 +1801,16 @@ void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) { /* further JP2 initializations go here */ } +void jp2_setup_decoder_v2(opj_jp2_v2_t *jp2, opj_dparameters_t *parameters) +{ + /* setup the J2K codec */ + j2k_setup_decoder_v2(jp2->j2k, parameters); + + /* further JP2 initializations go here */ + jp2->color.jp2_has_colr = 0; +} + + /* ----------------------------------------------------------------------- */ /* JP2 encoder interface */ /* ----------------------------------------------------------------------- */ @@ -1154,7 +1913,7 @@ void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_ opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) { - int pos_iptr, pos_cidx, pos_jp2c, len_jp2c, end_pos, pos_fidx, len_fidx; + int pos_iptr, pos_cidx, pos_jp2c, len_jp2c, len_cidx, end_pos, pos_fidx, len_fidx; /* JP2 encoding */ @@ -1181,18 +1940,832 @@ opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_ if( jp2->jpip_on){ pos_cidx = cio_tell( cio); - write_cidx( pos_jp2c+8, cio, image, *cstr_info, len_jp2c-8); + len_cidx = write_cidx( pos_jp2c+8, cio, image, *cstr_info, len_jp2c-8); pos_fidx = cio_tell( cio); - len_fidx = write_fidx( pos_jp2c, len_jp2c, pos_cidx, cio_tell(cio), cio); + len_fidx = write_fidx( pos_jp2c, len_jp2c, pos_cidx, len_cidx, cio); end_pos = cio_tell( cio); cio_seek( cio, pos_iptr); write_iptr( pos_fidx, len_fidx, cio); - - cio_seek( cio, end_pos); + cio_seek( cio, end_pos); + } + + return OPJ_TRUE; +} + +/** + * Ends the decompression procedures and possibiliy add data to be read after the + * codestream. + */ +opj_bool jp2_end_decompress(opj_jp2_v2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) +{ + // preconditions + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the end encoding */ + jp2_setup_end_header_reading(jp2); + + /* write header */ + if (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) { + return OPJ_FALSE; } + return j2k_end_decompress(jp2->j2k, cio, p_manager); +} + +/** + * Sets up the procedures to do on reading header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_end_header_reading (opj_jp2_v2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_read_header_procedure ); + /* DEVELOPER CORNER, add your custom procedures */ +} + + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +opj_bool jp2_read_header_procedure( + opj_jp2_v2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager) +{ + opj_jp2_box_t box; + OPJ_UINT32 l_nb_bytes_read; + const opj_jp2_header_handler_t * l_current_handler; + OPJ_UINT32 l_last_data_size = BOX_SIZE; + OPJ_UINT32 l_current_data_size; + unsigned char * l_current_data = 00; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + l_current_data = (unsigned char*)opj_malloc(l_last_data_size); + + if (l_current_data == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to handle jpeg2000 file header\n"); + return OPJ_FALSE; + } + memset(l_current_data, 0 , l_last_data_size); + + while (jp2_read_boxhdr_v2(&box,&l_nb_bytes_read,cio,p_manager)) { + // is it the codestream box ? + if (box.type == JP2_JP2C) { + if (jp2->jp2_state & JP2_STATE_HEADER) { + jp2->jp2_state |= JP2_STATE_CODESTREAM; + opj_free(l_current_data); + return OPJ_TRUE; + } + else { + opj_event_msg_v2(p_manager, EVT_ERROR, "bad placed jpeg codestream\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + } + else if (box.length == 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + + l_current_handler = jp2_find_handler(box.type); + l_current_data_size = box.length - l_nb_bytes_read; + + if (l_current_handler != 00) { + if (l_current_data_size > l_last_data_size) { + l_current_data = (unsigned char*)opj_realloc(l_current_data,l_current_data_size); + l_last_data_size = l_current_data_size; + } + + l_nb_bytes_read = opj_stream_read_data(cio,l_current_data,l_current_data_size,p_manager); + if (l_nb_bytes_read != l_current_data_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with reading JPEG2000 box, stream error\n"); + return OPJ_FALSE; + } + + if (! l_current_handler->handler(jp2,l_current_data,l_current_data_size,p_manager)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + } + else { + jp2->jp2_state |= JP2_STATE_UNKNOWN; + if (opj_stream_skip(cio,l_current_data_size,p_manager) != l_current_data_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with skipping JPEG2000 box, stream error\n"); + opj_free(l_current_data); + return OPJ_FALSE; + } + } + } + + opj_free(l_current_data); + return OPJ_TRUE; } + +/** + * Excutes the given procedures on the given codec. + * + * @param p_procedure_list the list of procedures to execute + * @param jp2 the jpeg2000 file codec to execute the procedures on. + * @param cio the stream to execute the procedures on. + * @param p_manager the user manager. + * + * @return true if all the procedures were successfully executed. + */ +opj_bool jp2_exec ( + opj_jp2_v2_t * jp2, + opj_procedure_list_t * p_procedure_list, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager + ) +{ + opj_bool (** l_procedure) (opj_jp2_v2_t * jp2, opj_stream_private_t *, opj_event_mgr_t *) = 00; + opj_bool l_result = OPJ_TRUE; + OPJ_UINT32 l_nb_proc, i; + + // preconditions + assert(p_procedure_list != 00); + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list); + l_procedure = (opj_bool (**) (opj_jp2_v2_t * jp2, opj_stream_private_t *, opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list); + + for (i=0;ijp2_state != JP2_STATE_NONE) { + opj_event_msg_v2(p_manager, EVT_ERROR, "The signature box must be the first box in the file.\n"); + return OPJ_FALSE; + } + + /* assure length of data is correct (4 -> magic number) */ + if (p_header_size != 4) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with JP signature Box size\n"); + return OPJ_FALSE; + } + + // rearrange data + opj_read_bytes(p_header_data,&l_magic_number,4); + if (l_magic_number != 0x0d0a870a ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with JP Signature : bad magic number\n"); + return OPJ_FALSE; + } + + jp2->jp2_state |= JP2_STATE_SIGNATURE; + + return OPJ_TRUE; +} + + +/** + * Reads a a FTYP box - File type box + * + * @param p_header_data the data contained in the FTYP box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the FTYP box. + * @param p_manager the user event manager. + * + * @return true if the FTYP box is valid. + */ +opj_bool jp2_read_ftyp_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 i, l_remaining_bytes; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + if (jp2->jp2_state != JP2_STATE_SIGNATURE) { + opj_event_msg_v2(p_manager, EVT_ERROR, "The ftyp box must be the second box in the file.\n"); + return OPJ_FALSE; + } + + /* assure length of data is correct */ + if (p_header_size < 8) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with FTYP signature Box size\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_header_data,&jp2->brand,4); /* BR */ + p_header_data += 4; + + opj_read_bytes(p_header_data,&jp2->minversion,4); /* MinV */ + p_header_data += 4; + + l_remaining_bytes = p_header_size - 8; + + /* the number of remaining bytes should be a multiple of 4 */ + if ((l_remaining_bytes & 0x3) != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Error with FTYP signature Box size\n"); + return OPJ_FALSE; + } + + /* div by 4 */ + jp2->numcl = l_remaining_bytes >> 2; + if (jp2->numcl) { + jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int)); + if (jp2->cl == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory with FTYP Box\n"); + return OPJ_FALSE; + } + memset(jp2->cl,0,jp2->numcl * sizeof(unsigned int)); + } + + for (i = 0; i < jp2->numcl; ++i) + { + opj_read_bytes(p_header_data,&jp2->cl[i],4); /* CLi */ + p_header_data += 4; + } + + jp2->jp2_state |= JP2_STATE_FILE_TYPE; + + return OPJ_TRUE; +} + + +/** + * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param p_header_data the data contained in the file header box. + * @param jp2 the jpeg2000 file codec. + * @param p_header_size the size of the data contained in the file header box. + * @param p_manager the user event manager. + * + * @return true if the JP2 Header box was successfully reconized. +*/ +opj_bool jp2_read_jp2h_v2( + opj_jp2_v2_t *jp2, + unsigned char * p_header_data, + unsigned int p_header_size, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 l_box_size=0, l_current_data_size = 0; + opj_jp2_box_t box; + const opj_jp2_header_handler_t * l_current_handler; + + // preconditions + assert(p_header_data != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + /* make sure the box is well placed */ + if ((jp2->jp2_state & JP2_STATE_FILE_TYPE) != JP2_STATE_FILE_TYPE ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "The box must be the first box in the file.\n"); + return OPJ_FALSE; + } + + jp2->jp2_img_state = JP2_IMG_STATE_NONE; + + /* iterate while remaining data */ + while (p_header_size > 0) { + + if (! jp2_read_boxhdr_char(&box,p_header_data,&l_box_size,p_header_size, p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box\n"); + return OPJ_FALSE; + } + + if (box.length > p_header_size) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box: box length is inconsistent.\n"); + return OPJ_FALSE; + } + + l_current_handler = jp2_img_find_handler(box.type); + l_current_data_size = box.length - l_box_size; + p_header_data += l_box_size; + + if (l_current_handler != 00) { + if (! l_current_handler->handler(jp2,p_header_data,l_current_data_size,p_manager)) { + return OPJ_FALSE; + } + } + else { + jp2->jp2_img_state |= JP2_IMG_STATE_UNKNOWN; + } + + p_header_data += l_current_data_size; + p_header_size -= box.length; + } + + jp2->jp2_state |= JP2_STATE_HEADER; + + return OPJ_TRUE; +} + +/** + * Reads a box header. The box is the way data is packed inside a jpeg2000 file structure. Data is read from a character string + * + * @param p_data the character string to read data from. + * @param box the box structure to fill. + * @param p_number_bytes_read pointer to an int that will store the number of bytes read from the stream (shoul usually be 2). + * @param p_box_max_size the maximum number of bytes in the box. + * + * @return true if the box is reconized, false otherwise +*/ +static opj_bool jp2_read_boxhdr_char( + opj_jp2_box_t *box, + OPJ_BYTE * p_data, + OPJ_UINT32 * p_number_bytes_read, + OPJ_UINT32 p_box_max_size, + opj_event_mgr_t * p_manager + ) +{ + OPJ_UINT32 l_value; + + // preconditions + assert(p_data != 00); + assert(box != 00); + assert(p_number_bytes_read != 00); + assert(p_manager != 00); + + if (p_box_max_size < 8) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle box of less than 8 bytes\n"); + return OPJ_FALSE; + } + + /* process read data */ + opj_read_bytes(p_data, &l_value, 4); + p_data += 4; + box->length = (OPJ_INT32)(l_value); + + opj_read_bytes(p_data, &l_value, 4); + p_data += 4; + box->type = (OPJ_INT32)(l_value); + + *p_number_bytes_read = 8; + + // do we have a "special very large box ?" + // read then the XLBox + if (box->length == 1) { + unsigned int l_xl_part_size; + + if (p_box_max_size < 16) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle XL box of less than 16 bytes\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_data,&l_xl_part_size, 4); + p_data += 4; + *p_number_bytes_read += 4; + + if (l_xl_part_size != 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle box sizes higher than 2^32\n"); + return OPJ_FALSE; + } + + opj_read_bytes(p_data, &l_value, 4); + *p_number_bytes_read += 4; + box->length = (OPJ_INT32)(l_value); + + if (box->length == 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return OPJ_FALSE; + } + } + else if (box->length == 0) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n"); + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + + +/** + * Reads a jpeg2000 file header structure. + * + * @param cio the stream to read data from. + * @param jp2 the jpeg2000 file header structure. + * @param p_manager the user event manager. + * + * @return true if the box is valid. + */ +opj_bool jp2_read_header( struct opj_stream_private *p_stream, + opj_jp2_v2_t *jp2, + opj_image_t** p_image, + struct opj_event_mgr * p_manager + ) +{ + /* preconditions */ + assert(jp2 != 00); + assert(p_stream != 00); + assert(p_manager != 00); + + /* customization of the validation */ + jp2_setup_decoding_validation (jp2); + + /* customization of the encoding */ + jp2_setup_header_reading(jp2); + + /* validation of the parameters codec */ + if (! jp2_exec(jp2,jp2->m_validation_list,p_stream,p_manager)) { + return OPJ_FALSE; + } + + /* read header */ + if (! jp2_exec (jp2,jp2->m_procedure_list,p_stream,p_manager)) { + return OPJ_FALSE; + } + + return j2k_read_header( p_stream, + jp2->j2k, + p_image, + p_manager); +} + +/** + * Sets up the validation ,i.e. adds the procedures to lauch to make sure the codec parameters + * are valid. Developpers wanting to extend the library can add their own validation procedures. + */ +void jp2_setup_decoding_validation (opj_jp2_v2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + /* DEVELOPER CORNER, add your custom validation procedure */ +} + +/** + * Sets up the procedures to do on reading header. + * Developpers wanting to extend the library can add their own writting procedures. + */ +void jp2_setup_header_reading (opj_jp2_v2_t *jp2) +{ + // preconditions + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_read_header_procedure ); + /* DEVELOPER CORNER, add your custom procedures */ +} + + +/** + * Reads a tile header. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +opj_bool jp2_read_tile_header( opj_jp2_v2_t * p_jp2, + OPJ_UINT32 * p_tile_index, + OPJ_UINT32 * p_data_size, + OPJ_INT32 * p_tile_x0, OPJ_INT32 * p_tile_y0, + OPJ_INT32 * p_tile_x1, OPJ_INT32 * p_tile_y1, + OPJ_UINT32 * p_nb_comps, + opj_bool * p_go_on, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager ) +{ + return j2k_read_tile_header(p_jp2->j2k, + p_tile_index, + p_data_size, + p_tile_x0, p_tile_y0, + p_tile_x1, p_tile_y1, + p_nb_comps, + p_go_on, + p_stream, + p_manager); +} + +/** + * Decode tile data. + * @param p_j2k the jpeg2000 codec. + * @param p_stream the stream to write data to. + * @param p_manager the user event manager. + */ +opj_bool jp2_decode_tile ( + opj_jp2_v2_t * p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager + ) +{ + return j2k_decode_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,p_stream,p_manager); +} + +/** + * Destroys a jpeg2000 file decompressor. + * + * @param jp2 a jpeg2000 file decompressor. + */ +void jp2_destroy(opj_jp2_v2_t *jp2) +{ + if (jp2) { + /* destroy the J2K codec */ + j2k_destroy(jp2->j2k); + jp2->j2k = 00; + + if (jp2->comps) { + opj_free(jp2->comps); + jp2->comps = 00; + } + + if (jp2->cl) { + opj_free(jp2->cl); + jp2->cl = 00; + } + + if (jp2->color.icc_profile_buf) { + opj_free(jp2->color.icc_profile_buf); + jp2->color.icc_profile_buf = 00; + } + + if (jp2->color.jp2_cdef) { + if (jp2->color.jp2_cdef->info) { + opj_free(jp2->color.jp2_cdef->info); + jp2->color.jp2_cdef->info = NULL; + } + + opj_free(jp2->color.jp2_cdef); + jp2->color.jp2_cdef = 00; + } + + if (jp2->color.jp2_pclr) { + if (jp2->color.jp2_pclr->cmap) { + opj_free(jp2->color.jp2_pclr->cmap); + jp2->color.jp2_pclr->cmap = NULL; + } + if (jp2->color.jp2_pclr->channel_sign) { + opj_free(jp2->color.jp2_pclr->channel_sign); + jp2->color.jp2_pclr->channel_sign = NULL; + } + if (jp2->color.jp2_pclr->channel_size) { + opj_free(jp2->color.jp2_pclr->channel_size); + jp2->color.jp2_pclr->channel_size = NULL; + } + if (jp2->color.jp2_pclr->entries) { + opj_free(jp2->color.jp2_pclr->entries); + jp2->color.jp2_pclr->entries = NULL; + } + + opj_free(jp2->color.jp2_pclr); + jp2->color.jp2_pclr = 00; + } + + if (jp2->m_validation_list) { + opj_procedure_list_destroy(jp2->m_validation_list); + jp2->m_validation_list = 00; + } + + if (jp2->m_procedure_list) { + opj_procedure_list_destroy(jp2->m_procedure_list); + jp2->m_procedure_list = 00; + } + + opj_free(jp2); + } +} + +/** + * Sets the given area to be decoded. This function should be called right after opj_read_header and before any tile header reading. + * + * @param p_jp2 the jpeg2000 codec. + * @param p_end_x the right position of the rectangle to decode (in image coordinates). + * @param p_start_y the up position of the rectangle to decode (in image coordinates). + * @param p_end_y the bottom position of the rectangle to decode (in image coordinates). + * @param p_manager the user event manager + * + * @return true if the area could be set. + */ +opj_bool jp2_set_decode_area( opj_jp2_v2_t *p_jp2, + opj_image_t* p_image, + OPJ_INT32 p_start_x, OPJ_INT32 p_start_y, + OPJ_INT32 p_end_x, OPJ_INT32 p_end_y, + struct opj_event_mgr * p_manager ) +{ + return j2k_set_decode_area(p_jp2->j2k, p_image, p_start_x, p_start_y, p_end_x, p_end_y, p_manager); +} + +/** + * Get the decoded tile. + * + * @param p_jp2 the jpeg2000 codec. + * @param p_stream input_stream + * @param p_image output image. . + * @param p_manager the user event manager + * @param tile_index index of the tile we want decode + * + * @return true if succeed. + */ +opj_bool jp2_get_tile( opj_jp2_v2_t *jp2, + opj_stream_private_t *p_stream, + opj_image_t* p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index ) +{ + if (!p_image) + return OPJ_FALSE; + + opj_event_msg_v2(p_manager, EVT_WARNING, "JP2 box which are after the codestream will not be read by this function.\n"); + + if (! j2k_get_tile(jp2->j2k, p_stream, p_image, p_manager, tile_index) ){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Failed to decode the codestream in the JP2 file\n"); + return OPJ_FALSE; + } + + /* Set Image Color Space */ + if (jp2->enumcs == 16) + p_image->color_space = CLRSPC_SRGB; + else if (jp2->enumcs == 17) + p_image->color_space = CLRSPC_GRAY; + else if (jp2->enumcs == 18) + p_image->color_space = CLRSPC_SYCC; + else + p_image->color_space = CLRSPC_UNKNOWN; + + /* Apply the color space if needed */ + if(jp2->color.jp2_cdef) { + jp2_apply_cdef(p_image, &(jp2->color)); + } + + if(jp2->color.jp2_pclr) { + /* Part 1, I.5.3.4: Either both or none : */ + if( !jp2->color.jp2_pclr->cmap) + jp2_free_pclr(&(jp2->color)); + else + jp2_apply_pclr(p_image, &(jp2->color)); + } + + if(jp2->color.icc_profile_buf) { + p_image->icc_profile_buf = jp2->color.icc_profile_buf; + p_image->icc_profile_len = jp2->color.icc_profile_len; + jp2->color.icc_profile_buf = NULL; + } + + return OPJ_TRUE; +} + + + +/* ----------------------------------------------------------------------- */ +/* JP2 encoder interface */ +/* ----------------------------------------------------------------------- */ + +opj_jp2_v2_t* jp2_create(opj_bool p_is_decoder) +{ + opj_jp2_v2_t *jp2 = (opj_jp2_v2_t*)opj_malloc(sizeof(opj_jp2_v2_t)); + if (jp2) { + memset(jp2,0,sizeof(opj_jp2_t)); + + /* create the J2K codec */ + if (! p_is_decoder) { + jp2->j2k = j2k_create_compress_v2(); + } + else { + jp2->j2k = j2k_create_decompress_v2(); + } + + if (jp2->j2k == 00) { + jp2_destroy(jp2); + return 00; + } + + /* Color structure */ + jp2->color.icc_profile_buf = NULL; + jp2->color.icc_profile_len = 0; + jp2->color.jp2_cdef = NULL; + jp2->color.jp2_pclr = NULL; + jp2->color.jp2_has_colr = 0; + + // validation list creation + jp2->m_validation_list = opj_procedure_list_create(); + if (! jp2->m_validation_list) { + jp2_destroy(jp2); + return 00; + } + + // execution list creation + jp2->m_procedure_list = opj_procedure_list_create(); + if (! jp2->m_procedure_list) { + jp2_destroy(jp2); + return 00; + } + } + + return jp2; +} + +void jp2_dump(opj_jp2_v2_t* p_jp2, OPJ_INT32 flag, FILE* out_stream) +{ + /* preconditions */ + assert(p_jp2 != 00); + + j2k_dump(p_jp2->j2k, + flag, + out_stream); +} + +opj_codestream_index_t* jp2_get_cstr_index(opj_jp2_v2_t* p_jp2) +{ + return j2k_get_cstr_index(p_jp2->j2k); +} + +opj_codestream_info_v2_t* jp2_get_cstr_info(opj_jp2_v2_t* p_jp2) +{ + return j2k_get_cstr_info(p_jp2->j2k); +} + +opj_bool jp2_set_decoded_resolution_factor(opj_jp2_v2_t *p_jp2, OPJ_UINT32 res_factor, opj_event_mgr_t * p_manager) +{ + return j2k_set_decoded_resolution_factor(p_jp2->j2k, res_factor, p_manager); +} +