Leptonica  1.73
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  * High-level procedures for writing images to file:
31  * l_int32 pixaWriteFiles()
32  * l_int32 pixWrite() [behavior depends on WRITE_AS_NAMED]
33  * l_int32 pixWriteAutoFormat()
34  * l_int32 pixWriteStream()
35  * l_int32 pixWriteImpliedFormat()
36  *
37  * Selection of output format if default is requested
38  * l_int32 pixChooseOutputFormat()
39  * l_int32 getImpliedFileFormat()
40  * l_int32 pixGetAutoFormat()
41  * const char *getFormatExtension()
42  *
43  * Write to memory
44  * l_int32 pixWriteMem()
45  *
46  * Image display for debugging
47  * l_int32 l_fileDisplay()
48  * l_int32 pixDisplay()
49  * l_int32 pixDisplayWithTitle()
50  * l_int32 pixSaveTiled()
51  * l_int32 pixSaveTiledOutline()
52  * l_int32 pixSaveTiledWithText()
53  * void l_chooseDisplayProg()
54  *
55  * Deprecated pix output for debugging
56  * l_int32 pixDisplayWrite()
57  * l_int32 pixDisplayWriteFormat()
58  * l_int32 pixDisplayMultiple()
59  *
60  * Supported file formats:
61  * (1) Writing is supported without any external libraries:
62  * bmp
63  * pnm (including pbm, pgm, etc)
64  * spix (raw serialized)
65  * (2) Writing is supported with installation of external libraries:
66  * png
67  * jpg (standard jfif version)
68  * tiff (including most varieties of compression)
69  * gif
70  * webp
71  * jp2 (jpeg2000)
72  * (3) Writing is supported through special interfaces:
73  * ps (PostScript, in psio1.c, psio2.c):
74  * level 1 (uncompressed)
75  * level 2 (g4 and dct encoding: requires tiff, jpg)
76  * level 3 (g4, dct and flate encoding: requires tiff, jpg, zlib)
77  * pdf (PDF, in pdfio.c):
78  * level 1 (g4 and dct encoding: requires tiff, jpg)
79  * level 2 (g4, dct and flate encoding: requires tiff, jpg, zlib)
80  */
81 
82 #include <string.h>
83 #include "allheaders.h"
84 
85  /* Special flag for pixWrite(). The default for both unix and */
86  /* windows is to use whatever filename is given, as opposed to */
87  /* insuring the filename extension matches the image compression. */
88 #define WRITE_AS_NAMED 1
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_BUF_SIZE = 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 = 19; /* 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  "default",
136  ""};
137 
138  /* Local map of image file name extension to output format */
140 {
141  char extension[8];
142  l_int32 format;
143 };
144 static const struct ExtensionMap extension_map[] =
145  { { ".bmp", IFF_BMP },
146  { ".jpg", IFF_JFIF_JPEG },
147  { ".jpeg", IFF_JFIF_JPEG },
148  { ".png", IFF_PNG },
149  { ".tif", IFF_TIFF },
150  { ".tiff", IFF_TIFF },
151  { ".pnm", IFF_PNM },
152  { ".gif", IFF_GIF },
153  { ".jp2", IFF_JP2 },
154  { ".ps", IFF_PS },
155  { ".pdf", IFF_LPDF },
156  { ".webp", IFF_WEBP } };
157 
158 
159 /*---------------------------------------------------------------------*
160  * Top-level procedures for writing images to file *
161  *---------------------------------------------------------------------*/
176 l_int32
177 pixaWriteFiles(const char *rootname,
178  PIXA *pixa,
179  l_int32 format)
180 {
181 char bigbuf[L_BUF_SIZE];
182 l_int32 i, n, pixformat;
183 PIX *pix;
184 
185  PROCNAME("pixaWriteFiles");
186 
187  if (!rootname)
188  return ERROR_INT("rootname not defined", procName, 1);
189  if (!pixa)
190  return ERROR_INT("pixa not defined", procName, 1);
191  if (format < 0 || format == IFF_UNKNOWN ||
192  format >= NumImageFileFormatExtensions)
193  return ERROR_INT("invalid format", procName, 1);
194 
195  n = pixaGetCount(pixa);
196  for (i = 0; i < n; i++) {
197  pix = pixaGetPix(pixa, i, L_CLONE);
198  if (format == IFF_DEFAULT)
199  pixformat = pixChooseOutputFormat(pix);
200  else
201  pixformat = format;
202  snprintf(bigbuf, L_BUF_SIZE, "%s%03d.%s", rootname, i,
203  ImageFileFormatExtensions[pixformat]);
204  pixWrite(bigbuf, pix, pixformat);
205  pixDestroy(&pix);
206  }
207 
208  return 0;
209 }
210 
211 
239 l_int32
240 pixWrite(const char *fname,
241  PIX *pix,
242  l_int32 format)
243 {
244 l_int32 ret;
245 FILE *fp;
246 
247  PROCNAME("pixWrite");
248 
249  if (!pix)
250  return ERROR_INT("pix not defined", procName, 1);
251  if (!fname)
252  return ERROR_INT("fname not defined", procName, 1);
253 
254 #if WRITE_AS_NAMED /* Default */
255 
256  if ((fp = fopenWriteStream(fname, "wb+")) == NULL)
257  return ERROR_INT("stream not opened", procName, 1);
258 
259 #else /* Add an extension to the output name if none exists */
260 
261  {l_int32 extlen;
262  char *extension, *filebuf;
263  splitPathAtExtension(fname, NULL, &extension);
264  extlen = strlen(extension);
265  LEPT_FREE(extension);
266  if (extlen == 0) {
267  if (format == IFF_DEFAULT || format == IFF_UNKNOWN)
268  format = pixChooseOutputFormat(pix);
269 
270  filebuf = (char *)LEPT_CALLOC(strlen(fname) + 10, sizeof(char));
271  if (!filebuf)
272  return ERROR_INT("filebuf not made", procName, 1);
273  strncpy(filebuf, fname, strlen(fname));
274  strcat(filebuf, ".");
275  strcat(filebuf, ImageFileFormatExtensions[format]);
276  } else {
277  filebuf = (char *)fname;
278  }
279 
280  fp = fopenWriteStream(filebuf, "wb+");
281  if (filebuf != fname)
282  LEPT_FREE(filebuf);
283  if (fp == NULL)
284  return ERROR_INT("stream not opened", procName, 1);
285  }
286 
287 #endif /* WRITE_AS_NAMED */
288 
289  ret = pixWriteStream(fp, pix, format);
290  fclose(fp);
291  if (ret)
292  return ERROR_INT("pix not written to stream", procName, 1);
293  return 0;
294 }
295 
296 
304 l_int32
305 pixWriteAutoFormat(const char *filename,
306  PIX *pix)
307 {
308 l_int32 format;
309 
310  PROCNAME("pixWriteAutoFormat");
311 
312  if (!pix)
313  return ERROR_INT("pix not defined", procName, 1);
314  if (!filename)
315  return ERROR_INT("filename not defined", procName, 1);
316 
317  if (pixGetAutoFormat(pix, &format))
318  return ERROR_INT("auto format not returned", procName, 1);
319  return pixWrite(filename, pix, format);
320 }
321 
322 
331 l_int32
332 pixWriteStream(FILE *fp,
333  PIX *pix,
334  l_int32 format)
335 {
336  PROCNAME("pixWriteStream");
337 
338  if (!fp)
339  return ERROR_INT("stream not defined", procName, 1);
340  if (!pix)
341  return ERROR_INT("pix not defined", procName, 1);
342 
343  if (format == IFF_DEFAULT)
344  format = pixChooseOutputFormat(pix);
345 
346  switch(format)
347  {
348  case IFF_BMP:
349  pixWriteStreamBmp(fp, pix);
350  break;
351 
352  case IFF_JFIF_JPEG: /* default quality; baseline sequential */
353  return pixWriteStreamJpeg(fp, pix, 75, 0);
354  break;
355 
356  case IFF_PNG: /* no gamma value stored */
357  return pixWriteStreamPng(fp, pix, 0.0);
358  break;
359 
360  case IFF_TIFF: /* uncompressed */
361  case IFF_TIFF_PACKBITS: /* compressed, binary only */
362  case IFF_TIFF_RLE: /* compressed, binary only */
363  case IFF_TIFF_G3: /* compressed, binary only */
364  case IFF_TIFF_G4: /* compressed, binary only */
365  case IFF_TIFF_LZW: /* compressed, all depths */
366  case IFF_TIFF_ZIP: /* compressed, all depths */
367  return pixWriteStreamTiff(fp, pix, format);
368  break;
369 
370  case IFF_PNM:
371  return pixWriteStreamPnm(fp, pix);
372  break;
373 
374  case IFF_PS:
375  return pixWriteStreamPS(fp, pix, NULL, 0, DEFAULT_SCALING);
376  break;
377 
378  case IFF_GIF:
379  return pixWriteStreamGif(fp, pix);
380  break;
381 
382  case IFF_JP2:
383  return pixWriteStreamJp2k(fp, pix, 34, 4, 0, 0);
384  break;
385 
386  case IFF_WEBP:
387  return pixWriteStreamWebP(fp, pix, 80, 0);
388  break;
389 
390  case IFF_LPDF:
391  return pixWriteStreamPdf(fp, pix, 0, NULL);
392  break;
393 
394  case IFF_SPIX:
395  return pixWriteStreamSpix(fp, pix);
396  break;
397 
398  default:
399  return ERROR_INT("unknown format", procName, 1);
400  break;
401  }
402 
403  return 0;
404 }
405 
406 
423 l_int32
424 pixWriteImpliedFormat(const char *filename,
425  PIX *pix,
426  l_int32 quality,
427  l_int32 progressive)
428 {
429 l_int32 format;
430 
431  PROCNAME("pixWriteImpliedFormat");
432 
433  if (!filename)
434  return ERROR_INT("filename not defined", procName, 1);
435  if (!pix)
436  return ERROR_INT("pix not defined", procName, 1);
437 
438  /* Determine output format */
439  format = getImpliedFileFormat(filename);
440  if (format == IFF_UNKNOWN) {
441  format = IFF_PNG;
442  } else if (format == IFF_TIFF) {
443  if (pixGetDepth(pix) == 1)
444  format = IFF_TIFF_G4;
445  else
446 #ifdef _WIN32
447  format = IFF_TIFF_LZW; /* poor compression */
448 #else
449  format = IFF_TIFF_ZIP; /* native windows tools can't handle this */
450 #endif /* _WIN32 */
451  }
452 
453  if (format == IFF_JFIF_JPEG) {
454  quality = L_MIN(quality, 100);
455  quality = L_MAX(quality, 0);
456  if (progressive != 0 && progressive != 1) {
457  progressive = 0;
458  L_WARNING("invalid progressive; setting to baseline\n", procName);
459  }
460  if (quality == 0)
461  quality = 75;
462  pixWriteJpeg (filename, pix, quality, progressive);
463  } else {
464  pixWrite(filename, pix, format);
465  }
466 
467  return 0;
468 }
469 
470 
471 /*---------------------------------------------------------------------*
472  * Selection of output format if default is requested *
473  *---------------------------------------------------------------------*/
488 l_int32
489 pixChooseOutputFormat(PIX *pix)
490 {
491 l_int32 d, format;
492 
493  PROCNAME("pixChooseOutputFormat");
494 
495  if (!pix)
496  return ERROR_INT("pix not defined", procName, 0);
497 
498  d = pixGetDepth(pix);
499  format = pixGetInputFormat(pix);
500  if (format == IFF_UNKNOWN) { /* output lossless */
501  if (d == 1)
502  format = IFF_TIFF_G4;
503  else
504  format = IFF_PNG;
505  }
506 
507  return format;
508 }
509 
510 
523 l_int32
524 getImpliedFileFormat(const char *filename)
525 {
526 char *extension;
527 int i, numext;
528 l_int32 format = IFF_UNKNOWN;
529 
530  if (splitPathAtExtension (filename, NULL, &extension))
531  return IFF_UNKNOWN;
532 
533  numext = sizeof(extension_map) / sizeof(extension_map[0]);
534  for (i = 0; i < numext; i++) {
535  if (!strcmp(extension, extension_map[i].extension)) {
536  format = extension_map[i].format;
537  break;
538  }
539  }
540 
541  LEPT_FREE(extension);
542  return format;
543 }
544 
545 
564 l_int32
565 pixGetAutoFormat(PIX *pix,
566  l_int32 *pformat)
567 {
568 l_int32 d;
569 PIXCMAP *cmap;
570 
571  PROCNAME("pixGetAutoFormat");
572 
573  if (!pformat)
574  return ERROR_INT("&format not defined", procName, 0);
575  *pformat = IFF_UNKNOWN;
576  if (!pix)
577  return ERROR_INT("pix not defined", procName, 0);
578 
579  d = pixGetDepth(pix);
580  cmap = pixGetColormap(pix);
581  if (d == 1 && !cmap) {
582  *pformat = IFF_TIFF_G4;
583  } else if ((d == 8 && !cmap) || d == 24 || d == 32) {
584  *pformat = IFF_JFIF_JPEG;
585  } else {
586  *pformat = IFF_PNG;
587  }
588 
589  return 0;
590 }
591 
592 
605 const char *
606 getFormatExtension(l_int32 format)
607 {
608  PROCNAME("getFormatExtension");
609 
610  if (format < 0 || format >= NumImageFileFormatExtensions)
611  return (const char *)ERROR_PTR("invalid format", procName, NULL);
612 
613  return ImageFileFormatExtensions[format];
614 }
615 
616 
617 /*---------------------------------------------------------------------*
618  * Write to memory *
619  *---------------------------------------------------------------------*/
638 l_int32
639 pixWriteMem(l_uint8 **pdata,
640  size_t *psize,
641  PIX *pix,
642  l_int32 format)
643 {
644 l_int32 ret;
645 
646  PROCNAME("pixWriteMem");
647 
648  if (!pdata)
649  return ERROR_INT("&data not defined", procName, 1 );
650  if (!psize)
651  return ERROR_INT("&size not defined", procName, 1 );
652  if (!pix)
653  return ERROR_INT("&pix not defined", procName, 1 );
654 
655  if (format == IFF_DEFAULT)
656  format = pixChooseOutputFormat(pix);
657 
658  switch(format)
659  {
660  case IFF_BMP:
661  ret = pixWriteMemBmp(pdata, psize, pix);
662  break;
663 
664  case IFF_JFIF_JPEG: /* default quality; baseline sequential */
665  ret = pixWriteMemJpeg(pdata, psize, pix, 75, 0);
666  break;
667 
668  case IFF_PNG: /* no gamma value stored */
669  ret = pixWriteMemPng(pdata, psize, pix, 0.0);
670  break;
671 
672  case IFF_TIFF: /* uncompressed */
673  case IFF_TIFF_PACKBITS: /* compressed, binary only */
674  case IFF_TIFF_RLE: /* compressed, binary only */
675  case IFF_TIFF_G3: /* compressed, binary only */
676  case IFF_TIFF_G4: /* compressed, binary only */
677  case IFF_TIFF_LZW: /* compressed, all depths */
678  case IFF_TIFF_ZIP: /* compressed, all depths */
679  ret = pixWriteMemTiff(pdata, psize, pix, format);
680  break;
681 
682  case IFF_PNM:
683  ret = pixWriteMemPnm(pdata, psize, pix);
684  break;
685 
686  case IFF_PS:
687  ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DEFAULT_SCALING);
688  break;
689 
690  case IFF_GIF:
691  ret = pixWriteMemGif(pdata, psize, pix);
692  break;
693 
694  case IFF_JP2:
695  ret = pixWriteMemJp2k(pdata, psize, pix, 34, 0, 0, 0);
696  break;
697 
698  case IFF_WEBP:
699  ret = pixWriteMemWebP(pdata, psize, pix, 80, 0);
700  break;
701 
702  case IFF_LPDF:
703  ret = pixWriteMemPdf(pdata, psize, pix, 0, NULL);
704  break;
705 
706  case IFF_SPIX:
707  ret = pixWriteMemSpix(pdata, psize, pix);
708  break;
709 
710  default:
711  return ERROR_INT("unknown format", procName, 1);
712  break;
713  }
714 
715  return ret;
716 }
717 
718 
719 /*---------------------------------------------------------------------*
720  * Image display for debugging *
721  *---------------------------------------------------------------------*/
737 l_int32
738 l_fileDisplay(const char *fname,
739  l_int32 x,
740  l_int32 y,
741  l_float32 scale)
742 {
743 PIX *pixs, *pixd;
744 
745  PROCNAME("l_fileDisplay");
746 
747  if (scale == 0.0)
748  return 0;
749 
750  if (scale < 0.0)
751  return ERROR_INT("invalid scale factor", procName, 1);
752  if ((pixs = pixRead(fname)) == NULL)
753  return ERROR_INT("pixs not read", procName, 1);
754 
755  if (scale == 1.0) {
756  pixd = pixClone(pixs);
757  } else {
758  if (scale < 1.0 && pixGetDepth(pixs) == 1)
759  pixd = pixScaleToGray(pixs, scale);
760  else
761  pixd = pixScale(pixs, scale, scale);
762  }
763  pixDisplay(pixd, x, y);
764  pixDestroy(&pixs);
765  pixDestroy(&pixd);
766  return 0;
767 }
768 
769 
808 l_int32
809 pixDisplay(PIX *pixs,
810  l_int32 x,
811  l_int32 y)
812 {
813  return pixDisplayWithTitle(pixs, x, y, NULL, 1);
814 }
815 
816 
832 l_int32
833 pixDisplayWithTitle(PIX *pixs,
834  l_int32 x,
835  l_int32 y,
836  const char *title,
837  l_int32 dispflag)
838 {
839 char *tempname;
840 char buffer[L_BUF_SIZE];
841 static l_int32 index = 0; /* caution: not .so or thread safe */
842 l_int32 w, h, d, spp, maxheight, opaque, threeviews, ignore;
843 l_float32 ratw, rath, ratmin;
844 PIX *pix0, *pix1, *pix2;
845 PIXCMAP *cmap;
846 #ifndef _WIN32
847 l_int32 wt, ht;
848 #else
849 char *pathname;
850 char fullpath[_MAX_PATH];
851 #endif /* _WIN32 */
852 
853  PROCNAME("pixDisplayWithTitle");
854 
855  if (dispflag != 1) return 0;
856  if (!pixs)
857  return ERROR_INT("pixs not defined", procName, 1);
858  if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV &&
859  var_DISPLAY_PROG != L_DISPLAY_WITH_XLI &&
860  var_DISPLAY_PROG != L_DISPLAY_WITH_XV &&
861  var_DISPLAY_PROG != L_DISPLAY_WITH_IV &&
862  var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) {
863  return ERROR_INT("no program chosen for display", procName, 1);
864  }
865 
866  /* Display with three views if either spp = 4 or if colormapped
867  * and the alpha component is not fully opaque */
868  opaque = TRUE;
869  if ((cmap = pixGetColormap(pixs)) != NULL)
870  pixcmapIsOpaque(cmap, &opaque);
871  spp = pixGetSpp(pixs);
872  threeviews = (spp == 4 || !opaque) ? TRUE : FALSE;
873 
874  /* If colormapped and not opaque, remove the colormap to RGBA */
875  if (!opaque)
877  else
878  pix0 = pixClone(pixs);
879 
880  /* Scale if necessary; this will also remove a colormap */
881  pixGetDimensions(pix0, &w, &h, &d);
882  maxheight = (threeviews) ? MAX_DISPLAY_HEIGHT / 3 : MAX_DISPLAY_HEIGHT;
883  if (w <= MAX_DISPLAY_WIDTH && h <= maxheight) {
884  if (d == 16) /* take MSB */
885  pix1 = pixConvert16To8(pix0, 1);
886  else
887  pix1 = pixClone(pix0);
888  } else {
889  ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w;
890  rath = (l_float32)maxheight / (l_float32)h;
891  ratmin = L_MIN(ratw, rath);
892  if (ratmin < 0.125 && d == 1)
893  pix1 = pixScaleToGray8(pix0);
894  else if (ratmin < 0.25 && d == 1)
895  pix1 = pixScaleToGray4(pix0);
896  else if (ratmin < 0.33 && d == 1)
897  pix1 = pixScaleToGray3(pix0);
898  else if (ratmin < 0.5 && d == 1)
899  pix1 = pixScaleToGray2(pix0);
900  else
901  pix1 = pixScale(pix0, ratmin, ratmin);
902  }
903  pixDestroy(&pix0);
904  if (!pix1)
905  return ERROR_INT("pix1 not made", procName, 1);
906 
907  /* Generate the three views if required */
908  if (threeviews)
909  pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0);
910  else
911  pix2 = pixClone(pix1);
912 
913  if (index == 0) { /* erase any existing images */
914  lept_rmdir("lept/disp");
915  lept_mkdir("lept/disp");
916  }
917 
918  index++;
919  if (pixGetDepth(pix2) < 8 || pixGetColormap(pix2) ||
920  (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) {
921  snprintf(buffer, L_BUF_SIZE, "/tmp/lept/disp/write.%03d.png", index);
922  pixWrite(buffer, pix2, IFF_PNG);
923  } else {
924  snprintf(buffer, L_BUF_SIZE, "/tmp/lept/disp/write.%03d.jpg", index);
925  pixWrite(buffer, pix2, IFF_JFIF_JPEG);
926  }
927  tempname = genPathname(buffer, NULL);
928 
929 #ifndef _WIN32
930 
931  /* Unix */
932  if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) {
933  /* no way to display title */
934  pixGetDimensions(pix2, &wt, &ht, NULL);
935  snprintf(buffer, L_BUF_SIZE,
936  "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10,
937  x, y, tempname);
938  } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) {
939  if (title) {
940  snprintf(buffer, L_BUF_SIZE,
941  "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &",
942  x, y, title, tempname);
943  } else {
944  snprintf(buffer, L_BUF_SIZE,
945  "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &",
946  x, y, tempname);
947  }
948  } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) {
949  if (title) {
950  snprintf(buffer, L_BUF_SIZE,
951  "xv -quit -geometry +%d+%d -name \"%s\" %s &",
952  x, y, title, tempname);
953  } else {
954  snprintf(buffer, L_BUF_SIZE,
955  "xv -quit -geometry +%d+%d %s &", x, y, tempname);
956  }
957  } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_OPEN) {
958  snprintf(buffer, L_BUF_SIZE, "open %s &", tempname);
959  }
960 #ifndef OS_IOS /* iOS 11 does not support system() */
961  ignore = system(buffer);
962 #endif /* !OS_IOS */
963 
964 #else /* _WIN32 */
965 
966  /* Windows: L_DISPLAY_WITH_IV */
967  pathname = genPathname(tempname, NULL);
968  _fullpath(fullpath, pathname, sizeof(fullpath));
969  if (title) {
970  snprintf(buffer, L_BUF_SIZE,
971  "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"",
972  fullpath, x, y, title);
973  } else {
974  snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d)",
975  fullpath, x, y);
976  }
977  ignore = system(buffer);
978  LEPT_FREE(pathname);
979 
980 #endif /* _WIN32 */
981 
982  pixDestroy(&pix1);
983  pixDestroy(&pix2);
984  LEPT_FREE(tempname);
985  return 0;
986 }
987 
988 
1000 l_int32
1001 pixSaveTiled(PIX *pixs,
1002  PIXA *pixa,
1003  l_float32 scalefactor,
1004  l_int32 newrow,
1005  l_int32 space,
1006  l_int32 dp)
1007 {
1008  /* Save without an outline */
1009  return pixSaveTiledOutline(pixs, pixa, scalefactor, newrow, space, 0, dp);
1010 }
1011 
1012 
1051 l_int32
1052 pixSaveTiledOutline(PIX *pixs,
1053  PIXA *pixa,
1054  l_float32 scalefactor,
1055  l_int32 newrow,
1056  l_int32 space,
1057  l_int32 linewidth,
1058  l_int32 dp)
1059 {
1060 l_int32 n, top, left, bx, by, bw, w, h, depth, bottom;
1061 BOX *box;
1062 PIX *pix1, *pix2, *pix3, *pix4;
1063 
1064  PROCNAME("pixSaveTiledOutline");
1065 
1066  if (scalefactor == 0.0) return 0;
1067 
1068  if (!pixs)
1069  return ERROR_INT("pixs not defined", procName, 1);
1070  if (!pixa)
1071  return ERROR_INT("pixa not defined", procName, 1);
1072 
1073  n = pixaGetCount(pixa);
1074  if (n == 0) {
1075  bottom = 0;
1076  if (dp != 8 && dp != 32) {
1077  L_WARNING("dp not 8 or 32 bpp; using 32\n", procName);
1078  depth = 32;
1079  } else {
1080  depth = dp;
1081  }
1082  } else { /* extract the depth and bottom params from the first pix */
1083  pix1 = pixaGetPix(pixa, 0, L_CLONE);
1084  depth = pixGetDepth(pix1);
1085  bottom = pixGetInputFormat(pix1); /* not typical usage! */
1086  pixDestroy(&pix1);
1087  }
1088 
1089  /* Remove colormap if it exists; otherwise a copy. This
1090  * guarantees that pix4 is not a clone of pixs. */
1092 
1093  /* Scale and convert to output depth */
1094  if (scalefactor == 1.0) {
1095  pix2 = pixClone(pix1);
1096  } else if (scalefactor > 1.0) {
1097  pix2 = pixScale(pix1, scalefactor, scalefactor);
1098  } else { /* scalefactor < 1.0) */
1099  if (pixGetDepth(pix1) == 1)
1100  pix2 = pixScaleToGray(pix1, scalefactor);
1101  else
1102  pix2 = pixScale(pix1, scalefactor, scalefactor);
1103  }
1104  pixDestroy(&pix1);
1105  if (depth == 8)
1106  pix3 = pixConvertTo8(pix2, 0);
1107  else
1108  pix3 = pixConvertTo32(pix2);
1109  pixDestroy(&pix2);
1110 
1111  /* Add black outline */
1112  if (linewidth > 0)
1113  pix4 = pixAddBorder(pix3, linewidth, 0);
1114  else
1115  pix4 = pixClone(pix3);
1116  pixDestroy(&pix3);
1117 
1118  /* Find position of current pix (UL corner plus size) */
1119  if (n == 0) {
1120  top = 0;
1121  left = 0;
1122  } else if (newrow == 1) {
1123  top = bottom + space;
1124  left = 0;
1125  } else { /* n > 0 */
1126  pixaGetBoxGeometry(pixa, n - 1, &bx, &by, &bw, NULL);
1127  top = by;
1128  left = bx + bw + space;
1129  }
1130 
1131  pixGetDimensions(pix4, &w, &h, NULL);
1132  bottom = L_MAX(bottom, top + h);
1133  box = boxCreate(left, top, w, h);
1134  pixaAddPix(pixa, pix4, L_INSERT);
1135  pixaAddBox(pixa, box, L_INSERT);
1136 
1137  /* Save the new bottom value */
1138  pix1 = pixaGetPix(pixa, 0, L_CLONE);
1139  pixSetInputFormat(pix1, bottom); /* not typical usage! */
1140  pixDestroy(&pix1);
1141  return 0;
1142 }
1143 
1144 
1181 l_int32
1182 pixSaveTiledWithText(PIX *pixs,
1183  PIXA *pixa,
1184  l_int32 outwidth,
1185  l_int32 newrow,
1186  l_int32 space,
1187  l_int32 linewidth,
1188  L_BMF *bmf,
1189  const char *textstr,
1190  l_uint32 val,
1191  l_int32 location)
1192 {
1193 PIX *pix1, *pix2, *pix3, *pix4;
1194 
1195  PROCNAME("pixSaveTiledWithText");
1196 
1197  if (outwidth == 0) return 0;
1198 
1199  if (!pixs)
1200  return ERROR_INT("pixs not defined", procName, 1);
1201  if (!pixa)
1202  return ERROR_INT("pixa not defined", procName, 1);
1203 
1204  pix1 = pixConvertTo32(pixs);
1205  if (linewidth > 0)
1206  pix2 = pixAddBorder(pix1, linewidth, 0);
1207  else
1208  pix2 = pixClone(pix1);
1209  if (bmf && textstr)
1210  pix3 = pixAddSingleTextblock(pix2, bmf, textstr, val, location, NULL);
1211  else
1212  pix3 = pixClone(pix2);
1213  pix4 = pixScaleToSize(pix3, outwidth, 0);
1214  pixSaveTiled(pix4, pixa, 1.0, newrow, space, 32);
1215  pixDestroy(&pix1);
1216  pixDestroy(&pix2);
1217  pixDestroy(&pix3);
1218  pixDestroy(&pix4);
1219  return 0;
1220 }
1221 
1222 
1223 void
1224 l_chooseDisplayProg(l_int32 selection)
1225 {
1226  if (selection == L_DISPLAY_WITH_XLI ||
1227  selection == L_DISPLAY_WITH_XZGV ||
1228  selection == L_DISPLAY_WITH_XV ||
1229  selection == L_DISPLAY_WITH_IV ||
1230  selection == L_DISPLAY_WITH_OPEN) {
1231  var_DISPLAY_PROG = selection;
1232  } else {
1233  L_ERROR("invalid display program\n", "l_chooseDisplayProg");
1234  }
1235  return;
1236 }
1237 
1238 
1239 /*---------------------------------------------------------------------*
1240  * Deprecated pix output for debugging *
1241  *---------------------------------------------------------------------*/
1261 l_int32
1262 pixDisplayWrite(PIX *pixs,
1263  l_int32 reduction)
1264 {
1265  return pixDisplayWriteFormat(pixs, reduction, IFF_DEFAULT);
1266 }
1267 
1268 
1305 l_int32
1306 pixDisplayWriteFormat(PIX *pixs,
1307  l_int32 reduction,
1308  l_int32 format)
1309 {
1310 char buf[L_BUF_SIZE];
1311 char *fname;
1312 l_float32 scale;
1313 PIX *pix1, *pix2;
1314 static l_int32 index = 0; /* caution: not .so or thread safe */
1315 
1316  PROCNAME("pixDisplayWriteFormat");
1317 
1318  if (reduction == 0) return 0;
1319 
1320  if (reduction < 0) { /* initialize */
1321  lept_rmdir("lept/display");
1322  index = 0;
1323  return 0;
1324  }
1325 
1326  if (!pixs)
1327  return ERROR_INT("pixs not defined", procName, 1);
1328  if (format != IFF_DEFAULT && format != IFF_PNG) {
1329  L_INFO("invalid format; using default\n", procName);
1330  format = IFF_DEFAULT;
1331  }
1332 
1333  if (index == 0)
1334  lept_mkdir("lept/display");
1335  index++;
1336 
1337  if (reduction == 1) {
1338  pix1 = pixClone(pixs);
1339  } else {
1340  scale = 1. / (l_float32)reduction;
1341  if (pixGetDepth(pixs) == 1)
1342  pix1 = pixScaleToGray(pixs, scale);
1343  else
1344  pix1 = pixScale(pixs, scale, scale);
1345  }
1346 
1347  if (pixGetDepth(pix1) == 16) {
1348  pix2 = pixMaxDynamicRange(pix1, L_LOG_SCALE);
1349  snprintf(buf, L_BUF_SIZE, "file.%03d.png", index);
1350  fname = pathJoin("/tmp/lept/display", buf);
1351  pixWrite(fname, pix2, IFF_PNG);
1352  pixDestroy(&pix2);
1353  } else if (pixGetDepth(pix1) < 8 || pixGetColormap(pix1) ||
1354  format == IFF_PNG) {
1355  snprintf(buf, L_BUF_SIZE, "file.%03d.png", index);
1356  fname = pathJoin("/tmp/lept/display", buf);
1357  pixWrite(fname, pix1, IFF_PNG);
1358  } else {
1359  snprintf(buf, L_BUF_SIZE, "file.%03d.jpg", index);
1360  fname = pathJoin("/tmp/lept/display", buf);
1361  pixWrite(fname, pix1, format);
1362  }
1363  LEPT_FREE(fname);
1364  pixDestroy(&pix1);
1365 
1366  return 0;
1367 }
1368 
1369 
1385 l_int32
1386 pixDisplayMultiple(l_int32 res,
1387  l_float32 scalefactor,
1388  const char *fileout)
1389 {
1390  PROCNAME("pixDisplayMultiple");
1391 
1392  if (res <= 0)
1393  return ERROR_INT("invalid res", procName, 1);
1394  if (scalefactor <= 0.0)
1395  return ERROR_INT("invalid scalefactor", procName, 1);
1396  if (!fileout)
1397  return ERROR_INT("fileout not defined", procName, 1);
1398 
1399  convertFilesToPdf("/tmp/lept/display", "file.", res, scalefactor, 0, 0,
1400  NULL, fileout);
1401  return 0;
1402 }
l_int32 pixWriteStreamPS(FILE *fp, PIX *pix, BOX *box, l_int32 res, l_float32 scale)
pixWriteStreamPS()
Definition: psio2.c:203
l_int32 pixWriteStreamPng(FILE *fp, PIX *pix, l_float32 gamma)
pixWriteStreamPng()
Definition: pngio.c:1006
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:1880
PIX * pixScaleToGray(PIX *pixs, l_float32 scalefactor)
pixScaleToGray()
Definition: scale2.c:204
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3233
char * genPathname(const char *dir, const char *fname)
genPathname()
Definition: utils2.c:2759
l_int32 pixWriteMemPS(l_uint8 **pdata, size_t *psize, PIX *pix, BOX *box, l_int32 res, l_float32 scale)
pixWriteMemPS()
Definition: psio2.c:1921
PIX * pixMaxDynamicRange(PIX *pixs, l_int32 type)
pixMaxDynamicRange()
Definition: pixarith.c:1155
l_int32 pixWriteMemJpeg(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 quality, l_int32 progressive)
pixWriteMemJpeg()
Definition: jpegio.c:1078
l_int32 pixWriteMemSpix(l_uint8 **pdata, size_t *psize, PIX *pix)
pixWriteMemSpix()
Definition: spixio.c:313
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
l_int32 pixWriteMemPng(l_uint8 **pfiledata, size_t *pfilesize, PIX *pix, l_float32 gamma)
pixWriteMemPng()
Definition: pngio.c:1855
PIX * pixRemoveColormapGeneral(PIX *pixs, l_int32 type, l_int32 ifnocmap)
pixRemoveColormapGeneral()
Definition: pixconv.c:272
l_int32 convertFilesToPdf(const char *dirname, const char *substr, l_int32 res, l_float32 scalefactor, l_int32 type, l_int32 quality, const char *title, const char *fileout)
convertFilesToPdf()
Definition: pdfio1.c:237
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:1736
PIX * pixScaleToGray8(PIX *pixs)
pixScaleToGray8()
Definition: scale2.c:600
l_int32 splitPathAtExtension(const char *pathname, char **pbasename, char **pextension)
splitPathAtExtension()
Definition: utils2.c:2486
l_int32 pixcmapIsOpaque(PIXCMAP *cmap, l_int32 *popaque)
pixcmapIsOpaque()
Definition: colormap.c:999
static const l_int32 L_INSERT
Definition: pix.h:710
l_int32 pixWriteMemTiff(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 comptype)
pixWriteMemTiff()
Definition: tiffio.c:2656
l_int32 pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
l_int32 pixWriteStreamJpeg(FILE *fp, PIX *pixs, l_int32 quality, l_int32 progressive)
pixWriteStreamJpeg()
Definition: jpegio.c:788
l_int32 pixWriteStreamPdf(FILE *fp, PIX *pix, l_int32 res, const char *title)
pixWriteStreamPdf()
Definition: pdfio1.c:1283
l_int32 pixWriteJpeg(const char *filename, PIX *pix, l_int32 quality, l_int32 progressive)
pixWriteJpeg()
Definition: jpegio.c:727
l_int32 pixWriteStreamBmp(FILE *fp, PIX *pix)
pixWriteStreamBmp()
Definition: bmpio.c:339
l_int32 pixWriteStreamSpix(FILE *fp, PIX *pix)
pixWriteStreamSpix()
Definition: spixio.c:265
l_int32 pixWriteStreamPnm(FILE *fp, PIX *pix)
pixWriteStreamPnm()
Definition: pnmio.c:667
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:517
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:316
l_int32 pixWriteMemBmp(l_uint8 **pfdata, size_t *pfsize, PIX *pixs)
pixWriteMemBmp()
Definition: bmpio.c:384
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:545
Definition: pix.h:454
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1636
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:189
l_int32 pixWriteMemPnm(l_uint8 **pdata, size_t *psize, PIX *pix)
pixWriteMemPnm()
Definition: pnmio.c:1159
char * pathJoin(const char *dir, const char *fname)
pathJoin()
Definition: utils2.c:2565
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:660
Definition: pix.h:705
PIX * pixScaleToGray4(PIX *pixs)
pixScaleToGray4()
Definition: scale2.c:497
PIX * pixDisplayLayersRGBA(PIX *pixs, l_uint32 val, l_int32 maxw)
pixDisplayLayersRGBA()
Definition: pix2.c:2264
l_int32 pixaGetBoxGeometry(PIXA *pixa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
pixaGetBoxGeometry()
Definition: pixabasic.c:823
Definition: pix.h:134
Definition: pix.h:706
l_int32 pixWriteMemPdf(l_uint8 **pdata, size_t *pnbytes, PIX *pix, l_int32 res, const char *title)
pixWriteMemPdf()
Definition: pdfio1.c:1332
l_int32 pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:537
l_int32 pixWriteStreamTiff(FILE *fp, PIX *pix, l_int32 comptype)
pixWriteStreamTiff()
Definition: tiffio.c:770
PIX * pixConvert16To8(PIX *pixs, l_int32 type)
pixConvert16To8()
Definition: pixconv.c:1689
l_int32 pixGetDimensions(PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1052
l_int32 lept_rmdir(const char *subdir)
lept_rmdir()
Definition: utils2.c:1951
Definition: pix.h:480
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:243
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:164
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:620
PIX * pixScaleToGray2(PIX *pixs)
pixScaleToGray2()
Definition: scale2.c:386
static const l_int32 L_BUF_SIZE
Definition: classapp.c:55