From cf5153c518045027f286e08af36809237a76a7df Mon Sep 17 00:00:00 2001 From: Antonin Descampe Date: Mon, 3 Nov 2014 14:12:01 +0000 Subject: [PATCH] [trunk] add a cdef box when alpha component is present (fixes issue 416) --- src/bin/jp2/convert.c | 5 +- src/lib/openjp2/jp2.c | 143 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/bin/jp2/convert.c b/src/bin/jp2/convert.c index 606238d1..6af7b7ab 100644 --- a/src/bin/jp2/convert.c +++ b/src/bin/jp2/convert.c @@ -3364,7 +3364,10 @@ opj_image_t *pngtoimage(const char *read_idf, opj_cparameters_t * params) r = image->comps[0].data; g = image->comps[1].data; b = image->comps[2].data; - if(has_alpha) a = image->comps[3].data; + if(has_alpha) { + a = image->comps[3].data; + image->comps[3].alpha = 1; + } for(i = 0; i < height; ++i) { diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c index bce8813c..219278fe 100644 --- a/src/lib/openjp2/jp2.c +++ b/src/lib/openjp2/jp2.c @@ -108,6 +108,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. * @@ -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); @@ -1385,7 +1445,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; @@ -1415,6 +1475,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); @@ -1614,9 +1679,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; + OPJ_UINT32 alpha_channel; + if(!jp2 || !parameters || !image) return OPJ_FALSE; @@ -1697,6 +1766,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 */