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