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