Leptonica  1.83.1
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 #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 
146 static void jpeg_error_catch_all_1(j_common_ptr cinfo);
147 static void jpeg_error_catch_all_2(j_common_ptr cinfo);
148 static 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. */
154 static 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  *---------------------------------------------------------------------*/
208 PIX *
209 pixReadJpeg(const char *filename,
210  l_int32 cmapflag,
211  l_int32 reduction,
212  l_int32 *pnwarn,
213  l_int32 hint)
214 {
215 l_int32 ret;
216 l_uint8 *comment;
217 FILE *fp;
218 PIX *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 
262 PIX *
264  l_int32 cmapflag,
265  l_int32 reduction,
266  l_int32 *pnwarn,
267  l_int32 hint)
268 {
269 l_int32 cyan, yellow, magenta, black, nwarn;
270 l_int32 i, j, k, rval, gval, bval;
271 l_int32 nlinesread, abort_on_warning;
272 l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
273 l_uint32 *data;
274 l_uint32 *line, *ppixel;
275 JSAMPROW rowbuffer;
276 PIX *pix;
277 PIXCMAP *cmap;
278 struct jpeg_decompress_struct cinfo;
279 struct jpeg_error_mgr jerr;
280 jmp_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  *---------------------------------------------------------------------*/
505 l_ok
506 readHeaderJpeg(const char *filename,
507  l_int32 *pw,
508  l_int32 *ph,
509  l_int32 *pspp,
510  l_int32 *pycck,
511  l_int32 *pcmyk)
512 {
513 l_int32 ret;
514 FILE *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 
545 l_ok
547  l_int32 *pw,
548  l_int32 *ph,
549  l_int32 *pspp,
550  l_int32 *pycck,
551  l_int32 *pcmyk)
552 {
553 l_int32 spp, w, h;
554 struct jpeg_decompress_struct cinfo;
555 struct jpeg_error_mgr jerr;
556 jmp_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  */
619 l_int32
620 fgetJpegResolution(FILE *fp,
621  l_int32 *pxres,
622  l_int32 *pyres)
623 {
624 struct jpeg_decompress_struct cinfo;
625 struct jpeg_error_mgr jerr;
626 jmp_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  */
677 l_int32
678 fgetJpegComment(FILE *fp,
679  l_uint8 **pcomment)
680 {
681 struct jpeg_decompress_struct cinfo;
682 struct jpeg_error_mgr jerr;
683 struct 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  *---------------------------------------------------------------------*/
729 l_ok
730 pixWriteJpeg(const char *filename,
731  PIX *pix,
732  l_int32 quality,
733  l_int32 progressive)
734 {
735 FILE *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 
788 l_ok
790  PIX *pixs,
791  l_int32 quality,
792  l_int32 progressive)
793 {
794 l_int32 xres, yres;
795 l_int32 i, j, k;
796 l_int32 w, h, d, wpl, spp, colorflag, rowsamples;
797 l_uint32 *ppixel, *line, *data;
798 JSAMPROW rowbuffer;
799 PIX *pix;
800 struct jpeg_compress_struct cinfo;
801 struct jpeg_error_mgr jerr;
802 char *text;
803 jmp_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__);
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 
985 PIX *
986 pixReadMemJpeg(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 {
993 l_int32 ret;
994 l_uint8 *comment;
995 FILE *fp;
996 PIX *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 
1030 l_ok
1031 readHeaderMemJpeg(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 {
1039 l_int32 ret;
1040 FILE *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 
1069 l_ok
1070 readResolutionMemJpeg(const l_uint8 *data,
1071  size_t size,
1072  l_int32 *pxres,
1073  l_int32 *pyres)
1074 {
1075 l_int32 ret;
1076 FILE *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 
1109 l_ok
1110 pixWriteMemJpeg(l_uint8 **pdata,
1111  size_t *psize,
1112  PIX *pix,
1113  l_int32 quality,
1114  l_int32 progressive)
1115 {
1116 l_int32 ret;
1117 FILE *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  *---------------------------------------------------------------------*/
1171 l_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  *---------------------------------------------------------------------*/
1197 static void
1198 jpeg_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 
1214 static void
1215 jpeg_error_catch_all_2(j_common_ptr cinfo)
1216 {
1217 struct 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 */
1226 static l_uint8
1227 jpeg_getc(j_decompress_ptr cinfo)
1228 {
1229 struct 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 
1249 static boolean
1250 jpeg_comment_callback(j_decompress_ptr cinfo)
1251 {
1252 l_int32 length, i;
1253 l_uint8 *comment;
1254 struct 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)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
@ 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
PIX * pixReadJpeg(const char *filename, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadJpeg()
Definition: jpegio.c:209
PIX * pixReadStreamJpeg(FILE *fp, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadStreamJpeg()
Definition: jpegio.c:263
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
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
l_ok pixWriteStreamJpeg(FILE *fp, PIX *pixs, l_int32 quality, l_int32 progressive)
pixWriteStreamJpeg()
Definition: jpegio.c:789
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
l_ok pixSetChromaSampling(PIX *pix, l_int32 sampling)
pixSetChromaSampling()
Definition: jpegio.c:1172
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1582
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1408
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1430
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1346
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
@ 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:1054
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
l_int32 special
Definition: pix_internal.h:193
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1358
FILE * fopenReadFromMemory(const l_uint8 *data, size_t size)
fopenReadFromMemory()
Definition: utils2.c:1937
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1905
FILE * fopenWriteWinTempfile(void)
fopenWriteWinTempfile()
Definition: utils2.c:1981
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1864