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 
145 static void jpeg_error_catch_all_1(j_common_ptr cinfo);
146 static void jpeg_error_catch_all_2(j_common_ptr cinfo);
147 static 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. */
153 static 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  *---------------------------------------------------------------------*/
207 PIX *
208 pixReadJpeg(const char *filename,
209  l_int32 cmapflag,
210  l_int32 reduction,
211  l_int32 *pnwarn,
212  l_int32 hint)
213 {
214 l_int32 ret;
215 l_uint8 *comment;
216 FILE *fp;
217 PIX *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 
263 PIX *
265  l_int32 cmapflag,
266  l_int32 reduction,
267  l_int32 *pnwarn,
268  l_int32 hint)
269 {
270 l_int32 cyan, yellow, magenta, black, nwarn;
271 l_int32 i, j, k, rval, gval, bval;
272 l_int32 nlinesread, abort_on_warning;
273 l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
274 l_uint32 *data;
275 l_uint32 *line, *ppixel;
276 JSAMPROW rowbuffer;
277 PIX *pix;
278 PIXCMAP *cmap;
279 struct jpeg_decompress_struct cinfo;
280 struct jpeg_error_mgr jerr;
281 jmp_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  *---------------------------------------------------------------------*/
508 l_ok
509 readHeaderJpeg(const char *filename,
510  l_int32 *pw,
511  l_int32 *ph,
512  l_int32 *pspp,
513  l_int32 *pycck,
514  l_int32 *pcmyk)
515 {
516 l_int32 ret;
517 FILE *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 
550 l_ok
552  l_int32 *pw,
553  l_int32 *ph,
554  l_int32 *pspp,
555  l_int32 *pycck,
556  l_int32 *pcmyk)
557 {
558 l_int32 spp, w, h;
559 struct jpeg_decompress_struct cinfo;
560 struct jpeg_error_mgr jerr;
561 jmp_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  */
626 l_int32
627 fgetJpegResolution(FILE *fp,
628  l_int32 *pxres,
629  l_int32 *pyres)
630 {
631 struct jpeg_decompress_struct cinfo;
632 struct jpeg_error_mgr jerr;
633 jmp_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  */
686 l_int32
687 fgetJpegComment(FILE *fp,
688  l_uint8 **pcomment)
689 {
690 struct jpeg_decompress_struct cinfo;
691 struct jpeg_error_mgr jerr;
692 struct 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  *---------------------------------------------------------------------*/
740 l_ok
741 pixWriteJpeg(const char *filename,
742  PIX *pix,
743  l_int32 quality,
744  l_int32 progressive)
745 {
746 FILE *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 
801 l_ok
803  PIX *pixs,
804  l_int32 quality,
805  l_int32 progressive)
806 {
807 l_int32 xres, yres;
808 l_int32 i, j, k;
809 l_int32 w, h, d, wpl, spp, colorflag, rowsamples;
810 l_uint32 *ppixel, *line, *data;
811 JSAMPROW rowbuffer;
812 PIX *pix;
813 struct jpeg_compress_struct cinfo;
814 struct jpeg_error_mgr jerr;
815 char *text;
816 jmp_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 
1000 PIX *
1001 pixReadMemJpeg(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 {
1008 l_int32 ret;
1009 l_uint8 *comment;
1010 FILE *fp;
1011 PIX *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 
1047 l_ok
1048 readHeaderMemJpeg(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 {
1056 l_int32 ret;
1057 FILE *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 
1088 l_ok
1089 readResolutionMemJpeg(const l_uint8 *data,
1090  size_t size,
1091  l_int32 *pxres,
1092  l_int32 *pyres)
1093 {
1094 l_int32 ret;
1095 FILE *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 
1130 l_ok
1131 pixWriteMemJpeg(l_uint8 **pdata,
1132  size_t *psize,
1133  PIX *pix,
1134  l_int32 quality,
1135  l_int32 progressive)
1136 {
1137 l_int32 ret;
1138 FILE *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  *---------------------------------------------------------------------*/
1194 l_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  *---------------------------------------------------------------------*/
1222 static void
1223 jpeg_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 
1239 static void
1240 jpeg_error_catch_all_2(j_common_ptr cinfo)
1241 {
1242 struct 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 */
1251 static l_uint8
1252 jpeg_getc(j_decompress_ptr cinfo)
1253 {
1254 struct 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 
1274 static boolean
1275 jpeg_comment_callback(j_decompress_ptr cinfo)
1276 {
1277 l_int32 length, i;
1278 l_uint8 *comment;
1279 struct 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
PIX * pixReadJpeg(const char *filename, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadJpeg()
Definition: jpegio.c:208
PIX * pixReadStreamJpeg(FILE *fp, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint)
pixReadStreamJpeg()
Definition: jpegio.c:264
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
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
l_ok pixWriteStreamJpeg(FILE *fp, PIX *pixs, l_int32 quality, l_int32 progressive)
pixWriteStreamJpeg()
Definition: jpegio.c:802
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
l_ok pixSetChromaSampling(PIX *pix, l_int32 sampling)
pixSetChromaSampling()
Definition: jpegio.c:1195
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
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
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1512
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1536
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
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 * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:328
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
Definition: pix.h:139
l_int32 special
Definition: pix.h:151
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:1402
FILE * fopenReadFromMemory(const l_uint8 *data, size_t size)
fopenReadFromMemory()
Definition: utils2.c:2009
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
FILE * fopenWriteWinTempfile(void)
fopenWriteWinTempfile()
Definition: utils2.c:2055
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932