diff --git a/CHANGES b/CHANGES index 166911c3..75927c23 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ What's New for OpenJPEG + : added November 8, 2011 ++ [mickael] WIP: add get_decoded_tile functionality + [mickael] WIP: clean and enhance j2K file + [mickael] WIP: clean and enhance openjpeg.c + [mickael] WIP: clean and enhance openjpeg.h and add deprecated macro diff --git a/applications/codec/j2k_dump.c b/applications/codec/j2k_dump.c index 9b5475ed..6d13bb11 100644 --- a/applications/codec/j2k_dump.c +++ b/applications/codec/j2k_dump.c @@ -525,77 +525,6 @@ int main(int argc, char *argv[]) cstr_index = opj_get_cstr_index(dinfo); -#ifdef MSD - fprintf(stdout,"Setting decoding area to %d,%d,%d,%d\n", - parameters.DA_x0, parameters.DA_y0, parameters.DA_x1, parameters.DA_y1); - - - /* FIXME WIP_MSD <*/ - if (! opj_set_decode_area( dinfo, - parameters.DA_x0, parameters.DA_y0, - parameters.DA_x1, parameters.DA_y1)){ - fprintf(stderr, "ERROR -> j2k_dump: failed to set the decoded area\n"); - opj_stream_destroy(cio); - opj_destroy_codec(dinfo); - fclose(fsrc); - fclose(fout); - return EXIT_FAILURE; - } - - while (l_go_on) { - OPJ_INT32 l_current_tile_x0,l_current_tile_y0,l_current_tile_x1,l_current_tile_y1; - OPJ_UINT32 l_nb_comps, l_tile_index, l_data_size; - - - if (! opj_read_tile_header( dinfo, - cio, - &l_tile_index, - &l_data_size, - &l_current_tile_x0, - &l_current_tile_y0, - &l_current_tile_x1, - &l_current_tile_y1, - &l_nb_comps, - &l_go_on - )) { - fprintf(stderr, "ERROR -> j2k_dump: failed read the tile header\n"); - opj_stream_destroy(cio); - fclose(fsrc); - opj_destroy_codec(dinfo); - return EXIT_FAILURE; - } - - if (l_go_on) { - - if (l_data_size > l_max_data_size) { - - l_data = (OPJ_BYTE *) realloc(l_data,l_data_size); - if (! l_data) { - opj_stream_destroy(cio); - opj_destroy_codec(dinfo); - fclose(fsrc); - fclose(fout); - return EXIT_FAILURE; - } - - l_max_data_size = l_data_size; - } - - if (! opj_decode_tile_data(dinfo,l_tile_index,l_data,l_data_size,cio)) - { - free(l_data); - opj_stream_destroy(cio); - opj_destroy_codec(dinfo); - fclose(fsrc); - fclose(fout); - return EXIT_FAILURE; - } - /** now should inspect image to know the reduction factor and then how to behave with data */ - } - } - /* FIXME WIP_MSD >*/ -#endif - /* close the byte stream */ opj_stream_destroy(cio); fclose(fsrc); diff --git a/libopenjpeg/cio.c b/libopenjpeg/cio.c index 85a320c8..32203a45 100644 --- a/libopenjpeg/cio.c +++ b/libopenjpeg/cio.c @@ -524,9 +524,7 @@ OPJ_API void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) { OPJ_UINT32 l_read_nb_bytes = 0; - if - (p_stream->m_bytes_in_buffer >= p_size) - { + if (p_stream->m_bytes_in_buffer >= p_size) { memcpy(p_buffer,p_stream->m_current_data,p_size); p_stream->m_current_data += p_size; p_stream->m_bytes_in_buffer -= p_size; @@ -535,10 +533,8 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu return l_read_nb_bytes; } - // we are now in the case when the remaining data if not sufficient - if - (p_stream->m_status & opj_stream_e_end) - { + /* we are now in the case when the remaining data if not sufficient */ + if (p_stream->m_status & opj_stream_e_end) { l_read_nb_bytes += p_stream->m_bytes_in_buffer; memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); p_stream->m_current_data += p_stream->m_bytes_in_buffer; @@ -547,10 +543,8 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu return l_read_nb_bytes ? l_read_nb_bytes : -1; } - // the flag is not set, we copy data and then do an actual read on the stream - if - (p_stream->m_bytes_in_buffer) - { + /* the flag is not set, we copy data and then do an actual read on the stream */ + if (p_stream->m_bytes_in_buffer) { l_read_nb_bytes += p_stream->m_bytes_in_buffer; memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); p_stream->m_current_data = p_stream->m_stored_data; @@ -559,37 +553,31 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; p_stream->m_bytes_in_buffer = 0; } - else - { + else { /* case where we are already at the end of the buffer so reset the m_current_data to point to the start of the stored buffer to get ready to read from disk*/ - p_stream->m_current_data = p_stream->m_stored_data; - } + p_stream->m_current_data = p_stream->m_stored_data; + } while(1){ - // we should read less than a chunk -> read a chunk - if - (p_size < p_stream->m_buffer_size) - { - // we should do an actual read on the media + /* we should read less than a chunk -> read a chunk */ + if (p_size < p_stream->m_buffer_size) { + /* we should do an actual read on the media */ p_stream->m_bytes_in_buffer = p_stream->m_read_fn(p_stream->m_stored_data,p_stream->m_buffer_size,p_stream->m_user_data); - if - (p_stream->m_bytes_in_buffer == -1) - { - // end of stream + + if (p_stream->m_bytes_in_buffer == -1) { + /* end of stream */ opj_event_msg_v2(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); p_stream->m_bytes_in_buffer = 0; p_stream->m_status |= opj_stream_e_end; - // end of stream + /* end of stream */ return l_read_nb_bytes ? l_read_nb_bytes : -1; } - else if - (p_stream->m_bytes_in_buffer < p_size) - { - // not enough data + else if (p_stream->m_bytes_in_buffer < p_size) { + /* not enough data */ l_read_nb_bytes += p_stream->m_bytes_in_buffer; memcpy(p_buffer,p_stream->m_current_data,p_stream->m_bytes_in_buffer); p_stream->m_current_data = p_stream->m_stored_data; @@ -598,8 +586,7 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; p_stream->m_bytes_in_buffer = 0; } - else - { + else { l_read_nb_bytes += p_size; memcpy(p_buffer,p_stream->m_current_data,p_size); p_stream->m_current_data += p_size; @@ -608,25 +595,21 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu return l_read_nb_bytes; } } - else - { - // direct read on the dest buffer + else { + /* direct read on the dest buffer */ p_stream->m_bytes_in_buffer = p_stream->m_read_fn(p_buffer,p_size,p_stream->m_user_data); - if - (p_stream->m_bytes_in_buffer == -1) - { - // end of stream + + if (p_stream->m_bytes_in_buffer == -1) { + /* end of stream */ opj_event_msg_v2(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); p_stream->m_bytes_in_buffer = 0; p_stream->m_status |= opj_stream_e_end; - // end of stream + /* end of stream */ return l_read_nb_bytes ? l_read_nb_bytes : -1; } - else if - (p_stream->m_bytes_in_buffer < p_size) - { - // not enough data + else if (p_stream->m_bytes_in_buffer < p_size) { + /* not enough data */ l_read_nb_bytes += p_stream->m_bytes_in_buffer; p_stream->m_current_data = p_stream->m_stored_data; p_buffer += p_stream->m_bytes_in_buffer; @@ -634,9 +617,8 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; p_stream->m_bytes_in_buffer = 0; } - else - { - // we have read the exact size + else { + /* we have read the exact size */ l_read_nb_bytes += p_stream->m_bytes_in_buffer; p_stream->m_byte_offset += p_stream->m_bytes_in_buffer; p_stream->m_current_data = p_stream->m_stored_data; @@ -903,19 +885,18 @@ opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_siz { p_stream->m_current_data = p_stream->m_stored_data; p_stream->m_bytes_in_buffer = 0; - if - (! p_stream->m_seek_fn(p_size,p_stream->m_user_data)) - { + + if( p_stream->m_seek_fn(p_size,p_stream->m_user_data)) { p_stream->m_status |= opj_stream_e_end; return EXIT_FAILURE; } - else - { + else { // reset stream status p_stream->m_status &= (~opj_stream_e_end); p_stream->m_byte_offset = p_size; } + return EXIT_SUCCESS; } diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index 111e8c71..281b087f 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -3687,12 +3687,17 @@ opj_bool j2k_read_sot_v2 ( p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPH; - /* Check if the current tile is outside the area we want decode (in tile index)*/ - p_j2k->m_specific_param.m_decoder.m_skip_data = - (l_tile_x < p_j2k->m_specific_param.m_decoder.m_start_tile_x) - || (l_tile_x >= p_j2k->m_specific_param.m_decoder.m_end_tile_x) - || (l_tile_y < p_j2k->m_specific_param.m_decoder.m_start_tile_y) - || (l_tile_y >= p_j2k->m_specific_param.m_decoder.m_end_tile_y); + /* Check if the current tile is outside the area we want decode or not corresponding to the tile index*/ + if (p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec == -1) { + p_j2k->m_specific_param.m_decoder.m_skip_data = + (l_tile_x < p_j2k->m_specific_param.m_decoder.m_start_tile_x) + || (l_tile_x >= p_j2k->m_specific_param.m_decoder.m_end_tile_x) + || (l_tile_y < p_j2k->m_specific_param.m_decoder.m_start_tile_y) + || (l_tile_y >= p_j2k->m_specific_param.m_decoder.m_end_tile_y); + } + else + p_j2k->m_specific_param.m_decoder.m_skip_data = + (p_j2k->m_current_tile_number != p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec); /* Index */ if (p_j2k->cstr_index) @@ -6636,9 +6641,6 @@ opj_bool j2k_read_tile_header( opj_j2k_v2_t * p_j2k, return OPJ_FALSE; } -/* if (l_current_marker == J2K_MS_SOT) - j2k_add_tlmarker();*/ - /* Add the marker to the codestream index*/ j2k_add_tlmarker_v2(p_j2k->m_current_tile_number, p_j2k->cstr_index, @@ -6646,6 +6648,16 @@ opj_bool j2k_read_tile_header( opj_j2k_v2_t * p_j2k, (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4, l_marker_size + 4 ); + /* Keep the position of the last SOT marker read */ + if ( l_marker_handler->id == J2K_MS_SOT ) { + OPJ_UINT32 sot_pos = (OPJ_UINT32) opj_stream_tell(p_stream) - l_marker_size - 4 ; + if (sot_pos > p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos) + { + p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos = sot_pos; + } + } + + if (p_j2k->m_specific_param.m_decoder.m_skip_data) { /* Skip the rest of the tile part header*/ if (opj_stream_skip(p_stream,p_j2k->m_specific_param.m_decoder.m_sot_length,p_manager) != p_j2k->m_specific_param.m_decoder.m_sot_length) { @@ -6733,7 +6745,7 @@ opj_bool j2k_read_tile_header( opj_j2k_v2_t * p_j2k, } opj_event_msg_v2(p_manager, EVT_INFO, "Header of tile %d / %d has been read.\n", - p_j2k->m_current_tile_number +1, p_j2k->m_cp.th * p_j2k->m_cp.tw); + p_j2k->m_current_tile_number, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); *p_tile_index = p_j2k->m_current_tile_number; *p_go_on = OPJ_TRUE; @@ -6963,7 +6975,7 @@ opj_bool j2k_update_image_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data, opj_ima /* Move the output buffer to the first place where we will write*/ l_dest_ptr = l_img_comp_dest->data + l_start_offset_dest; - if (i == 0) { + /*if (i == 0) { fprintf(stdout, "COMPO[%d]:\n",i); fprintf(stdout, "SRC: l_start_x_src=%d, l_start_y_src=%d, l_width_src=%d, l_height_src=%d\n" "\t tile offset:%d, %d, %d, %d\n" @@ -6975,7 +6987,7 @@ opj_bool j2k_update_image_data (opj_tcd_v2_t * p_tcd, OPJ_BYTE * p_data, opj_ima fprintf(stdout, "DEST: l_start_x_dest=%d, l_start_y_dest=%d, l_width_dest=%d, l_height_dest=%d\n" "\t start offset: %d, line offset= %d\n", l_start_x_dest, l_start_y_dest, l_width_dest, l_height_dest, l_start_offset_dest, l_line_offset_dest); - } + }*/ switch (l_size_comp) { @@ -7260,6 +7272,10 @@ opj_j2k_v2_t* j2k_create_decompress_v2() l_j2k->m_specific_param.m_decoder.m_header_data_size = J2K_DEFAULT_HEADER_SIZE; + l_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = -1 ; + + l_j2k->m_specific_param.m_decoder.m_last_sot_read_pos = 0 ; + /* codestream index creation */ l_j2k->cstr_index = j2k_create_cstr_index(); @@ -8161,6 +8177,133 @@ void j2k_setup_decoding (opj_j2k_v2_t *p_j2k) } +/* + * Read and decode one tile. + */ +opj_bool j2k_decode_one_tile ( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_event_mgr_t * p_manager) +{ + opj_bool l_go_on = OPJ_TRUE; + OPJ_UINT32 l_current_tile_no; + OPJ_UINT32 l_tile_no_to_dec; + OPJ_UINT32 l_data_size,l_max_data_size; + OPJ_INT32 l_tile_x0,l_tile_y0,l_tile_x1,l_tile_y1; + OPJ_UINT32 l_nb_comps; + OPJ_BYTE * l_current_data; + + l_current_data = (OPJ_BYTE*)opj_malloc(1000); + if (! l_current_data) { + return OPJ_FALSE; + } + l_max_data_size = 1000; + + /*Allocate and initialize some elements of codestrem index if not already done*/ + if( !p_j2k->cstr_index->tile_index) + { + if (!j2k_allocate_tile_element_cstr_index(p_j2k)) + return OPJ_FALSE; + } + + /* Move into the codestream to the first SOT used to decode the desired tile */ + l_tile_no_to_dec = p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec; + if (p_j2k->cstr_index->tile_index) + if(p_j2k->cstr_index->tile_index->tp_index) + { + if ( ! p_j2k->cstr_index->tile_index[l_tile_no_to_dec].nb_tps) { + /* not build the index for this tile, so we will move to the last SOT read*/ + if ( opj_stream_read_seek(p_stream, p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos+2, p_manager) ){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); + return OPJ_FALSE; + } + } + else{ + if (opj_stream_read_seek(p_stream, p_j2k->cstr_index->tile_index[l_tile_no_to_dec].tp_index[0].start_pos+2, p_manager)) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); + return OPJ_FALSE; + } + } + /* Special case if we have previously read the EOC marker (if the previous tile getted is the last ) */ + if(p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_EOC) + p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_TPHSOT; + } + + while (OPJ_TRUE) { + if (! j2k_read_tile_header( p_j2k, + &l_current_tile_no, + &l_data_size, + &l_tile_x0, &l_tile_y0, + &l_tile_x1, &l_tile_y1, + &l_nb_comps, + &l_go_on, + p_stream, + p_manager)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + + + if (! l_go_on) { + break; + } + + if (l_data_size > l_max_data_size) { + l_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_data_size); + if (! l_current_data) { + return OPJ_FALSE; + } + + l_max_data_size = l_data_size; + } + + + + if (! j2k_decode_tile(p_j2k,l_current_tile_no,l_current_data,l_data_size,p_stream,p_manager)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + opj_event_msg_v2(p_manager, EVT_INFO, "Tile %d/%d has been decode.\n", l_current_tile_no, (p_j2k->m_cp.th * p_j2k->m_cp.tw) - 1); + + if (! j2k_update_image_data(p_j2k->m_tcd,l_current_data, p_j2k->m_output_image)) { + opj_free(l_current_data); + return OPJ_FALSE; + } + opj_event_msg_v2(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no); + + if(l_current_tile_no == l_tile_no_to_dec) + { + /* move into the codestream to the the first SOT (FIXME or not move?)*/ + if (opj_stream_read_seek(p_stream, p_j2k->cstr_index->main_head_end + 2, p_manager) ) { + opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); + return OPJ_FALSE; + } + break; + } + else { + opj_event_msg_v2(p_manager, EVT_WARNING, "Tile read, decode and updated is not the desired (%d vs %d).\n", l_current_tile_no, l_tile_no_to_dec); + } + + } + + opj_free(l_current_data); + + return OPJ_TRUE; +} + + +/** + * Sets up the procedures to do on decoding one tile. Developpers wanting to extend the library can add their own reading procedures. + */ +void j2k_setup_decoding_tile (opj_j2k_v2_t *p_j2k) +{ + // preconditions + assert(p_j2k != 00); + + opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(void*)j2k_decode_one_tile); + /* DEVELOPER CORNER, add your custom procedures */ + +} + /** * Decodes the tiles of the stream. @@ -8200,3 +8343,98 @@ opj_bool j2k_decode_v2( opj_j2k_v2_t * p_j2k, return OPJ_TRUE; } + + +/** + * Get the decoded tile. + * + * @param p_j2k the jpeg2000 codestream 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 j2k_get_tile( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t* p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index ) +{ + OPJ_UINT32 compno; + OPJ_UINT32 l_tile_x, l_tile_y; + opj_image_comp_t* l_img_comp; + + if (!p_image) { + opj_event_msg_v2(p_manager, EVT_ERROR, "We need a image previously created.\n"); + return OPJ_FALSE; + } + + /* Compute the dimension of the desired tile*/ + l_tile_x = tile_index % p_j2k->m_cp.tw; + l_tile_y = tile_index / p_j2k->m_cp.tw; + + p_image->x0 = l_tile_x * p_j2k->m_cp.tdx + p_j2k->m_cp.tx0; + p_image->x1 = (l_tile_x + 1) * p_j2k->m_cp.tdx + p_j2k->m_cp.tx0; + p_image->y0 = l_tile_y * p_j2k->m_cp.tdy + p_j2k->m_cp.ty0; + p_image->y1 = (l_tile_y + 1) * p_j2k->m_cp.tdy + p_j2k->m_cp.ty0; + + l_img_comp = p_image->comps; + for (compno=0; compno < p_image->numcomps; ++compno) + { + OPJ_INT32 l_comp_x1, l_comp_y1; + + l_img_comp->x0 = int_ceildiv(p_image->x0, l_img_comp->dx); + l_img_comp->y0 = int_ceildiv(p_image->y0, l_img_comp->dy); + l_comp_x1 = int_ceildiv(p_image->x1, l_img_comp->dx); + l_comp_y1 = int_ceildiv(p_image->y1, l_img_comp->dy); + + l_img_comp->w = int_ceildivpow2(l_comp_x1 - l_img_comp->x0, l_img_comp->factor); + l_img_comp->h = int_ceildivpow2(l_comp_y1 - l_img_comp->y0, l_img_comp->factor); + + l_img_comp++; + } + + /* Destroy the previous output image*/ + if (p_j2k->m_output_image) + opj_image_destroy(p_j2k->m_output_image); + + /* Create the ouput image from the information previously computed*/ + p_j2k->m_output_image = opj_image_create0(); + if (! (p_j2k->m_output_image)) { + return OPJ_FALSE; + } + opj_copy_image_header(p_image, p_j2k->m_output_image); + + if ( (tile_index < 0) && (tile_index >= p_j2k->m_cp.tw * p_j2k->m_cp.th) ){ + opj_event_msg_v2(p_manager, EVT_ERROR, "Tile index provided by the user is incorrect %d (max = %d) \n", tile_index, (p_j2k->m_cp.tw * p_j2k->m_cp.th) - 1); + return OPJ_FALSE; + } + + p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = tile_index; + + /* customization of the decoding */ + j2k_setup_decoding_tile(p_j2k); + + /* Decode the codestream */ + if (! j2k_exec (p_j2k,p_j2k->m_procedure_list,p_stream,p_manager)) { + opj_image_destroy(p_j2k->m_private_image); + p_j2k->m_private_image = NULL; + return OPJ_FALSE; + } + + /* Move data and copy one information from codec to output image*/ + for (compno = 0; compno < p_image->numcomps; compno++) { + p_image->comps[compno].resno_decoded = p_j2k->m_output_image->comps[compno].resno_decoded; + + if (p_image->comps[compno].data) + opj_free(p_image->comps[compno].data); + + p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data; + + p_j2k->m_output_image->comps[compno].data = NULL; + } + + return OPJ_TRUE; +} diff --git a/libopenjpeg/j2k.h b/libopenjpeg/j2k.h index d5fd2bea..04a387b8 100644 --- a/libopenjpeg/j2k.h +++ b/libopenjpeg/j2k.h @@ -607,6 +607,12 @@ typedef struct opj_j2k_dec OPJ_UINT32 m_DA_y0; OPJ_UINT32 m_DA_x1; OPJ_UINT32 m_DA_y1; + + /** Index of the tile to decode (used in get_tile) */ + OPJ_INT32 m_tile_ind_to_dec; + /** Position of the last SOT marker read */ + OPJ_UINT32 m_last_sot_read_pos; + /** * Indicate that the current tile-part is assume as the last tile part of the codestream. * It is useful in the case of PSot is equal to zero. The sot length will be compute in the @@ -1009,4 +1015,11 @@ opj_codestream_index_t* j2k_get_cstr_index(opj_j2k_v2_t* p_j2k); opj_bool j2k_decode_v2(opj_j2k_v2_t *j2k, struct opj_stream_private *cio, opj_image_t* p_image, opj_event_mgr_t * p_manager); +opj_bool j2k_get_tile( opj_j2k_v2_t *p_j2k, + opj_stream_private_t *p_stream, + opj_image_t* p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index ); + + #endif /* __J2K_H */ diff --git a/libopenjpeg/jp2.c b/libopenjpeg/jp2.c index 322abc75..57f97070 100644 --- a/libopenjpeg/jp2.c +++ b/libopenjpeg/jp2.c @@ -2635,6 +2635,67 @@ opj_bool jp2_set_decode_area( opj_jp2_v2_t *p_jp2, 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 */ /* ----------------------------------------------------------------------- */ diff --git a/libopenjpeg/jp2.h b/libopenjpeg/jp2.h index 4d44aacb..ddd61e41 100644 --- a/libopenjpeg/jp2.h +++ b/libopenjpeg/jp2.h @@ -418,6 +418,12 @@ opj_bool jp2_set_decode_area( opj_jp2_v2_t *p_jp2, OPJ_INT32 p_end_x, OPJ_INT32 p_end_y, struct opj_event_mgr * p_manager ); +opj_bool jp2_get_tile( opj_jp2_v2_t *p_jp2, + opj_stream_private_t *p_stream, + opj_image_t* p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index ); + /** * Dump some elements from the JP2 decompression structure . diff --git a/libopenjpeg/openjpeg.c b/libopenjpeg/openjpeg.c index b1795f8f..aa77a5e1 100644 --- a/libopenjpeg/openjpeg.c +++ b/libopenjpeg/openjpeg.c @@ -78,6 +78,13 @@ typedef struct opj_decompression OPJ_INT32 p_start_x, OPJ_INT32 p_end_x, OPJ_INT32 p_start_y, OPJ_INT32 p_end_y, struct opj_event_mgr * p_manager); + + /** Get tile function */ + opj_bool (*opj_get_decoded_tile) ( void *p_codec, + opj_stream_private_t *p_cio, + opj_image_t *p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index); }opj_decompression_t; /** @@ -286,6 +293,12 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress_v2(OPJ_CODEC_FORMAT p_format) l_info->m_codec_data.m_decompression.opj_set_decode_area = (opj_bool (*) (void *, opj_image_t*, OPJ_INT32, OPJ_INT32, OPJ_INT32, OPJ_INT32, struct opj_event_mgr *)) j2k_set_decode_area; + l_info->m_codec_data.m_decompression.opj_get_decoded_tile = (opj_bool (*) ( void *p_codec, + opj_stream_private_t *p_cio, + opj_image_t *p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index)) j2k_get_tile; + l_info->m_codec = j2k_create_decompress_v2(); if (! l_info->m_codec) { @@ -338,6 +351,12 @@ opj_codec_t* OPJ_CALLCONV opj_create_decompress_v2(OPJ_CODEC_FORMAT p_format) l_info->m_codec_data.m_decompression.opj_set_decode_area = (opj_bool (*) (void *,opj_image_t*, OPJ_INT32,OPJ_INT32,OPJ_INT32,OPJ_INT32, struct opj_event_mgr * )) jp2_set_decode_area; + l_info->m_codec_data.m_decompression.opj_get_decoded_tile = (opj_bool (*) ( void *p_codec, + opj_stream_private_t *p_cio, + opj_image_t *p_image, + struct opj_event_mgr * p_manager, + OPJ_UINT32 tile_index)) jp2_get_tile; + l_info->m_codec = jp2_create(OPJ_TRUE); if (! l_info->m_codec) { @@ -937,6 +956,10 @@ opj_bool OPJ_CALLCONV opj_decode_v2(opj_codec_t *p_info, return OPJ_FALSE; } +/* + * + * + */ opj_bool OPJ_CALLCONV opj_end_decompress (opj_codec_t *p_codec,opj_stream_t *p_cio) { if (p_codec && p_cio) { @@ -953,3 +976,29 @@ opj_bool OPJ_CALLCONV opj_end_decompress (opj_codec_t *p_codec,opj_stream_t *p_c return OPJ_FALSE; } + +/* + * + * + */ +opj_bool OPJ_CALLCONV opj_get_decoded_tile( opj_codec_t *p_codec, + opj_stream_t *p_cio, + opj_image_t *p_image, + OPJ_UINT32 tile_index) +{ + if (p_codec && p_cio) { + opj_codec_private_t * l_codec = (opj_codec_private_t *) p_codec; + opj_stream_private_t * l_stream = (opj_stream_private_t *) p_cio; + + if (! l_codec->is_decompressor) { + return OPJ_FALSE; + } + return l_codec->m_codec_data.m_decompression.opj_get_decoded_tile( l_codec->m_codec, + l_stream, + p_image, + l_codec->m_event_mgr, + tile_index); + } + + return OPJ_FALSE; +} diff --git a/libopenjpeg/openjpeg.h b/libopenjpeg/openjpeg.h index 0ac208f1..3c82498c 100644 --- a/libopenjpeg/openjpeg.h +++ b/libopenjpeg/openjpeg.h @@ -1270,6 +1270,19 @@ OPJ_API opj_bool OPJ_CALLCONV opj_decode_v2(opj_codec_t *p_decompressor, opj_image_t *p_image); +/** + * Get the decoded tile from the codec + * @param p_codec the jpeg2000 codec. + * @param p_cio input streamm + * @param p_image output image + * @param tile_index index of the tile which will be decode + * + * @return a pointer to a JP2 index structure. + */ +OPJ_API opj_bool OPJ_CALLCONV opj_get_decoded_tile( opj_codec_t *p_codec, + opj_stream_t *p_cio, + opj_image_t *p_image, + OPJ_UINT32 tile_index); /** * Reads a tile header. This function is compulsory and allows one to know the size of the tile thta will be decoded. @@ -1477,6 +1490,8 @@ OPJ_API opj_jp2_index_t* OPJ_CALLCONV opj_get_jp2_index(opj_codec_t *p_codec); + + #ifdef __cplusplus } #endif