NCEPLIBS-g2c 1.9.0
Loading...
Searching...
No Matches
decenc_openjpeg.c
Go to the documentation of this file.
1
6/* Copyright 2005-2019 ECMWF.
7 *
8 * This software is licensed under the terms of the Apache Licence
9 * Version 2.0 which can be obtained at
10 * http://www.apache.org/licenses/LICENSE-2.0.
11 *
12 * In applying this licence, ECMWF does not waive the privileges and
13 * immunities granted to it by virtue of its status as an
14 * intergovernmental organisation nor does it submit to any
15 * jurisdiction.
16 */
17
18#if !defined USE_JPEG2000 && defined USE_OPENJPEG
19
20#include "grib2_int.h"
21#include "openjpeg.h"
22
23#include <assert.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
36static void openjpeg_warning(const char *msg, void *client_data)
37{
38 (void)client_data;
39 fprintf(stderr,"openjpeg: %s",msg);
40}
41
50static void openjpeg_error(const char *msg, void *client_data)
51{
52 (void)client_data;
53 fprintf(stderr,"openjpeg: %s",msg);
54}
55
64static void openjpeg_info(const char *msg, void *client_data)
65{
66 (void)msg;
67 (void)client_data;
68 /* fprintf(stderr,"openjpeg: %s",msg); */
69}
70
71/* opj_* Helper code from
72 * https://groups.google.com/forum/#!topic/openjpeg/8cebr0u7JgY
73 */
74/* These routines are added to use memory instead of a file for input and output */
75/* struct need to treat memory as a stream */
76typedef struct
77{
78 OPJ_UINT8* pData; /* our data */
79 OPJ_SIZE_T dataSize; /* how big is our data */
80 OPJ_SIZE_T offset; /* where we are currently in our data */
81} opj_memory_stream;
82
94static OPJ_SIZE_T opj_memory_stream_read(void *buffer, OPJ_SIZE_T nb_bytes, void * p_user_data)
95{
96 opj_memory_stream* mstream = (opj_memory_stream*) p_user_data; /* Our data */
97 OPJ_SIZE_T nb_bytes_read = nb_bytes; /* Amount to move to buffer */
98
99 /* Check if the current offset is outside our data buffer */
100 if (mstream->offset >= mstream->dataSize)
101 return (OPJ_SIZE_T) -1;
102
103 /* Check if we are reading more than we have */
104 if (nb_bytes > (mstream->dataSize - mstream->offset))
105 nb_bytes_read = mstream->dataSize - mstream->offset;
106
107 memcpy(buffer, &(mstream->pData[mstream->offset]), nb_bytes_read);
108 mstream->offset += nb_bytes_read; /* Update the pointer to the new location */
109 return nb_bytes_read;
110}
111
123static OPJ_SIZE_T opj_memory_stream_write(void *buffer, OPJ_SIZE_T nb_bytes, void *user_data)
124{
125 opj_memory_stream* mstream = (opj_memory_stream*) user_data; /* our data */
126 OPJ_SIZE_T nb_bytes_write = nb_bytes; /* Amount to move to buffer */
127
128 /* Check if the current offset is outside our data buffer */
129 if (mstream->offset >= mstream->dataSize)
130 return (OPJ_SIZE_T)-1;
131
132 /* Check if we are writing more than we have space for */
133 if (nb_bytes > (mstream->dataSize - mstream->offset))
134 nb_bytes_write = mstream->dataSize - mstream->offset;
135
136 /* Copy the data from the internal buffer */
137 memcpy(&(mstream->pData[mstream->offset]), buffer, nb_bytes_write);
138 mstream->offset += nb_bytes_write; /* Update the pointer to the new location */
139 return nb_bytes_write;
140}
141
152static OPJ_OFF_T opj_memory_stream_skip(OPJ_OFF_T nb_bytes, void *user_data)
153{
154 opj_memory_stream* mstream = (opj_memory_stream*) user_data;
155 OPJ_SIZE_T l_nb_bytes;
156
157 if (nb_bytes < 0)
158 return -1; /* No skipping backwards */
159 l_nb_bytes = (OPJ_SIZE_T) nb_bytes; /* Allowed because it is positive */
160 /* Do not allow jumping past the end */
161 if (l_nb_bytes > mstream->dataSize - mstream->offset)
162 l_nb_bytes = mstream->dataSize - mstream->offset;
163 mstream->offset += l_nb_bytes;
164 return (OPJ_OFF_T)l_nb_bytes; /* Return how far we jumped */
165}
166
177static OPJ_BOOL opj_memory_stream_seek(OPJ_OFF_T nb_bytes, void * user_data)
178{
179 opj_memory_stream* mstream = (opj_memory_stream*) user_data;
180
181 if (nb_bytes < 0)
182 return OPJ_FALSE; /* Not before the buffer */
183 if (nb_bytes >(OPJ_OFF_T) mstream->dataSize)
184 return OPJ_FALSE; /* Not after the buffer */
185 mstream->offset = (OPJ_SIZE_T) nb_bytes; /* Move to new position */
186 return OPJ_TRUE;
187}
188
196static void opj_memory_stream_do_nothing(void * p_user_data)
197{
198 OPJ_ARG_NOT_USED(p_user_data);
199}
200
211static opj_stream_t* opj_stream_create_default_memory_stream(opj_memory_stream* memoryStream, OPJ_BOOL is_read_stream)
212{
213 opj_stream_t* stream;
214
215 if (!(stream = opj_stream_default_create(is_read_stream)))
216 return (NULL);
217 /* Set how to work with the frame buffer */
218 if (is_read_stream)
219 opj_stream_set_read_function(stream, opj_memory_stream_read);
220 else
221 opj_stream_set_write_function(stream, opj_memory_stream_write);
222
223 opj_stream_set_seek_function(stream, opj_memory_stream_seek);
224 opj_stream_set_skip_function(stream, opj_memory_stream_skip);
225 opj_stream_set_user_data(stream, memoryStream, opj_memory_stream_do_nothing);
226 opj_stream_set_user_data_length(stream, memoryStream->dataSize);
227 return stream;
228}
229
251int dec_jpeg2000(char *injpc,g2int bufsize,g2int *outfld)
252{
253 int iret = 0;
254 OPJ_INT32 mask;
255
256 opj_stream_t *stream = NULL;
257 opj_image_t *image = NULL;
258 opj_codec_t *codec = NULL;
259
260 /* set decoding parameters to default values */
261 opj_dparameters_t parameters = {0,}; /* decompression parameters */
262 opj_set_default_decoder_parameters(&parameters);
263 parameters.decod_format = 1; /* JP2_FMT */
264
265 /* get a decoder handle */
266 codec = opj_create_decompress(OPJ_CODEC_J2K);
267
268 /* catch events using our callbacks */
269 opj_set_info_handler(codec, openjpeg_info, NULL);
270 opj_set_warning_handler(codec, openjpeg_warning, NULL);
271 opj_set_error_handler(codec, openjpeg_error,NULL);
272
273 /* initialize our memory stream */
274 opj_memory_stream mstream;
275 mstream.pData = (OPJ_UINT8 *)injpc;
276 mstream.dataSize = (OPJ_SIZE_T)bufsize;
277 mstream.offset = 0;
278 /* open a byte stream from memory stream */
279 stream = opj_stream_create_default_memory_stream( &mstream, OPJ_STREAM_READ);
280
281 /* setup the decoder decoding parameters using user parameters */
282 if (!opj_setup_decoder(codec, &parameters)) {
283 fprintf(stderr,"openjpeg: failed to setup decoder");
284 iret = -3;
285 goto cleanup;
286 }
287 if (!opj_read_header(stream, codec, &image)) {
288 fprintf(stderr,"openjpeg: failed to read the header");
289 iret = -3;
290 goto cleanup;
291 }
292 if (!opj_decode(codec, stream, image)) {
293 fprintf(stderr,"openjpeg: failed to decode");
294 iret = -3;
295 goto cleanup;
296 }
297
298 if ( (image->numcomps != 1) || (image->x1 * image->y1)==0 ) {
299 iret = -3;
300 goto cleanup;
301 }
302
303 assert(image->comps[0].sgnd == 0);
304 assert(image->comps[0].prec < sizeof(mask)*8-1);
305
306 mask = (1 << image->comps[0].prec) - 1;
307
308 for(unsigned int i = 0; i < image->comps[0].w * image->comps[0].h ; i++)
309 outfld[i] = (g2int) (image->comps[0].data[i] & mask);
310
311 if (!opj_end_decompress(codec, stream)) {
312 fprintf(stderr,"openjpeg: failed in opj_end_decompress");
313 iret = -3;
314 }
315
316cleanup:
317 /* close the byte stream */
318 if (codec) opj_destroy_codec(codec);
319 if (stream) opj_stream_destroy(stream);
320 if (image) opj_image_destroy(image);
321
322 return iret;
323}
324
358int enc_jpeg2000(unsigned char *cin, g2int width, g2int height, g2int nbits,
359 g2int ltype, g2int ratio, g2int retry, char *outjpc,
360 g2int jpclen)
361{
362 (void) retry;
363 int iret = 0;
364 const int numcomps = 1;
365
366 opj_codec_t *codec = NULL;
367 opj_image_t *image = NULL;
368 opj_stream_t *stream = NULL;
369
370 /* set encoding parameters to default values */
371 opj_cparameters_t parameters = {0,}; /* compression parameters */
372 opj_set_default_encoder_parameters(&parameters);
373
374 parameters.tcp_numlayers = 1;
375 parameters.cp_disto_alloc = 1;
376 if (ltype == 1) {
377 assert(ratio != 255);
378 parameters.tcp_rates[0] = 1.0f/(float)ratio;
379 }
380
381 /* By default numresolution = 6 (must be between 1 and 32)
382 * This may be too large for some of our datasets, eg. 1xn, so adjust ...
383 */
384 parameters.numresolution = 6;
385 while ((width < (1 << (parameters.numresolution - 1))) ||
386 (height < (1 << (parameters.numresolution - 1))))
387 {
388 parameters.numresolution--;
389 }
390
391 /* initialize image component */
392 opj_image_cmptparm_t cmptparm = {0,};
393 cmptparm.prec = (OPJ_UINT32)nbits;
394 cmptparm.bpp = (OPJ_UINT32)nbits;
395 cmptparm.sgnd = 0;
396 cmptparm.dx = 1;
397 cmptparm.dy = 1;
398 cmptparm.w = (OPJ_UINT32)width;
399 cmptparm.h = (OPJ_UINT32)height;
400
401 /* create the image */
402 image = opj_image_create(numcomps, &cmptparm, OPJ_CLRSPC_GRAY);
403 if (!image)
404 {
405 iret = -3;
406 goto cleanup;
407 }
408 image->x0 = 0;
409 image->y0 = 0;
410 image->x1 = (OPJ_UINT32)width;
411 image->y1 = (OPJ_UINT32)height;
412
413 assert(cmptparm.prec <= sizeof(image->comps[0].data[0])*8 - 1); /* BR: -1 because I don't know what happens if the sign bit is set */
414
415 /* Simple packing */
416 for (int i = 0; i < width * height; i++)
417 image->comps[0].data[i] = cin[i];
418
419 /* get a J2K compressor handle */
420 codec = opj_create_compress(OPJ_CODEC_J2K);
421
422 opj_set_info_handler(codec, openjpeg_info, NULL);
423 opj_set_warning_handler(codec, openjpeg_warning, NULL);
424 opj_set_error_handler(codec, openjpeg_error,NULL);
425
426 /* setup the encoder parameters using the current image and user parameters */
427 if (!opj_setup_encoder(codec, &parameters, image))
428 {
429 fprintf(stderr,"openjpeg: failed to setup encoder");
430 iret = -3;
431 goto cleanup;
432 }
433
434 /* open a byte stream for writing */
435 opj_memory_stream mstream;
436 mstream.pData = (OPJ_UINT8 *)outjpc;
437 mstream.offset = 0;
438 mstream.dataSize = (OPJ_SIZE_T)jpclen;
439 stream = opj_stream_create_default_memory_stream(&mstream, OPJ_STREAM_WRITE);
440 if (!stream)
441 {
442 fprintf(stderr,"openjpeg: failed create default memory stream");
443 iret = -3;
444 goto cleanup;
445 }
446
447 if (!opj_start_compress(codec, image, stream))
448 {
449 fprintf(stderr,"openjpeg: failed to setup encoder");
450 iret = -3;
451 goto cleanup;
452 }
453
454 /* encode image */
455 if (!opj_encode(codec, stream))
456 {
457 fprintf(stderr,"openjpeg: opj_encode failed");
458 iret = -3;
459 goto cleanup;
460 }
461
462 if (!opj_end_compress(codec, stream))
463 {
464 fprintf(stderr,"openjpeg: opj_end_compress failed");
465 iret = -3;
466 goto cleanup;
467 }
468 iret = (int)mstream.offset;
469
470cleanup:
471 if (codec)
472 opj_destroy_codec(codec);
473 if (stream)
474 opj_stream_destroy(stream);
475 if (image)
476 opj_image_destroy(image);
477
478 return iret;
479}
480
481#endif
int dec_jpeg2000(char *injpc, g2int bufsize, g2int *outfld)
Decode a JPEG2000 code stream specified in the JPEG2000 Part-1 standard (i.e., ISO/IEC 15444-1) using...
int enc_jpeg2000(unsigned char *cin, g2int width, g2int height, g2int nbits, g2int ltype, g2int ratio, g2int retry, char *outjpc, g2int jpclen)
Encode a grayscale image into a JPEG2000 code stream specified in the JPEG2000 Part-1 standard (i....
int64_t g2int
Long integer type.
Definition grib2.h:32
Header file with internal function prototypes NCEPLIBS-g2c library.