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