2013-03-25 14:23:07 +00:00
|
|
|
/*
|
2020-01-28 14:32:34 +00:00
|
|
|
* (C) Copyright 2005- ECMWF.
|
2013-03-25 14:23:07 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2013-03-25 12:04:10 +00:00
|
|
|
#include "grib_api_internal.h"
|
|
|
|
|
|
|
|
#if HAVE_LIBJASPER
|
2014-10-23 12:41:22 +00:00
|
|
|
/* Remove compiler warnings re macros being redefined */
|
|
|
|
#undef PACKAGE_BUGREPORT
|
|
|
|
#undef PACKAGE_NAME
|
|
|
|
#undef PACKAGE_STRING
|
|
|
|
#undef PACKAGE_TARNAME
|
|
|
|
#undef PACKAGE_VERSION
|
2013-03-25 12:04:10 +00:00
|
|
|
#include "jasper/jasper.h"
|
|
|
|
#define MAXOPTSSIZE 1024
|
|
|
|
|
2022-03-07 16:18:30 +00:00
|
|
|
static int ecc_jasper_initialise()
|
2022-03-06 21:30:44 +00:00
|
|
|
{
|
2022-11-21 21:53:18 +00:00
|
|
|
#if JASPER_VERSION_MAJOR >= 3
|
2022-03-07 16:18:30 +00:00
|
|
|
int jaserr = 0;
|
2022-03-06 21:30:44 +00:00
|
|
|
jas_conf_clear();
|
|
|
|
jas_conf_set_max_mem_usage(jas_get_total_mem_size());
|
2023-02-22 14:13:08 +00:00
|
|
|
|
|
|
|
#if defined GRIB_PTHREADS || defined GRIB_OMP_THREADS
|
|
|
|
jas_conf_set_multithread(1);
|
|
|
|
#endif
|
|
|
|
|
2022-03-07 16:18:30 +00:00
|
|
|
jaserr = jas_init_library();
|
|
|
|
if (jaserr) return jaserr;
|
|
|
|
jaserr = jas_init_thread();
|
|
|
|
if (jaserr) return jaserr;
|
2022-03-06 21:30:44 +00:00
|
|
|
#endif
|
2022-03-07 16:18:30 +00:00
|
|
|
return 0;
|
2022-03-06 21:30:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static jas_image_t* ecc_jasper_decode(jas_stream_t *in)
|
|
|
|
{
|
2022-11-21 21:53:18 +00:00
|
|
|
#if JASPER_VERSION_MAJOR >= 3
|
2022-03-06 21:30:44 +00:00
|
|
|
/* 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
|
|
|
|
}
|
|
|
|
|
2022-03-07 13:54:10 +00:00
|
|
|
static int ecc_jasper_encode(jas_image_t *image, jas_stream_t *jpcstream, char *optstr)
|
2022-03-06 21:30:44 +00:00
|
|
|
{
|
2022-11-21 21:53:18 +00:00
|
|
|
#if JASPER_VERSION_MAJOR >= 3
|
2022-03-06 21:30:44 +00:00
|
|
|
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()
|
|
|
|
{
|
2022-11-21 21:53:18 +00:00
|
|
|
#if JASPER_VERSION_MAJOR >= 3
|
2022-03-06 21:30:44 +00:00
|
|
|
jas_cleanup_thread();
|
|
|
|
jas_cleanup_library();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-03-07 16:42:22 +00:00
|
|
|
int grib_jasper_decode(grib_context* c, unsigned char* buf, const size_t* buflen, double* values, const size_t* n_vals)
|
2016-08-03 10:30:19 +00:00
|
|
|
{
|
2022-03-06 21:30:44 +00:00
|
|
|
/* jas_setdbglevel(99999); */
|
2020-01-22 13:10:59 +00:00
|
|
|
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;
|
2022-03-07 13:54:10 +00:00
|
|
|
int jaserr = 0; /* 0 means success */
|
2022-03-06 21:30:44 +00:00
|
|
|
|
2022-03-07 16:18:30 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-03-06 21:30:44 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
jpeg = jas_stream_memopen((char*)buf, *buflen);
|
|
|
|
if (!jpeg) {
|
2013-09-30 13:08:41 +00:00
|
|
|
code = GRIB_DECODING_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2022-03-07 16:18:30 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_DEBUG, "grib_jasper_decode: JasPer version %s", jas_getversion());
|
2022-03-06 21:30:44 +00:00
|
|
|
|
|
|
|
image = ecc_jasper_decode(jpeg);
|
2020-01-22 13:10:59 +00:00
|
|
|
if (!image) {
|
2013-09-30 13:08:41 +00:00
|
|
|
code = GRIB_DECODING_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-09-30 13:08:41 +00:00
|
|
|
p = image->cmpts_[0];
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
if (image->numcmpts_ != 1) {
|
2013-09-30 13:08:41 +00:00
|
|
|
/* Image not gray scale */
|
|
|
|
code = GRIB_DECODING_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-09-30 13:08:41 +00:00
|
|
|
matrix = jas_matrix_create(jas_image_height(image), jas_image_width(image));
|
2020-01-22 13:10:59 +00:00
|
|
|
if (!matrix) {
|
2013-09-30 13:08:41 +00:00
|
|
|
code = GRIB_DECODING_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2022-03-07 13:54:10 +00:00
|
|
|
jaserr = jas_image_readcmpt(image, 0, 0, 0, jas_image_width(image), jas_image_height(image), matrix);
|
|
|
|
if (jaserr) {
|
2022-03-07 16:18:30 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_decode: Failed to read JasPer component data. JasPer error %d", jaserr);
|
2022-03-07 13:54:10 +00:00
|
|
|
code = GRIB_DECODING_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2022-03-07 16:42:22 +00:00
|
|
|
Assert(p->height_ * p->width_ == *n_vals);
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
k = 0;
|
|
|
|
for (i = 0; i < p->height_; i++)
|
|
|
|
for (j = 0; j < p->width_; j++) {
|
2013-09-30 13:08:41 +00:00
|
|
|
values[k++] = matrix->rows_[i][j];
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
|
|
|
cleanup:
|
2020-01-22 13:10:59 +00:00
|
|
|
if (matrix)
|
|
|
|
jas_matrix_destroy(matrix);
|
|
|
|
if (image)
|
|
|
|
jas_image_destroy(image);
|
|
|
|
if (jpeg)
|
|
|
|
jas_stream_close(jpeg);
|
2022-03-06 21:30:44 +00:00
|
|
|
ecc_jasper_cleanup();
|
|
|
|
|
2013-09-30 13:08:41 +00:00
|
|
|
return code;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
int grib_jasper_encode(grib_context* c, j2k_encode_helper* helper)
|
2016-08-03 10:30:19 +00:00
|
|
|
{
|
2013-09-30 13:08:41 +00:00
|
|
|
int code = GRIB_SUCCESS;
|
2022-03-07 13:54:10 +00:00
|
|
|
int jaserr = 0;
|
2013-09-30 13:08:41 +00:00
|
|
|
|
|
|
|
char opts[MAXOPTSSIZE];
|
|
|
|
double reference_value = helper->reference_value;
|
2020-01-22 13:10:59 +00:00
|
|
|
double decimal = helper->decimal;
|
|
|
|
double divisor = helper->divisor;
|
|
|
|
const double* values = helper->values;
|
|
|
|
long no_values = helper->no_values;
|
2013-09-30 13:08:41 +00:00
|
|
|
long bits8;
|
|
|
|
int i;
|
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
size_t buflen = 0;
|
|
|
|
unsigned char* encoded = NULL;
|
|
|
|
unsigned char* p = NULL;
|
2013-09-30 13:08:41 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
jas_image_t image = { 0 };
|
|
|
|
jas_stream_t* jpcstream = 0;
|
|
|
|
jas_stream_t* istream = 0;
|
2020-01-22 14:48:06 +00:00
|
|
|
jas_image_cmpt_t cmpt = {0,};
|
2020-01-22 13:10:59 +00:00
|
|
|
jas_image_cmpt_t* pcmpt = 0;
|
2013-09-30 13:08:41 +00:00
|
|
|
|
|
|
|
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;
|
2016-12-06 11:51:41 +00:00
|
|
|
|
|
|
|
#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 */
|
2020-01-22 13:10:59 +00:00
|
|
|
image.inmem_ = 1;
|
2016-12-06 11:51:41 +00:00
|
|
|
#endif
|
2013-09-30 13:08:41 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
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;
|
2013-09-30 13:08:41 +00:00
|
|
|
|
|
|
|
/* Simple packing encoding */
|
2020-01-22 13:10:59 +00:00
|
|
|
bits8 = (helper->bits_per_value + 7) / 8 * 8;
|
2013-09-30 13:08:41 +00:00
|
|
|
Assert(bits8 > 0);
|
2020-01-22 13:10:59 +00:00
|
|
|
encoded = (unsigned char*)grib_context_malloc_clear(c, bits8 / 8 * no_values);
|
2013-09-30 13:08:41 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
if (!encoded) {
|
2013-09-30 13:08:41 +00:00
|
|
|
code = GRIB_OUT_OF_MEMORY;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
buflen = 0;
|
2016-08-03 10:30:19 +00:00
|
|
|
p = encoded;
|
2013-09-30 13:08:41 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
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;
|
2013-09-30 13:08:41 +00:00
|
|
|
*p = (unsigned_val >> blen);
|
|
|
|
p++;
|
|
|
|
buflen++;
|
|
|
|
}
|
|
|
|
}
|
2022-03-06 21:30:44 +00:00
|
|
|
|
|
|
|
ecc_jasper_initialise();
|
|
|
|
|
2013-09-30 13:08:41 +00:00
|
|
|
opts[0] = 0;
|
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
if (helper->compression != 0) {
|
2013-09-30 13:08:41 +00:00
|
|
|
/* Lossy */
|
2022-11-10 21:51:06 +00:00
|
|
|
snprintf(opts, MAXOPTSSIZE, "mode=real\nrate=%f", 1.0 / helper->compression);
|
2013-09-30 13:08:41 +00:00
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-09-30 13:08:41 +00:00
|
|
|
Assert(cmpt.width_ * cmpt.height_ * cmpt.cps_ == buflen);
|
2022-03-07 16:18:30 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_DEBUG, "grib_jasper_encode: JasPer version %s", jas_getversion());
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
pcmpt = &cmpt;
|
|
|
|
image.cmpts_ = &pcmpt;
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
istream = jas_stream_memopen((char*)encoded, buflen);
|
|
|
|
cmpt.stream_ = istream;
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
jpcstream = jas_stream_memopen((char*)helper->jpeg_buffer, helper->buffer_size);
|
2022-03-06 21:30:44 +00:00
|
|
|
|
|
|
|
jaserr = ecc_jasper_encode(&image, jpcstream, opts);
|
2022-03-07 13:54:10 +00:00
|
|
|
if (jaserr) {
|
|
|
|
/* Failed to encode. Increase the number of guard bits */
|
2020-01-22 13:10:59 +00:00
|
|
|
strcat(opts, "\nnumgbits=4");
|
2022-03-07 16:18:30 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_encode: JasPer error %d, increasing the number of guard bits", jaserr);
|
2020-01-22 13:10:59 +00:00
|
|
|
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);
|
2022-03-06 21:30:44 +00:00
|
|
|
jaserr = ecc_jasper_encode(&image, jpcstream, opts);
|
2013-09-30 13:08:41 +00:00
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2022-03-07 13:54:10 +00:00
|
|
|
if (jaserr) {
|
2022-03-07 16:18:30 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_encode: Failed to encode. JasPer error %d", jaserr);
|
2013-09-30 13:08:41 +00:00
|
|
|
code = GRIB_ENCODING_ERROR;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2013-09-30 13:08:41 +00:00
|
|
|
helper->jpeg_length = jpcstream->rwcnt_;
|
2020-02-11 14:39:09 +00:00
|
|
|
jas_stream_close(istream);
|
2020-01-22 13:10:59 +00:00
|
|
|
istream = 0;
|
2020-02-11 14:39:09 +00:00
|
|
|
jas_stream_close(jpcstream);
|
2020-01-22 13:10:59 +00:00
|
|
|
jpcstream = 0;
|
2013-03-25 12:04:10 +00:00
|
|
|
|
|
|
|
cleanup:
|
2020-01-22 13:10:59 +00:00
|
|
|
grib_context_free(c, encoded);
|
|
|
|
if (istream)
|
|
|
|
jas_stream_close(istream);
|
|
|
|
if (jpcstream)
|
|
|
|
jas_stream_close(jpcstream);
|
2022-03-06 21:30:44 +00:00
|
|
|
ecc_jasper_cleanup();
|
2013-09-30 13:08:41 +00:00
|
|
|
return code;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2023-12-26 17:54:09 +00:00
|
|
|
#else // HAVE_LIBJASPER
|
2013-03-25 12:04:10 +00:00
|
|
|
|
2022-03-07 16:44:55 +00:00
|
|
|
int grib_jasper_decode(grib_context* c, unsigned char* buf, const size_t* buflen, double* val, const size_t* n_vals)
|
2016-08-03 10:30:19 +00:00
|
|
|
{
|
2023-12-26 17:54:09 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_decode: JasPer JPEG support not enabled.");
|
2019-08-15 14:58:52 +00:00
|
|
|
return GRIB_FUNCTIONALITY_NOT_ENABLED;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 13:10:59 +00:00
|
|
|
int grib_jasper_encode(grib_context* c, j2k_encode_helper* helper)
|
2016-08-03 10:30:19 +00:00
|
|
|
{
|
2023-12-26 17:54:09 +00:00
|
|
|
grib_context_log(c, GRIB_LOG_ERROR, "grib_jasper_encode: JasPer JPEG support not enabled.");
|
2019-08-15 14:58:52 +00:00
|
|
|
return GRIB_FUNCTIONALITY_NOT_ENABLED;
|
2013-03-25 12:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|