Index: core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c |
diff --git a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c |
index 78a15026a970eae4402d0b540f5c2892ac779641..1830c11a194386db1f18c51380ff3f722e30841f 100644 |
--- a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c |
+++ b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c |
@@ -109,6 +109,17 @@ static OPJ_BOOL opj_jp2_read_cdef( opj_jp2_t * jp2, |
static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color); |
/** |
+ * Writes the Channel Definition 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 OPJ_BYTE * opj_jp2_write_cdef( opj_jp2_t *jp2, |
+ OPJ_UINT32 * p_nb_bytes_written ); |
+ |
+/** |
* Writes the Colour Specification box. |
* |
* @param jp2 jpeg2000 file codec. |
@@ -680,6 +691,55 @@ OPJ_BOOL opj_jp2_read_bpcc( opj_jp2_t *jp2, |
return OPJ_TRUE; |
} |
+static OPJ_BYTE * opj_jp2_write_cdef(opj_jp2_t *jp2, OPJ_UINT32 * p_nb_bytes_written) |
+{ |
+ /* room for 8 bytes for box, 2 for n */ |
+ OPJ_UINT32 l_cdef_size = 10; |
+ OPJ_BYTE * l_cdef_data,* l_current_cdef_ptr; |
+ OPJ_UINT32 l_value; |
+ OPJ_UINT16 i; |
+ |
+ /* preconditions */ |
+ assert(jp2 != 00); |
+ assert(p_nb_bytes_written != 00); |
+ assert(jp2->color.jp2_cdef != 00); |
+ assert(jp2->color.jp2_cdef->info != 00); |
+ assert(jp2->color.jp2_cdef->n > 0U); |
+ |
+ l_cdef_size += 6 * jp2->color.jp2_cdef->n; |
+ |
+ l_cdef_data = (OPJ_BYTE *) opj_malloc(l_cdef_size); |
+ if (l_cdef_data == 00) { |
+ return 00; |
+ } |
+ |
+ l_current_cdef_ptr = l_cdef_data; |
+ |
+ opj_write_bytes(l_current_cdef_ptr,l_cdef_size,4); /* write box size */ |
+ l_current_cdef_ptr += 4; |
+ |
+ opj_write_bytes(l_current_cdef_ptr,JP2_CDEF,4); /* BPCC */ |
+ l_current_cdef_ptr += 4; |
+ |
+ l_value = jp2->color.jp2_cdef->n; |
+ opj_write_bytes(l_current_cdef_ptr,l_value,2); /* N */ |
+ l_current_cdef_ptr += 2; |
+ |
+ for (i = 0U; i < jp2->color.jp2_cdef->n; ++i) { |
+ l_value = jp2->color.jp2_cdef->info[i].cn; |
+ opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Cni */ |
+ l_current_cdef_ptr += 2; |
+ l_value = jp2->color.jp2_cdef->info[i].typ; |
+ opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Typi */ |
+ l_current_cdef_ptr += 2; |
+ l_value = jp2->color.jp2_cdef->info[i].asoc; |
+ opj_write_bytes(l_current_cdef_ptr,l_value,2); /* Asoci */ |
+ l_current_cdef_ptr += 2; |
+ } |
+ *p_nb_bytes_written = l_cdef_size; |
+ |
+ return l_cdef_data; |
+} |
OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, |
OPJ_UINT32 * p_nb_bytes_written |
@@ -688,7 +748,7 @@ OPJ_BYTE * opj_jp2_write_colr( opj_jp2_t *jp2, |
/* room for 8 bytes for box 3 for common data and variable upon profile*/ |
OPJ_UINT32 l_colr_size = 11; |
OPJ_BYTE * l_colr_data,* l_current_colr_ptr; |
- |
+ |
/* preconditions */ |
assert(jp2 != 00); |
assert(p_nb_bytes_written != 00); |
@@ -772,12 +832,12 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, |
} |
for (i = 0; i < n; i++) { |
- if (info[i].cn >= image->numcomps) { |
- opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, image->numcomps); |
+ if (info[i].cn >= nr_channels) { |
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, nr_channels); |
return OPJ_FALSE; |
} |
- if (info[i].asoc > 0 && (OPJ_UINT32)(info[i].asoc - 1) >= image->numcomps) { |
- opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, image->numcomps); |
+ if (info[i].asoc > 0 && (OPJ_UINT32)(info[i].asoc - 1) >= nr_channels) { |
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, nr_channels); |
return OPJ_FALSE; |
} |
} |
@@ -982,12 +1042,20 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2, |
opj_read_bytes(p_pclr_header_data, &l_value , 2); /* NE */ |
p_pclr_header_data += 2; |
nr_entries = (OPJ_UINT16) l_value; |
+ if ((nr_entries == 0U) || (nr_entries > 1024U)) { |
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports %d entries\n", (int)nr_entries); |
+ return OPJ_FALSE; |
+ } |
opj_read_bytes(p_pclr_header_data, &l_value , 1); /* NPC */ |
++p_pclr_header_data; |
nr_channels = (OPJ_UINT16) l_value; |
+ if (nr_channels == 0U) { |
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports 0 palette columns\n"); |
+ return OPJ_FALSE; |
+ } |
- if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels || nr_channels == 0 || nr_entries >= (OPJ_UINT32)-1 / nr_channels) |
+ if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels) |
return OPJ_FALSE; |
entries = (OPJ_UINT32*) opj_malloc((size_t)nr_channels * nr_entries * sizeof(OPJ_UINT32)); |
@@ -1120,35 +1188,51 @@ void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color) |
info = color->jp2_cdef->info; |
n = color->jp2_cdef->n; |
- for(i = 0; i < n; ++i) |
- { |
- /* WATCH: acn = asoc - 1 ! */ |
- asoc = info[i].asoc; |
- if(asoc == 0 || asoc == 65535) |
- { |
- if (i < image->numcomps) |
- image->comps[i].alpha = info[i].typ; |
- continue; |
- } |
+ for(i = 0; i < n; ++i) |
+ { |
+ /* WATCH: acn = asoc - 1 ! */ |
+ asoc = info[i].asoc; |
+ cn = info[i].cn; |
- cn = info[i].cn; |
- acn = (OPJ_UINT16)(asoc - 1); |
- if( cn >= image->numcomps || acn >= image->numcomps ) |
- { |
- fprintf(stderr, "cn=%d, acn=%d, numcomps=%d\n", cn, acn, image->numcomps); |
- continue; |
- } |
+ if( cn >= image->numcomps) |
+ { |
+ fprintf(stderr, "cn=%d, numcomps=%d\n", cn, image->numcomps); |
+ continue; |
+ } |
+ if(asoc == 0 || asoc == 65535) |
+ { |
+ image->comps[cn].alpha = info[i].typ; |
+ continue; |
+ } |
+ |
+ acn = (OPJ_UINT16)(asoc - 1); |
+ if( acn >= image->numcomps ) |
+ { |
+ fprintf(stderr, "acn=%d, numcomps=%d\n", acn, image->numcomps); |
+ continue; |
+ } |
- if(cn != acn) |
+ /* Swap only if color channel */ |
+ if((cn != acn) && (info[i].typ == 0)) |
{ |
opj_image_comp_t saved; |
+ OPJ_UINT16 j; |
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 = (OPJ_UINT16)(cn + 1); |
- info[acn].asoc = (OPJ_UINT16)(info[acn].cn + 1); |
+ /* Swap channels in following channel definitions, don't bother with j <= i that are already processed */ |
+ for (j = i + 1; j < n ; ++j) |
+ { |
+ if (info[j].cn == cn) { |
+ info[j].cn = acn; |
+ } |
+ else if (info[j].cn == acn) { |
+ info[j].cn = cn; |
+ } |
+ /* asoc is related to color index. Do not update. */ |
+ } |
} |
image->comps[cn].alpha = info[i].typ; |
@@ -1341,11 +1425,6 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, |
else |
p_image->color_space = OPJ_CLRSPC_UNKNOWN; |
- /* Apply the color space if needed */ |
- if(jp2->color.jp2_cdef) { |
- opj_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) |
@@ -1354,6 +1433,11 @@ OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2, |
opj_jp2_apply_pclr(p_image, &(jp2->color)); |
} |
+ /* Apply the color space if needed */ |
+ if(jp2->color.jp2_cdef) { |
+ opj_jp2_apply_cdef(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; |
@@ -1369,7 +1453,7 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, |
opj_event_mgr_t * p_manager |
) |
{ |
- opj_jp2_img_header_writer_handler_t l_writers [3]; |
+ opj_jp2_img_header_writer_handler_t l_writers [4]; |
opj_jp2_img_header_writer_handler_t * l_current_writer; |
OPJ_INT32 i, l_nb_pass; |
@@ -1399,6 +1483,11 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2, |
l_writers[1].handler = opj_jp2_write_colr; |
} |
+ if (jp2->color.jp2_cdef != NULL) { |
+ l_writers[l_nb_pass].handler = opj_jp2_write_cdef; |
+ l_nb_pass++; |
+ } |
+ |
/* write box header */ |
/* write JP2H type */ |
opj_write_bytes(l_jp2h_data+4,JP2_JP2H,4); |
@@ -1598,9 +1687,13 @@ OPJ_BOOL opj_jp2_setup_encoder( opj_jp2_t *jp2, |
opj_image_t *image, |
opj_event_mgr_t * p_manager) |
{ |
- OPJ_UINT32 i; |
+ OPJ_UINT32 i; |
OPJ_UINT32 depth_0; |
OPJ_UINT32 sign; |
+ OPJ_UINT32 alpha_count; |
+ OPJ_UINT32 color_channels = 0U; |
+ OPJ_UINT32 alpha_channel = 0U; |
+ |
if(!jp2 || !parameters || !image) |
return OPJ_FALSE; |
@@ -1681,6 +1774,74 @@ OPJ_BOOL opj_jp2_setup_encoder( opj_jp2_t *jp2, |
jp2->enumcs = 18; /* YUV */ |
} |
+ /* Channel Definition box */ |
+ /* FIXME not provided by parameters */ |
+ /* We try to do what we can... */ |
+ alpha_count = 0U; |
+ for (i = 0; i < image->numcomps; i++) { |
+ if (image->comps[i].alpha != 0) { |
+ alpha_count++; |
+ alpha_channel = i; |
+ } |
+ } |
+ if (alpha_count == 1U) { /* no way to deal with more than 1 alpha channel */ |
+ switch (jp2->enumcs) { |
+ case 16: |
+ case 18: |
+ color_channels = 3; |
+ break; |
+ case 17: |
+ color_channels = 1; |
+ break; |
+ default: |
+ alpha_count = 0U; |
+ break; |
+ } |
+ if (alpha_count == 0U) { |
+ opj_event_msg(p_manager, EVT_WARNING, "Alpha channel specified but unknown enumcs. No cdef box will be created.\n"); |
+ } else if (image->numcomps < (color_channels+1)) { |
+ opj_event_msg(p_manager, EVT_WARNING, "Alpha channel specified but not enough image components for an automatic cdef box creation.\n"); |
+ alpha_count = 0U; |
+ } else if ((OPJ_UINT32)alpha_channel < color_channels) { |
+ opj_event_msg(p_manager, EVT_WARNING, "Alpha channel position conflicts with color channel. No cdef box will be created.\n"); |
+ alpha_count = 0U; |
+ } |
+ } else if (alpha_count > 1) { |
+ opj_event_msg(p_manager, EVT_WARNING, "Multiple alpha channels specified. No cdef box will be created.\n"); |
+ } |
+ if (alpha_count == 1U) { /* if here, we know what we can do */ |
+ jp2->color.jp2_cdef = (opj_jp2_cdef_t*)opj_malloc(sizeof(opj_jp2_cdef_t)); |
+ if(!jp2->color.jp2_cdef) { |
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to setup the JP2 encoder\n"); |
+ return OPJ_FALSE; |
+ } |
+ /* no memset needed, all values will be overwritten except if jp2->color.jp2_cdef->info allocation fails, */ |
+ /* in which case jp2->color.jp2_cdef->info will be NULL => valid for destruction */ |
+ jp2->color.jp2_cdef->info = (opj_jp2_cdef_info_t*) opj_malloc(image->numcomps * sizeof(opj_jp2_cdef_info_t)); |
+ if (!jp2->color.jp2_cdef->info) { |
+ /* memory will be freed by opj_jp2_destroy */ |
+ opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to setup the JP2 encoder\n"); |
+ return OPJ_FALSE; |
+ } |
+ jp2->color.jp2_cdef->n = (OPJ_UINT16) image->numcomps; /* cast is valid : image->numcomps [1,16384] */ |
+ for (i = 0U; i < color_channels; i++) { |
+ jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ |
+ jp2->color.jp2_cdef->info[i].typ = 0U; |
+ jp2->color.jp2_cdef->info[i].asoc = (OPJ_UINT16)(i+1U); /* No overflow + cast is valid : image->numcomps [1,16384] */ |
+ } |
+ for (; i < image->numcomps; i++) { |
+ if (image->comps[i].alpha != 0) { /* we'll be here exactly once */ |
+ jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ |
+ jp2->color.jp2_cdef->info[i].typ = 1U; /* Opacity channel */ |
+ jp2->color.jp2_cdef->info[i].asoc = 0U; /* Apply alpha channel to the whole image */ |
+ } else { |
+ /* Unknown channel */ |
+ jp2->color.jp2_cdef->info[i].cn = (OPJ_UINT16)i; /* cast is valid : image->numcomps [1,16384] */ |
+ jp2->color.jp2_cdef->info[i].typ = 65535U; |
+ jp2->color.jp2_cdef->info[i].asoc = 65535U; |
+ } |
+ } |
+ } |
jp2->precedence = 0; /* PRECEDENCE */ |
jp2->approx = 0; /* APPROX */ |
@@ -2551,11 +2712,6 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, |
else |
p_image->color_space = OPJ_CLRSPC_UNKNOWN; |
- /* Apply the color space if needed */ |
- if(p_jp2->color.jp2_cdef) { |
- opj_jp2_apply_cdef(p_image, &(p_jp2->color)); |
- } |
- |
if(p_jp2->color.jp2_pclr) { |
/* Part 1, I.5.3.4: Either both or none : */ |
if( !p_jp2->color.jp2_pclr->cmap) |
@@ -2564,6 +2720,11 @@ OPJ_BOOL opj_jp2_get_tile( opj_jp2_t *p_jp2, |
opj_jp2_apply_pclr(p_image, &(p_jp2->color)); |
} |
+ /* Apply the color space if needed */ |
+ if(p_jp2->color.jp2_cdef) { |
+ opj_jp2_apply_cdef(p_image, &(p_jp2->color)); |
+ } |
+ |
if(p_jp2->color.icc_profile_buf) { |
p_image->icc_profile_buf = p_jp2->color.icc_profile_buf; |
p_image->icc_profile_len = p_jp2->color.icc_profile_len; |