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