Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
jpegio.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
124#ifdef HAVE_CONFIG_H
125#include <config_auto.h>
126#endif /* HAVE_CONFIG_H */
127
128#include <string.h>
129#include "allheaders.h"
130#include "pix_internal.h"
131
132/* --------------------------------------------*/
133#if HAVE_LIBJPEG /* defined in environ.h */
134/* --------------------------------------------*/
135
136#include <setjmp.h>
137
138 /* jconfig.h makes the error of setting
139 * #define HAVE_STDLIB_H
140 * which conflicts with config_auto.h (where it is set to 1) and results
141 * for some gcc compiler versions in a warning. The conflict is harmless
142 * but we suppress it by undefining the variable. */
143#undef HAVE_STDLIB_H
144#include "jpeglib.h"
145
146static void jpeg_error_catch_all_1(j_common_ptr cinfo);
147static void jpeg_error_catch_all_2(j_common_ptr cinfo);
148static l_uint8 jpeg_getc(j_decompress_ptr cinfo);
149
150 /* Note: 'boolean' is defined in jmorecfg.h. We use it explicitly
151 * here because for Windows where __MINGW32__ is defined,
152 * the prototype for jpeg_comment_callback() is given as
153 * returning a boolean. */
154static boolean jpeg_comment_callback(j_decompress_ptr cinfo);
155
156 /* This is saved in the client_data field of cinfo, and used both
157 * to retrieve the comment from its callback and to handle
158 * exceptions with a longjmp. */
160 jmp_buf jmpbuf;
161 l_uint8 *comment;
162};
163
164#ifndef NO_CONSOLE_IO
165#define DEBUG_INFO 0
166#endif /* ~NO_CONSOLE_IO */
167
168
169/*---------------------------------------------------------------------*
170 * Read jpeg from file (special function) *
171 *---------------------------------------------------------------------*/
208PIX *
209pixReadJpeg(const char *filename,
210 l_int32 cmapflag,
211 l_int32 reduction,
212 l_int32 *pnwarn,
213 l_int32 hint)
214{
215l_int32 ret;
216l_uint8 *comment;
217FILE *fp;
218PIX *pix;
219
220 if (pnwarn) *pnwarn = 0;
221 if (!filename)
222 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL);
223 if (cmapflag != 0 && cmapflag != 1)
224 cmapflag = 0; /* default */
225 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
226 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL);
227
228 if ((fp = fopenReadStream(filename)) == NULL)
229 return (PIX *)ERROR_PTR_1("image file not found",
230 filename, __func__, NULL);
231 pix = pixReadStreamJpeg(fp, cmapflag, reduction, pnwarn, hint);
232 if (pix) {
233 ret = fgetJpegComment(fp, &comment);
234 if (!ret && comment)
235 pixSetText(pix, (char *)comment);
236 LEPT_FREE(comment);
237 }
238 fclose(fp);
239
240 if (!pix)
241 return (PIX *)ERROR_PTR_1("image not returned",
242 filename, __func__, NULL);
243 return pix;
244}
245
246
264PIX *
266 l_int32 cmapflag,
267 l_int32 reduction,
268 l_int32 *pnwarn,
269 l_int32 hint)
270{
271l_int32 cyan, yellow, magenta, black, nwarn;
272l_int32 i, j, k, rval, gval, bval;
273l_int32 nlinesread, abort_on_warning;
274l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
275l_uint32 *data;
276l_uint32 *line, *ppixel;
277JSAMPROW rowbuffer;
278PIX *pix;
279PIXCMAP *cmap;
280struct jpeg_decompress_struct cinfo = { 0 };
281struct jpeg_error_mgr jerr = { 0 };
282jmp_buf jmpbuf; /* must be local to the function */
283
284 if (pnwarn) *pnwarn = 0;
285 if (!fp)
286 return (PIX *)ERROR_PTR("fp not defined", __func__, NULL);
287 if (cmapflag != 0 && cmapflag != 1)
288 cmapflag = 0; /* default */
289 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
290 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL);
291
292 if (BITS_IN_JSAMPLE != 8) /* set in jmorecfg.h */
293 return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", __func__, NULL);
294
295 rewind(fp);
296 pix = NULL;
297 rowbuffer = NULL;
298
299 /* Modify the jpeg error handling to catch fatal errors */
300 cinfo.err = jpeg_std_error(&jerr);
301 jerr.error_exit = jpeg_error_catch_all_1;
302 cinfo.client_data = (void *)&jmpbuf;
303 if (setjmp(jmpbuf)) {
304 jpeg_destroy_decompress(&cinfo);
305 pixDestroy(&pix);
306 LEPT_FREE(rowbuffer);
307 return (PIX *)ERROR_PTR("internal jpeg error", __func__, NULL);
308 }
309
310 /* Initialize jpeg structs for decompression */
311 jpeg_create_decompress(&cinfo);
312 jpeg_stdio_src(&cinfo, fp);
313 jpeg_read_header(&cinfo, TRUE);
314 cinfo.scale_denom = reduction;
315 cinfo.scale_num = 1;
316 jpeg_calc_output_dimensions(&cinfo);
317 if (hint & L_JPEG_READ_LUMINANCE) {
318 cinfo.out_color_space = JCS_GRAYSCALE;
319 spp = 1;
320 L_INFO("reading luminance channel only\n", __func__);
321 } else {
322 spp = cinfo.out_color_components;
323 }
324
325 /* Allocate the image and a row buffer */
326 w = cinfo.output_width;
327 h = cinfo.output_height;
328 ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmapflag == 0);
329 cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmapflag == 0);
330 if (spp != 1 && spp != 3 && !ycck && !cmyk) {
331 jpeg_destroy_decompress(&cinfo);
332 return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK",
333 __func__, NULL);
334 }
335 if ((spp == 3 && cmapflag == 0) || ycck || cmyk) { /* rgb or 4 bpp color */
336 rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), (size_t)spp * w);
337 pix = pixCreate(w, h, 32);
338 } else { /* 8 bpp gray or colormapped */
339 rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), w);
340 pix = pixCreate(w, h, 8);
341 }
342 if (!rowbuffer || !pix) {
343 LEPT_FREE(rowbuffer);
344 rowbuffer = NULL;
345 pixDestroy(&pix);
346 jpeg_destroy_decompress(&cinfo);
347 return (PIX *)ERROR_PTR("rowbuffer or pix not made", __func__, NULL);
348 }
349 pixSetInputFormat(pix, IFF_JFIF_JPEG);
350
351 /* Initialize decompression.
352 * Set up a colormap for color quantization if requested.
353 * Arithmetic coding is rarely used on the jpeg data, but if it
354 * is, jpeg_start_decompress() handles the decoding.
355 * With corrupted encoded data, this can take an arbitrarily
356 * long time, and fuzzers are finding examples. Unfortunately,
357 * there is no way to get a callback from an error in this phase. */
358 if (spp == 1) { /* Grayscale or colormapped */
359 jpeg_start_decompress(&cinfo);
360 } else { /* Color; spp == 3 or YCCK or CMYK */
361 if (cmapflag == 0) { /* 24 bit color in 32 bit pix or YCCK/CMYK */
362 cinfo.quantize_colors = FALSE;
363 jpeg_start_decompress(&cinfo);
364 } else { /* Color quantize to 8 bits */
365 cinfo.quantize_colors = TRUE;
366 cinfo.desired_number_of_colors = 256;
367 jpeg_start_decompress(&cinfo);
368
369 /* Construct a pix cmap */
370 cmap = pixcmapCreate(8);
371 ncolors = cinfo.actual_number_of_colors;
372 for (cindex = 0; cindex < ncolors; cindex++) {
373 rval = cinfo.colormap[0][cindex];
374 gval = cinfo.colormap[1][cindex];
375 bval = cinfo.colormap[2][cindex];
376 pixcmapAddColor(cmap, rval, gval, bval);
377 }
378 pixSetColormap(pix, cmap);
379 }
380 }
381 wpl = pixGetWpl(pix);
382 data = pixGetData(pix);
383
384 /* Decompress. It appears that jpeg_read_scanlines() always
385 * returns 1 when you ask for one scanline, but we test anyway.
386 * During decoding of scanlines, warnings are issued if corrupted
387 * data is found. The default behavior is to abort reading
388 * when a warning is encountered. By setting the hint to have
389 * the same bit set as in L_JPEG_CONTINUE_WITH_BAD_DATA, e.g.,
390 * hint = hint | L_JPEG_CONTINUE_WITH_BAD_DATA
391 * reading will continue after warnings, in an attempt to return
392 * the (possibly corrupted) image. */
393 abort_on_warning = (hint & L_JPEG_CONTINUE_WITH_BAD_DATA) ? 0 : 1;
394 for (i = 0; i < h; i++) {
395 nlinesread = jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1);
396 nwarn = cinfo.err->num_warnings;
397 if (nlinesread == 0 || (abort_on_warning && nwarn > 0)) {
398 L_ERROR("read error at scanline %d; nwarn = %d\n",
399 __func__, i, nwarn);
400 pixDestroy(&pix);
401 jpeg_destroy_decompress(&cinfo);
402 LEPT_FREE(rowbuffer);
403 rowbuffer = NULL;
404 if (pnwarn) *pnwarn = nwarn;
405 return (PIX *)ERROR_PTR("bad data", __func__, NULL);
406 }
407
408 /* -- 24 bit color -- */
409 if ((spp == 3 && cmapflag == 0) || ycck || cmyk) {
410 ppixel = data + i * wpl;
411 if (spp == 3) {
412 for (j = k = 0; j < w; j++) {
413 SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]);
414 SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]);
415 SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]);
416 ppixel++;
417 }
418 } else {
419 /* This is a conversion from CMYK -> RGB that ignores
420 color profiles, and is invoked when the image header
421 claims to be in CMYK or YCCK colorspace. If in YCCK,
422 libjpeg may be doing YCCK -> CMYK under the hood.
423 To understand why the colors need to be inverted on
424 read-in for the Adobe marker, see the "Special
425 color spaces" section of "Using the IJG JPEG
426 Library" by Thomas G. Lane:
427 http://www.jpegcameras.com/libjpeg/libjpeg-3.html#ss3.1
428 The non-Adobe conversion is equivalent to:
429 rval = black - black * cyan / 255
430 ...
431 The Adobe conversion is equivalent to:
432 rval = black - black * (255 - cyan) / 255
433 ...
434 Note that cyan is the complement to red, and we
435 are subtracting the complement color (weighted
436 by black) from black. For Adobe conversions,
437 where they've already inverted the CMY but not
438 the K, we have to invert again. The results
439 must be clipped to [0 ... 255]. */
440 for (j = k = 0; j < w; j++) {
441 cyan = rowbuffer[k++];
442 magenta = rowbuffer[k++];
443 yellow = rowbuffer[k++];
444 black = rowbuffer[k++];
445 if (cinfo.saw_Adobe_marker) {
446 rval = (black * cyan) / 255;
447 gval = (black * magenta) / 255;
448 bval = (black * yellow) / 255;
449 } else {
450 rval = black * (255 - cyan) / 255;
451 gval = black * (255 - magenta) / 255;
452 bval = black * (255 - yellow) / 255;
453 }
454 rval = L_MIN(L_MAX(rval, 0), 255);
455 gval = L_MIN(L_MAX(gval, 0), 255);
456 bval = L_MIN(L_MAX(bval, 0), 255);
457 composeRGBPixel(rval, gval, bval, ppixel);
458 ppixel++;
459 }
460 }
461 } else { /* 8 bpp grayscale or colormapped pix */
462 line = data + i * wpl;
463 for (j = 0; j < w; j++)
464 SET_DATA_BYTE(line, j, rowbuffer[j]);
465 }
466 }
467
468 /* If the pixel density is neither 1 nor 2, it may not be defined.
469 * In that case, don't set the resolution. */
470 if (cinfo.density_unit == 1) { /* pixels per inch */
471 pixSetXRes(pix, cinfo.X_density);
472 pixSetYRes(pix, cinfo.Y_density);
473 } else if (cinfo.density_unit == 2) { /* pixels per centimeter */
474 pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5));
475 pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5));
476 }
477
478 if (cinfo.output_components != spp)
479 lept_stderr("output spp = %d, spp = %d\n",
480 cinfo.output_components, spp);
481
482 jpeg_finish_decompress(&cinfo);
483 jpeg_destroy_decompress(&cinfo);
484 LEPT_FREE(rowbuffer);
485 rowbuffer = NULL;
486 if (pnwarn) *pnwarn = nwarn;
487 if (nwarn > 0)
488 L_WARNING("%d warning(s) of bad data\n", __func__, nwarn);
489 return pix;
490}
491
492
493/*---------------------------------------------------------------------*
494 * Read jpeg metadata from file *
495 *---------------------------------------------------------------------*/
507l_ok
508readHeaderJpeg(const char *filename,
509 l_int32 *pw,
510 l_int32 *ph,
511 l_int32 *pspp,
512 l_int32 *pycck,
513 l_int32 *pcmyk)
514{
515l_int32 ret;
516FILE *fp;
517
518 if (pw) *pw = 0;
519 if (ph) *ph = 0;
520 if (pspp) *pspp = 0;
521 if (pycck) *pycck = 0;
522 if (pcmyk) *pcmyk = 0;
523 if (!filename)
524 return ERROR_INT("filename not defined", __func__, 1);
525 if (!pw && !ph && !pspp && !pycck && !pcmyk)
526 return ERROR_INT("no results requested", __func__, 1);
527
528 if ((fp = fopenReadStream(filename)) == NULL)
529 return ERROR_INT_1("image file not found", filename, __func__, 1);
530 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk);
531 fclose(fp);
532 return ret;
533}
534
535
547l_ok
549 l_int32 *pw,
550 l_int32 *ph,
551 l_int32 *pspp,
552 l_int32 *pycck,
553 l_int32 *pcmyk)
554{
555l_int32 spp, w, h;
556struct jpeg_decompress_struct cinfo = { 0 };
557struct jpeg_error_mgr jerr = { 0 };
558jmp_buf jmpbuf; /* must be local to the function */
559
560 if (pw) *pw = 0;
561 if (ph) *ph = 0;
562 if (pspp) *pspp = 0;
563 if (pycck) *pycck = 0;
564 if (pcmyk) *pcmyk = 0;
565 if (!fp)
566 return ERROR_INT("stream not defined", __func__, 1);
567 if (!pw && !ph && !pspp && !pycck && !pcmyk)
568 return ERROR_INT("no results requested", __func__, 1);
569
570 rewind(fp);
571
572 /* Modify the jpeg error handling to catch fatal errors */
573 cinfo.err = jpeg_std_error(&jerr);
574 cinfo.client_data = (void *)&jmpbuf;
575 jerr.error_exit = jpeg_error_catch_all_1;
576 if (setjmp(jmpbuf))
577 return ERROR_INT("internal jpeg error", __func__, 1);
578
579 /* Initialize the jpeg structs for reading the header */
580 jpeg_create_decompress(&cinfo);
581 jpeg_stdio_src(&cinfo, fp);
582 jpeg_read_header(&cinfo, TRUE);
583 jpeg_calc_output_dimensions(&cinfo);
584 spp = cinfo.out_color_components;
585 w = cinfo.output_width;
586 h = cinfo.output_height;
587 if (w < 1 || h < 1 || spp < 1 || spp > 4) {
588 jpeg_destroy_decompress(&cinfo);
589 rewind(fp);
590 return ERROR_INT("bad jpeg image parameters", __func__, 1);
591 }
592
593 if (pspp) *pspp = spp;
594 if (pw) *pw = cinfo.output_width;
595 if (ph) *ph = cinfo.output_height;
596 if (pycck) *pycck =
597 (cinfo.jpeg_color_space == JCS_YCCK && spp == 4);
598 if (pcmyk) *pcmyk =
599 (cinfo.jpeg_color_space == JCS_CMYK && spp == 4);
600
601 jpeg_destroy_decompress(&cinfo);
602 rewind(fp);
603 return 0;
604}
605
606
607/*
608 * \brief fgetJpegResolution()
609 *
610 * \param[in] fp file stream
611 * \param[out] pxres, pyres resolutions
612 * \return 0 if OK; 1 on error
613 *
614 * <pre>
615 * Notes:
616 * (1) If neither resolution field is set, this is not an error;
617 * the returned resolution values are 0 (designating 'unknown').
618 * (2) Side-effect: this rewinds the stream.
619 * </pre>
620 */
621l_int32
622fgetJpegResolution(FILE *fp,
623 l_int32 *pxres,
624 l_int32 *pyres)
625{
626struct jpeg_decompress_struct cinfo = { 0 };
627struct jpeg_error_mgr jerr = { 0 };
628jmp_buf jmpbuf; /* must be local to the function */
629
630 if (pxres) *pxres = 0;
631 if (pyres) *pyres = 0;
632 if (!pxres || !pyres)
633 return ERROR_INT("&xres and &yres not both defined", __func__, 1);
634 if (!fp)
635 return ERROR_INT("stream not opened", __func__, 1);
636
637 rewind(fp);
638
639 /* Modify the jpeg error handling to catch fatal errors */
640 cinfo.err = jpeg_std_error(&jerr);
641 cinfo.client_data = (void *)&jmpbuf;
642 jerr.error_exit = jpeg_error_catch_all_1;
643 if (setjmp(jmpbuf))
644 return ERROR_INT("internal jpeg error", __func__, 1);
645
646 /* Initialize the jpeg structs for reading the header */
647 jpeg_create_decompress(&cinfo);
648 jpeg_stdio_src(&cinfo, fp);
649 jpeg_read_header(&cinfo, TRUE);
650
651 /* It is common for the input resolution to be omitted from the
652 * jpeg file. If density_unit is not 1 or 2, simply return 0. */
653 if (cinfo.density_unit == 1) { /* pixels/inch */
654 *pxres = cinfo.X_density;
655 *pyres = cinfo.Y_density;
656 } else if (cinfo.density_unit == 2) { /* pixels/cm */
657 *pxres = (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5);
658 *pyres = (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5);
659 }
660
661 jpeg_destroy_decompress(&cinfo);
662 rewind(fp);
663 return 0;
664}
665
666
667/*
668 * \brief fgetJpegComment()
669 *
670 * \param[in] fp file stream opened for read
671 * \param[out] pcomment comment
672 * \return 0 if OK; 1 on error
673 *
674 * <pre>
675 * Notes:
676 * (1) Side-effect: this rewinds the stream.
677 * </pre>
678 */
679l_int32
680fgetJpegComment(FILE *fp,
681 l_uint8 **pcomment)
682{
683struct jpeg_decompress_struct cinfo = { 0 };
684struct jpeg_error_mgr jerr = { 0 };
685struct callback_data cb_data = { 0 }; /* contains local jmp_buf */
686
687 if (!pcomment)
688 return ERROR_INT("&comment not defined", __func__, 1);
689 *pcomment = NULL;
690 if (!fp)
691 return ERROR_INT("stream not opened", __func__, 1);
692
693 rewind(fp);
694
695 /* Modify the jpeg error handling to catch fatal errors */
696 cinfo.err = jpeg_std_error(&jerr);
697 jerr.error_exit = jpeg_error_catch_all_2;
698 cb_data.comment = NULL;
699 cinfo.client_data = (void *)&cb_data;
700 if (setjmp(cb_data.jmpbuf)) {
701 LEPT_FREE(cb_data.comment);
702 return ERROR_INT("internal jpeg error", __func__, 1);
703 }
704
705 /* Initialize the jpeg structs for reading the header */
706 jpeg_create_decompress(&cinfo);
707 jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback);
708 jpeg_stdio_src(&cinfo, fp);
709 jpeg_read_header(&cinfo, TRUE);
710
711 /* Save the result */
712 *pcomment = cb_data.comment;
713 jpeg_destroy_decompress(&cinfo);
714 rewind(fp);
715 return 0;
716}
717
718
719/*---------------------------------------------------------------------*
720 * Writing Jpeg *
721 *---------------------------------------------------------------------*/
731l_ok
732pixWriteJpeg(const char *filename,
733 PIX *pix,
734 l_int32 quality,
735 l_int32 progressive)
736{
737FILE *fp;
738
739 if (!pix)
740 return ERROR_INT("pix not defined", __func__, 1);
741 if (!filename)
742 return ERROR_INT("filename not defined", __func__, 1);
743
744 if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
745 return ERROR_INT_1("stream not opened", filename, __func__, 1);
746
747 if (pixWriteStreamJpeg(fp, pix, quality, progressive)) {
748 fclose(fp);
749 return ERROR_INT_1("pix not written to stream", filename, __func__, 1);
750 }
751
752 fclose(fp);
753 return 0;
754}
755
756
790l_ok
792 PIX *pixs,
793 l_int32 quality,
794 l_int32 progressive)
795{
796l_int32 xres, yres;
797l_int32 i, j, k;
798l_int32 w, h, d, wpl, spp, colorflag, rowsamples;
799l_uint32 *ppixel, *line, *data;
800JSAMPROW rowbuffer;
801PIX *pix;
802struct jpeg_compress_struct cinfo = { 0 };
803struct jpeg_error_mgr jerr = { 0 };
804char *text;
805jmp_buf jmpbuf; /* must be local to the function */
806
807 if (!fp)
808 return ERROR_INT("stream not open", __func__, 1);
809 if (!pixs)
810 return ERROR_INT("pixs not defined", __func__, 1);
811 if (quality <= 0) quality = 75; /* default */
812 if (quality > 100) {
813 L_ERROR("invalid jpeg quality; setting to 75\n", __func__);
814 quality = 75;
815 }
816
817 /* If necessary, convert the pix so that it can be jpeg compressed.
818 * The colormap is removed based on the source, so if the colormap
819 * has only gray colors, the image will be compressed with spp = 1. */
820 pixGetDimensions(pixs, &w, &h, &d);
821 pix = NULL;
822 if (pixGetColormap(pixs) != NULL) {
823 L_INFO("removing colormap; may be better to compress losslessly\n",
824 __func__);
825 pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
826 } else if (d >= 8 && d != 16) { /* normal case; no rewrite */
827 pix = pixClone(pixs);
828 } else if (d < 8 || d == 16) {
829 L_INFO("converting from %d to 8 bpp\n", __func__, d);
830 pix = pixConvertTo8(pixs, 0); /* 8 bpp, no cmap */
831 } else {
832 L_ERROR("unknown pix type with d = %d and no cmap\n", __func__, d);
833 return 1;
834 }
835 if (!pix)
836 return ERROR_INT("pix not made", __func__, 1);
837 pixSetPadBits(pix, 0);
838
839 rewind(fp);
840 rowbuffer = NULL;
841
842 /* Modify the jpeg error handling to catch fatal errors */
843 cinfo.err = jpeg_std_error(&jerr);
844 cinfo.client_data = (void *)&jmpbuf;
845 jerr.error_exit = jpeg_error_catch_all_1;
846 if (setjmp(jmpbuf)) {
847 LEPT_FREE(rowbuffer);
848 pixDestroy(&pix);
849 return ERROR_INT("internal jpeg error", __func__, 1);
850 }
851
852 /* Initialize the jpeg structs for compression */
853 jpeg_create_compress(&cinfo);
854 jpeg_stdio_dest(&cinfo, fp);
855 cinfo.image_width = w;
856 cinfo.image_height = h;
857
858 /* Set the color space and number of components */
859 d = pixGetDepth(pix);
860 if (d == 8) {
861 colorflag = 0; /* 8 bpp grayscale; no cmap */
862 cinfo.input_components = 1;
863 cinfo.in_color_space = JCS_GRAYSCALE;
864 } else { /* d == 32 || d == 24 */
865 colorflag = 1; /* rgb */
866 cinfo.input_components = 3;
867 cinfo.in_color_space = JCS_RGB;
868 }
869
870 jpeg_set_defaults(&cinfo);
871
872 /* Setting optimize_coding to TRUE seems to improve compression
873 * by approx 2-4 percent, and increases comp time by approx 20%. */
874 cinfo.optimize_coding = FALSE;
875
876 /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */
877 xres = pixGetXRes(pix);
878 yres = pixGetYRes(pix);
879 if ((xres != 0) && (yres != 0)) {
880 cinfo.density_unit = 1; /* designates pixels per inch */
881 cinfo.X_density = xres;
882 cinfo.Y_density = yres;
883 }
884
885 /* Set the quality and progressive parameters */
886 jpeg_set_quality(&cinfo, quality, TRUE);
887 if (progressive)
888 jpeg_simple_progression(&cinfo);
889
890 /* Set the chroma subsampling parameters. This is done in
891 * YUV color space. The Y (intensity) channel is never subsampled.
892 * The standard subsampling is 2x2 on both the U and V channels.
893 * Notation on this is confusing. For a nice illustrations, see
894 * http://en.wikipedia.org/wiki/Chroma_subsampling
895 * The standard subsampling is written as 4:2:0.
896 * We allow high quality where there is no subsampling on the
897 * chroma channels: denoted as 4:4:4. */
898 if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) {
899 cinfo.comp_info[0].h_samp_factor = 1;
900 cinfo.comp_info[0].v_samp_factor = 1;
901 cinfo.comp_info[1].h_samp_factor = 1;
902 cinfo.comp_info[1].v_samp_factor = 1;
903 cinfo.comp_info[2].h_samp_factor = 1;
904 cinfo.comp_info[2].v_samp_factor = 1;
905 }
906
907 jpeg_start_compress(&cinfo, TRUE);
908
909 /* Cap the text the length limit, 65533, for JPEG_COM payload.
910 * Just to be safe, subtract 100 to cover the Adobe name space. */
911 if ((text = pixGetText(pix)) != NULL) {
912 if (strlen(text) > 65433) {
913 L_WARNING("text is %zu bytes; clipping to 65433\n",
914 __func__, strlen(text));
915 text[65433] = '\0';
916 }
917 jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text));
918 }
919
920 /* Allocate row buffer */
921 spp = cinfo.input_components;
922 rowsamples = spp * w;
923 if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples))
924 == NULL) {
925 pixDestroy(&pix);
926 return ERROR_INT("calloc fail for rowbuffer", __func__, 1);
927 }
928
929 data = pixGetData(pix);
930 wpl = pixGetWpl(pix);
931 for (i = 0; i < h; i++) {
932 line = data + i * wpl;
933 if (colorflag == 0) { /* 8 bpp gray */
934 for (j = 0; j < w; j++)
935 rowbuffer[j] = GET_DATA_BYTE(line, j);
936 } else { /* colorflag == 1 */
937 if (d == 24) { /* See note 3 above; special case of 24 bpp rgb */
938 jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1);
939 } else { /* standard 32 bpp rgb */
940 ppixel = line;
941 for (j = k = 0; j < w; j++) {
942 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
943 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
944 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
945 ppixel++;
946 }
947 }
948 }
949 if (d != 24)
950 jpeg_write_scanlines(&cinfo, &rowbuffer, 1);
951 }
952 jpeg_finish_compress(&cinfo);
953
954 pixDestroy(&pix);
955 LEPT_FREE(rowbuffer);
956 rowbuffer = NULL;
957 jpeg_destroy_compress(&cinfo);
958 return 0;
959}
960
961
962/*---------------------------------------------------------------------*
963 * Read/write to memory *
964 *---------------------------------------------------------------------*/
965
987PIX *
988pixReadMemJpeg(const l_uint8 *data,
989 size_t size,
990 l_int32 cmflag,
991 l_int32 reduction,
992 l_int32 *pnwarn,
993 l_int32 hint)
994{
995l_int32 ret;
996l_uint8 *comment;
997FILE *fp;
998PIX *pix;
999
1000 if (pnwarn) *pnwarn = 0;
1001 if (!data)
1002 return (PIX *)ERROR_PTR("data not defined", __func__, NULL);
1003
1004 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1005 return (PIX *)ERROR_PTR("stream not opened", __func__, NULL);
1006 pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint);
1007 if (pix) {
1008 ret = fgetJpegComment(fp, &comment);
1009 if (!ret && comment) {
1010 pixSetText(pix, (char *)comment);
1011 LEPT_FREE(comment);
1012 }
1013 }
1014 fclose(fp);
1015 if (!pix) L_ERROR("pix not read\n", __func__);
1016 return pix;
1017}
1018
1019
1032l_ok
1033readHeaderMemJpeg(const l_uint8 *data,
1034 size_t size,
1035 l_int32 *pw,
1036 l_int32 *ph,
1037 l_int32 *pspp,
1038 l_int32 *pycck,
1039 l_int32 *pcmyk)
1040{
1041l_int32 ret;
1042FILE *fp;
1043
1044 if (pw) *pw = 0;
1045 if (ph) *ph = 0;
1046 if (pspp) *pspp = 0;
1047 if (pycck) *pycck = 0;
1048 if (pcmyk) *pcmyk = 0;
1049 if (!data)
1050 return ERROR_INT("data not defined", __func__, 1);
1051 if (!pw && !ph && !pspp && !pycck && !pcmyk)
1052 return ERROR_INT("no results requested", __func__, 1);
1053
1054 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1055 return ERROR_INT("stream not opened", __func__, 1);
1056 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk);
1057 fclose(fp);
1058 return ret;
1059}
1060
1061
1071l_ok
1072readResolutionMemJpeg(const l_uint8 *data,
1073 size_t size,
1074 l_int32 *pxres,
1075 l_int32 *pyres)
1076{
1077l_int32 ret;
1078FILE *fp;
1079
1080 if (pxres) *pxres = 0;
1081 if (pyres) *pyres = 0;
1082 if (!data)
1083 return ERROR_INT("data not defined", __func__, 1);
1084 if (!pxres && !pyres)
1085 return ERROR_INT("no results requested", __func__, 1);
1086
1087 if ((fp = fopenReadFromMemory(data, size)) == NULL)
1088 return ERROR_INT("stream not opened", __func__, 1);
1089 ret = fgetJpegResolution(fp, pxres, pyres);
1090 fclose(fp);
1091 return ret;
1092}
1093
1094
1111l_ok
1112pixWriteMemJpeg(l_uint8 **pdata,
1113 size_t *psize,
1114 PIX *pix,
1115 l_int32 quality,
1116 l_int32 progressive)
1117{
1118l_int32 ret;
1119FILE *fp;
1120
1121 if (pdata) *pdata = NULL;
1122 if (psize) *psize = 0;
1123 if (!pdata)
1124 return ERROR_INT("&data not defined", __func__, 1 );
1125 if (!psize)
1126 return ERROR_INT("&size not defined", __func__, 1 );
1127 if (!pix)
1128 return ERROR_INT("&pix not defined", __func__, 1 );
1129
1130#if HAVE_FMEMOPEN
1131 if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1132 return ERROR_INT("stream not opened", __func__, 1);
1133 ret = pixWriteStreamJpeg(fp, pix, quality, progressive);
1134 fputc('\0', fp);
1135 fclose(fp);
1136 if (*psize > 0) *psize = *psize - 1;
1137#else
1138 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__);
1139 #ifdef _WIN32
1140 if ((fp = fopenWriteWinTempfile()) == NULL)
1141 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1142 #else
1143 if ((fp = tmpfile()) == NULL)
1144 return ERROR_INT("tmpfile stream not opened", __func__, 1);
1145 #endif /* _WIN32 */
1146 ret = pixWriteStreamJpeg(fp, pix, quality, progressive);
1147 rewind(fp);
1148 *pdata = l_binaryReadStream(fp, psize);
1149 fclose(fp);
1150#endif /* HAVE_FMEMOPEN */
1151 return ret;
1152}
1153
1154
1155/*---------------------------------------------------------------------*
1156 * Setting special flag for chroma sampling on write *
1157 *---------------------------------------------------------------------*/
1173l_ok
1175 l_int32 sampling)
1176{
1177 if (!pix)
1178 return ERROR_INT("pix not defined", __func__, 1 );
1179 if (sampling)
1180 pixSetSpecial(pix, 0); /* default */
1181 else
1182 pixSetSpecial(pix, L_NO_CHROMA_SAMPLING_JPEG);
1183 return 0;
1184}
1185
1186
1187/*---------------------------------------------------------------------*
1188 * Static system helpers *
1189 *---------------------------------------------------------------------*/
1199static void
1200jpeg_error_catch_all_1(j_common_ptr cinfo)
1201{
1202 jmp_buf *pjmpbuf = (jmp_buf *)cinfo->client_data;
1203 (*cinfo->err->output_message) (cinfo);
1204 jpeg_destroy(cinfo);
1205 longjmp(*pjmpbuf, 1);
1206}
1207
1216static void
1217jpeg_error_catch_all_2(j_common_ptr cinfo)
1218{
1219struct callback_data *pcb_data;
1220
1221 pcb_data = (struct callback_data *)cinfo->client_data;
1222 (*cinfo->err->output_message) (cinfo);
1223 jpeg_destroy(cinfo);
1224 longjmp(pcb_data->jmpbuf, 1);
1225}
1226
1227/* This function was borrowed from libjpeg */
1228static l_uint8
1229jpeg_getc(j_decompress_ptr cinfo)
1230{
1231struct jpeg_source_mgr *datasrc;
1232
1233 datasrc = cinfo->src;
1234 if (datasrc->bytes_in_buffer == 0) {
1235 if (! (*datasrc->fill_input_buffer) (cinfo)) {
1236 return 0;
1237 }
1238 }
1239 datasrc->bytes_in_buffer--;
1240 return GETJOCTET(*datasrc->next_input_byte++);
1241}
1242
1251static boolean
1252jpeg_comment_callback(j_decompress_ptr cinfo)
1253{
1254l_int32 length, i;
1255l_uint8 *comment;
1256struct callback_data *pcb_data;
1257
1258 /* Get the size of the comment */
1259 length = jpeg_getc(cinfo) << 8;
1260 length += jpeg_getc(cinfo);
1261 length -= 2;
1262 if (length <= 0)
1263 return 1;
1264
1265 /* Extract the comment from the file */
1266 if ((comment = (l_uint8 *)LEPT_CALLOC(length + 1, sizeof(l_uint8))) == NULL)
1267 return 0;
1268 for (i = 0; i < length; i++)
1269 comment[i] = jpeg_getc(cinfo);
1270
1271 /* Save the comment and return */
1272 pcb_data = (struct callback_data *)cinfo->client_data;
1273 if (pcb_data->comment) { /* clear before overwriting previous comment */
1274 LEPT_FREE(pcb_data->comment);
1275 pcb_data->comment = NULL;
1276 }
1277 pcb_data->comment = comment;
1278 return 1;
1279}
1280
1281/* --------------------------------------------*/
1282#endif /* HAVE_LIBJPEG */
1283/* --------------------------------------------*/
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
@ L_JPEG_CONTINUE_WITH_BAD_DATA
Definition imageio.h:139
@ L_JPEG_READ_LUMINANCE
Definition imageio.h:138
static void jpeg_error_catch_all_1(j_common_ptr cinfo)
jpeg_error_catch_all_1()
Definition jpegio.c:1200
l_ok pixWriteMemJpeg(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 quality, l_int32 progressive)
pixWriteMemJpeg()
Definition jpegio.c:1112
static void jpeg_error_catch_all_2(j_common_ptr cinfo)
jpeg_error_catch_all_2()
Definition jpegio.c:1217
l_ok readHeaderMemJpeg(const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pspp, l_int32 *pycck, l_int32 *pcmyk)
readHeaderMemJpeg()
Definition jpegio.c:1033
l_ok readResolutionMemJpeg(const l_uint8 *data, size_t size, l_int32 *pxres, l_int32 *pyres)
readResolutionMemJpeg()
Definition jpegio.c:1072
l_ok freadHeaderJpeg(FILE *fp, l_int32 *pw, l_int32 *ph, l_int32 *pspp, l_int32 *pycck, l_int32 *pcmyk)
freadHeaderJpeg()
Definition jpegio.c:548
PIX * pixReadJpeg(const char *filename, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadJpeg()
Definition jpegio.c:209
l_ok pixWriteStreamJpeg(FILE *fp, PIX *pixs, l_int32 quality, l_int32 progressive)
pixWriteStreamJpeg()
Definition jpegio.c:791
PIX * pixReadStreamJpeg(FILE *fp, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadStreamJpeg()
Definition jpegio.c:265
l_ok readHeaderJpeg(const char *filename, l_int32 *pw, l_int32 *ph, l_int32 *pspp, l_int32 *pycck, l_int32 *pcmyk)
readHeaderJpeg()
Definition jpegio.c:508
l_ok pixWriteJpeg(const char *filename, PIX *pix, l_int32 quality, l_int32 progressive)
pixWriteJpeg()
Definition jpegio.c:732
static boolean jpeg_comment_callback(j_decompress_ptr cinfo)
jpeg_comment_callback()
Definition jpegio.c:1252
PIX * pixReadMemJpeg(const l_uint8 *data, size_t size, l_int32 cmflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadMemJpeg()
Definition jpegio.c:988
l_ok pixSetChromaSampling(PIX *pix, l_int32 sampling)
pixSetChromaSampling()
Definition jpegio.c:1174
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ COLOR_GREEN
Definition pix.h:329
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
@ L_NO_CHROMA_SAMPLING_JPEG
Definition pix.h:1055
l_int32 special