eccodes/src/grib_jasper_encoding.cc

291 lines
8.1 KiB
C++

/*
* (C) Copyright 2005- ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
#include "grib_api_internal.h"
#if HAVE_LIBJASPER
/* Remove compiler warnings re macros being redefined */
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include "jasper/jasper.h"
#define MAXOPTSSIZE 1024
static int ecc_jasper_initialise()
{
#if JASPER_VERSION_MAJOR >= 3
int jaserr = 0;
jas_conf_clear();
jas_conf_set_max_mem_usage(jas_get_total_mem_size());
#if defined GRIB_PTHREADS || defined GRIB_OMP_THREADS
jas_conf_set_multithread(1);
#endif
jaserr = jas_init_library();
if (jaserr) return jaserr;
jaserr = jas_init_thread();
if (jaserr) return jaserr;
#endif
return 0;
}
static jas_image_t* ecc_jasper_decode(jas_stream_t *in)
{
#if JASPER_VERSION_MAJOR >= 3
/* Second argument (=fmt) < 0 means "If possible, try to determine the format of the input data" */
return jas_image_decode(in, -1, 0);
#else
return jpc_decode(in, NULL);
#endif
}
static int ecc_jasper_encode(jas_image_t *image, jas_stream_t *jpcstream, char *optstr)
{
#if JASPER_VERSION_MAJOR >= 3
const int fmt = jas_image_strtofmt("jpc");
return jas_image_encode(image, jpcstream, fmt, optstr);
#else
return jpc_encode(image, jpcstream, optstr);
#endif
}
static void ecc_jasper_cleanup()
{
#if JASPER_VERSION_MAJOR >= 3
jas_cleanup_thread();
jas_cleanup_library();
#endif
}
int grib_jasper_decode(grib_context* c, unsigned char* buf, const size_t* buflen, double* values, const size_t* n_vals)
{
/* jas_setdbglevel(99999); */
jas_image_t* image = NULL;
jas_stream_t* jpeg = NULL;
int code = GRIB_SUCCESS;
jas_matrix_t* matrix = NULL;
jas_image_cmpt_t* p;
int i, j, k;
int jaserr = 0; /* 0 means success */
jaserr = ecc_jasper_initialise();
if (jaserr) {
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_decode: Failed to initialize JasPer library. JasPer error %d", jaserr);
code = GRIB_DECODING_ERROR;
goto cleanup;
}
jpeg = jas_stream_memopen((char*)buf, *buflen);
if (!jpeg) {
code = GRIB_DECODING_ERROR;
goto cleanup;
}
grib_context_log(c, GRIB_LOG_DEBUG, "grib_jasper_decode: JasPer version %s", jas_getversion());
image = ecc_jasper_decode(jpeg);
if (!image) {
code = GRIB_DECODING_ERROR;
goto cleanup;
}
p = image->cmpts_[0];
if (image->numcmpts_ != 1) {
/* Image not gray scale */
code = GRIB_DECODING_ERROR;
goto cleanup;
}
matrix = jas_matrix_create(jas_image_height(image), jas_image_width(image));
if (!matrix) {
code = GRIB_DECODING_ERROR;
goto cleanup;
}
jaserr = jas_image_readcmpt(image, 0, 0, 0, jas_image_width(image), jas_image_height(image), matrix);
if (jaserr) {
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_decode: Failed to read JasPer component data. JasPer error %d", jaserr);
code = GRIB_DECODING_ERROR;
goto cleanup;
}
Assert(p->height_ * p->width_ == *n_vals);
k = 0;
for (i = 0; i < p->height_; i++)
for (j = 0; j < p->width_; j++) {
values[k++] = matrix->rows_[i][j];
}
cleanup:
if (matrix)
jas_matrix_destroy(matrix);
if (image)
jas_image_destroy(image);
if (jpeg)
jas_stream_close(jpeg);
ecc_jasper_cleanup();
return code;
}
int grib_jasper_encode(grib_context* c, j2k_encode_helper* helper)
{
int code = GRIB_SUCCESS;
int jaserr = 0;
char opts[MAXOPTSSIZE];
double reference_value = helper->reference_value;
double decimal = helper->decimal;
double divisor = helper->divisor;
const double* values = helper->values;
long no_values = helper->no_values;
long bits8;
int i;
size_t buflen = 0;
unsigned char* encoded = NULL;
unsigned char* p = NULL;
jas_image_t image = { 0 };
jas_stream_t* jpcstream = 0;
jas_stream_t* istream = 0;
jas_image_cmpt_t cmpt = {0,};
jas_image_cmpt_t* pcmpt = 0;
image.tlx_ = 0;
image.tly_ = 0;
image.brx_ = helper->width;
image.bry_ = helper->height;
image.numcmpts_ = 1;
image.maxcmpts_ = 1;
image.clrspc_ = JAS_CLRSPC_SGRAY;
image.cmprof_ = 0;
#if JASPER_VERSION_MAJOR == 1
/* ECC-396: Support for Jasper 2.0
* Jasper version 1 had the 'inmem_' data member but
* version 2 removed it from the interface */
image.inmem_ = 1;
#endif
cmpt.tlx_ = 0;
cmpt.tly_ = 0;
cmpt.hstep_ = 1;
cmpt.vstep_ = 1;
cmpt.width_ = helper->width;
cmpt.height_ = helper->height;
cmpt.type_ = JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y);
cmpt.prec_ = helper->bits_per_value;
cmpt.sgnd_ = 0;
cmpt.cps_ = (helper->bits_per_value + 7) / 8;
/* Simple packing encoding */
bits8 = (helper->bits_per_value + 7) / 8 * 8;
Assert(bits8 > 0);
encoded = (unsigned char*)grib_context_malloc_clear(c, bits8 / 8 * no_values);
if (!encoded) {
code = GRIB_OUT_OF_MEMORY;
goto cleanup;
}
buflen = 0;
p = encoded;
for (i = 0; i < no_values; i++) {
long blen = bits8;
unsigned long unsigned_val = (unsigned long)((((values[i] * decimal) - (reference_value)) * divisor) + 0.5);
while (blen >= 8) {
blen -= 8;
*p = (unsigned_val >> blen);
p++;
buflen++;
}
}
ecc_jasper_initialise();
opts[0] = 0;
if (helper->compression != 0) {
/* Lossy */
snprintf(opts, MAXOPTSSIZE, "mode=real\nrate=%f", 1.0 / helper->compression);
}
Assert(cmpt.width_ * cmpt.height_ * cmpt.cps_ == buflen);
grib_context_log(c, GRIB_LOG_DEBUG, "grib_jasper_encode: JasPer version %s", jas_getversion());
pcmpt = &cmpt;
image.cmpts_ = &pcmpt;
istream = jas_stream_memopen((char*)encoded, buflen);
cmpt.stream_ = istream;
jpcstream = jas_stream_memopen((char*)helper->jpeg_buffer, helper->buffer_size);
jaserr = ecc_jasper_encode(&image, jpcstream, opts);
if (jaserr) {
/* Failed to encode. Increase the number of guard bits */
strcat(opts, "\nnumgbits=4");
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_encode: JasPer error %d, increasing the number of guard bits", jaserr);
jas_stream_close(istream);
istream = 0;
jas_stream_close(jpcstream);
jpcstream = 0;
istream = jas_stream_memopen((char*)encoded, buflen);
cmpt.stream_ = istream;
jpcstream = jas_stream_memopen((char*)helper->jpeg_buffer, helper->buffer_size);
jaserr = ecc_jasper_encode(&image, jpcstream, opts);
}
if (jaserr) {
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_encode: Failed to encode. JasPer error %d", jaserr);
code = GRIB_ENCODING_ERROR;
goto cleanup;
}
helper->jpeg_length = jpcstream->rwcnt_;
jas_stream_close(istream);
istream = 0;
jas_stream_close(jpcstream);
jpcstream = 0;
cleanup:
grib_context_free(c, encoded);
if (istream)
jas_stream_close(istream);
if (jpcstream)
jas_stream_close(jpcstream);
ecc_jasper_cleanup();
return code;
}
#else // HAVE_LIBJASPER
int grib_jasper_decode(grib_context* c, unsigned char* buf, const size_t* buflen, double* val, const size_t* n_vals)
{
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_decode: JasPer JPEG support not enabled.");
return GRIB_FUNCTIONALITY_NOT_ENABLED;
}
int grib_jasper_encode(grib_context* c, j2k_encode_helper* helper)
{
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_encode: JasPer JPEG support not enabled.");
return GRIB_FUNCTIONALITY_NOT_ENABLED;
}
#endif