Leptonica  1.77.0
Image processing and image analysis suite
writefile.c
1 /*====================================================================*
2  - Copyright (C) 2001-2016 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 
27 /*
28  * writefile.c
29  *
30  * Set jpeg quality for pixWrite() and pixWriteMem()
31  * l_int32 l_jpegSetQuality()
32  *
33  * Set global variable LeptDebugOK for writing to named temp files
34  * l_int32 setLeptDebugOK()
35  *
36  * High-level procedures for writing images to file:
37  * l_int32 pixaWriteFiles()
38  * l_int32 pixWriteDebug()
39  * l_int32 pixWrite()
40  * l_int32 pixWriteAutoFormat()
41  * l_int32 pixWriteStream()
42  * l_int32 pixWriteImpliedFormat()
43  *
44  * Selection of output format if default is requested
45  * l_int32 pixChooseOutputFormat()
46  * l_int32 getImpliedFileFormat()
47  * l_int32 pixGetAutoFormat()
48  * const char *getFormatExtension()
49  *
50  * Write to memory
51  * l_int32 pixWriteMem()
52  *
53  * Image display for debugging
54  * l_int32 l_fileDisplay()
55  * l_int32 pixDisplay()
56  * l_int32 pixDisplayWithTitle()
57  * l_int32 pixSaveTiled()
58  * l_int32 pixSaveTiledOutline()
59  * l_int32 pixSaveTiledWithText()
60  * void l_chooseDisplayProg()
61  *
62  * Deprecated pix output for debugging (still used in tesseract 3.05)
63  * l_int32 pixDisplayWrite()
64  *
65  * Supported file formats:
66  * (1) Writing is supported without any external libraries:
67  * bmp
68  * pnm (including pbm, pgm, etc)
69  * spix (raw serialized)
70  * (2) Writing is supported with installation of external libraries:
71  * png
72  * jpg (standard jfif version)
73  * tiff (including most varieties of compression)
74  * gif
75  * webp
76  * jp2 (jpeg2000)
77  * (3) Writing is supported through special interfaces:
78  * ps (PostScript, in psio1.c, psio2.c):
79  * level 1 (uncompressed)
80  * level 2 (g4 and dct encoding: requires tiff, jpg)
81  * level 3 (g4, dct and flate encoding: requires tiff, jpg, zlib)
82  * pdf (PDF, in pdfio.c):
83  * level 1 (g4 and dct encoding: requires tiff, jpg)
84  * level 2 (g4, dct and flate encoding: requires tiff, jpg, zlib)
85  */
86 
87 #include <string.h>
88 #include "allheaders.h"
89 
90  /* Display program (xv, xli, xzgv, open) to be invoked by pixDisplay() */
91 #ifdef _WIN32
92 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_IV; /* default */
93 #elif defined(__APPLE__)
94 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_OPEN; /* default */
95 #else
96 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_XZGV; /* default */
97 #endif /* _WIN32 */
98 
99 static const l_int32 L_BUFSIZE = 512;
100 static const l_int32 MAX_DISPLAY_WIDTH = 1000;
101 static const l_int32 MAX_DISPLAY_HEIGHT = 800;
102 static const l_int32 MAX_SIZE_FOR_PNG = 200;
103 
104  /* PostScript output for printing */
105 static const l_float32 DEFAULT_SCALING = 1.0;
106 
107  /* Global array of image file format extension names. */
108  /* This is in 1-1 corrspondence with format enum in imageio.h. */
109  /* The empty string at the end represents the serialized format, */
110  /* which has no recognizable extension name, but the array must */
111  /* be padded to agree with the format enum. */
112  /* (Note on 'const': The size of the array can't be defined 'const' */
113  /* because that makes it static. The 'const' in the definition of */
114  /* the array refers to the strings in the array; the ptr to the */
115  /* array is not const and can be used 'extern' in other files.) */
116 LEPT_DLL l_int32 NumImageFileFormatExtensions = 20; /* array size */
117 LEPT_DLL const char *ImageFileFormatExtensions[] =
118  {"unknown",
119  "bmp",
120  "jpg",
121  "png",
122  "tif",
123  "tif",
124  "tif",
125  "tif",
126  "tif",
127  "tif",
128  "tif",
129  "pnm",
130  "ps",
131  "gif",
132  "jp2",
133  "webp",
134  "pdf",
135  "tif",
136  "default",
137  ""};
138 
139  /* Local map of image file name extension to output format */
141 {
142  char extension[8];
143  l_int32 format;
144 };
145 static const struct ExtensionMap extension_map[] =
146  { { ".bmp", IFF_BMP },
147  { ".jpg", IFF_JFIF_JPEG },
148  { ".jpeg", IFF_JFIF_JPEG },
149  { ".png", IFF_PNG },
150  { ".tif", IFF_TIFF },
151  { ".tiff", IFF_TIFF },
152  { ".pnm", IFF_PNM },
153  { ".gif", IFF_GIF },
154  { ".jp2", IFF_JP2 },
155  { ".ps", IFF_PS },
156  { ".pdf", IFF_LPDF },
157  { ".webp", IFF_WEBP } };
158 
159 
160 /*---------------------------------------------------------------------*
161  * Set jpeg quality for pixWrite() and pixWriteMem() *
162  *---------------------------------------------------------------------*/
163  /* Parameter that controls jpeg quality for high-level calls. */
164 static l_int32 var_JPEG_QUALITY = 75; /* default */
165 
182 l_int32
183 l_jpegSetQuality(l_int32 new_quality)
184 {
185 l_int32 prevq, newq;
186 
187  PROCNAME("l_jpeqSetQuality");
188 
189  prevq = var_JPEG_QUALITY;
190  newq = (new_quality == 0) ? 75 : new_quality;
191  if (newq < 1 || newq > 100)
192  L_ERROR("invalid jpeg quality; unchanged\n", procName);
193  else
194  var_JPEG_QUALITY = newq;
195  return prevq;
196 }
197 
198 
199 /*----------------------------------------------------------------------*
200  * Set global variable LeptDebugOK for writing to named temp files *
201  *----------------------------------------------------------------------*/
202 l_int32 LeptDebugOK = 0; /* default value */
217 void
218 setLeptDebugOK(l_int32 allow)
219 {
220  if (allow != 0) allow = 1;
221  LeptDebugOK = allow;
222 }
223 
224 
225 /*---------------------------------------------------------------------*
226  * Top-level procedures for writing images to file *
227  *---------------------------------------------------------------------*/
242 l_ok
243 pixaWriteFiles(const char *rootname,
244  PIXA *pixa,
245  l_int32 format)
246 {
247 char bigbuf[L_BUFSIZE];
248 l_int32 i, n, pixformat;
249 PIX *pix;
250 
251  PROCNAME("pixaWriteFiles");
252 
253  if (!rootname)
254  return ERROR_INT("rootname not defined", procName, 1);
255  if (!pixa)
256  return ERROR_INT("pixa not defined", procName, 1);
257  if (format < 0 || format == IFF_UNKNOWN ||
258  format >= NumImageFileFormatExtensions)
259  return ERROR_INT("invalid format", procName, 1);
260 
261  n = pixaGetCount(pixa);
262  for (i = 0; i < n; i++) {
263  pix = pixaGetPix(pixa, i, L_CLONE);
264  if (format == IFF_DEFAULT)
265  pixformat = pixChooseOutputFormat(pix);
266  else
267  pixformat = format;
268  snprintf(bigbuf, L_BUFSIZE, "%s%03d.%s", rootname, i,
269  ImageFileFormatExtensions[pixformat]);
270  pixWrite(bigbuf, pix, pixformat);
271  pixDestroy(&pix);
272  }
273 
274  return 0;
275 }
276 
277 
295 l_ok
296 pixWriteDebug(const char *fname,
297  PIX *pix,
298  l_int32 format)
299 {
300  PROCNAME("pixWriteDebug");
301 
302  if (LeptDebugOK) {
303  return pixWrite(fname, pix, format);
304  } else {
305  L_INFO("write to named temp file %s is disabled\n", procName, fname);
306  return 0;
307  }
308 }
309 
310 
332 l_ok
333 pixWrite(const char *fname,
334  PIX *pix,
335  l_int32 format)
336 {
337 l_int32 ret;
338 FILE *fp;
339 
340  PROCNAME("pixWrite");
341 
342  if (!pix)
343  return ERROR_INT("pix not defined", procName, 1);
344  if (!fname)
345  return ERROR_INT("fname not defined", procName, 1);
346 
347  if ((fp = fopenWriteStream(fname, "wb+")) == NULL)
348  return ERROR_INT("stream not opened", procName, 1);
349 
350  ret = pixWriteStream(fp, pix, format);
351  fclose(fp);
352  if (ret)
353  return ERROR_INT("pix not written to stream", procName, 1);
354  return 0;
355 }
356 
357 
365 l_ok
366 pixWriteAutoFormat(const char *filename,
367  PIX *pix)
368 {
369 l_int32 format;
370 
371  PROCNAME("pixWriteAutoFormat");
372 
373  if (!pix)
374  return ERROR_INT("pix not defined", procName, 1);
375  if (!filename)
376  return ERROR_INT("filename not defined", procName, 1);
377 
378  if (pixGetAutoFormat(pix, &format))
379  return ERROR_INT("auto format not returned", procName, 1);
380  return pixWrite(filename, pix, format);
381 }
382 
383 
392 l_ok
393 pixWriteStream(FILE *fp,
394  PIX *pix,
395  l_int32 format)
396 {
397  PROCNAME("pixWriteStream");
398 
399  if (!fp)
400  return ERROR_INT("stream not defined", procName, 1);
401  if (!pix)
402  return ERROR_INT("pix not defined", procName, 1);
403 
404  if (format == IFF_DEFAULT)
405  format = pixChooseOutputFormat(pix);
406 
407  switch(format)
408  {
409  case IFF_BMP:
410  pixWriteStreamBmp(fp, pix);
411  break;
412 
413  case IFF_JFIF_JPEG: /* default quality; baseline sequential */
414  return pixWriteStreamJpeg(fp, pix, var_JPEG_QUALITY, 0);
415  break;
416 
417  case IFF_PNG: /* no gamma value stored */
418  return pixWriteStreamPng(fp, pix, 0.0);
419  break;
420 
421  case IFF_TIFF: /* uncompressed */
422  case IFF_TIFF_PACKBITS: /* compressed, binary only */
423  case IFF_TIFF_RLE: /* compressed, binary only */
424  case IFF_TIFF_G3: /* compressed, binary only */
425  case IFF_TIFF_G4: /* compressed, binary only */
426  case IFF_TIFF_LZW: /* compressed, all depths */
427  case IFF_TIFF_ZIP: /* compressed, all depths */
428  case IFF_TIFF_JPEG: /* compressed, 8 bpp gray and 32 bpp rgb */
429  return pixWriteStreamTiff(fp, pix, format);
430  break;
431 
432  case IFF_PNM:
433  return pixWriteStreamPnm(fp, pix);
434  break;
435 
436  case IFF_PS:
437  return pixWriteStreamPS(fp, pix, NULL, 0, DEFAULT_SCALING);
438  break;
439 
440  case IFF_GIF:
441  return pixWriteStreamGif(fp, pix);
442  break;
443 
444  case IFF_JP2:
445  return pixWriteStreamJp2k(fp, pix, 34, 4, 0, 0);
446  break;
447 
448  case IFF_WEBP:
449  return pixWriteStreamWebP(fp, pix, 80, 0);
450  break;
451 
452  case IFF_LPDF:
453  return pixWriteStreamPdf(fp, pix, 0, NULL);
454  break;
455 
456  case IFF_SPIX:
457  return pixWriteStreamSpix(fp, pix);
458  break;
459 
460  default:
461  return ERROR_INT("unknown format", procName, 1);
462  break;
463  }
464 
465  return 0;
466 }
467 
468 
485 l_ok
486 pixWriteImpliedFormat(const char *filename,
487  PIX *pix,
488  l_int32 quality,
489  l_int32 progressive)
490 {
491 l_int32 format;
492 
493  PROCNAME("pixWriteImpliedFormat");
494 
495  if (!filename)
496  return ERROR_INT("filename not defined", procName, 1);
497  if (!pix)
498  return ERROR_INT("pix not defined", procName, 1);
499 
500  /* Determine output format */
501  format = getImpliedFileFormat(filename);
502  if (format == IFF_UNKNOWN) {
503  format = IFF_PNG;
504  } else if (format == IFF_TIFF) {
505  if (pixGetDepth(pix) == 1)
506  format = IFF_TIFF_G4;
507  else
508 #ifdef _WIN32
509  format = IFF_TIFF_LZW; /* poor compression */
510 #else
511  format = IFF_TIFF_ZIP; /* native windows tools can't handle this */
512 #endif /* _WIN32 */
513  }
514 
515  if (format == IFF_JFIF_JPEG) {
516  quality = L_MIN(quality, 100);
517  quality = L_MAX(quality, 0);
518  if (progressive != 0 && progressive != 1) {
519  progressive = 0;
520  L_WARNING("invalid progressive; setting to baseline\n", procName);
521  }
522  if (quality == 0)
523  quality = 75;
524  pixWriteJpeg (filename, pix, quality, progressive);
525  } else {
526  pixWrite(filename, pix, format);
527  }
528 
529  return 0;
530 }
531 
532 
533 /*---------------------------------------------------------------------*
534  * Selection of output format if default is requested *
535  *---------------------------------------------------------------------*/
550 l_int32
551 pixChooseOutputFormat(PIX *pix)
552 {
553 l_int32 d, format;
554 
555  PROCNAME("pixChooseOutputFormat");
556 
557  if (!pix)
558  return ERROR_INT("pix not defined", procName, 0);
559 
560  d = pixGetDepth(pix);
561  format = pixGetInputFormat(pix);
562  if (format == IFF_UNKNOWN) { /* output lossless */
563  if (d == 1)
564  format = IFF_TIFF_G4;
565  else
566  format = IFF_PNG;
567  }
568 
569  return format;
570 }
571 
572 
585 l_int32
586 getImpliedFileFormat(const char *filename)
587 {
588 char *extension;
589 int i, numext;
590 l_int32 format = IFF_UNKNOWN;
591 
592  if (splitPathAtExtension (filename, NULL, &extension))
593  return IFF_UNKNOWN;
594 
595  numext = sizeof(extension_map) / sizeof(extension_map[0]);
596  for (i = 0; i < numext; i++) {
597  if (!strcmp(extension, extension_map[i].extension)) {
598  format = extension_map[i].format;
599  break;
600  }
601  }
602 
603  LEPT_FREE(extension);
604  return format;
605 }
606 
607 
626 l_ok
627 pixGetAutoFormat(PIX *pix,
628  l_int32 *pformat)
629 {
630 l_int32 d;
631 PIXCMAP *cmap;
632 
633  PROCNAME("pixGetAutoFormat");
634 
635  if (!pformat)
636  return ERROR_INT("&format not defined", procName, 0);
637  *pformat = IFF_UNKNOWN;
638  if (!pix)
639  return ERROR_INT("pix not defined", procName, 0);
640 
641  d = pixGetDepth(pix);
642  cmap = pixGetColormap(pix);
643  if (d == 1 && !cmap) {
644  *pformat = IFF_TIFF_G4;
645  } else if ((d == 8 && !cmap) || d == 24 || d == 32) {
646  *pformat = IFF_JFIF_JPEG;
647  } else {
648  *pformat = IFF_PNG;
649  }
650 
651  return 0;
652 }
653 
654 
667 const char *
668 getFormatExtension(l_int32 format)
669 {
670  PROCNAME("getFormatExtension");
671 
672  if (format < 0 || format >= NumImageFileFormatExtensions)
673  return (const char *)ERROR_PTR("invalid format", procName, NULL);
674 
675  return ImageFileFormatExtensions[format];
676 }
677 
678 
679 /*---------------------------------------------------------------------*
680  * Write to memory *
681  *---------------------------------------------------------------------*/
702 l_ok
703 pixWriteMem(l_uint8 **pdata,
704  size_t *psize,
705  PIX *pix,
706  l_int32 format)
707 {
708 l_int32 ret;
709 
710  PROCNAME("pixWriteMem");
711 
712  if (!pdata)
713  return ERROR_INT("&data not defined", procName, 1 );
714  if (!psize)
715  return ERROR_INT("&size not defined", procName, 1 );
716  if (!pix)
717  return ERROR_INT("&pix not defined", procName, 1 );
718 
719  if (format == IFF_DEFAULT)
720  format = pixChooseOutputFormat(pix);
721 
722  switch(format)
723  {
724  case IFF_BMP:
725  ret = pixWriteMemBmp(pdata, psize, pix);
726  break;
727 
728  case IFF_JFIF_JPEG: /* default quality; baseline sequential */
729  ret = pixWriteMemJpeg(pdata, psize, pix, var_JPEG_QUALITY, 0);
730  break;
731 
732  case IFF_PNG: /* no gamma value stored */
733  ret = pixWriteMemPng(pdata, psize, pix, 0.0);
734  break;
735 
736  case IFF_TIFF: /* uncompressed */
737  case IFF_TIFF_PACKBITS: /* compressed, binary only */
738  case IFF_TIFF_RLE: /* compressed, binary only */
739  case IFF_TIFF_G3: /* compressed, binary only */
740  case IFF_TIFF_G4: /* compressed, binary only */
741  case IFF_TIFF_LZW: /* compressed, all depths */
742  case IFF_TIFF_ZIP: /* compressed, all depths */
743  ret = pixWriteMemTiff(pdata, psize, pix, format);
744  break;
745 
746  case IFF_PNM:
747  ret = pixWriteMemPnm(pdata, psize, pix);
748  break;
749 
750  case IFF_PS:
751  ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DEFAULT_SCALING);
752  break;
753 
754  case IFF_GIF:
755  ret = pixWriteMemGif(pdata, psize, pix);
756  break;
757 
758  case IFF_JP2:
759  ret = pixWriteMemJp2k(pdata, psize, pix, 34, 0, 0, 0);
760  break;
761 
762  case IFF_WEBP:
763  ret = pixWriteMemWebP(pdata, psize, pix, 80, 0);
764  break;
765 
766  case IFF_LPDF:
767  ret = pixWriteMemPdf(pdata, psize, pix, 0, NULL);
768  break;
769 
770  case IFF_SPIX:
771  ret = pixWriteMemSpix(pdata, psize, pix);
772  break;
773 
774  default:
775  return ERROR_INT("unknown format", procName, 1);
776  break;
777  }
778 
779  return ret;
780 }
781 
782 
783 /*---------------------------------------------------------------------*
784  * Image display for debugging *
785  *---------------------------------------------------------------------*/
802 l_ok
803 l_fileDisplay(const char *fname,
804  l_int32 x,
805  l_int32 y,
806  l_float32 scale)
807 {
808 PIX *pixs, *pixd;
809 
810  PROCNAME("l_fileDisplay");
811 
812  if (!LeptDebugOK) {
813  L_INFO("displaying files is disabled; "
814  "use setLeptDebugOK(1) to enable\n", procName);
815  return 0;
816  }
817  if (scale == 0.0)
818  return 0;
819  if (scale < 0.0)
820  return ERROR_INT("invalid scale factor", procName, 1);
821  if ((pixs = pixRead(fname)) == NULL)
822  return ERROR_INT("pixs not read", procName, 1);
823 
824  if (scale == 1.0) {
825  pixd = pixClone(pixs);
826  } else {
827  if (scale < 1.0 && pixGetDepth(pixs) == 1)
828  pixd = pixScaleToGray(pixs, scale);
829  else
830  pixd = pixScale(pixs, scale, scale);
831  }
832  pixDisplay(pixd, x, y);
833  pixDestroy(&pixs);
834  pixDestroy(&pixd);
835  return 0;
836 }
837 
838 
878 l_ok
879 pixDisplay(PIX *pixs,
880  l_int32 x,
881  l_int32 y)
882 {
883  return pixDisplayWithTitle(pixs, x, y, NULL, 1);
884 }
885 
886 
902 l_ok
903 pixDisplayWithTitle(PIX *pixs,
904  l_int32 x,
905  l_int32 y,
906  const char *title,
907  l_int32 dispflag)
908 {
909 char *tempname;
910 char buffer[L_BUFSIZE];
911 static l_int32 index = 0; /* caution: not .so or thread safe */
912 l_int32 w, h, d, spp, maxheight, opaque, threeviews;
913 l_float32 ratw, rath, ratmin;
914 PIX *pix0, *pix1, *pix2;
915 PIXCMAP *cmap;
916 #ifndef _WIN32
917 l_int32 wt, ht;
918 #else
919 char *pathname;
920 char fullpath[_MAX_PATH];
921 #endif /* _WIN32 */
922 
923  PROCNAME("pixDisplayWithTitle");
924 
925  if (!LeptDebugOK) {
926  L_INFO("displaying images is disabled;\n "
927  "use setLeptDebugOK(1) to enable\n", procName);
928  return 0;
929  }
930 
931 #ifdef OS_IOS /* iOS 11 does not support system() */
932  return ERROR_INT("iOS 11 does not support system()", procName, 1);
933 #endif /* OS_IOS */
934 
935  if (dispflag != 1) return 0;
936  if (!pixs)
937  return ERROR_INT("pixs not defined", procName, 1);
938  if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV &&
939  var_DISPLAY_PROG != L_DISPLAY_WITH_XLI &&
940  var_DISPLAY_PROG != L_DISPLAY_WITH_XV &&
941  var_DISPLAY_PROG != L_DISPLAY_WITH_IV &&
942  var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) {
943  return ERROR_INT("no program chosen for display", procName, 1);
944  }
945 
946  /* Display with three views if either spp = 4 or if colormapped
947  * and the alpha component is not fully opaque */
948  opaque = TRUE;
949  if ((cmap = pixGetColormap(pixs)) != NULL)
950  pixcmapIsOpaque(cmap, &opaque);
951  spp = pixGetSpp(pixs);
952  threeviews = (spp == 4 || !opaque) ? TRUE : FALSE;
953 
954  /* If colormapped and not opaque, remove the colormap to RGBA */
955  if (!opaque)
957  else
958  pix0 = pixClone(pixs);
959 
960  /* Scale if necessary; this will also remove a colormap */
961  pixGetDimensions(pix0, &w, &h, &d);
962  maxheight = (threeviews) ? MAX_DISPLAY_HEIGHT / 3 : MAX_DISPLAY_HEIGHT;
963  if (w <= MAX_DISPLAY_WIDTH && h <= maxheight) {
964  if (d == 16) /* take MSB */
965  pix1 = pixConvert16To8(pix0, 1);
966  else
967  pix1 = pixClone(pix0);
968  } else {
969  ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w;
970  rath = (l_float32)maxheight / (l_float32)h;
971  ratmin = L_MIN(ratw, rath);
972  if (ratmin < 0.125 && d == 1)
973  pix1 = pixScaleToGray8(pix0);
974  else if (ratmin < 0.25 && d == 1)
975  pix1 = pixScaleToGray4(pix0);
976  else if (ratmin < 0.33 && d == 1)
977  pix1 = pixScaleToGray3(pix0);
978  else if (ratmin < 0.5 && d == 1)
979  pix1 = pixScaleToGray2(pix0);
980  else
981  pix1 = pixScale(pix0, ratmin, ratmin);
982  }
983  pixDestroy(&pix0);
984  if (!pix1)
985  return ERROR_INT("pix1 not made", procName, 1);
986 
987  /* Generate the three views if required */
988  if (threeviews)
989  pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0);
990  else
991  pix2 = pixClone(pix1);
992 
993  if (index == 0) { /* erase any existing images */
994  lept_rmdir("lept/disp");
995  lept_mkdir("lept/disp");
996  }
997 
998  index++;
999  if (pixGetDepth(pix2) < 8 || pixGetColormap(pix2) ||
1000  (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) {
1001  snprintf(buffer, L_BUFSIZE, "/tmp/lept/disp/write.%03d.png", index);
1002  pixWrite(buffer, pix2, IFF_PNG);
1003  } else {
1004  snprintf(buffer, L_BUFSIZE, "/tmp/lept/disp/write.%03d.jpg", index);
1005  pixWrite(buffer, pix2, IFF_JFIF_JPEG);
1006  }
1007  tempname = genPathname(buffer, NULL);
1008 
1009 #ifndef _WIN32
1010 
1011  /* Unix */
1012  if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) {
1013  /* no way to display title */
1014  pixGetDimensions(pix2, &wt, &ht, NULL);
1015  snprintf(buffer, L_BUFSIZE,
1016  "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10,
1017  x, y, tempname);
1018  } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) {
1019  if (title) {
1020  snprintf(buffer, L_BUFSIZE,
1021  "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &",
1022  x, y, title, tempname);
1023  } else {
1024  snprintf(buffer, L_BUFSIZE,
1025  "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &",
1026  x, y, tempname);
1027  }
1028  } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) {
1029  if (title) {
1030  snprintf(buffer, L_BUFSIZE,
1031  "xv -quit -geometry +%d+%d -name \"%s\" %s &",
1032  x, y, title, tempname);
1033  } else {
1034  snprintf(buffer, L_BUFSIZE,
1035  "xv -quit -geometry +%d+%d %s &", x, y, tempname);
1036  }
1037  } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_OPEN) {
1038  snprintf(buffer, L_BUFSIZE, "open %s &", tempname);
1039  }
1040  callSystemDebug(buffer);
1041 
1042 #else /* _WIN32 */
1043 
1044  /* Windows: L_DISPLAY_WITH_IV */
1045  pathname = genPathname(tempname, NULL);
1046  _fullpath(fullpath, pathname, sizeof(fullpath));
1047  if (title) {
1048  snprintf(buffer, L_BUFSIZE,
1049  "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"",
1050  fullpath, x, y, title);
1051  } else {
1052  snprintf(buffer, L_BUFSIZE, "i_view32.exe \"%s\" /pos=(%d,%d)",
1053  fullpath, x, y);
1054  }
1055  callSystemDebug(buffer);
1056  LEPT_FREE(pathname);
1057 
1058 #endif /* _WIN32 */
1059 
1060  pixDestroy(&pix1);
1061  pixDestroy(&pix2);
1062  LEPT_FREE(tempname);
1063  return 0;
1064 }
1065 
1066 
1078 l_ok
1079 pixSaveTiled(PIX *pixs,
1080  PIXA *pixa,
1081  l_float32 scalefactor,
1082  l_int32 newrow,
1083  l_int32 space,
1084  l_int32 dp)
1085 {
1086  /* Save without an outline */
1087  return pixSaveTiledOutline(pixs, pixa, scalefactor, newrow, space, 0, dp);
1088 }
1089 
1090 
1129 l_ok
1130 pixSaveTiledOutline(PIX *pixs,
1131  PIXA *pixa,
1132  l_float32 scalefactor,
1133  l_int32 newrow,
1134  l_int32 space,
1135  l_int32 linewidth,
1136  l_int32 dp)
1137 {
1138 l_int32 n, top, left, bx, by, bw, w, h, depth, bottom;
1139 BOX *box;
1140 PIX *pix1, *pix2, *pix3, *pix4;
1141 
1142  PROCNAME("pixSaveTiledOutline");
1143 
1144  if (scalefactor == 0.0) return 0;
1145 
1146  if (!pixs)
1147  return ERROR_INT("pixs not defined", procName, 1);
1148  if (!pixa)
1149  return ERROR_INT("pixa not defined", procName, 1);
1150 
1151  n = pixaGetCount(pixa);
1152  if (n == 0) {
1153  bottom = 0;
1154  if (dp != 8 && dp != 32) {
1155  L_WARNING("dp not 8 or 32 bpp; using 32\n", procName);
1156  depth = 32;
1157  } else {
1158  depth = dp;
1159  }
1160  } else { /* extract the depth and bottom params from the first pix */
1161  pix1 = pixaGetPix(pixa, 0, L_CLONE);
1162  depth = pixGetDepth(pix1);
1163  bottom = pixGetInputFormat(pix1); /* not typical usage! */
1164  pixDestroy(&pix1);
1165  }
1166 
1167  /* Remove colormap if it exists; otherwise a copy. This
1168  * guarantees that pix4 is not a clone of pixs. */
1170 
1171  /* Scale and convert to output depth */
1172  if (scalefactor == 1.0) {
1173  pix2 = pixClone(pix1);
1174  } else if (scalefactor > 1.0) {
1175  pix2 = pixScale(pix1, scalefactor, scalefactor);
1176  } else { /* scalefactor < 1.0) */
1177  if (pixGetDepth(pix1) == 1)
1178  pix2 = pixScaleToGray(pix1, scalefactor);
1179  else
1180  pix2 = pixScale(pix1, scalefactor, scalefactor);
1181  }
1182  pixDestroy(&pix1);
1183  if (depth == 8)
1184  pix3 = pixConvertTo8(pix2, 0);
1185  else
1186  pix3 = pixConvertTo32(pix2);
1187  pixDestroy(&pix2);
1188 
1189  /* Add black outline */
1190  if (linewidth > 0)
1191  pix4 = pixAddBorder(pix3, linewidth, 0);
1192  else
1193  pix4 = pixClone(pix3);
1194  pixDestroy(&pix3);
1195 
1196  /* Find position of current pix (UL corner plus size) */
1197  if (n == 0) {
1198  top = 0;
1199  left = 0;
1200  } else if (newrow == 1) {
1201  top = bottom + space;
1202  left = 0;
1203  } else { /* n > 0 */
1204  pixaGetBoxGeometry(pixa, n - 1, &bx, &by, &bw, NULL);
1205  top = by;
1206  left = bx + bw + space;
1207  }
1208 
1209  pixGetDimensions(pix4, &w, &h, NULL);
1210  bottom = L_MAX(bottom, top + h);
1211  box = boxCreate(left, top, w, h);
1212  pixaAddPix(pixa, pix4, L_INSERT);
1213  pixaAddBox(pixa, box, L_INSERT);
1214 
1215  /* Save the new bottom value */
1216  pix1 = pixaGetPix(pixa, 0, L_CLONE);
1217  pixSetInputFormat(pix1, bottom); /* not typical usage! */
1218  pixDestroy(&pix1);
1219  return 0;
1220 }
1221 
1222 
1259 l_ok
1260 pixSaveTiledWithText(PIX *pixs,
1261  PIXA *pixa,
1262  l_int32 outwidth,
1263  l_int32 newrow,
1264  l_int32 space,
1265  l_int32 linewidth,
1266  L_BMF *bmf,
1267  const char *textstr,
1268  l_uint32 val,
1269  l_int32 location)
1270 {
1271 PIX *pix1, *pix2, *pix3, *pix4;
1272 
1273  PROCNAME("pixSaveTiledWithText");
1274 
1275  if (outwidth == 0) return 0;
1276 
1277  if (!pixs)
1278  return ERROR_INT("pixs not defined", procName, 1);
1279  if (!pixa)
1280  return ERROR_INT("pixa not defined", procName, 1);
1281 
1282  pix1 = pixConvertTo32(pixs);
1283  if (linewidth > 0)
1284  pix2 = pixAddBorder(pix1, linewidth, 0);
1285  else
1286  pix2 = pixClone(pix1);
1287  if (bmf && textstr)
1288  pix3 = pixAddSingleTextblock(pix2, bmf, textstr, val, location, NULL);
1289  else
1290  pix3 = pixClone(pix2);
1291  pix4 = pixScaleToSize(pix3, outwidth, 0);
1292  pixSaveTiled(pix4, pixa, 1.0, newrow, space, 32);
1293  pixDestroy(&pix1);
1294  pixDestroy(&pix2);
1295  pixDestroy(&pix3);
1296  pixDestroy(&pix4);
1297  return 0;
1298 }
1299 
1300 
1301 void
1302 l_chooseDisplayProg(l_int32 selection)
1303 {
1304  if (selection == L_DISPLAY_WITH_XLI ||
1305  selection == L_DISPLAY_WITH_XZGV ||
1306  selection == L_DISPLAY_WITH_XV ||
1307  selection == L_DISPLAY_WITH_IV ||
1308  selection == L_DISPLAY_WITH_OPEN) {
1309  var_DISPLAY_PROG = selection;
1310  } else {
1311  L_ERROR("invalid display program\n", "l_chooseDisplayProg");
1312  }
1313  return;
1314 }
1315 
1316 
1317 /*---------------------------------------------------------------------*
1318  * Deprecated pix output for debugging *
1319  *---------------------------------------------------------------------*/
1348 l_ok
1349 pixDisplayWrite(PIX *pixs,
1350  l_int32 reduction)
1351 {
1352 char buf[L_BUFSIZE];
1353 char *fname;
1354 l_float32 scale;
1355 PIX *pix1, *pix2;
1356 static l_int32 index = 0; /* caution: not .so or thread safe */
1357 
1358  PROCNAME("pixDisplayWrite");
1359 
1360  if (reduction == 0) return 0;
1361  if (reduction < 0) { /* initialize */
1362  lept_rmdir("lept/display");
1363  index = 0;
1364  return 0;
1365  }
1366  if (!pixs)
1367  return ERROR_INT("pixs not defined", procName, 1);
1368  if (index == 0)
1369  lept_mkdir("lept/display");
1370  index++;
1371 
1372  if (reduction == 1) {
1373  pix1 = pixClone(pixs);
1374  } else {
1375  scale = 1. / (l_float32)reduction;
1376  if (pixGetDepth(pixs) == 1)
1377  pix1 = pixScaleToGray(pixs, scale);
1378  else
1379  pix1 = pixScale(pixs, scale, scale);
1380  }
1381 
1382  if (pixGetDepth(pix1) == 16) {
1383  pix2 = pixMaxDynamicRange(pix1, L_LOG_SCALE);
1384  snprintf(buf, L_BUFSIZE, "file.%03d.png", index);
1385  fname = pathJoin("/tmp/lept/display", buf);
1386  pixWrite(fname, pix2, IFF_PNG);
1387  pixDestroy(&pix2);
1388  } else if (pixGetDepth(pix1) < 8 || pixGetColormap(pix1)) {
1389  snprintf(buf, L_BUFSIZE, "file.%03d.png", index);
1390  fname = pathJoin("/tmp/lept/display", buf);
1391  pixWrite(fname, pix1, IFF_PNG);
1392  } else {
1393  snprintf(buf, L_BUFSIZE, "file.%03d.jpg", index);
1394  fname = pathJoin("/tmp/lept/display", buf);
1395  pixWrite(fname, pix1, IFF_JFIF_JPEG);
1396  }
1397  LEPT_FREE(fname);
1398  pixDestroy(&pix1);
1399  return 0;
1400 }
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
l_ok pixWriteStreamBmp(FILE *fp, PIX *pix)
pixWriteStreamBmp()
Definition: bmpio.c:359
l_ok pixWriteMemPS(l_uint8 **pdata, size_t *psize, PIX *pix, BOX *box, l_int32 res, l_float32 scale)
pixWriteMemPS()
Definition: psio2.c:1922
l_ok pixWriteMemTiff(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype)
pixWriteMemTiff()
Definition: tiffio.c:2730
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:1944
Definition: pix.h:717
PIX * pixScaleToGray(PIX *pixs, l_float32 scalefactor)
pixScaleToGray()
Definition: scale2.c:204
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3233
l_ok splitPathAtExtension(const char *pathname, char **pbasename, char **pextension)
splitPathAtExtension()
Definition: utils2.c:2607
l_ok pixWriteMemBmp(l_uint8 **pfdata, size_t *pfsize, PIX *pixs)
pixWriteMemBmp()
Definition: bmpio.c:404
char * genPathname(const char *dir, const char *fname)
genPathname()
Definition: utils2.c:2880
PIX * pixMaxDynamicRange(PIX *pixs, l_int32 type)
pixMaxDynamicRange()
Definition: pixarith.c:1155
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
l_ok pixWriteStreamTiff(FILE *fp, PIX *pix, l_int32 comptype)
pixWriteStreamTiff()
Definition: tiffio.c:803
l_ok pixWriteMemPdf(l_uint8 **pdata, size_t *pnbytes, PIX *pix, l_int32 res, const char *title)
pixWriteMemPdf()
Definition: pdfio1.c:1335
PIX * pixRemoveColormapGeneral(PIX *pixs, l_int32 type, l_int32 ifnocmap)
pixRemoveColormapGeneral()
Definition: pixconv.c:272
l_ok pixWriteStreamPng(FILE *fp, PIX *pix, l_float32 gamma)
pixWriteStreamPng()
Definition: pngio.c:1007
l_ok pixWriteStreamSpix(FILE *fp, PIX *pix)
pixWriteStreamSpix()
Definition: spixio.c:265
PIX * pixScaleToGray3(PIX *pixs)
pixScaleToGray3()
Definition: scale2.c:443
Definition: bmf.h:45
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1748
PIX * pixScaleToGray8(PIX *pixs)
pixScaleToGray8()
Definition: scale2.c:600
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
l_ok pixWriteStreamJpeg(FILE *fp, PIX *pixs, l_int32 quality, l_int32 progressive)
pixWriteStreamJpeg()
Definition: jpegio.c:793
l_ok pixWriteStreamPdf(FILE *fp, PIX *pix, l_int32 res, const char *title)
pixWriteStreamPdf()
Definition: pdfio1.c:1286
l_ok pixWriteMemPng(l_uint8 **pfiledata, size_t *pfilesize, PIX *pix, l_float32 gamma)
pixWriteMemPng()
Definition: pngio.c:1859
l_ok pixaGetBoxGeometry(PIXA *pixa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
pixaGetBoxGeometry()
Definition: pixabasic.c:835
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
l_ok pixcmapIsOpaque(PIXCMAP *cmap, l_int32 *popaque)
pixcmapIsOpaque()
Definition: colormap.c:1041
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:317
l_ok pixWriteStreamPnm(FILE *fp, PIX *pix)
pixWriteStreamPnm()
Definition: pnmio.c:667
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
Definition: pix.h:454
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
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:190
l_ok pixWriteStreamPS(FILE *fp, PIX *pix, BOX *box, l_int32 res, l_float32 scale)
pixWriteStreamPS()
Definition: psio2.c:205
l_ok pixWriteMemSpix(l_uint8 **pdata, size_t *psize, PIX *pix)
pixWriteMemSpix()
Definition: spixio.c:313
char * pathJoin(const char *dir, const char *fname)
pathJoin()
Definition: utils2.c:2686
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
Definition: pix.h:718
PIX * pixScaleToGray4(PIX *pixs)
pixScaleToGray4()
Definition: scale2.c:497
PIX * pixDisplayLayersRGBA(PIX *pixs, l_uint32 val, l_int32 maxw)
pixDisplayLayersRGBA()
Definition: pix2.c:2276
Definition: pix.h:134
Definition: pix.h:719
void callSystemDebug(const char *cmd)
callSystemDebug()
Definition: utils2.c:2474
PIX * pixConvert16To8(PIX *pixs, l_int32 type)
pixConvert16To8()
Definition: pixconv.c:1689
l_int32 lept_rmdir(const char *subdir)
lept_rmdir()
Definition: utils2.c:2021
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:547
Definition: pix.h:480
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:244
PIX * pixAddSingleTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location, l_int32 *poverflow)
pixAddSingleTextblock()
Definition: textops.c:115
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:165
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:631
l_ok pixWriteMemPnm(l_uint8 **pdata, size_t *psize, PIX *pix)
pixWriteMemPnm()
Definition: pnmio.c:1159
PIX * pixScaleToGray2(PIX *pixs)
pixScaleToGray2()
Definition: scale2.c:386