Added a basic saving capability to OPJViewer
This commit is contained in:
@@ -231,17 +231,275 @@ bool wxJ2KHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose,
|
||||
}
|
||||
|
||||
// save the j2k codestream
|
||||
bool wxJ2KHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
|
||||
bool wxJ2KHandler::SaveFile( wxImage *wimage, wxOutputStream& stream, bool verbose )
|
||||
{
|
||||
opj_cparameters_t parameters; /* compression parameters */
|
||||
opj_event_mgr_t event_mgr; /* event manager */
|
||||
opj_image_t *oimage = NULL;
|
||||
opj_image_cmptparm_t *cmptparm;
|
||||
opj_cio_t *cio = NULL;
|
||||
int codestream_length;
|
||||
bool bSuccess;
|
||||
int i;
|
||||
|
||||
/*
|
||||
configure the event callbacks (not required)
|
||||
setting of each callback is optionnal
|
||||
*/
|
||||
memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
|
||||
event_mgr.error_handler = j2k_error_callback;
|
||||
event_mgr.warning_handler = j2k_warning_callback;
|
||||
event_mgr.info_handler = j2k_info_callback;
|
||||
|
||||
/* set encoding parameters to default values */
|
||||
opj_set_default_encoder_parameters(¶meters);
|
||||
|
||||
/* load parameters */
|
||||
|
||||
/* subsampling */
|
||||
if (sscanf(m_subsampling.c_str(), wxT("%d,%d"), &(parameters.subsampling_dx), &(parameters.subsampling_dy)) != 2) {
|
||||
wxLogError(wxT("Wrong sub-sampling encoder setting: dx,dy"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* compression rates */
|
||||
if (m_rates != wxT("")) {
|
||||
char *s1 = (char *) m_rates.c_str();
|
||||
wxLogMessage("rates %s", s1);
|
||||
while (sscanf(s1, "%f", &(parameters.tcp_rates[parameters.tcp_numlayers])) == 1) {
|
||||
parameters.tcp_numlayers++;
|
||||
while (*s1 && *s1 != ',') {
|
||||
s1++;
|
||||
}
|
||||
if (!*s1)
|
||||
break;
|
||||
s1++;
|
||||
}
|
||||
wxLogMessage("%d layers", parameters.tcp_numlayers);
|
||||
parameters.cp_disto_alloc = 1;
|
||||
}
|
||||
|
||||
/* image quality, dB */
|
||||
if (m_rates == wxT("")) {
|
||||
char *s2 = (char *) m_quality.c_str();
|
||||
wxLogMessage("qualities %s", s2);
|
||||
while (sscanf(s2, "%f", ¶meters.tcp_distoratio[parameters.tcp_numlayers]) == 1) {
|
||||
parameters.tcp_numlayers++;
|
||||
while (*s2 && *s2 != ',') {
|
||||
s2++;
|
||||
}
|
||||
if (!*s2)
|
||||
break;
|
||||
s2++;
|
||||
}
|
||||
wxLogMessage("%d layers", parameters.tcp_numlayers);
|
||||
parameters.cp_fixed_quality = 1;
|
||||
}
|
||||
|
||||
/* image origin */
|
||||
if (sscanf(m_origin.c_str(), "%d,%d", ¶meters.image_offset_x0, ¶meters.image_offset_y0) != 2) {
|
||||
wxLogError(wxT("bad coordinate of the image origin: x0,y0"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create comment for codestream */
|
||||
if(m_enablecomm) {
|
||||
parameters.cp_comment = (char *) malloc(strlen(m_comment.c_str()) + 1);
|
||||
if(parameters.cp_comment) {
|
||||
strcpy(parameters.cp_comment, m_comment.c_str());
|
||||
}
|
||||
} else {
|
||||
parameters.cp_comment = NULL;
|
||||
}
|
||||
|
||||
/* indexing file */
|
||||
if (m_enableidx) {
|
||||
strncpy(parameters.index, m_index.c_str(), m_index.Len());
|
||||
wxLogMessage("index file is %s", parameters.index);
|
||||
parameters.index_on = 1;
|
||||
} else {
|
||||
parameters.index_on = 0;
|
||||
}
|
||||
|
||||
/* if no rate entered, lossless by default */
|
||||
if (parameters.tcp_numlayers == 0) {
|
||||
parameters.tcp_rates[0] = 0; /* MOD antonin : losslessbug */
|
||||
parameters.tcp_numlayers++;
|
||||
parameters.cp_disto_alloc = 1;
|
||||
}
|
||||
|
||||
/* irreversible transform */
|
||||
parameters.irreversible = (m_irreversible == true) ? 1 : 0;
|
||||
|
||||
/* resolutions */
|
||||
parameters.numresolution = m_resolutions;
|
||||
|
||||
/* codeblocks size */
|
||||
if (m_cbsize != wxT("")) {
|
||||
int cblockw_init = 0, cblockh_init = 0;
|
||||
sscanf(m_cbsize.c_str(), "%d,%d", &cblockw_init, &cblockh_init);
|
||||
if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) {
|
||||
wxLogError("!! Size of code_block error !! Restrictions:\n width*height<=4096\n 4<=width,height<= 1024");
|
||||
return false;
|
||||
}
|
||||
parameters.cblockw_init = cblockw_init;
|
||||
parameters.cblockh_init = cblockh_init;
|
||||
}
|
||||
|
||||
/* precincts size */
|
||||
if (m_prsize != wxT("")) {
|
||||
char sep;
|
||||
int res_spec = 0;
|
||||
char *s = (char *) m_prsize.c_str();
|
||||
do {
|
||||
sep = 0;
|
||||
sscanf(s, "[%d,%d]%c", ¶meters.prcw_init[res_spec], ¶meters.prch_init[res_spec], &sep);
|
||||
parameters.csty |= 0x01;
|
||||
res_spec++;
|
||||
s = strpbrk(s, "]") + 2;
|
||||
} while (sep == ',');
|
||||
parameters.res_spec = res_spec;
|
||||
}
|
||||
|
||||
/* tiles */
|
||||
if (m_tsize != wxT("")) {
|
||||
sscanf(m_tsize.c_str(), "%d,%d", ¶meters.cp_tdx, ¶meters.cp_tdy);
|
||||
parameters.tile_size_on = true;
|
||||
}
|
||||
|
||||
/* tile origin */
|
||||
if (sscanf(m_torigin.c_str(), "%d,%d", ¶meters.cp_tx0, ¶meters.cp_ty0) != 2) {
|
||||
wxLogError("tile offset setting error: X0,Y0");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* use SOP */
|
||||
if (m_enablesop)
|
||||
parameters.csty |= 0x02;
|
||||
|
||||
/* use EPH */
|
||||
if (m_enableeph)
|
||||
parameters.csty |= 0x04;
|
||||
|
||||
|
||||
|
||||
/* compression settings */
|
||||
//parameters.tcp_numlayers = 1;
|
||||
//parameters.tcp_rates[0] = 10.0;
|
||||
//parameters.cp_disto_alloc = 1;
|
||||
//parameters.irreversible = 1;
|
||||
parameters.tcp_mct = 1;
|
||||
|
||||
/* convert wx image into opj image */
|
||||
cmptparm = (opj_image_cmptparm_t*) malloc(3 * sizeof(opj_image_cmptparm_t));
|
||||
|
||||
/* initialize opj image components */
|
||||
memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t));
|
||||
for(i = 0; i < 3; i++) {
|
||||
cmptparm[i].prec = 8;
|
||||
cmptparm[i].bpp = 8;
|
||||
cmptparm[i].sgnd = false;
|
||||
cmptparm[i].dx = parameters.subsampling_dx;
|
||||
cmptparm[i].dy = parameters.subsampling_dy;
|
||||
cmptparm[i].w = wimage->GetWidth();
|
||||
cmptparm[i].h = wimage->GetHeight();
|
||||
}
|
||||
|
||||
/* create the image */
|
||||
oimage = opj_image_create(3, &cmptparm[0], CLRSPC_SRGB);
|
||||
if(!oimage) {
|
||||
if (cmptparm)
|
||||
free(cmptparm);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* set image offset and reference grid */
|
||||
oimage->x0 = parameters.image_offset_x0;
|
||||
oimage->y0 = parameters.image_offset_y0;
|
||||
oimage->x1 = parameters.image_offset_x0 + (wimage->GetWidth() - 1) * 1 + 1;
|
||||
oimage->y1 = parameters.image_offset_y0 + (wimage->GetHeight() - 1) * 1 + 1;
|
||||
|
||||
/* load image data */
|
||||
unsigned char *value = wimage->GetData();
|
||||
int area = wimage->GetWidth() * wimage->GetHeight();
|
||||
for (i = 0; i < area; i++) {
|
||||
oimage->comps[0].data[i] = *(value++);
|
||||
oimage->comps[1].data[i] = *(value++);
|
||||
oimage->comps[2].data[i] = *(value++);
|
||||
}
|
||||
|
||||
/* get a J2K compressor handle */
|
||||
opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K);
|
||||
|
||||
/* catch events using our callbacks and give a local context */
|
||||
opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
|
||||
|
||||
/* setup the encoder parameters using the current image and user parameters */
|
||||
opj_setup_encoder(cinfo, ¶meters, oimage);
|
||||
|
||||
/* open a byte stream for writing */
|
||||
/* allocate memory for all tiles */
|
||||
cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
|
||||
|
||||
/* encode the image */
|
||||
bSuccess = opj_encode(cinfo, cio, oimage, parameters.index);
|
||||
if (!bSuccess) {
|
||||
|
||||
opj_cio_close(cio);
|
||||
opj_destroy_compress(cinfo);
|
||||
opj_image_destroy(oimage);
|
||||
if (cmptparm)
|
||||
free(cmptparm);
|
||||
if(parameters.cp_comment)
|
||||
free(parameters.cp_comment);
|
||||
if(parameters.cp_matrice)
|
||||
free(parameters.cp_matrice);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
wxMutexGuiEnter();
|
||||
#endif /* __WXGTK__ */
|
||||
wxLogError(wxT("J2K: Couldn't save image -> not implemented."));
|
||||
|
||||
wxLogError(wxT("failed to encode image"));
|
||||
|
||||
#ifndef __WXGTK__
|
||||
wxMutexGuiLeave();
|
||||
#endif /* __WXGTK__ */
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
codestream_length = cio_tell(cio);
|
||||
wxLogMessage(wxT("Codestream: %d bytes"), codestream_length);
|
||||
|
||||
/* write the buffer to stream */
|
||||
stream.Write(cio->buffer, codestream_length);
|
||||
|
||||
/* close and free the byte stream */
|
||||
opj_cio_close(cio);
|
||||
|
||||
/* free remaining compression structures */
|
||||
opj_destroy_compress(cinfo);
|
||||
|
||||
/* free image data */
|
||||
opj_image_destroy(oimage);
|
||||
|
||||
if (cmptparm)
|
||||
free(cmptparm);
|
||||
if(parameters.cp_comment)
|
||||
free(parameters.cp_comment);
|
||||
if(parameters.cp_matrice)
|
||||
free(parameters.cp_matrice);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
wxMutexGuiEnter();
|
||||
#endif /* __WXGTK__ */
|
||||
|
||||
wxLogMessage(wxT("J2K: Image encoded!"));
|
||||
|
||||
#ifndef __WXGTK__
|
||||
wxMutexGuiLeave();
|
||||
#endif /* __WXGTK__ */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __VISUALC__
|
||||
|
Reference in New Issue
Block a user