X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libopenjpeg%2Fjp2.c;h=f359f29742e8a57d39d5890159436b5a137f06aa;hb=202d5ab754ed2bb14bc44edc177633754a8cee14;hp=43766b14dc2ee4bd26267d3ea2143c8d173b53fd;hpb=5d0b813cecee07f2bf69e94e826385b38b5dfb4c;p=openjpeg.git diff --git a/libopenjpeg/jp2.c b/libopenjpeg/jp2.c index 43766b14..f359f297 100644 --- a/libopenjpeg/jp2.c +++ b/libopenjpeg/jp2.c @@ -74,7 +74,31 @@ static opj_bool jp2_read_ihdr_v2( ); static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio); + +/** + * Writes the Image Header box - Image Header box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_ihdr_v2( opj_jp2_v2_t *jp2, + unsigned int * p_nb_bytes_written ); + static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); + +/** + * Writes the Bit per Component box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_bpcc_v2( opj_jp2_v2_t *jp2, + unsigned int * p_nb_bytes_written ); + static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio); /** @@ -106,6 +130,18 @@ Write the FTYP box - File type box @param jp2 JP2 handle @param cio Output buffer stream */ + +/** + * Writes the Colour Specification box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char *jp2_write_colr_v2(opj_jp2_v2_t *jp2, + unsigned int * p_nb_bytes_written ); + static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); /** Read the FTYP box - File type box @@ -115,6 +151,19 @@ Read the FTYP box - File type box */ static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); +/** + * Writes a FTYP box - File type box + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +static opj_bool jp2_write_ftyp_v2( opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager ); + /** * Reads a a FTYP box - File type box * @@ -125,12 +174,23 @@ static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio); * * @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 - ); +static opj_bool jp2_read_ftyp_v2( opj_jp2_v2_t *jp2, + unsigned char * p_header_data, + OPJ_UINT32 p_header_size, + struct opj_event_mgr * p_manager ); + +/** + * Skips the Jpeg2000 Codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +opj_bool jp2_skip_jp2c( opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager ); /** * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). @@ -191,7 +251,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 @@ -286,6 +346,13 @@ static void write_prxy( int offset_jp2c, int length_jp2c, int offset_idx, int le /*@}*/ +/** + * Sets up the procedures to do on writting header after the codestream. + * Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_end_header_writting (opj_jp2_v2_t *jp2); + + /** * Sets up the procedures to do on reading header after the codestream. * Developpers wanting to extend the library can add their own writting procedures. @@ -350,6 +417,31 @@ static opj_bool jp2_read_boxhdr_v2( */ static const opj_jp2_header_handler_t * jp2_find_handler (int p_id ); +/** + * 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_encoding_validation (opj_jp2_v2_t *jp2); + + +/** + * Sets up the procedures to do on writting header. Developpers wanting to extend the library can add their own writting procedures. + */ +static void jp2_setup_header_writting (opj_jp2_v2_t *jp2); + +/** + * The default validation procedure without any extension. + * + * @param jp2 the jpeg2000 codec to validate. + * @param cio the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool jp2_default_validation ( opj_jp2_v2_t * jp2, + struct opj_stream_private *cio, + struct opj_event_mgr * p_manager ); + /** * Finds the image execution function related to the given box id. * @@ -446,7 +538,7 @@ opj_bool jp2_read_boxhdr_v2(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read /* read header from file */ unsigned char l_data_header [8]; - // preconditions + /* preconditions */ assert(cio != 00); assert(box != 00); assert(p_number_bytes_read != 00); @@ -461,8 +553,8 @@ opj_bool jp2_read_boxhdr_v2(opj_jp2_box_t *box, OPJ_UINT32 * p_number_bytes_read 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 + /* do we have a "special very large box ?" */ + /* read then the XLBox */ if (box->length == 1) { OPJ_UINT32 l_xl_part_size; @@ -542,10 +634,9 @@ 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_data pointer to actual data (already read from file) * @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. @@ -557,7 +648,7 @@ opj_bool jp2_read_ihdr_v2( opj_event_mgr_t * p_manager ) { - // preconditions + /* preconditions */ assert(p_image_header_data != 00); assert(jp2 != 00); assert(p_manager != 00); @@ -585,15 +676,15 @@ opj_bool jp2_read_ihdr_v2( 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 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 + 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 + /* 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); } @@ -629,6 +720,64 @@ static void jp2_write_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) { cio_seek(cio, box.init_pos + box.length); } +/** + * Writes the Image Header box - Image Header box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +static unsigned char * jp2_write_ihdr_v2( opj_jp2_v2_t *jp2, + unsigned int * p_nb_bytes_written ) +{ + unsigned char * l_ihdr_data,* l_current_ihdr_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + /* default image header is 22 bytes wide */ + l_ihdr_data = (unsigned char *) opj_malloc(22); + if (l_ihdr_data == 00) { + return 00; + } + memset(l_ihdr_data,0,22); + + l_current_ihdr_ptr = l_ihdr_data; + + opj_write_bytes(l_current_ihdr_ptr,22,4); /* write box size */ + l_current_ihdr_ptr+=4; + + opj_write_bytes(l_current_ihdr_ptr,JP2_IHDR, 4); /* IHDR */ + l_current_ihdr_ptr+=4; + + opj_write_bytes(l_current_ihdr_ptr,jp2->h, 4); /* HEIGHT */ + l_current_ihdr_ptr+=4; + + opj_write_bytes(l_current_ihdr_ptr, jp2->w, 4); /* WIDTH */ + l_current_ihdr_ptr+=4; + + opj_write_bytes(l_current_ihdr_ptr, jp2->numcomps, 2); /* NC */ + l_current_ihdr_ptr+=2; + + opj_write_bytes(l_current_ihdr_ptr, jp2->bpc, 1); /* BPC */ + ++l_current_ihdr_ptr; + + opj_write_bytes(l_current_ihdr_ptr, jp2->C, 1); /* C : Always 7 */ + ++l_current_ihdr_ptr; + + opj_write_bytes(l_current_ihdr_ptr, jp2->UnkC, 1); /* UnkC, colorspace unknown */ + ++l_current_ihdr_ptr; + + opj_write_bytes(l_current_ihdr_ptr, jp2->IPR, 1); /* IPR, no intellectual property */ + ++l_current_ihdr_ptr; + + *p_nb_bytes_written = 22; + + return l_ihdr_data; +} + static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { unsigned int i; opj_jp2_box_t box; @@ -648,6 +797,52 @@ static void jp2_write_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { } +/** + * Writes the Bit per Component box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +unsigned char * jp2_write_bpcc_v2( opj_jp2_v2_t *jp2, + unsigned int * p_nb_bytes_written ) +{ + unsigned int i; + /* room for 8 bytes for box and 1 byte for each component */ + int l_bpcc_size = 8 + jp2->numcomps; + unsigned char * l_bpcc_data,* l_current_bpcc_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + l_bpcc_data = (unsigned char *) opj_malloc(l_bpcc_size); + if (l_bpcc_data == 00) { + return 00; + } + memset(l_bpcc_data,0,l_bpcc_size); + + l_current_bpcc_ptr = l_bpcc_data; + + opj_write_bytes(l_current_bpcc_ptr,l_bpcc_size,4); /* write box size */ + l_current_bpcc_ptr += 4; + + opj_write_bytes(l_current_bpcc_ptr,JP2_BPCC,4); /* BPCC */ + l_current_bpcc_ptr += 4; + + for (i = 0; i < jp2->numcomps; ++i) { + opj_write_bytes(l_current_bpcc_ptr, jp2->comps[i].bpcc, 1); /* write each component information */ + ++l_current_bpcc_ptr; + } + + *p_nb_bytes_written = l_bpcc_size; + + return l_bpcc_data; +} + + + static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) { unsigned int i; opj_jp2_box_t box; @@ -675,13 +870,12 @@ 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_data pointer to actual data (already read from file) * @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. + * @return true if the bpc header is valid, false otherwise. */ opj_bool jp2_read_bpcc_v2( opj_jp2_v2_t *jp2, unsigned char * p_bpc_header_data, @@ -691,23 +885,23 @@ opj_bool jp2_read_bpcc_v2( opj_jp2_v2_t *jp2, { OPJ_UINT32 i; - // preconditions + /* preconditions */ assert(p_bpc_header_data != 00); assert(jp2 != 00); assert(p_manager != 00); - // TODO MSD + /* 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 + /* 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 + /* 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; @@ -738,6 +932,71 @@ static void jp2_write_colr(opj_jp2_t *jp2, opj_cio_t *cio) { cio_seek(cio, box.init_pos + box.length); } +/** + * Writes the Colour Specification box. + * + * @param jp2 jpeg2000 file codec. + * @param p_nb_bytes_written pointer to store the nb of bytes written by the function. + * + * @return the data being copied. +*/ +unsigned char *jp2_write_colr_v2( opj_jp2_v2_t *jp2, + unsigned int * p_nb_bytes_written ) +{ + /* room for 8 bytes for box 3 for common data and variable upon profile*/ + unsigned int l_colr_size = 11; + unsigned char * l_colr_data,* l_current_colr_ptr; + + // preconditions + assert(jp2 != 00); + assert(p_nb_bytes_written != 00); + + switch (jp2->meth) { + case 1 : + l_colr_size += 4; + break; + case 2 : + ++l_colr_size; + break; + default : + return 00; + } + + l_colr_data = (unsigned char *) opj_malloc(l_colr_size); + if (l_colr_data == 00) { + return 00; + } + memset(l_colr_data,0,l_colr_size); + + l_current_colr_ptr = l_colr_data; + + opj_write_bytes(l_current_colr_ptr,l_colr_size,4); /* write box size */ + l_current_colr_ptr += 4; + + opj_write_bytes(l_current_colr_ptr,JP2_COLR,4); /* BPCC */ + l_current_colr_ptr += 4; + + opj_write_bytes(l_current_colr_ptr, jp2->meth,1); /* METH */ + ++l_current_colr_ptr; + + opj_write_bytes(l_current_colr_ptr, jp2->precedence,1); /* PRECEDENCE */ + ++l_current_colr_ptr; + + opj_write_bytes(l_current_colr_ptr, jp2->approx,1); /* APPROX */ + ++l_current_colr_ptr; + + if (jp2->meth == 1) { + opj_write_bytes(l_current_colr_ptr, jp2->enumcs,4); /* EnumCS */ + } + else { + opj_write_bytes(l_current_colr_ptr, 0, 1); /* PROFILE (??) */ + } + + *p_nb_bytes_written = l_colr_size; + + return l_colr_data; +} + static void jp2_free_pclr(opj_jp2_color_t *color) { opj_free(color->jp2_pclr->channel_sign); @@ -763,16 +1022,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; @@ -782,50 +1042,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; @@ -834,6 +1096,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) { @@ -892,10 +1155,9 @@ static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio, /** * 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_pclr_header_data pointer to actual data (already read from file) + * @param p_pclr_header_size pointer that will hold the size of the PCLR header * @param p_manager the user event manager. * * @return true if the bpc header is valid, fale else. @@ -912,7 +1174,7 @@ opj_bool jp2_read_pclr_v2( opj_jp2_v2_t *jp2, OPJ_UINT16 i, j; OPJ_UINT32 l_value; - // preconditions + /* preconditions */ assert(p_pclr_header_data != 00); assert(jp2 != 00); assert(p_manager != 00); @@ -952,7 +1214,7 @@ opj_bool jp2_read_pclr_v2( opj_jp2_v2_t *jp2, for(j = 0; j < nr_entries; ++j) { for(i = 0; i < nr_channels; ++i) { - //*entries++ = cio_read(cio, channel_size[i]>>3); + /**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; @@ -1018,7 +1280,7 @@ static opj_bool jp2_read_cmap_v2( opj_jp2_v2_t * jp2, OPJ_BYTE i, nr_channels; OPJ_UINT32 l_value; - // preconditions + /* preconditions */ assert(jp2 != 00); assert(p_cmap_header_data != 00); assert(p_manager != 00); @@ -1062,32 +1324,33 @@ static opj_bool jp2_read_cmap_v2( opj_jp2_v2_t * jp2, 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; @@ -1147,7 +1410,7 @@ static opj_bool jp2_read_cdef_v2( opj_jp2_v2_t * jp2, unsigned short i; OPJ_UINT32 l_value; - // preconditions + /* preconditions */ assert(jp2 != 00); assert(p_cdef_header_data != 00); assert(p_manager != 00); @@ -1262,7 +1525,7 @@ static opj_bool jp2_read_colr_v2( opj_jp2_v2_t * jp2, { OPJ_UINT32 l_value; - // preconditions + /* preconditions */ assert(jp2 != 00); assert(p_colr_header_data != 00); assert(p_manager != 00); @@ -1299,7 +1562,7 @@ static opj_bool jp2_read_colr_v2( opj_jp2_v2_t * jp2, opj_read_bytes(p_colr_header_data,&jp2->enumcs ,4); /* EnumCS */ } else if (jp2->meth == 2) { - // ICC profile + /* ICC profile */ int it_icc_value = 0; int icc_len = p_colr_header_size - 3; @@ -1316,7 +1579,7 @@ static opj_bool jp2_read_colr_v2( opj_jp2_v2_t * jp2, } } - else // TODO MSD + 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; @@ -1372,7 +1635,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color) jp2_read_boxhdr(cinfo, cio, &box); continue; } - if(box.type == JP2_CDEF) + if(box.type == JP2_CDEF && !jp2->ignore_pclr_cmap_cdef) { if( !jp2_read_cdef(jp2, cio, &box, color)) { @@ -1382,7 +1645,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color) jp2_read_boxhdr(cinfo, cio, &box); continue; } - if(box.type == JP2_PCLR) + if(box.type == JP2_PCLR && !jp2->ignore_pclr_cmap_cdef) { if( !jp2_read_pclr(jp2, cio, &box, color)) { @@ -1392,7 +1655,7 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color) jp2_read_boxhdr(cinfo, cio, &box); continue; } - if(box.type == JP2_CMAP) + if(box.type == JP2_CMAP && !jp2->ignore_pclr_cmap_cdef) { if( !jp2_read_cmap(jp2, cio, &box, color)) { @@ -1446,8 +1709,10 @@ opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_event_msg(cinfo, EVT_ERROR, "Failed to decode J2K image\n"); return NULL; } + + if (!jp2->ignore_pclr_cmap_cdef){ -/* Set Image Color Space */ + /* Set Image Color Space */ if (jp2->enumcs == 16) image->color_space = CLRSPC_SRGB; else if (jp2->enumcs == 17) @@ -1467,7 +1732,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) { @@ -1475,10 +1740,58 @@ opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, color.icc_profile_buf = NULL; image->icc_profile_len = color.icc_profile_len; } + } + return image; }/* 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; @@ -1500,6 +1813,112 @@ void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio) { cio_seek(cio, box.init_pos + box.length); } +/** + * Writes the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +opj_bool jp2_write_jp2h_v2( opj_jp2_v2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager ) +{ + opj_jp2_img_header_writer_handler_t l_writers [3]; + opj_jp2_img_header_writer_handler_t * l_current_writer; + + int i, l_nb_pass; + /* size of data for super box*/ + int l_jp2h_size = 8; + opj_bool l_result = OPJ_TRUE; + + /* to store the data of the super box */ + unsigned char l_jp2h_data [8]; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + memset(l_writers,0,sizeof(l_writers)); + + if (jp2->bpc == 255) { + l_nb_pass = 3; + l_writers[0].handler = jp2_write_ihdr_v2; + l_writers[1].handler = jp2_write_bpcc_v2; + l_writers[2].handler = jp2_write_colr_v2; + } + else { + l_nb_pass = 2; + l_writers[0].handler = jp2_write_ihdr_v2; + l_writers[1].handler = jp2_write_colr_v2; + } + + /* write box header */ + /* write JP2H type */ + opj_write_bytes(l_jp2h_data+4,JP2_JP2H,4); + + l_current_writer = l_writers; + for (i=0;im_data = l_current_writer->handler(jp2,&(l_current_writer->m_size)); + if (l_current_writer->m_data == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to hold JP2 Header data\n"); + l_result = OPJ_FALSE; + break; + } + + l_jp2h_size += l_current_writer->m_size; + ++l_current_writer; + } + + if (! l_result) { + l_current_writer = l_writers; + for (i=0;im_data != 00) { + opj_free(l_current_writer->m_data ); + } + ++l_current_writer; + } + + return OPJ_FALSE; + } + + /* write super box size */ + opj_write_bytes(l_jp2h_data,l_jp2h_size,4); + + /* write super box data on stream */ + if (opj_stream_write_data(cio,l_jp2h_data,8,p_manager) != 8) { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while writting JP2 Header box\n"); + l_result = OPJ_FALSE; + } + + if (l_result) { + l_current_writer = l_writers; + for (i=0;im_data,l_current_writer->m_size,p_manager) != l_current_writer->m_size) { + opj_event_msg(p_manager, EVT_ERROR, "Stream error while writting JP2 Header box\n"); + l_result = OPJ_FALSE; + break; + } + ++l_current_writer; + } + } + + l_current_writer = l_writers; + + /* cleanup */ + for (i=0;im_data != 00) { + opj_free(l_current_writer->m_data ); + } + ++l_current_writer; + } + + return l_result; +} + static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { unsigned int i; opj_jp2_box_t box; @@ -1521,6 +1940,67 @@ static void jp2_write_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { cio_seek(cio, box.init_pos + box.length); } +/** + * Writes a FTYP box - File type box + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +opj_bool jp2_write_ftyp_v2( opj_jp2_v2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager ) +{ + unsigned int i; + unsigned int l_ftyp_size = 16 + 4 * jp2->numcl; + unsigned char * l_ftyp_data, * l_current_data_ptr; + opj_bool l_result; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + l_ftyp_data = (unsigned char *) opj_malloc(l_ftyp_size); + + if (l_ftyp_data == 00) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Not enough memory to handle ftyp data\n"); + return OPJ_FALSE; + } + + memset(l_ftyp_data,0,l_ftyp_size); + + l_current_data_ptr = l_ftyp_data; + + opj_write_bytes(l_current_data_ptr, l_ftyp_size,4); /* box size */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, JP2_FTYP,4); /* FTYP */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, jp2->brand,4); /* BR */ + l_current_data_ptr += 4; + + opj_write_bytes(l_current_data_ptr, jp2->minversion,4); /* MinV */ + l_current_data_ptr += 4; + + for (i = 0; i < jp2->numcl; i++) { + opj_write_bytes(l_current_data_ptr, jp2->cl[i],4); /* CL */ + } + + l_result = (opj_stream_write_data(cio,l_ftyp_data,l_ftyp_size,p_manager) == l_ftyp_size); + if (! l_result) + { + opj_event_msg(p_manager, EVT_ERROR, "Error while writting ftyp data to stream\n"); + } + + opj_free(l_ftyp_data); + + return l_result; +} + static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) { int i; opj_jp2_box_t box; @@ -1613,6 +2093,41 @@ static void jp2_write_jp(opj_cio_t *cio) { cio_seek(cio, box.init_pos + box.length); } +/** + * Writes a jpeg2000 file signature box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager the user event manager. + * + * @return true if writting was successful. + */ +opj_bool jp2_write_jp_v2( opj_jp2_v2_t *jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager ) +{ + /* 12 bytes will be read */ + unsigned char l_signature_data [12]; + + // preconditions + assert(cio != 00); + assert(jp2 != 00); + assert(p_manager != 00); + + /* write box length */ + opj_write_bytes(l_signature_data,12,4); + /* writes box type */ + opj_write_bytes(l_signature_data+4,JP2_JP,4); + /* writes magic number*/ + opj_write_bytes(l_signature_data+8,0x0d0a870a,4); + + if (opj_stream_write_data(cio,l_signature_data,12,p_manager) != 12) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} + static opj_bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio) { opj_jp2_box_t box; @@ -1659,7 +2174,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); @@ -1748,6 +2263,7 @@ void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) { /* setup the J2K codec */ j2k_setup_decoder(jp2->j2k, parameters); /* further JP2 initializations go here */ + jp2->ignore_pclr_cmap_cdef = parameters->flags & OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; } void jp2_setup_decoder_v2(opj_jp2_v2_t *jp2, opj_dparameters_t *parameters) @@ -1793,7 +2309,10 @@ void jp2_destroy_compress(opj_jp2_t *jp2) { } } -void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_t *image) { +void jp2_setup_encoder( opj_jp2_v2_t *jp2, + opj_cparameters_t *parameters, + opj_image_t *image, + opj_event_mgr_t * p_manager) { int i; int depth_0, sign; @@ -1805,11 +2324,11 @@ void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_ /* Check if number of components respects standard */ if (image->numcomps < 1 || image->numcomps > 16384) { - opj_event_msg(jp2->cinfo, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); + opj_event_msg_v2(p_manager, EVT_ERROR, "Invalid number of components specified while setting up JP2 encoder\n"); return; } - j2k_setup_encoder(jp2->j2k, parameters, image); + j2k_setup_encoder_v2(jp2->j2k, parameters, image, p_manager ); /* setup the JP2 codec */ /* ------------------- */ @@ -1843,26 +2362,36 @@ void jp2_setup_encoder(opj_jp2_t *jp2, opj_cparameters_t *parameters, opj_image_ jp2->IPR = 0; /* IPR, no intellectual property */ /* BitsPerComponent box */ - for (i = 0; i < image->numcomps; i++) { jp2->comps[i].bpcc = image->comps[i].prec - 1 + (image->comps[i].sgnd << 7); } - jp2->meth = 1; - if (image->color_space == 1) - jp2->enumcs = 16; /* sRGB as defined by IEC 61966-2.1 */ - else if (image->color_space == 2) - jp2->enumcs = 17; /* greyscale */ - else if (image->color_space == 3) - jp2->enumcs = 18; /* YUV */ + + /* Colour Specification box */ + if ((image->numcomps == 1 || image->numcomps == 3) && (jp2->bpc != 255)) { + jp2->meth = 1; /* METH: Enumerated colourspace */ + } else { + jp2->meth = 2; /* METH: Restricted ICC profile */ + } + if (jp2->meth == 1) { + if (image->color_space == 1) + jp2->enumcs = 16; /* sRGB as defined by IEC 61966–2–1 */ + else if (image->color_space == 2) + jp2->enumcs = 17; /* greyscale */ + else if (image->color_space == 3) + jp2->enumcs = 18; /* YUV */ + } else { + jp2->enumcs = 0; /* PROFILE (??) */ + } jp2->precedence = 0; /* PRECEDENCE */ jp2->approx = 0; /* APPROX */ - jp2->jpip_on = parameters->jpip_on; + // jp2->jpip_on = parameters->jpip_on; } 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; + pos_jp2c = pos_iptr = -1; /* remove a warning */ /* JP2 encoding */ @@ -1889,10 +2418,10 @@ 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); @@ -1910,7 +2439,7 @@ opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_ */ opj_bool jp2_end_decompress(opj_jp2_v2_t *jp2, opj_stream_private_t *cio, opj_event_mgr_t * p_manager) { - // preconditions + /* preconditions */ assert(jp2 != 00); assert(cio != 00); assert(p_manager != 00); @@ -1926,18 +2455,118 @@ opj_bool jp2_end_decompress(opj_jp2_v2_t *jp2, opj_stream_private_t *cio, opj_ev return j2k_end_decompress(jp2->j2k, cio, p_manager); } +/** + * Ends the compression procedures and possibility add data to be read after the + * codestream. + */ +opj_bool jp2_end_compress( 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_writting(jp2); + + if (! j2k_end_compress(jp2->j2k,cio,p_manager)) { + return OPJ_FALSE; + } + + /* write header */ + return jp2_exec(jp2,jp2->m_procedure_list,cio,p_manager); +} + + +/** + * Sets up the procedures to do on writing header after the codestream. + * Developers wanting to extend the library can add their own writing procedures. + */ +void jp2_setup_end_header_writting (opj_jp2_v2_t *jp2) +{ + /* preconditions */ + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_write_jp2c ); + /* DEVELOPER CORNER, add your custom procedures */ +} + /** * Sets up the procedures to do on reading header after the codestream. - * Developpers wanting to extend the library can add their own writting procedures. + * Developers wanting to extend the library can add their own writing procedures. */ void jp2_setup_end_header_reading (opj_jp2_v2_t *jp2) { - // preconditions + /* preconditions */ assert(jp2 != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_read_header_procedure ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_read_header_procedure ); /* DEVELOPER CORNER, add your custom procedures */ } +/** + * The default validation procedure without any extension. + * + * @param jp2 the jpeg2000 codec to validate. + * @param cio the input stream to validate. + * @param p_manager the user event manager. + * + * @return true if the parameters are correct. + */ +opj_bool jp2_default_validation ( opj_jp2_v2_t * jp2, + opj_stream_private_t *cio, + opj_event_mgr_t * p_manager ) +{ + opj_bool l_is_valid = OPJ_TRUE; + unsigned int i; + + /* preconditions */ + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* JPEG2000 codec validation */ + /*TODO*/ + + /* STATE checking */ + /* make sure the state is at 0 */ + l_is_valid &= (jp2->jp2_state == JP2_STATE_NONE); + + /* make sure not reading a jp2h ???? WEIRD */ + l_is_valid &= (jp2->jp2_img_state == JP2_IMG_STATE_NONE); + + /* POINTER validation */ + /* make sure a j2k codec is present */ + l_is_valid &= (jp2->j2k != 00); + + /* make sure a procedure list is present */ + l_is_valid &= (jp2->m_procedure_list != 00); + + /* make sure a validation list is present */ + l_is_valid &= (jp2->m_validation_list != 00); + + /* PARAMETER VALIDATION */ + /* number of components */ + l_is_valid &= (jp2->numcl > 0); + /* width */ + l_is_valid &= (jp2->h > 0); + /* height */ + l_is_valid &= (jp2->w > 0); + /* precision */ + for (i = 0; i < jp2->numcomps; ++i) { + l_is_valid &= (jp2->comps[i].bpcc > 0); + } + + /* METH */ + l_is_valid &= ((jp2->meth > 0) && (jp2->meth < 3)); + + /* stream validation */ + /* back and forth is needed */ + l_is_valid &= opj_stream_has_seek(cio); + + return l_is_valid; +} /** * Reads a jpeg2000 file header structure. @@ -1960,7 +2589,7 @@ opj_bool jp2_read_header_procedure( OPJ_UINT32 l_current_data_size; unsigned char * l_current_data = 00; - // preconditions + /* preconditions */ assert(cio != 00); assert(jp2 != 00); assert(p_manager != 00); @@ -1974,7 +2603,7 @@ opj_bool jp2_read_header_procedure( 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 ? + /* is it the codestream box ? */ if (box.type == JP2_JP2C) { if (jp2->jp2_state & JP2_STATE_HEADER) { jp2->jp2_state |= JP2_STATE_CODESTREAM; @@ -1999,6 +2628,10 @@ opj_bool jp2_read_header_procedure( 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); + if (!l_current_data){ + opj_free(l_current_data); + return OPJ_FALSE; + } l_last_data_size = l_current_data_size; } @@ -2049,7 +2682,7 @@ opj_bool jp2_exec ( opj_bool l_result = OPJ_TRUE; OPJ_UINT32 l_nb_proc, i; - // preconditions + /* preconditions */ assert(p_procedure_list != 00); assert(jp2 != 00); assert(cio != 00); @@ -2063,11 +2696,47 @@ opj_bool jp2_exec ( ++l_procedure; } - // and clear the procedure list at the end. + /* and clear the procedure list at the end. */ opj_procedure_list_clear(p_procedure_list); return l_result; } +/** + * Starts a compression scheme, i.e. validates the codec parameters, writes the header. + * + * @param jp2 the jpeg2000 file codec. + * @param cio the stream object. + * + * @return true if the codec is valid. + */ +opj_bool jp2_start_compress(opj_jp2_v2_t *jp2, + struct opj_stream_private *cio, + opj_image_t * p_image, + struct opj_event_mgr * p_manager) +{ + /* preconditions */ + assert(jp2 != 00); + assert(cio != 00); + assert(p_manager != 00); + + /* customization of the validation */ + jp2_setup_encoding_validation (jp2); + + /* validation of the parameters codec */ + if (! jp2_exec(jp2,jp2->m_validation_list,cio,p_manager)) { + return OPJ_FALSE; + } + + /* customization of the encoding */ + jp2_setup_header_writting(jp2); + + /* write header */ + if (! jp2_exec (jp2,jp2->m_procedure_list,cio,p_manager)) { + return OPJ_FALSE; + } + + return j2k_start_compress(jp2->j2k,cio,p_image,p_manager); +} /** * Finds the execution function related to the given box id. @@ -2130,7 +2799,7 @@ opj_bool jp2_read_jp_v2( { unsigned int l_magic_number; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(jp2 != 00); assert(p_manager != 00); @@ -2146,7 +2815,7 @@ opj_bool jp2_read_jp_v2( return OPJ_FALSE; } - // rearrange data + /* 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"); @@ -2178,7 +2847,7 @@ opj_bool jp2_read_ftyp_v2( { OPJ_UINT32 i, l_remaining_bytes; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(jp2 != 00); assert(p_manager != 00); @@ -2230,6 +2899,32 @@ opj_bool jp2_read_ftyp_v2( return OPJ_TRUE; } +/** + * Skips the Jpeg2000 Codestream Header box - JP2C Header box. + * + * @param cio the stream to write data to. + * @param jp2 the jpeg2000 file codec. + * @param p_manager user event manager. + * + * @return true if writting was successful. +*/ +opj_bool jp2_skip_jp2c( opj_jp2_v2_t *jp2, + struct opj_stream_private *stream, + struct opj_event_mgr * p_manager ) +{ + /* preconditions */ + assert(jp2 != 00); + assert(stream != 00); + assert(p_manager != 00); + + jp2->j2k_codestream_offset = opj_stream_tell(stream); + + if (opj_stream_skip(stream,8,p_manager) != 8) { + return OPJ_FALSE; + } + + return OPJ_TRUE; +} /** * Reads the Jpeg2000 file Header box - JP2 Header box (warning, this is a super box). @@ -2252,7 +2947,7 @@ opj_bool jp2_read_jp2h_v2( opj_jp2_box_t box; const opj_jp2_header_handler_t * l_current_handler; - // preconditions + /* preconditions */ assert(p_header_data != 00); assert(jp2 != 00); assert(p_manager != 00); @@ -2320,7 +3015,7 @@ static opj_bool jp2_read_boxhdr_char( { OPJ_UINT32 l_value; - // preconditions + /* preconditions */ assert(p_data != 00); assert(box != 00); assert(p_number_bytes_read != 00); @@ -2342,8 +3037,8 @@ static opj_bool jp2_read_boxhdr_char( *p_number_bytes_read = 8; - // do we have a "special very large box ?" - // read then the XLBox + /* do we have a "special very large box ?" */ + /* read then the XLBox */ if (box->length == 1) { unsigned int l_xl_part_size; @@ -2390,11 +3085,11 @@ static opj_bool jp2_read_boxhdr_char( */ opj_bool jp2_read_header( struct opj_stream_private *p_stream, opj_jp2_v2_t *jp2, - opj_file_info_t * p_file_info, + opj_image_t** p_image, struct opj_event_mgr * p_manager ) { - // preconditions + /* preconditions */ assert(jp2 != 00); assert(p_stream != 00); assert(p_manager != 00); @@ -2417,31 +3112,62 @@ opj_bool jp2_read_header( struct opj_stream_private *p_stream, return j2k_read_header( p_stream, jp2->j2k, - p_file_info, + p_image, p_manager); } +/** + * Sets up the validation ,i.e. adds the procedures to launch to make sure the codec parameters + * are valid. Developers wanting to extend the library can add their own validation procedures. + */ +void jp2_setup_encoding_validation (opj_jp2_v2_t *jp2) +{ + /* preconditions */ + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_validation_list, (opj_procedure)jp2_default_validation); + /* DEVELOPER CORNER, add your custom validation procedure */ +} + /** * 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 + /* preconditions */ assert(jp2 != 00); /* DEVELOPER CORNER, add your custom validation procedure */ } +/** + * Sets up the procedures to do on writting header. + * Developers wanting to extend the library can add their own writing procedures. + */ +void jp2_setup_header_writting (opj_jp2_v2_t *jp2) +{ + /* preconditions */ + assert(jp2 != 00); + + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_write_jp_v2 ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_write_ftyp_v2 ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_write_jp2h_v2 ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_skip_jp2c ); + + /* DEVELOPER CORNER, insert your custom procedures */ + +} + /** * 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 + /* preconditions */ assert(jp2 != 00); - opj_procedure_list_add_procedure(jp2->m_procedure_list,(void*)jp2_read_header_procedure ); + opj_procedure_list_add_procedure(jp2->m_procedure_list,(opj_procedure)jp2_read_header_procedure ); /* DEVELOPER CORNER, add your custom procedures */ } @@ -2473,13 +3199,29 @@ opj_bool jp2_read_tile_header( opj_jp2_v2_t * p_jp2, p_manager); } +/** + * Writes a tile. + * @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_write_tile ( opj_jp2_v2_t *p_jp2, + OPJ_UINT32 p_tile_index, + OPJ_BYTE * p_data, + OPJ_UINT32 p_data_size, + struct opj_stream_private *p_stream, + struct opj_event_mgr * p_manager ) +{ + return j2k_write_tile (p_jp2->j2k,p_tile_index,p_data,p_data_size,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 opj_jp2_decode_tile ( +opj_bool jp2_decode_tile ( opj_jp2_v2_t * p_jp2, OPJ_UINT32 p_tile_index, OPJ_BYTE * p_data, @@ -2519,11 +3261,33 @@ void jp2_destroy(opj_jp2_v2_t *jp2) } 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; } @@ -2554,13 +3318,75 @@ void jp2_destroy(opj_jp2_v2_t *jp2) * @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_start_x, p_start_y, p_end_x, p_end_y, 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 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 */ /* ----------------------------------------------------------------------- */ @@ -2584,14 +3410,21 @@ opj_jp2_v2_t* jp2_create(opj_bool p_is_decoder) return 00; } - // validation list creation + /* 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 + /* execution list creation */ jp2->m_procedure_list = opj_procedure_list_create(); if (! jp2->m_procedure_list) { jp2_destroy(jp2); @@ -2601,3 +3434,29 @@ opj_jp2_v2_t* jp2_create(opj_bool p_is_decoder) 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); +} +