* Copyright (c) 2010-2011, Kaori Hagihara
* Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
* Copyright (c) 2012, CS Systemes d'Information, France
+ * Copyright (c) 2017, IntoPIX SA <support@intopix.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
opj_event_mgr_t * p_manager);
/**
- * Creates a tile-coder decoder.
+ * Creates a tile-coder encoder.
*
* @param p_stream the stream to write data to.
* @param p_j2k J2K codec.
* Writes the SOT marker (Start of tile-part)
*
* @param p_j2k J2K codec.
- * @param p_data FIXME DOC
- * @param p_data_written FIXME DOC
+ * @param p_data Output buffer
+ * @param p_total_data_size Output buffer size
+ * @param p_data_written Number of bytes written into stream
* @param p_stream the stream to write data to.
* @param p_manager the user event manager.
*/
static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
+ OPJ_UINT32 p_total_data_size,
OPJ_UINT32 * p_data_written,
const opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager);
char str_prog[5];
} j2k_prog_order_t;
-static j2k_prog_order_t j2k_prog_order_list[] = {
+static const j2k_prog_order_t j2k_prog_order_list[] = {
{OPJ_CPRL, "CPRL"},
{OPJ_LRCP, "LRCP"},
{OPJ_PCRL, "PCRL"},
}
}
-char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order)
+const char *opj_j2k_convert_progression_order(OPJ_PROG_ORDER prg_order)
{
- j2k_prog_order_t *po;
+ const j2k_prog_order_t *po;
for (po = j2k_prog_order_list; po->enum_prog != -1; po++) {
if (po->enum_prog == prg_order) {
return po->str_prog;
OPJ_UINT32 l_remaining_size;
OPJ_UINT32 l_nb_tiles;
OPJ_UINT32 l_tmp, l_tx1, l_ty1;
+ OPJ_UINT32 l_prec0, l_sgnd0;
opj_image_t *l_image = 00;
opj_cp_t *l_cp = 00;
opj_image_comp_t * l_img_comp = 00;
"Error with SIZ marker: illegal tile offset\n");
return OPJ_FALSE;
}
+ if (!p_j2k->dump_state) {
+ OPJ_UINT32 siz_w, siz_h;
+
+ siz_w = l_image->x1 - l_image->x0;
+ siz_h = l_image->y1 - l_image->y0;
+ if (p_j2k->ihdr_w > 0 && p_j2k->ihdr_h > 0
+ && (p_j2k->ihdr_w != siz_w || p_j2k->ihdr_h != siz_h)) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Error with SIZ marker: IHDR w(%u) h(%u) vs. SIZ w(%u) h(%u)\n", p_j2k->ihdr_w,
+ p_j2k->ihdr_h, siz_w, siz_h);
+ return OPJ_FALSE;
+ }
+ }
#ifdef USE_JPWL
if (l_cp->correct) {
/* if JPWL is on, we check whether TX errors have damaged
l_img_comp = l_image->comps;
+ l_prec0 = 0;
+ l_sgnd0 = 0;
/* Read the component information */
for (i = 0; i < l_image->numcomps; ++i) {
OPJ_UINT32 tmp;
++p_header_data;
l_img_comp->prec = (tmp & 0x7f) + 1;
l_img_comp->sgnd = tmp >> 7;
+
+ if (p_j2k->dump_state == 0) {
+ if (i == 0) {
+ l_prec0 = l_img_comp->prec;
+ l_sgnd0 = l_img_comp->sgnd;
+ } else if (!l_cp->allow_different_bit_depth_sign
+ && (l_img_comp->prec != l_prec0 || l_img_comp->sgnd != l_sgnd0)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "Despite JP2 BPC!=255, precision and/or sgnd values for comp[%d] is different than comp[0]:\n"
+ " [0] prec(%d) sgnd(%d) [%d] prec(%d) sgnd(%d)\n", i, l_prec0, l_sgnd0,
+ i, l_img_comp->prec, l_img_comp->sgnd);
+ }
+ /* TODO: we should perhaps also check against JP2 BPCC values */
+ }
opj_read_bytes(p_header_data, &tmp, 1); /* XRsiz_i */
++p_header_data;
l_img_comp->dx = (OPJ_UINT32)tmp; /* should be between 1 and 255 */
i, l_img_comp->prec);
return OPJ_FALSE;
}
-
#ifdef USE_JPWL
if (l_cp->correct) {
/* if JPWL is on, we check whether TX errors have damaged
++l_img_comp;
}
+ if (l_cp->tdx == 0 || l_cp->tdy == 0) {
+ return OPJ_FALSE;
+ }
+
/* Compute the number of tiles */
l_cp->tw = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)(l_image->x1 - l_cp->tx0),
(OPJ_INT32)l_cp->tdx);
++l_current_tile_param;
}
- p_j2k->m_specific_param.m_decoder.m_state =
- J2K_STATE_MH; /* FIXME J2K_DEC_STATE_MH; */
+ p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MH;
opj_image_comp_header_update(l_image, l_cp);
return OPJ_TRUE;
l_cp = &(p_j2k->m_cp);
l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH)
- ? /*FIXME J2K_DEC_STATE_TPH*/
+ ?
&l_cp->tcps[p_j2k->m_current_tile_number] :
p_j2k->m_specific_param.m_decoder.m_default_tcp;
l_image = p_j2k->m_private_image;
static OPJ_BOOL opj_j2k_write_sot(opj_j2k_t *p_j2k,
OPJ_BYTE * p_data,
+ OPJ_UINT32 p_total_data_size,
OPJ_UINT32 * p_data_written,
const opj_stream_private_t *p_stream,
opj_event_mgr_t * p_manager
assert(p_stream != 00);
OPJ_UNUSED(p_stream);
- OPJ_UNUSED(p_manager);
+
+ if (p_total_data_size < 12) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Not enough bytes in output buffer to write SOT marker\n");
+ return OPJ_FALSE;
+ }
opj_write_bytes(p_data, J2K_MS_SOT,
2); /* SOT */
p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
}
+ if (l_tcp->m_nb_tile_parts != 0 && l_current_part >= l_tcp->m_nb_tile_parts) {
+ /* Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2851 */
+ opj_event_msg(p_manager, EVT_ERROR,
+ "In SOT marker, TPSot (%d) is not valid regards to the previous "
+ "number of tile-part (%d), giving up\n", l_current_part,
+ l_tcp->m_nb_tile_parts);
+ p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
+ return OPJ_FALSE;
+ }
+
if (l_num_parts !=
0) { /* Number of tile-part header is provided by this tile-part header */
l_num_parts += p_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction;
OPJ_UNUSED(p_stream);
+ if (p_total_data_size < 4) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Not enough bytes in output buffer to write SOD marker\n");
+ return OPJ_FALSE;
+ }
+
opj_write_bytes(p_data, J2K_MS_SOD,
2); /* SOD */
p_data += 2;
*p_data_written = 0;
if (! opj_tcd_encode_tile(p_tile_coder, p_j2k->m_current_tile_number, p_data,
- p_data_written, l_remaining_data, l_cstr_info)) {
+ p_data_written, l_remaining_data, l_cstr_info,
+ p_manager)) {
opj_event_msg(p_manager, EVT_ERROR, "Cannot encode tile\n");
return OPJ_FALSE;
}
"Tile part length size inconsistent with stream length\n");
return OPJ_FALSE;
}
+ if (p_j2k->m_specific_param.m_decoder.m_sot_length >
+ UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "p_j2k->m_specific_param.m_decoder.m_sot_length > "
+ "UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA");
+ return OPJ_FALSE;
+ }
+ /* Add a margin of OPJ_COMMON_CBLK_DATA_EXTRA to the allocation we */
+ /* do so that opj_mqc_init_dec_common() can safely add a synthetic */
+ /* 0xFFFF marker. */
if (! *l_current_data) {
/* LH: oddly enough, in this path, l_tile_len!=0.
* TODO: If this was consistent, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...).
*/
*l_current_data = (OPJ_BYTE*) opj_malloc(
- p_j2k->m_specific_param.m_decoder.m_sot_length);
+ p_j2k->m_specific_param.m_decoder.m_sot_length + OPJ_COMMON_CBLK_DATA_EXTRA);
} else {
- OPJ_BYTE *l_new_current_data = (OPJ_BYTE *) opj_realloc(*l_current_data,
- *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length);
+ OPJ_BYTE *l_new_current_data;
+ if (*l_tile_len > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA -
+ p_j2k->m_specific_param.m_decoder.m_sot_length) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "*l_tile_len > UINT_MAX - OPJ_COMMON_CBLK_DATA_EXTRA - "
+ "p_j2k->m_specific_param.m_decoder.m_sot_length");
+ return OPJ_FALSE;
+ }
+
+ l_new_current_data = (OPJ_BYTE *) opj_realloc(*l_current_data,
+ *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length +
+ OPJ_COMMON_CBLK_DATA_EXTRA);
if (! l_new_current_data) {
opj_free(*l_current_data);
/*nothing more is done as l_current_data will be set to null, and just
++l_img_comp;
}
- l_tile_size = (OPJ_UINT32)(l_tile_size * 0.1625); /* 1.3/8 = 0.1625 */
+ /* TODO: where does this magic value come from ? */
+ /* This used to be 1.3 / 8, but with random data and very small code */
+ /* block sizes, this is not enough. For example with */
+ /* bin/test_tile_encoder 1 256 256 32 32 8 0 reversible_with_precinct.j2k 4 4 3 0 0 1 16 16 */
+ /* TODO revise this to take into account the overhead linked to the */
+ /* number of packets and number of code blocks in packets */
+ l_tile_size = (OPJ_UINT32)(l_tile_size * 1.4 / 8);
+
+ /* Arbitrary amount to make the following work: */
+ /* bin/test_tile_encoder 1 256 256 17 16 8 0 reversible_no_precinct.j2k 4 4 3 0 0 1 */
+ l_tile_size += 500;
l_tile_size += opj_j2k_get_specific_header_sizes(p_j2k);
j2k->m_cp.m_specific_param.m_dec.m_layer = parameters->cp_layer;
j2k->m_cp.m_specific_param.m_dec.m_reduce = parameters->cp_reduce;
+ j2k->dump_state = (parameters->flags & OPJ_DPARAMETERS_DUMP_FLAG);
#ifdef USE_JPWL
j2k->m_cp.correct = parameters->jpwl_correct;
j2k->m_cp.exp_comps = parameters->jpwl_exp_comps;
/* Precincts */
parameters->csty |= 0x01;
- parameters->res_spec = parameters->numresolution - 1;
- for (i = 0; i < parameters->res_spec; i++) {
- parameters->prcw_init[i] = 256;
- parameters->prch_init[i] = 256;
+ if (parameters->numresolution == 1) {
+ parameters->res_spec = 1;
+ parameters->prcw_init[0] = 128;
+ parameters->prch_init[0] = 128;
+ } else {
+ parameters->res_spec = parameters->numresolution - 1;
+ for (i = 0; i < parameters->res_spec; i++) {
+ parameters->prcw_init[i] = 256;
+ parameters->prch_init[i] = 256;
+ }
}
/* The progression order shall be CPRL */
}
}
+ /* If no explicit layers are provided, use lossless settings */
+ if (parameters->tcp_numlayers == 0) {
+ parameters->tcp_numlayers = 1;
+ parameters->cp_disto_alloc = 1;
+ parameters->tcp_rates[0] = 0;
+ }
+
+ if (parameters->cp_disto_alloc) {
+ /* Emit warnings if tcp_rates are not decreasing */
+ for (i = 1; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
+ OPJ_FLOAT32 rate_i_corr = parameters->tcp_rates[i];
+ OPJ_FLOAT32 rate_i_m_1_corr = parameters->tcp_rates[i - 1];
+ if (rate_i_corr <= 1.0) {
+ rate_i_corr = 1.0;
+ }
+ if (rate_i_m_1_corr <= 1.0) {
+ rate_i_m_1_corr = 1.0;
+ }
+ if (rate_i_corr >= rate_i_m_1_corr) {
+ if (rate_i_corr != parameters->tcp_rates[i] &&
+ rate_i_m_1_corr != parameters->tcp_rates[i - 1]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f (corrected as %f) should be strictly lesser "
+ "than tcp_rates[%d]=%f (corrected as %f)\n",
+ i, parameters->tcp_rates[i], rate_i_corr,
+ i - 1, parameters->tcp_rates[i - 1], rate_i_m_1_corr);
+ } else if (rate_i_corr != parameters->tcp_rates[i]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f (corrected as %f) should be strictly lesser "
+ "than tcp_rates[%d]=%f\n",
+ i, parameters->tcp_rates[i], rate_i_corr,
+ i - 1, parameters->tcp_rates[i - 1]);
+ } else if (rate_i_m_1_corr != parameters->tcp_rates[i - 1]) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f should be strictly lesser "
+ "than tcp_rates[%d]=%f (corrected as %f)\n",
+ i, parameters->tcp_rates[i],
+ i - 1, parameters->tcp_rates[i - 1], rate_i_m_1_corr);
+ } else {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_rates[%d]=%f should be strictly lesser "
+ "than tcp_rates[%d]=%f\n",
+ i, parameters->tcp_rates[i],
+ i - 1, parameters->tcp_rates[i - 1]);
+ }
+ }
+ }
+ } else if (parameters->cp_fixed_quality) {
+ /* Emit warnings if tcp_distoratio are not increasing */
+ for (i = 1; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
+ if (parameters->tcp_distoratio[i] < parameters->tcp_distoratio[i - 1] &&
+ !(i == (OPJ_UINT32)parameters->tcp_numlayers - 1 &&
+ parameters->tcp_distoratio[i] == 0)) {
+ opj_event_msg(p_manager, EVT_WARNING,
+ "tcp_distoratio[%d]=%f should be strictly greater "
+ "than tcp_distoratio[%d]=%f\n",
+ i, parameters->tcp_distoratio[i], i - 1,
+ parameters->tcp_distoratio[i - 1]);
+ }
+ }
+ }
+
/* see if max_codestream_size does limit input rate */
if (parameters->max_cs_size <= 0) {
if (parameters->tcp_rates[parameters->tcp_numlayers - 1] > 0) {
OPJ_FLOAT32 temp_size;
- temp_size = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w *
- image->comps[0].h * image->comps[0].prec) /
- (parameters->tcp_rates[parameters->tcp_numlayers - 1] * 8 *
- (OPJ_FLOAT32)image->comps[0].dx * (OPJ_FLOAT32)image->comps[0].dy);
- parameters->max_cs_size = (int) floor(temp_size);
+ temp_size = (OPJ_FLOAT32)(((double)image->numcomps * image->comps[0].w *
+ image->comps[0].h * image->comps[0].prec) /
+ ((double)parameters->tcp_rates[parameters->tcp_numlayers - 1] * 8 *
+ image->comps[0].dx * image->comps[0].dy));
+ if (temp_size > INT_MAX) {
+ parameters->max_cs_size = INT_MAX;
+ } else {
+ parameters->max_cs_size = (int) floor(temp_size);
+ }
} else {
parameters->max_cs_size = 0;
}
} else {
OPJ_FLOAT32 temp_rate;
OPJ_BOOL cap = OPJ_FALSE;
- temp_rate = (OPJ_FLOAT32)(image->numcomps * image->comps[0].w *
- image->comps[0].h * image->comps[0].prec) /
- (OPJ_FLOAT32)(((OPJ_UINT32)parameters->max_cs_size) * 8 * image->comps[0].dx *
- image->comps[0].dy);
+ temp_rate = (OPJ_FLOAT32)(((double)image->numcomps * image->comps[0].w *
+ image->comps[0].h * image->comps[0].prec) /
+ (((double)parameters->max_cs_size) * 8 * image->comps[0].dx *
+ image->comps[0].dy));
for (i = 0; i < (OPJ_UINT32) parameters->tcp_numlayers; i++) {
if (parameters->tcp_rates[i] < temp_rate) {
parameters->tcp_rates[i] = temp_rate;
tcp->rates[j] = parameters->tcp_rates[j];
}
}
+ if (!cp->m_specific_param.m_enc.m_fixed_quality &&
+ tcp->rates[j] <= 1.0) {
+ tcp->rates[j] = 0.0; /* force lossless */
+ }
}
tcp->csty = (OPJ_UINT32)parameters->csty;
}
/* Create the current tile decoder*/
- p_j2k->m_tcd = (opj_tcd_t*)opj_tcd_create(OPJ_TRUE); /* FIXME why a cast ? */
+ p_j2k->m_tcd = opj_tcd_create(OPJ_TRUE);
if (! p_j2k->m_tcd) {
return OPJ_FALSE;
}
*p_tile_y1 = p_j2k->m_tcd->tcd_image->tiles->y1;
*p_nb_comps = p_j2k->m_tcd->tcd_image->tiles->numcomps;
- p_j2k->m_specific_param.m_decoder.m_state |=
- 0x0080;/* FIXME J2K_DEC_STATE_DATA;*/
+ p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_DATA;
return OPJ_TRUE;
}
OPJ_UINT32 l_current_marker;
OPJ_BYTE l_data [2];
opj_tcp_t * l_tcp;
+ opj_image_t* l_image_for_bounds;
/* preconditions */
assert(p_stream != 00);
assert(p_j2k != 00);
assert(p_manager != 00);
- if (!(p_j2k->m_specific_param.m_decoder.m_state &
- 0x0080/*FIXME J2K_DEC_STATE_DATA*/)
+ if (!(p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_DATA)
|| (p_tile_index != p_j2k->m_current_tile_number)) {
return OPJ_FALSE;
}
return OPJ_FALSE;
}
+ /* When using the opj_read_tile_header / opj_decode_tile_data API */
+ /* such as in test_tile_decoder, m_output_image is NULL, so fall back */
+ /* to the full image dimension. This is a bit surprising that */
+ /* opj_set_decode_area() is only used to determinte intersecting tiles, */
+ /* but full tile decoding is done */
+ l_image_for_bounds = p_j2k->m_output_image ? p_j2k->m_output_image :
+ p_j2k->m_private_image;
if (! opj_tcd_decode_tile(p_j2k->m_tcd,
+ l_image_for_bounds->x0,
+ l_image_for_bounds->y0,
+ l_image_for_bounds->x1,
+ l_image_for_bounds->y1,
l_tcp->m_data,
l_tcp->m_data_size,
p_tile_index,
p_j2k->cstr_index, p_manager)) {
opj_j2k_tcp_destroy(l_tcp);
- p_j2k->m_specific_param.m_decoder.m_state |= 0x8000;/*FIXME J2K_DEC_STATE_ERR;*/
+ p_j2k->m_specific_param.m_decoder.m_state |= J2K_STATE_ERR;
opj_event_msg(p_manager, EVT_ERROR, "Failed to decode.\n");
return OPJ_FALSE;
}
- if (! opj_tcd_update_tile_data(p_j2k->m_tcd, p_data, p_data_size)) {
- return OPJ_FALSE;
- }
+ /* p_data can be set to NULL when the call will take care of using */
+ /* itself the TCD data. This is typically the case for whole single */
+ /* tile decoding optimization. */
+ if (p_data != NULL) {
+ if (! opj_tcd_update_tile_data(p_j2k->m_tcd, p_data, p_data_size)) {
+ return OPJ_FALSE;
+ }
- /* To avoid to destroy the tcp which can be useful when we try to decode a tile decoded before (cf j2k_random_tile_access)
- * we destroy just the data which will be re-read in read_tile_header*/
- /*opj_j2k_tcp_destroy(l_tcp);
- p_j2k->m_tcd->tcp = 0;*/
- opj_j2k_tcp_data_destroy(l_tcp);
+ /* To avoid to destroy the tcp which can be useful when we try to decode a tile decoded before (cf j2k_random_tile_access)
+ * we destroy just the data which will be re-read in read_tile_header*/
+ /*opj_j2k_tcp_destroy(l_tcp);
+ p_j2k->m_tcd->tcp = 0;*/
+ opj_j2k_tcp_data_destroy(l_tcp);
+ }
p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
- p_j2k->m_specific_param.m_decoder.m_state &= (~
- (0x0080u)); /* FIXME J2K_DEC_STATE_DATA);*/
+ p_j2k->m_specific_param.m_decoder.m_state &= (~(OPJ_UINT32)J2K_STATE_DATA);
if (opj_stream_get_number_byte_left(p_stream) == 0
&& p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NEOC) {
return OPJ_TRUE;
}
- if (p_j2k->m_specific_param.m_decoder.m_state !=
- 0x0100) { /*FIXME J2K_DEC_STATE_EOC)*/
+ if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_EOC) {
if (opj_stream_read_data(p_stream, l_data, 2, p_manager) != 2) {
opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
return OPJ_FALSE;
if (l_current_marker == J2K_MS_EOC) {
p_j2k->m_current_tile_number = 0;
- p_j2k->m_specific_param.m_decoder.m_state = 0x0100;/*FIXME J2K_DEC_STATE_EOC;*/
+ p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_EOC;
} else if (l_current_marker != J2K_MS_SOT) {
if (opj_stream_get_number_byte_left(p_stream) == 0) {
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
OPJ_SIZE_T l_width = l_img_comp_dest->w;
OPJ_SIZE_T l_height = l_img_comp_dest->h;
- if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height))) {
+ if ((l_height == 0U) || (l_width > (SIZE_MAX / l_height)) ||
+ l_width * l_height > SIZE_MAX / sizeof(OPJ_INT32)) {
/* would overflow */
return OPJ_FALSE;
}
- l_img_comp_dest->data = (OPJ_INT32*) opj_calloc(l_width * l_height,
+ l_img_comp_dest->data = (OPJ_INT32*) opj_image_data_alloc(l_width * l_height *
sizeof(OPJ_INT32));
if (! l_img_comp_dest->data) {
return OPJ_FALSE;
}
+ /* Do we really need this memset ? */
+ memset(l_img_comp_dest->data, 0, l_width * l_height * sizeof(OPJ_INT32));
}
/* Copy info from decoded comp image to output image */
return OPJ_TRUE;
}
+static OPJ_BOOL opj_j2k_update_image_dimensions(opj_image_t* p_image,
+ opj_event_mgr_t * p_manager)
+{
+ OPJ_UINT32 it_comp;
+ OPJ_INT32 l_comp_x1, l_comp_y1;
+ opj_image_comp_t* l_img_comp = NULL;
+
+ l_img_comp = p_image->comps;
+ for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) {
+ OPJ_INT32 l_h, l_w;
+
+ l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0,
+ (OPJ_INT32)l_img_comp->dx);
+ l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0,
+ (OPJ_INT32)l_img_comp->dy);
+ l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx);
+ l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy);
+
+ l_w = opj_int_ceildivpow2(l_comp_x1, (OPJ_INT32)l_img_comp->factor)
+ - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->x0, (OPJ_INT32)l_img_comp->factor);
+ if (l_w < 0) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Size x of the decoded component image is incorrect (comp[%d].w=%d).\n",
+ it_comp, l_w);
+ return OPJ_FALSE;
+ }
+ l_img_comp->w = (OPJ_UINT32)l_w;
+
+ l_h = opj_int_ceildivpow2(l_comp_y1, (OPJ_INT32)l_img_comp->factor)
+ - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->y0, (OPJ_INT32)l_img_comp->factor);
+ if (l_h < 0) {
+ opj_event_msg(p_manager, EVT_ERROR,
+ "Size y of the decoded component image is incorrect (comp[%d].h=%d).\n",
+ it_comp, l_h);
+ return OPJ_FALSE;
+ }
+ l_img_comp->h = (OPJ_UINT32)l_h;
+
+ l_img_comp++;
+ }
+
+ return OPJ_TRUE;
+}
+
+
OPJ_BOOL opj_j2k_set_decode_area(opj_j2k_t *p_j2k,
opj_image_t* p_image,
OPJ_INT32 p_start_x, OPJ_INT32 p_start_y,
{
opj_cp_t * l_cp = &(p_j2k->m_cp);
opj_image_t * l_image = p_j2k->m_private_image;
-
+ OPJ_BOOL ret;
OPJ_UINT32 it_comp;
- OPJ_INT32 l_comp_x1, l_comp_y1;
- opj_image_comp_t* l_img_comp = NULL;
/* Check if we are read the main header */
- if (p_j2k->m_specific_param.m_decoder.m_state !=
- J2K_STATE_TPHSOT) { /* FIXME J2K_DEC_STATE_TPHSOT)*/
+ if (p_j2k->m_specific_param.m_decoder.m_state != J2K_STATE_TPHSOT) {
opj_event_msg(p_manager, EVT_ERROR,
"Need to decode the main header before begin to decode the remaining codestream");
return OPJ_FALSE;
}
+ /* Update the comps[].factor member of the output image with the one */
+ /* of m_reduce */
+ for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) {
+ p_image->comps[it_comp].factor = p_j2k->m_cp.m_specific_param.m_dec.m_reduce;
+ }
+
if (!p_start_x && !p_start_y && !p_end_x && !p_end_y) {
opj_event_msg(p_manager, EVT_INFO,
"No decoded area parameters, set the decoded area to the whole image\n");
p_j2k->m_specific_param.m_decoder.m_end_tile_x = l_cp->tw;
p_j2k->m_specific_param.m_decoder.m_end_tile_y = l_cp->th;
- return OPJ_TRUE;
+ p_image->x0 = l_image->x0;
+ p_image->y0 = l_image->y0;
+ p_image->x1 = l_image->x1;
+ p_image->y1 = l_image->y1;
+
+ return opj_j2k_update_image_dimensions(p_image, p_manager);
}
/* ----- */
p_j2k->m_specific_param.m_decoder.m_discard_tiles = 1;
- l_img_comp = p_image->comps;
- for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) {
- OPJ_INT32 l_h, l_w;
-
- l_img_comp->x0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->x0,
- (OPJ_INT32)l_img_comp->dx);
- l_img_comp->y0 = (OPJ_UINT32)opj_int_ceildiv((OPJ_INT32)p_image->y0,
- (OPJ_INT32)l_img_comp->dy);
- l_comp_x1 = opj_int_ceildiv((OPJ_INT32)p_image->x1, (OPJ_INT32)l_img_comp->dx);
- l_comp_y1 = opj_int_ceildiv((OPJ_INT32)p_image->y1, (OPJ_INT32)l_img_comp->dy);
-
- l_w = opj_int_ceildivpow2(l_comp_x1, (OPJ_INT32)l_img_comp->factor)
- - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->x0, (OPJ_INT32)l_img_comp->factor);
- if (l_w < 0) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Size x of the decoded component image is incorrect (comp[%d].w=%d).\n",
- it_comp, l_w);
- return OPJ_FALSE;
- }
- l_img_comp->w = (OPJ_UINT32)l_w;
+ ret = opj_j2k_update_image_dimensions(p_image, p_manager);
- l_h = opj_int_ceildivpow2(l_comp_y1, (OPJ_INT32)l_img_comp->factor)
- - opj_int_ceildivpow2((OPJ_INT32)l_img_comp->y0, (OPJ_INT32)l_img_comp->factor);
- if (l_h < 0) {
- opj_event_msg(p_manager, EVT_ERROR,
- "Size y of the decoded component image is incorrect (comp[%d].h=%d).\n",
- it_comp, l_h);
- return OPJ_FALSE;
- }
- l_img_comp->h = (OPJ_UINT32)l_h;
-
- l_img_comp++;
+ if (ret) {
+ opj_event_msg(p_manager, EVT_INFO, "Setting decoding area to %d,%d,%d,%d\n",
+ p_image->x0, p_image->y0, p_image->x1, p_image->y1);
}
- opj_event_msg(p_manager, EVT_INFO, "Setting decoding area to %d,%d,%d,%d\n",
- p_image->x0, p_image->y0, p_image->x1, p_image->y1);
-
- return OPJ_TRUE;
+ return ret;
}
opj_j2k_t* opj_j2k_create_decompress(void)
l_j2k->m_is_decoder = 1;
l_j2k->m_cp.m_is_decoder = 1;
+ /* in the absence of JP2 boxes, consider different bit depth / sign */
+ /* per component is allowed */
+ l_j2k->m_cp.allow_different_bit_depth_sign = 1;
#ifdef OPJ_DISABLE_TPSOT_FIX
l_j2k->m_specific_param.m_decoder.m_nb_tile_parts_correction_checked = 1;
l_cp = &(p_j2k->m_cp);
l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH)
- ? /* FIXME J2K_DEC_STATE_TPH*/
+ ?
&l_cp->tcps[p_j2k->m_current_tile_number] :
p_j2k->m_specific_param.m_decoder.m_default_tcp;
l_cp = &(p_j2k->m_cp);
/* come from tile part header or main header ?*/
l_tcp = (p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH)
- ? /*FIXME J2K_DEC_STATE_TPH*/
+ ?
&l_cp->tcps[p_j2k->m_current_tile_number] :
p_j2k->m_specific_param.m_decoder.m_default_tcp;
OPJ_BYTE * l_current_data;
OPJ_UINT32 nr_tiles = 0;
+ /* Particular case for whole single tile decoding */
+ /* We can avoid allocating intermediate tile buffers */
+ if (p_j2k->m_cp.tw == 1 && p_j2k->m_cp.th == 1 &&
+ p_j2k->m_cp.tx0 == 0 && p_j2k->m_cp.ty0 == 0 &&
+ p_j2k->m_output_image->x0 == 0 &&
+ p_j2k->m_output_image->y0 == 0 &&
+ p_j2k->m_output_image->x1 == p_j2k->m_cp.tdx &&
+ p_j2k->m_output_image->y1 == p_j2k->m_cp.tdy &&
+ p_j2k->m_output_image->comps[0].factor == 0) {
+ OPJ_UINT32 i;
+ if (! opj_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)) {
+ return OPJ_FALSE;
+ }
+
+ if (! opj_j2k_decode_tile(p_j2k, l_current_tile_no, NULL, 0,
+ p_stream, p_manager)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Failed to decode tile 1/1\n");
+ return OPJ_FALSE;
+ }
+
+ /* Transfer TCD data to output image data */
+ for (i = 0; i < p_j2k->m_output_image->numcomps; i++) {
+ opj_image_data_free(p_j2k->m_output_image->comps[i].data);
+ p_j2k->m_output_image->comps[i].data =
+ p_j2k->m_tcd->tcd_image->tiles->comps[i].data;
+ p_j2k->m_output_image->comps[i].resno_decoded =
+ p_j2k->m_tcd->image->comps[i].resno_decoded;
+ p_j2k->m_tcd->tcd_image->tiles->comps[i].data = NULL;
+ }
+
+ return OPJ_TRUE;
+ }
+
l_current_data = (OPJ_BYTE*)opj_malloc(1000);
if (! l_current_data) {
opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to decode tiles\n");
return OPJ_FALSE;
}
+ /* Heuristics to detect sequence opj_read_header(), opj_set_decoded_resolution_factor() */
+ /* and finally opj_decode_image() without manual setting of comps[].factor */
+ /* We could potentially always execute it, if we don't allow people to do */
+ /* opj_read_header(), modify x0,y0,x1,y1 of returned image an call opj_decode_image() */
+ if (p_j2k->m_cp.m_specific_param.m_dec.m_reduce > 0 &&
+ p_j2k->m_private_image != NULL &&
+ p_j2k->m_private_image->numcomps > 0 &&
+ p_j2k->m_private_image->comps[0].factor ==
+ p_j2k->m_cp.m_specific_param.m_dec.m_reduce &&
+ p_image->numcomps > 0 &&
+ p_image->comps[0].factor == 0 &&
+ /* Don't mess with image dimension if the user has allocated it */
+ p_image->comps[0].data == NULL) {
+ OPJ_UINT32 it_comp;
+
+ /* Update the comps[].factor member of the output image with the one */
+ /* of m_reduce */
+ for (it_comp = 0; it_comp < p_image->numcomps; ++it_comp) {
+ p_image->comps[it_comp].factor = p_j2k->m_cp.m_specific_param.m_dec.m_reduce;
+ }
+ if (!opj_j2k_update_image_dimensions(p_image, p_manager)) {
+ return OPJ_FALSE;
+ }
+ }
+
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);
/* customization of the decoding */
- opj_j2k_setup_decoding(p_j2k, p_manager);
+ if (!opj_j2k_setup_decoding(p_j2k, p_manager)) {
+ return OPJ_FALSE;
+ }
/* Decode the codestream */
if (! opj_j2k_exec(p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) {
p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec = (OPJ_INT32)tile_index;
/* customization of the decoding */
- opj_j2k_setup_decoding_tile(p_j2k, p_manager);
+ if (!opj_j2k_setup_decoding_tile(p_j2k, p_manager)) {
+ return OPJ_FALSE;
+ }
/* Decode the codestream */
if (! opj_j2k_exec(p_j2k, p_j2k->m_procedure_list, p_stream, p_manager)) {
p_j2k->m_output_image->comps[compno].resno_decoded;
if (p_image->comps[compno].data) {
- opj_free(p_image->comps[compno].data);
+ opj_image_data_free(p_image->comps[compno].data);
}
p_image->comps[compno].data = p_j2k->m_output_image->comps[compno].data;
l_current_nb_bytes_written = 0;
l_begin_data = p_data;
- if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream,
+ if (! opj_j2k_write_sot(p_j2k, p_data, p_total_data_size,
+ &l_current_nb_bytes_written, p_stream,
p_manager)) {
return OPJ_FALSE;
}
l_part_tile_size = 0;
l_begin_data = p_data;
- if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream,
+ if (! opj_j2k_write_sot(p_j2k, p_data,
+ p_total_data_size,
+ &l_current_nb_bytes_written,
+ p_stream,
p_manager)) {
return OPJ_FALSE;
}
l_part_tile_size = 0;
l_begin_data = p_data;
- if (! opj_j2k_write_sot(p_j2k, p_data, &l_current_nb_bytes_written, p_stream,
+ if (! opj_j2k_write_sot(p_j2k, p_data,
+ p_total_data_size,
+ &l_current_nb_bytes_written, p_stream,
p_manager)) {
return OPJ_FALSE;
}
}
/**
- * Creates a tile-coder decoder.
+ * Creates a tile-coder encoder.
*
* @param p_stream the stream to write data to.
* @param p_j2k J2K codec.