Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
jp2kio.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
103#ifdef HAVE_CONFIG_H
104#include <config_auto.h>
105#endif /* HAVE_CONFIG_H */
106
107#include <string.h>
108#include "allheaders.h"
109
110/* --------------------------------------------*/
111#if HAVE_LIBJP2K /* defined in environ.h */
112/* --------------------------------------------*/
113
114 /* Leptonica supports versions 2.1 and later */
115#ifdef LIBJP2K_HEADER
116#include LIBJP2K_HEADER
117#else
118#include <openjpeg.h>
119#endif
120
122typedef struct OpjBuffer
123{
124 l_uint8 *data;
125 size_t size;
126 size_t pos;
127 size_t len;
128} OpjBuffer;
129
130 /* Static converter pix --> opj_image. Used for compressing pix,
131 * because the codec works on data stored in their raster format. */
132static opj_image_t *pixConvertToOpjImage(PIX *pix);
133
134 /* Static generator of opj_stream from a memory buffer. */
135static opj_stream_t *opjCreateMemoryStream(OpjBuffer *buf, l_int32 is_read);
136
137 /* Static generator of opj_stream from file stream.
138 * In 2.0.1, this functionality is provided by
139 * opj_stream_create_default_file_stream(),
140 * but it was removed in 2.1.0. Because we must have either
141 * a file stream or a memory interface to the compressed data,
142 * it is necessary to recreate the stream interface here. */
143static opj_stream_t *opjCreateStream(FILE *fp, l_int32 is_read);
144
145
146/*---------------------------------------------------------------------*
147 * Callback event handlers *
148 *---------------------------------------------------------------------*/
149static void error_callback(const char *msg, void *client_data) {
150 (void)client_data;
151 fprintf(stdout, "[ERROR] %s", msg);
152}
153
154static void warning_callback(const char *msg, void *client_data) {
155 (void)client_data;
156 fprintf(stdout, "[WARNING] %s", msg);
157}
158
159static void info_callback(const char *msg, void *client_data) {
160 (void)client_data;
161 fprintf(stdout, "[INFO] %s", msg);
162}
163
164
165/*---------------------------------------------------------------------*
166 * Read jp2k from file (special function) *
167 *---------------------------------------------------------------------*/
208PIX *
209pixReadJp2k(const char *filename,
210 l_uint32 reduction,
211 BOX *box,
212 l_int32 hint,
213 l_int32 debug)
214{
215FILE *fp;
216PIX *pix;
217
218 if (!filename)
219 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL);
220
221 if ((fp = fopenReadStream(filename)) == NULL)
222 return (PIX *)ERROR_PTR_1("image file not found",
223 filename, __func__, NULL);
224 pix = pixReadStreamJp2k(fp, reduction, box, hint, debug);
225 fclose(fp);
226
227 if (!pix)
228 return (PIX *)ERROR_PTR_1("image not returned",
229 filename, __func__, NULL);
230 return pix;
231}
232
233
249PIX *
250pixReadStreamJp2k(FILE *fp,
251 l_uint32 reduction,
252 BOX *box,
253 l_int32 hint,
254 l_int32 debug)
255{
256l_uint8 *data;
257size_t size;
258PIX *pix;
259
260 if (!fp)
261 return (PIX *)ERROR_PTR("fp not defined", __func__, NULL);
262
263 /* fgetJp2kResolution() would read the whole stream anyway,
264 * so we might as well start off by doing that */
265 rewind(fp);
266 if ((data = l_binaryReadStream(fp, &size)) == NULL)
267 return (PIX *)ERROR_PTR("data not read", __func__, NULL);
268
269 pix = pixReadMemJp2k(data, size, reduction, box, hint, debug);
270
271 LEPT_FREE(data);
272 return pix;
273}
274
275
276static PIX *
277pixReadMemJp2kCore(const l_uint8 *bytes,
278 size_t nbytes,
279 l_uint32 reduction,
280 BOX *box,
281 l_int32 hint,
282 l_int32 debug)
283{
284const char *opjVersion;
285l_int32 i, j, index, bx, by, bw, bh, val, rval, gval, bval, aval;
286l_int32 w, h, wpl, bps, spp, xres, yres, reduce, prec, colorspace;
287l_int32 codec; /* L_J2K_CODEC or L_JP2_CODEC */
288l_uint32 pixel;
289l_uint32 *data, *line;
290opj_dparameters_t parameters; /* decompression parameters */
291opj_image_t *image = NULL;
292opj_codec_t *l_codec = NULL; /* handle to decompressor */
293opj_stream_t *l_stream = NULL; /* opj stream */
294PIX *pix = NULL;
295OpjBuffer buffer;
296
297 opjVersion = opj_version();
298 if (!opjVersion || opjVersion[0] == '\0')
299 return (PIX *)ERROR_PTR("opj version not defined", __func__, NULL);
300 if (opjVersion[0] - 0x30 < 2 ||
301 (opjVersion[0] == '2' && opjVersion[2] - 0x30 == 0)) {
302 L_ERROR("version is %s; must be 2.1 or higher\n", __func__, opjVersion);
303 return NULL;
304 }
305
306 /* Get the resolution, bits/sample and codec type */
307 readResolutionMemJp2k(bytes, nbytes, &xres, &yres);
308 readHeaderMemJp2k(bytes, nbytes, NULL, NULL, &bps, NULL, &codec);
309 if (codec != L_J2K_CODEC && codec != L_JP2_CODEC) {
310 L_ERROR("valid codec not identified\n", __func__);
311 return NULL;
312 }
313
314 if (bps != 8) {
315 L_ERROR("found %d bps; can only handle 8 bps\n", __func__, bps);
316 return NULL;
317 }
318
319 /* Set decoding parameters to default values */
320 opj_set_default_decoder_parameters(&parameters);
321
322 /* Find and set the reduce parameter, which is log2(reduction).
323 * Valid reductions are powers of 2, and are determined when the
324 * compressed string is made. A request for an invalid reduction
325 * will cause an error in opj_read_header(), and no image will
326 * be returned. */
327 for (reduce = 0; (1L << reduce) < reduction; reduce++) { }
328 if ((1L << reduce) != reduction) {
329 L_ERROR("invalid reduction %d; not power of 2\n", __func__, reduction);
330 return NULL;
331 }
332 parameters.cp_reduce = reduce;
333
334 /* Get a decoder handle */
335 if (codec == L_JP2_CODEC)
336 l_codec = opj_create_decompress(OPJ_CODEC_JP2);
337 else if (codec == L_J2K_CODEC)
338 l_codec = opj_create_decompress(OPJ_CODEC_J2K);
339 if (!l_codec) {
340 L_ERROR("failed to make the codec\n", __func__);
341 return NULL;
342 }
343
344 /* Catch and report events using callbacks */
345 if (debug) {
346 opj_set_info_handler(l_codec, info_callback, NULL);
347 opj_set_warning_handler(l_codec, warning_callback, NULL);
348 opj_set_error_handler(l_codec, error_callback, NULL);
349 }
350
351 /* Setup the decoding parameters using user parameters */
352 if (!opj_setup_decoder(l_codec, &parameters)){
353 L_ERROR("failed to set up decoder\n", __func__);
354 opj_destroy_codec(l_codec);
355 return NULL;
356 }
357
358 /* Open decompression 'stream'. */
359 buffer.data = (l_uint8 *)bytes;
360 buffer.size = nbytes;
361 buffer.len = nbytes;
362 buffer.pos = 0;
363 if ((l_stream = opjCreateMemoryStream(&buffer, 1)) == NULL) {
364 L_ERROR("failed to open the stream\n", __func__);
365 opj_destroy_codec(l_codec);
366 return NULL;
367 }
368
369 /* Read the main header of the codestream and, if necessary,
370 * the JP2 boxes */
371 if(!opj_read_header(l_stream, l_codec, &image)){
372 L_ERROR("failed to read the header\n", __func__);
373 opj_stream_destroy(l_stream);
374 opj_destroy_codec(l_codec);
375 opj_image_destroy(image);
376 return NULL;
377 }
378
379 /* Set up to decode a rectangular region */
380 if (box) {
381 boxGetGeometry(box, &bx, &by, &bw, &bh);
382 if (!opj_set_decode_area(l_codec, image, bx, by,
383 bx + bw, by + bh)) {
384 L_ERROR("failed to set the region for decoding\n", __func__);
385 opj_stream_destroy(l_stream);
386 opj_destroy_codec(l_codec);
387 opj_image_destroy(image);
388 return NULL;
389 }
390 }
391
392 /* Get the decoded image */
393 if (!(opj_decode(l_codec, l_stream, image) &&
394 opj_end_decompress(l_codec, l_stream))) {
395 L_ERROR("failed to decode the image\n", __func__);
396 opj_destroy_codec(l_codec);
397 opj_stream_destroy(l_stream);
398 opj_image_destroy(image);
399 return NULL;
400 }
401
402 /* Finished with the byte stream and the codec */
403 opj_stream_destroy(l_stream);
404 opj_destroy_codec(l_codec);
405
406 /* Get the image parameters */
407 spp = image->numcomps;
408 w = image->comps[0].w;
409 h = image->comps[0].h;
410 prec = image->comps[0].prec;
411 if (prec != bps)
412 L_WARNING("precision %d != bps %d!\n", __func__, prec, bps);
413 if (debug) {
414 L_INFO("w = %d, h = %d, bps = %d, spp = %d\n",
415 __func__, w, h, bps, spp);
416 colorspace = image->color_space;
417 if (colorspace == OPJ_CLRSPC_SRGB)
418 L_INFO("colorspace is sRGB\n", __func__);
419 else if (colorspace == OPJ_CLRSPC_GRAY)
420 L_INFO("colorspace is grayscale\n", __func__);
421 else if (colorspace == OPJ_CLRSPC_SYCC)
422 L_INFO("colorspace is YUV\n", __func__);
423 }
424
425 /* Convert the image to a pix */
426 if (spp == 1)
427 pix = pixCreate(w, h, 8);
428 else
429 pix = pixCreate(w, h, 32);
430 pixSetInputFormat(pix, IFF_JP2);
431 pixSetResolution(pix, xres, yres);
432 data = pixGetData(pix);
433 wpl = pixGetWpl(pix);
434 index = 0;
435 if (spp == 1) {
436 for (i = 0; i < h; i++) {
437 line = data + i * wpl;
438 for (j = 0; j < w; j++) {
439 val = image->comps[0].data[index];
440 SET_DATA_BYTE(line, j, val);
441 index++;
442 }
443 }
444 } else if (spp == 2) { /* convert to RGBA */
445 for (i = 0; i < h; i++) {
446 line = data + i * wpl;
447 for (j = 0; j < w; j++) {
448 val = image->comps[0].data[index];
449 aval = image->comps[1].data[index];
450 composeRGBAPixel(val, val, val, aval, &pixel);
451 line[j] = pixel;
452 index++;
453 }
454 }
455 } else if (spp >= 3) {
456 for (i = 0; i < h; i++) {
457 line = data + i * wpl;
458 for (j = 0; j < w; j++) {
459 rval = image->comps[0].data[index];
460 gval = image->comps[1].data[index];
461 bval = image->comps[2].data[index];
462 if (spp == 3) {
463 composeRGBPixel(rval, gval, bval, &pixel);
464 } else { /* spp == 4 */
465 aval = image->comps[3].data[index];
466 composeRGBAPixel(rval, gval, bval, aval, &pixel);
467 }
468 line[j] = pixel;
469 index++;
470 }
471 }
472 }
473
474 /* Free the opj image data structure */
475 opj_image_destroy(image);
476
477 return pix;
478}
479
480
481/*---------------------------------------------------------------------*
482 * Write jp2k to file *
483 *---------------------------------------------------------------------*/
520l_ok
521pixWriteJp2k(const char *filename,
522 PIX *pix,
523 l_int32 quality,
524 l_int32 nlevels,
525 l_int32 hint,
526 l_int32 debug)
527{
528FILE *fp;
529
530 if (!pix)
531 return ERROR_INT("pix not defined", __func__, 1);
532 if (!filename)
533 return ERROR_INT("filename not defined", __func__, 1);
534
535 if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
536 return ERROR_INT_1("stream not opened", filename, __func__, 1);
537
538 if (pixWriteStreamJp2k(fp, pix, quality, nlevels, L_JP2_CODEC,
539 hint, debug)) {
540 fclose(fp);
541 return ERROR_INT_1("pix not written to stream", filename, __func__, 1);
542 }
543
544 fclose(fp);
545 return 0;
546}
547
548
565static l_ok
566pixWriteOpjStreamJp2k(opj_stream_t *l_stream,
567 PIX *pix,
568 l_int32 quality,
569 l_int32 nlevels,
570 l_int32 codec,
571 l_int32 hint,
572 l_int32 debug)
573{
574l_int32 i, w, h, d, depth, channels, success;
575l_float64 snr;
576const char *opjVersion;
577PIX *pixs;
578opj_cparameters_t parameters; /* compression parameters */
579opj_codec_t* l_codec = NULL;;
580opj_image_t *image = NULL;
581
582 if (!l_stream)
583 return ERROR_INT("stream not open", __func__, 1);
584 if (!pix)
585 return ERROR_INT("pix not defined", __func__, 1);
586
587 snr = (l_float64)quality;
588 if (snr <= 0.0) snr = 34.0; /* default */
589 if (snr < 27.0)
590 L_WARNING("SNR = %d < 27; very low\n", __func__, (l_int32)snr);
591 if (snr == 100.0) snr = 0.0; /* for lossless */
592 if (snr > 45.0) {
593 L_WARNING("SNR > 45; using lossless encoding\n", __func__);
594 snr = 0.0;
595 }
596
597 if (nlevels == 0) nlevels = 6; /* default */
598 if (nlevels < 6) {
599 L_WARNING("nlevels = %d < 6; setting to 6\n", __func__, nlevels);
600 nlevels = 6;
601 }
602 if (nlevels > 7) {
603 L_WARNING("nlevels = %d > 7; setting to 7\n", __func__, nlevels);
604 nlevels = 7;
605 }
606
607 if (codec != L_JP2_CODEC && codec != L_J2K_CODEC)
608 return ERROR_INT("valid codec not identified\n", __func__, 1);
609
610 opjVersion = opj_version();
611 if (!opjVersion || opjVersion[0] == '\0')
612 return ERROR_INT("opj version not defined", __func__, 1);
613 if (opjVersion[0] - 0x30 < 2 ||
614 (opjVersion[0] == '2' && opjVersion[2] - 0x30 == 0)) {
615 L_ERROR("version is %s; must be 2.1 or higher\n", __func__, opjVersion);
616 return 1;
617 }
618
619 /* Remove colormap if it exists; result is 8 or 32 bpp */
620 pixGetDimensions(pix, &w, &h, &d);
621 if (d == 24) {
622 pixs = pixConvert24To32(pix);
623 } else if (d == 32) {
624 pixs = pixClone(pix);
625 } else if (pixGetColormap(pix) == NULL) {
626 pixs = pixConvertTo8(pix, 0);
627 } else { /* colormap */
628 L_INFO("removing colormap; may be better to compress losslessly\n",
629 __func__);
630 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
631 }
632 depth = pixGetDepth(pixs); /* 8 or 32 */
633
634 /* Reduce nlevels if the image has at least one small dimension */
635 for (i = 1; i < 7; i++) {
636 if ((w < (1 << i)) || (h < (1 << i))) {
637 if (i < nlevels) {
638 L_INFO("small image: w = %d, h = %d; setting nlevels to %d\n",
639 __func__, w, h, i);
640 nlevels = i;
641 }
642 break;
643 }
644 }
645
646 /* Convert to opj image format. */
647 pixSetPadBits(pixs, 0);
648 image = pixConvertToOpjImage(pixs);
649 pixDestroy(&pixs);
650
651 /* Set encoding parameters to default values.
652 * We use one layer with the input SNR. */
653 opj_set_default_encoder_parameters(&parameters);
654 parameters.cp_fixed_quality = 1;
655 parameters.cp_disto_alloc = 0;
656 parameters.tcp_distoratio[0] = snr;
657 parameters.tcp_numlayers = 1;
658 parameters.numresolution = nlevels;
659 channels = (depth == 32) ? 3 : 1;
660 parameters.tcp_mct = (channels == 3) ? 1 : 0;
661
662 /* Create comment for codestream */
663 if (parameters.cp_comment == NULL) {
664 const char comment1[] = "Created by Leptonica, version ";
665 const char comment2[] = "; using OpenJPEG, version ";
666 size_t len1 = strlen(comment1);
667 size_t len2 = strlen(comment2);
668 char *version1 = getLeptonicaVersion();
669 const char *version2 = opj_version();
670 len1 += len2 + strlen(version1) + strlen(version2) + 1;
671 parameters.cp_comment = (char *)LEPT_MALLOC(len1);
672 snprintf(parameters.cp_comment, len1, "%s%s%s%s", comment1, version1,
673 comment2, version2);
674 LEPT_FREE(version1);
675 }
676
677 /* Get the encoder handle */
678 if (codec == L_JP2_CODEC)
679 l_codec = opj_create_compress(OPJ_CODEC_JP2);
680 else /* codec == L_J2K_CODEC */
681 l_codec = opj_create_compress(OPJ_CODEC_J2K);
682 if (!l_codec) {
683 opj_image_destroy(image);
684 LEPT_FREE(parameters.cp_comment);
685 return ERROR_INT("failed to get the encoder handle\n", __func__, 1);
686 }
687
688 /* Catch and report events using callbacks */
689 if (debug) {
690 opj_set_info_handler(l_codec, info_callback, NULL);
691 opj_set_warning_handler(l_codec, warning_callback, NULL);
692 opj_set_error_handler(l_codec, error_callback, NULL);
693 }
694
695 /* Set up the encoder */
696 if (!opj_setup_encoder(l_codec, &parameters, image)) {
697 opj_destroy_codec(l_codec);
698 opj_image_destroy(image);
699 LEPT_FREE(parameters.cp_comment);
700 return ERROR_INT("failed to set up the encoder\n", __func__, 1);
701 }
702
703 /* Set the resolution (TBD) */
704
705 /* Encode the image into the l_stream data interface */
706 if (!opj_start_compress(l_codec, image, l_stream)) {
707 opj_destroy_codec(l_codec);
708 opj_image_destroy(image);
709 LEPT_FREE(parameters.cp_comment);
710 return ERROR_INT("opj_start_compress failed\n", __func__, 1);
711 }
712 if (!opj_encode(l_codec, l_stream)) {
713 opj_destroy_codec(l_codec);
714 opj_image_destroy(image);
715 LEPT_FREE(parameters.cp_comment);
716 return ERROR_INT("opj_encode failed\n", __func__, 1);
717 }
718 success = opj_end_compress(l_codec, l_stream);
719
720 /* Clean up */
721 opj_destroy_codec(l_codec);
722 opj_image_destroy(image);
723 LEPT_FREE(parameters.cp_comment);
724 if (success)
725 return 0;
726 else
727 return ERROR_INT("opj_end_compress failed\n", __func__, 1);
728}
729
730
749l_ok
750pixWriteStreamJp2k(FILE *fp,
751 PIX *pix,
752 l_int32 quality,
753 l_int32 nlevels,
754 l_int32 codec,
755 l_int32 hint,
756 l_int32 debug)
757{
758l_ok ok;
759opj_stream_t *l_stream;
760
761 if (!fp)
762 return ERROR_INT("stream not open", __func__, 1);
763
764 /* Open a compression stream for writing, borrowed from
765 * the 2.0 implementation because the file stream interface
766 * was removed in 2.1. */
767 rewind(fp);
768 if ((l_stream = opjCreateStream(fp, 0)) == NULL)
769 return ERROR_INT("failed to open l_stream\n", __func__, 1);
770
771 ok = pixWriteOpjStreamJp2k(l_stream, pix, quality, nlevels,
772 codec, hint, debug);
773
774 /* Clean up */
775 opj_stream_destroy(l_stream);
776 return ok;
777}
778
779
792static opj_image_t *
793pixConvertToOpjImage(PIX *pix)
794{
795l_int32 i, j, k, w, h, d, spp, wpl;
796OPJ_COLOR_SPACE colorspace;
797l_int32 *ir = NULL;
798l_int32 *ig = NULL;
799l_int32 *ib = NULL;
800l_int32 *ia = NULL;
801l_uint32 *line, *data;
802opj_image_t *image;
803opj_image_cmptparm_t cmptparm[4];
804
805 if (!pix)
806 return (opj_image_t *)ERROR_PTR("pix not defined", __func__, NULL);
807 pixGetDimensions(pix, &w, &h, &d);
808 if (d != 8 && d != 32) {
809 L_ERROR("invalid depth: %d\n", __func__, d);
810 return NULL;
811 }
812
813 /* Allocate the opj_image. */
814 spp = pixGetSpp(pix);
815 memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
816 for (i = 0; i < spp; i++) {
817 cmptparm[i].prec = 8;
818 cmptparm[i].sgnd = 0;
819 cmptparm[i].dx = 1;
820 cmptparm[i].dy = 1;
821 cmptparm[i].w = w;
822 cmptparm[i].h = h;
823 }
824 colorspace = (spp == 1) ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB;
825 if ((image = opj_image_create(spp, &cmptparm[0], colorspace)) == NULL)
826 return (opj_image_t *)ERROR_PTR("image not made", __func__, NULL);
827 image->x0 = 0;
828 image->y0 = 0;
829 image->x1 = w;
830 image->y1 = h;
831
832 /* Set the component pointers */
833 ir = image->comps[0].data;
834 if (spp > 1) {
835 ig = image->comps[1].data;
836 ib = image->comps[2].data;
837 }
838 if(spp == 4)
839 ia = image->comps[3].data;
840
841 /* Transfer the data from the pix */
842 data = pixGetData(pix);
843 wpl = pixGetWpl(pix);
844 for (i = 0, k = 0; i < h; i++) {
845 line = data + i * wpl;
846 for (j = 0; j < w; j++, k++) {
847 if (spp == 1) {
848 ir[k] = GET_DATA_BYTE(line, j);
849 } else if (spp > 1) {
850 ir[k] = GET_DATA_BYTE(line + j, COLOR_RED);
851 ig[k] = GET_DATA_BYTE(line + j, COLOR_GREEN);
852 ib[k] = GET_DATA_BYTE(line + j, COLOR_BLUE);
853 }
854 if (spp == 4)
855 ia[k] = GET_DATA_BYTE(line + j, L_ALPHA_CHANNEL);
856 }
857 }
858
859 return image;
860}
861
862
863/*---------------------------------------------------------------------*
864 * Read/write to memory *
865 *---------------------------------------------------------------------*/
882PIX *
883pixReadMemJp2k(const l_uint8 *data,
884 size_t size,
885 l_uint32 reduction,
886 BOX *box,
887 l_int32 hint,
888 l_int32 debug)
889{
890PIX *pix;
891
892 if (!data)
893 return (PIX *)ERROR_PTR("data not defined", __func__, NULL);
894
895 pix = pixReadMemJp2kCore(data, size, reduction, box, hint, debug);
896 if (!pix) L_ERROR("pix not read\n", __func__);
897 return pix;
898}
899
900
919l_ok
920pixWriteMemJp2k(l_uint8 **pdata,
921 size_t *psize,
922 PIX *pix,
923 l_int32 quality,
924 l_int32 nlevels,
925 l_int32 hint,
926 l_int32 debug)
927{
928l_ok ok;
929opj_stream_t *l_stream;
930OpjBuffer buffer;
931
932 if (pdata) *pdata = NULL;
933 if (psize) *psize = 0;
934 if (!pdata)
935 return ERROR_INT("&data not defined", __func__, 1 );
936 if (!psize)
937 return ERROR_INT("&size not defined", __func__, 1 );
938 if (!pix)
939 return ERROR_INT("&pix not defined", __func__, 1 );
940
941 buffer.pos = 0;
942 buffer.len = 0;
943 buffer.size = OPJ_J2K_STREAM_CHUNK_SIZE;
944 buffer.data = (l_uint8 *)LEPT_MALLOC(buffer.size);
945 if (!buffer.data)
946 return ERROR_INT("failed to allocate buffer", __func__, 1 );
947
948 if ((l_stream = opjCreateMemoryStream(&buffer, 0)) == NULL) {
949 return ERROR_INT("failed to open l_stream\n", __func__, 1);
950 }
951
952 ok = pixWriteOpjStreamJp2k(l_stream, pix, quality, nlevels, L_JP2_CODEC,
953 hint, debug);
954
955 /* Clean up */
956 opj_stream_destroy(l_stream);
957
958 if (!ok) {
959 *pdata = buffer.data;
960 *psize = buffer.len;
961 } else {
962 LEPT_FREE(buffer.data);
963 }
964
965 return ok;
966}
967
968
969/*---------------------------------------------------------------------*
970 * Static functions for the memory stream interface *
971 *---------------------------------------------------------------------*/
972static OPJ_SIZE_T
973opj_read_from_buffer(void *p_buffer, OPJ_SIZE_T p_nb_bytes, OpjBuffer *pbuf) {
974 if (pbuf->pos > pbuf->len)
975 return (OPJ_SIZE_T) - 1;
976
977 OPJ_SIZE_T l_nb_read = pbuf->len - pbuf->pos;
978 if (l_nb_read > p_nb_bytes)
979 l_nb_read = p_nb_bytes;
980 memcpy(p_buffer, pbuf->data + pbuf->pos, l_nb_read);
981 pbuf->pos += l_nb_read;
982 return l_nb_read ? l_nb_read : (OPJ_SIZE_T) - 1;
983}
984
985static OPJ_SIZE_T
986opj_write_from_buffer(const void *p_buffer, OPJ_SIZE_T p_nb_bytes,
987 OpjBuffer *pbuf) {
988 size_t newpos = pbuf->pos + p_nb_bytes;
989 if (newpos > pbuf->size) {
990 size_t oldsize = pbuf->size;
991 size_t newsize = oldsize * 2;
992 if (newsize < newpos)
993 newsize = newpos;
994 if (newsize <= 0) {
995 L_ERROR("buffer too large\n", __func__);
996 return 0;
997 }
998
999 l_uint8 *newdata = (l_uint8 *)LEPT_REALLOC(pbuf->data, newsize);
1000 if (!newdata) {
1001 L_ERROR("out of memory\n", __func__);
1002 return 0;
1003 }
1004
1005 /* clear out any garbage left by realloc */
1006 memset(newdata + oldsize, 0, newsize - oldsize);
1007 pbuf->data = newdata;
1008 pbuf->size = newsize;
1009 }
1010
1011 memcpy(pbuf->data + pbuf->pos, p_buffer, p_nb_bytes);
1012 pbuf->pos = newpos;
1013 if (pbuf->len < newpos)
1014 pbuf->len = newpos;
1015 return p_nb_bytes;
1016}
1017
1018static OPJ_OFF_T
1019opj_skip_from_buffer(OPJ_OFF_T offset, OpjBuffer *pbuf) {
1020 pbuf->pos += offset;
1021 return offset;
1022}
1023
1024static l_int32
1025opj_seek_from_buffer(OPJ_OFF_T offset, OpjBuffer *pbuf) {
1026 pbuf->pos = offset;
1027 return 1;
1028}
1029
1030
1031/*---------------------------------------------------------------------*
1032 * Static generator of opj_stream from memory buffer *
1033 *---------------------------------------------------------------------*/
1034static opj_stream_t *
1035opjCreateMemoryStream(OpjBuffer *pbuf,
1036 l_int32 is_read_stream)
1037{
1038opj_stream_t *l_stream;
1039
1040 if (!pbuf)
1041 return (opj_stream_t *)ERROR_PTR("pbuf not defined", __func__, NULL);
1042
1043 l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, is_read_stream);
1044 if (!l_stream)
1045 return (opj_stream_t *)ERROR_PTR("stream not made", __func__, NULL);
1046
1047 opj_stream_set_user_data(l_stream, pbuf,
1048 (opj_stream_free_user_data_fn)NULL);
1049 opj_stream_set_user_data_length(l_stream, pbuf->len);
1050 opj_stream_set_read_function(l_stream,
1051 (opj_stream_read_fn)opj_read_from_buffer);
1052 opj_stream_set_skip_function(l_stream,
1053 (opj_stream_skip_fn)opj_skip_from_buffer);
1054 opj_stream_set_seek_function(l_stream,
1055 (opj_stream_seek_fn)opj_seek_from_buffer);
1056
1057 if (is_read_stream)
1058 return l_stream;
1059
1060 opj_stream_set_write_function(l_stream,
1061 (opj_stream_write_fn)opj_write_from_buffer);
1062 return l_stream;
1063}
1064
1065
1066/*---------------------------------------------------------------------*
1067 * Static functions from opj 2.0 to retain file stream interface *
1068 *---------------------------------------------------------------------*/
1069static l_uint64
1070opj_get_user_data_length(FILE *fp) {
1071 OPJ_OFF_T length = 0;
1072 fseek(fp, 0, SEEK_END);
1073 length = (OPJ_OFF_T)ftell(fp);
1074 fseek(fp, 0, SEEK_SET);
1075 return (l_uint64)length;
1076}
1077
1078static OPJ_SIZE_T
1079opj_read_from_file(void *p_buffer, OPJ_SIZE_T p_nb_bytes, FILE *fp) {
1080 OPJ_SIZE_T l_nb_read = fread(p_buffer, 1, p_nb_bytes, fp);
1081 return l_nb_read ? l_nb_read : (OPJ_SIZE_T) - 1;
1082}
1083
1084static OPJ_SIZE_T
1085opj_write_from_file(void *p_buffer, OPJ_SIZE_T p_nb_bytes, FILE *fp)
1086{
1087 return fwrite(p_buffer, 1, p_nb_bytes, fp);
1088}
1089
1090static OPJ_OFF_T
1091opj_skip_from_file(OPJ_OFF_T offset, FILE *fp) {
1092 if (fseek(fp, offset, SEEK_CUR)) {
1093 return -1;
1094 }
1095 return offset;
1096}
1097
1098static l_int32
1099opj_seek_from_file(OPJ_OFF_T offset, FILE *fp) {
1100 if (fseek(fp, offset, SEEK_SET)) {
1101 return 0;
1102 }
1103 return 1;
1104}
1105
1106
1107/*---------------------------------------------------------------------*
1108 * Static generator of opj_stream from a file stream *
1109 *---------------------------------------------------------------------*/
1110static opj_stream_t *
1111opjCreateStream(FILE *fp,
1112 l_int32 is_read_stream)
1113{
1114opj_stream_t *l_stream;
1115
1116 if (!fp)
1117 return (opj_stream_t *)ERROR_PTR("fp not defined", __func__, NULL);
1118
1119 l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, is_read_stream);
1120 if (!l_stream)
1121 return (opj_stream_t *)ERROR_PTR("stream not made", __func__, NULL);
1122
1123 opj_stream_set_user_data(l_stream, fp,
1124 (opj_stream_free_user_data_fn)NULL);
1125 opj_stream_set_user_data_length(l_stream, opj_get_user_data_length(fp));
1126 opj_stream_set_read_function(l_stream,
1127 (opj_stream_read_fn)opj_read_from_file);
1128 opj_stream_set_write_function(l_stream,
1129 (opj_stream_write_fn)opj_write_from_file);
1130 opj_stream_set_skip_function(l_stream,
1131 (opj_stream_skip_fn)opj_skip_from_file);
1132 opj_stream_set_seek_function(l_stream,
1133 (opj_stream_seek_fn)opj_seek_from_file);
1134
1135 return l_stream;
1136}
1137
1138/* --------------------------------------------*/
1139#endif /* HAVE_LIBJP2K */
1140/* --------------------------------------------*/
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
@ L_J2K_CODEC
Definition imageio.h:148
@ L_JP2_CODEC
Definition imageio.h:149
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ L_ALPHA_CHANNEL
Definition pix.h:331
@ COLOR_GREEN
Definition pix.h:329
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384