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 = 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 */
139 struct ExtensionMap
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 * Set jpeg quality for pixWrite() and pixWriteMem() *
161 *---------------------------------------------------------------------*/
162 /* Parameter that controls jpeg quality for high-level calls. */
163 static l_int32 var_JPEG_QUALITY = 75; /* default */
164
165 /*!
166 * \brief l_jpegSetQuality()
167 *
168 * \param[in] new_quality 1 - 100; 75 is default; 0 defaults to 75
169 * \return prev previous quality
170 *
171 * <pre>
172 * Notes:
173 * (1) This variable is used in pixWriteStream() and pixWriteMem(),
174 * to control the jpeg quality. The default is 75.
175 * (2) It returns the previous quality, so for example:
176 * l_int32 prev = l_jpegSetQuality(85); //sets to 85
177 * pixWriteStream(...);
178 * l_jpegSetQuality(prev); // resets to previous value
179 * (3) On error, logs a message and does not change the variable.
180 */
181 l_int32
l_jpegSetQuality(l_int32 new_quality)182 l_jpegSetQuality(l_int32 new_quality)
183 {
184 l_int32 prevq, newq;
185
186 PROCNAME("l_jpeqSetQuality");
187
188 prevq = var_JPEG_QUALITY;
189 newq = (new_quality == 0) ? 75 : new_quality;
190 if (newq < 1 || newq > 100)
191 L_ERROR("invalid jpeg quality; unchanged\n", procName);
192 else
193 var_JPEG_QUALITY = newq;
194 return prevq;
195 }
196
197
198 /*----------------------------------------------------------------------*
199 * Set global variable LeptDebugOK for writing to named temp files *
200 *----------------------------------------------------------------------*/
201 l_int32 LeptDebugOK = 0; /* default value */
202 /*!
203 * \brief setLeptDebugOK()
204 *
205 * \param[in] allow TRUE (1) or FALSE (0)
206 * \return void
207 *
208 * <pre>
209 * Notes:
210 * (1) This sets or clears the global variable LeptDebugOK, to
211 * control writing files in a temp directory with names that
212 * are compiled in.
213 * (2) The default in the library distribution is 0. Call with
214 * %allow = 1 for development and debugging.
215 */
216 void
setLeptDebugOK(l_int32 allow)217 setLeptDebugOK(l_int32 allow)
218 {
219 if (allow != 0) allow = 1;
220 LeptDebugOK = allow;
221 }
222
223
224 /*---------------------------------------------------------------------*
225 * Top-level procedures for writing images to file *
226 *---------------------------------------------------------------------*/
227 /*!
228 * \brief pixaWriteFiles()
229 *
230 * \param[in] rootname
231 * \param[in] pixa
232 * \param[in] format defined in imageio.h; see notes for default
233 * \return 0 if OK; 1 on error
234 *
235 * <pre>
236 * Notes:
237 * (1) Use %format = IFF_DEFAULT to decide the output format
238 * individually for each pix.
239 * </pre>
240 */
241 l_int32
pixaWriteFiles(const char * rootname,PIXA * pixa,l_int32 format)242 pixaWriteFiles(const char *rootname,
243 PIXA *pixa,
244 l_int32 format)
245 {
246 char bigbuf[L_BUFSIZE];
247 l_int32 i, n, pixformat;
248 PIX *pix;
249
250 PROCNAME("pixaWriteFiles");
251
252 if (!rootname)
253 return ERROR_INT("rootname not defined", procName, 1);
254 if (!pixa)
255 return ERROR_INT("pixa not defined", procName, 1);
256 if (format < 0 || format == IFF_UNKNOWN ||
257 format >= NumImageFileFormatExtensions)
258 return ERROR_INT("invalid format", procName, 1);
259
260 n = pixaGetCount(pixa);
261 for (i = 0; i < n; i++) {
262 pix = pixaGetPix(pixa, i, L_CLONE);
263 if (format == IFF_DEFAULT)
264 pixformat = pixChooseOutputFormat(pix);
265 else
266 pixformat = format;
267 snprintf(bigbuf, L_BUFSIZE, "%s%03d.%s", rootname, i,
268 ImageFileFormatExtensions[pixformat]);
269 pixWrite(bigbuf, pix, pixformat);
270 pixDestroy(&pix);
271 }
272
273 return 0;
274 }
275
276
277 /*!
278 * \brief pixWriteDebug()
279 *
280 * \param[in] fname
281 * \param[in] pix
282 * \param[in] format defined in imageio.h
283 * \return 0 if OK; 1 on error
284 *
285 * <pre>
286 * Notes:
287 * (1) Debug version, intended for use in the library when writing
288 * to files in a temp directory with names that are compiled in.
289 * This is used instead of pixWrite() for all such library calls.
290 * (2) The global variable LeptDebugOK defaults to 0, and can be set
291 * or cleared by the function setLeptDebugOK().
292 * </pre>
293 */
294 l_int32
pixWriteDebug(const char * fname,PIX * pix,l_int32 format)295 pixWriteDebug(const char *fname,
296 PIX *pix,
297 l_int32 format)
298 {
299 PROCNAME("pixWriteDebug");
300
301 if (LeptDebugOK) {
302 return pixWrite(fname, pix, format);
303 } else {
304 L_INFO("write to named temp file %s is disabled\n", procName, fname);
305 return 0;
306 }
307 }
308
309
310 /*!
311 * \brief pixWrite()
312 *
313 * \param[in] fname
314 * \param[in] pix
315 * \param[in] format defined in imageio.h
316 * \return 0 if OK; 1 on error
317 *
318 * <pre>
319 * Notes:
320 * (1) Open for write using binary mode (with the "b" flag)
321 * to avoid having Windows automatically translate the NL
322 * into CRLF, which corrupts image files. On non-windows
323 * systems this flag should be ignored, per ISO C90.
324 * Thanks to Dave Bryan for pointing this out.
325 * (2) If the default image format IFF_DEFAULT is requested:
326 * use the input format if known; otherwise, use a lossless format.
327 * (3) The default jpeg quality is 75. For some other value,
328 * Use l_jpegSetQuality().
329 * </pre>
330 */
331 l_int32
pixWrite(const char * fname,PIX * pix,l_int32 format)332 pixWrite(const char *fname,
333 PIX *pix,
334 l_int32 format)
335 {
336 l_int32 ret;
337 FILE *fp;
338
339 PROCNAME("pixWrite");
340
341 if (!pix)
342 return ERROR_INT("pix not defined", procName, 1);
343 if (!fname)
344 return ERROR_INT("fname not defined", procName, 1);
345
346 if ((fp = fopenWriteStream(fname, "wb+")) == NULL)
347 return ERROR_INT("stream not opened", procName, 1);
348
349 ret = pixWriteStream(fp, pix, format);
350 fclose(fp);
351 if (ret)
352 return ERROR_INT("pix not written to stream", procName, 1);
353 return 0;
354 }
355
356
357 /*!
358 * \brief pixWriteAutoFormat()
359 *
360 * \param[in] filename
361 * \param[in] pix
362 * \return 0 if OK; 1 on error
363 */
364 l_int32
pixWriteAutoFormat(const char * filename,PIX * pix)365 pixWriteAutoFormat(const char *filename,
366 PIX *pix)
367 {
368 l_int32 format;
369
370 PROCNAME("pixWriteAutoFormat");
371
372 if (!pix)
373 return ERROR_INT("pix not defined", procName, 1);
374 if (!filename)
375 return ERROR_INT("filename not defined", procName, 1);
376
377 if (pixGetAutoFormat(pix, &format))
378 return ERROR_INT("auto format not returned", procName, 1);
379 return pixWrite(filename, pix, format);
380 }
381
382
383 /*!
384 * \brief pixWriteStream()
385 *
386 * \param[in] fp file stream
387 * \param[in] pix
388 * \param[in] format
389 * \return 0 if OK; 1 on error.
390 */
391 l_int32
pixWriteStream(FILE * fp,PIX * pix,l_int32 format)392 pixWriteStream(FILE *fp,
393 PIX *pix,
394 l_int32 format)
395 {
396 PROCNAME("pixWriteStream");
397
398 if (!fp)
399 return ERROR_INT("stream not defined", procName, 1);
400 if (!pix)
401 return ERROR_INT("pix not defined", procName, 1);
402
403 if (format == IFF_DEFAULT)
404 format = pixChooseOutputFormat(pix);
405
406 switch(format)
407 {
408 case IFF_BMP:
409 pixWriteStreamBmp(fp, pix);
410 break;
411
412 case IFF_JFIF_JPEG: /* default quality; baseline sequential */
413 return pixWriteStreamJpeg(fp, pix, var_JPEG_QUALITY, 0);
414 break;
415
416 case IFF_PNG: /* no gamma value stored */
417 return pixWriteStreamPng(fp, pix, 0.0);
418 break;
419
420 case IFF_TIFF: /* uncompressed */
421 case IFF_TIFF_PACKBITS: /* compressed, binary only */
422 case IFF_TIFF_RLE: /* compressed, binary only */
423 case IFF_TIFF_G3: /* compressed, binary only */
424 case IFF_TIFF_G4: /* compressed, binary only */
425 case IFF_TIFF_LZW: /* compressed, all depths */
426 case IFF_TIFF_ZIP: /* compressed, all depths */
427 return pixWriteStreamTiff(fp, pix, format);
428 break;
429
430 case IFF_PNM:
431 return pixWriteStreamPnm(fp, pix);
432 break;
433
434 case IFF_PS:
435 return pixWriteStreamPS(fp, pix, NULL, 0, DEFAULT_SCALING);
436 break;
437
438 case IFF_GIF:
439 return pixWriteStreamGif(fp, pix);
440 break;
441
442 case IFF_JP2:
443 return pixWriteStreamJp2k(fp, pix, 34, 4, 0, 0);
444 break;
445
446 case IFF_WEBP:
447 return pixWriteStreamWebP(fp, pix, 80, 0);
448 break;
449
450 case IFF_LPDF:
451 return pixWriteStreamPdf(fp, pix, 0, NULL);
452 break;
453
454 case IFF_SPIX:
455 return pixWriteStreamSpix(fp, pix);
456 break;
457
458 default:
459 return ERROR_INT("unknown format", procName, 1);
460 break;
461 }
462
463 return 0;
464 }
465
466
467 /*!
468 * \brief pixWriteImpliedFormat()
469 *
470 * \param[in] filename
471 * \param[in] pix
472 * \param[in] quality iff JPEG; 1 - 100, 0 for default
473 * \param[in] progressive iff JPEG; 0 for baseline seq., 1 for progressive
474 * \return 0 if OK; 1 on error
475 *
476 * <pre>
477 * Notes:
478 * (1) This determines the output format from the filename extension.
479 * (2) The last two args are ignored except for requests for jpeg files.
480 * (3) The jpeg default quality is 75.
481 * </pre>
482 */
483 l_int32
pixWriteImpliedFormat(const char * filename,PIX * pix,l_int32 quality,l_int32 progressive)484 pixWriteImpliedFormat(const char *filename,
485 PIX *pix,
486 l_int32 quality,
487 l_int32 progressive)
488 {
489 l_int32 format;
490
491 PROCNAME("pixWriteImpliedFormat");
492
493 if (!filename)
494 return ERROR_INT("filename not defined", procName, 1);
495 if (!pix)
496 return ERROR_INT("pix not defined", procName, 1);
497
498 /* Determine output format */
499 format = getImpliedFileFormat(filename);
500 if (format == IFF_UNKNOWN) {
501 format = IFF_PNG;
502 } else if (format == IFF_TIFF) {
503 if (pixGetDepth(pix) == 1)
504 format = IFF_TIFF_G4;
505 else
506 #ifdef _WIN32
507 format = IFF_TIFF_LZW; /* poor compression */
508 #else
509 format = IFF_TIFF_ZIP; /* native windows tools can't handle this */
510 #endif /* _WIN32 */
511 }
512
513 if (format == IFF_JFIF_JPEG) {
514 quality = L_MIN(quality, 100);
515 quality = L_MAX(quality, 0);
516 if (progressive != 0 && progressive != 1) {
517 progressive = 0;
518 L_WARNING("invalid progressive; setting to baseline\n", procName);
519 }
520 if (quality == 0)
521 quality = 75;
522 pixWriteJpeg (filename, pix, quality, progressive);
523 } else {
524 pixWrite(filename, pix, format);
525 }
526
527 return 0;
528 }
529
530
531 /*---------------------------------------------------------------------*
532 * Selection of output format if default is requested *
533 *---------------------------------------------------------------------*/
534 /*!
535 * \brief pixChooseOutputFormat()
536 *
537 * \param[in] pix
538 * \return output format, or 0 on error
539 *
540 * <pre>
541 * Notes:
542 * (1) This should only be called if the requested format is IFF_DEFAULT.
543 * (2) If the pix wasn't read from a file, its input format value
544 * will be IFF_UNKNOWN, and in that case it is written out
545 * in a compressed but lossless format.
546 * </pre>
547 */
548 l_int32
pixChooseOutputFormat(PIX * pix)549 pixChooseOutputFormat(PIX *pix)
550 {
551 l_int32 d, format;
552
553 PROCNAME("pixChooseOutputFormat");
554
555 if (!pix)
556 return ERROR_INT("pix not defined", procName, 0);
557
558 d = pixGetDepth(pix);
559 format = pixGetInputFormat(pix);
560 if (format == IFF_UNKNOWN) { /* output lossless */
561 if (d == 1)
562 format = IFF_TIFF_G4;
563 else
564 format = IFF_PNG;
565 }
566
567 return format;
568 }
569
570
571 /*!
572 * \brief getImpliedFileFormat()
573 *
574 * \param[in] filename
575 * \return output format, or IFF_UNKNOWN on error or invalid extension.
576 *
577 * <pre>
578 * Notes:
579 * (1) This determines the output file format from the extension
580 * of the input filename.
581 * </pre>
582 */
583 l_int32
getImpliedFileFormat(const char * filename)584 getImpliedFileFormat(const char *filename)
585 {
586 char *extension;
587 int i, numext;
588 l_int32 format = IFF_UNKNOWN;
589
590 if (splitPathAtExtension (filename, NULL, &extension))
591 return IFF_UNKNOWN;
592
593 numext = sizeof(extension_map) / sizeof(extension_map[0]);
594 for (i = 0; i < numext; i++) {
595 if (!strcmp(extension, extension_map[i].extension)) {
596 format = extension_map[i].format;
597 break;
598 }
599 }
600
601 LEPT_FREE(extension);
602 return format;
603 }
604
605
606 /*!
607 * \brief pixGetAutoFormat()
608 *
609 * \param[in] pix
610 * \param[in] &format
611 * \return 0 if OK, 1 on error
612 *
613 * <pre>
614 * Notes:
615 * (1) The output formats are restricted to tiff, jpeg and png
616 * because these are the most commonly used image formats and
617 * the ones that are typically installed with leptonica.
618 * (2) This decides what compression to use based on the pix.
619 * It chooses tiff-g4 if 1 bpp without a colormap, jpeg with
620 * quality 75 if grayscale, rgb or rgba (where it loses
621 * the alpha layer), and lossless png for all other situations.
622 * </pre>
623 */
624 l_int32
pixGetAutoFormat(PIX * pix,l_int32 * pformat)625 pixGetAutoFormat(PIX *pix,
626 l_int32 *pformat)
627 {
628 l_int32 d;
629 PIXCMAP *cmap;
630
631 PROCNAME("pixGetAutoFormat");
632
633 if (!pformat)
634 return ERROR_INT("&format not defined", procName, 0);
635 *pformat = IFF_UNKNOWN;
636 if (!pix)
637 return ERROR_INT("pix not defined", procName, 0);
638
639 d = pixGetDepth(pix);
640 cmap = pixGetColormap(pix);
641 if (d == 1 && !cmap) {
642 *pformat = IFF_TIFF_G4;
643 } else if ((d == 8 && !cmap) || d == 24 || d == 32) {
644 *pformat = IFF_JFIF_JPEG;
645 } else {
646 *pformat = IFF_PNG;
647 }
648
649 return 0;
650 }
651
652
653 /*!
654 * \brief getFormatExtension()
655 *
656 * \param[in] format integer
657 * \return extension string, or NULL if format is out of range
658 *
659 * <pre>
660 * Notes:
661 * (1) This string is NOT owned by the caller; it is just a pointer
662 * to a global string. Do not free it.
663 * </pre>
664 */
665 const char *
getFormatExtension(l_int32 format)666 getFormatExtension(l_int32 format)
667 {
668 PROCNAME("getFormatExtension");
669
670 if (format < 0 || format >= NumImageFileFormatExtensions)
671 return (const char *)ERROR_PTR("invalid format", procName, NULL);
672
673 return ImageFileFormatExtensions[format];
674 }
675
676
677 /*---------------------------------------------------------------------*
678 * Write to memory *
679 *---------------------------------------------------------------------*/
680 /*!
681 * \brief pixWriteMem()
682 *
683 * \param[out] pdata data of tiff compressed image
684 * \param[out] psize size of returned data
685 * \param[in] pix
686 * \param[in] format defined in imageio.h
687 * \return 0 if OK, 1 on error
688 *
689 * <pre>
690 * Notes:
691 * (1) On windows, this will only write tiff and PostScript to memory.
692 * For other formats, it requires open_memstream(3).
693 * (2) PostScript output is uncompressed, in hex ascii.
694 * Most printers support level 2 compression (tiff_g4 for 1 bpp,
695 * jpeg for 8 and 32 bpp).
696 * (3) The default jpeg quality is 75. For some other value,
697 * Use l_jpegSetQuality().
698 * </pre>
699 */
700 l_int32
pixWriteMem(l_uint8 ** pdata,size_t * psize,PIX * pix,l_int32 format)701 pixWriteMem(l_uint8 **pdata,
702 size_t *psize,
703 PIX *pix,
704 l_int32 format)
705 {
706 l_int32 ret;
707
708 PROCNAME("pixWriteMem");
709
710 if (!pdata)
711 return ERROR_INT("&data not defined", procName, 1 );
712 if (!psize)
713 return ERROR_INT("&size not defined", procName, 1 );
714 if (!pix)
715 return ERROR_INT("&pix not defined", procName, 1 );
716
717 if (format == IFF_DEFAULT)
718 format = pixChooseOutputFormat(pix);
719
720 switch(format)
721 {
722 case IFF_BMP:
723 ret = pixWriteMemBmp(pdata, psize, pix);
724 break;
725
726 case IFF_JFIF_JPEG: /* default quality; baseline sequential */
727 ret = pixWriteMemJpeg(pdata, psize, pix, var_JPEG_QUALITY, 0);
728 break;
729
730 case IFF_PNG: /* no gamma value stored */
731 ret = pixWriteMemPng(pdata, psize, pix, 0.0);
732 break;
733
734 case IFF_TIFF: /* uncompressed */
735 case IFF_TIFF_PACKBITS: /* compressed, binary only */
736 case IFF_TIFF_RLE: /* compressed, binary only */
737 case IFF_TIFF_G3: /* compressed, binary only */
738 case IFF_TIFF_G4: /* compressed, binary only */
739 case IFF_TIFF_LZW: /* compressed, all depths */
740 case IFF_TIFF_ZIP: /* compressed, all depths */
741 ret = pixWriteMemTiff(pdata, psize, pix, format);
742 break;
743
744 case IFF_PNM:
745 ret = pixWriteMemPnm(pdata, psize, pix);
746 break;
747
748 case IFF_PS:
749 ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DEFAULT_SCALING);
750 break;
751
752 case IFF_GIF:
753 ret = pixWriteMemGif(pdata, psize, pix);
754 break;
755
756 case IFF_JP2:
757 ret = pixWriteMemJp2k(pdata, psize, pix, 34, 0, 0, 0);
758 break;
759
760 case IFF_WEBP:
761 ret = pixWriteMemWebP(pdata, psize, pix, 80, 0);
762 break;
763
764 case IFF_LPDF:
765 ret = pixWriteMemPdf(pdata, psize, pix, 0, NULL);
766 break;
767
768 case IFF_SPIX:
769 ret = pixWriteMemSpix(pdata, psize, pix);
770 break;
771
772 default:
773 return ERROR_INT("unknown format", procName, 1);
774 break;
775 }
776
777 return ret;
778 }
779
780
781 /*---------------------------------------------------------------------*
782 * Image display for debugging *
783 *---------------------------------------------------------------------*/
784 /*!
785 * \brief l_fileDisplay()
786 *
787 * \param[in] fname
788 * \param[in] x, y location of display frame on the screen
789 * \param[in] scale scale factor (use 0 to skip display)
790 * \return 0 if OK; 1 on error
791 *
792 * <pre>
793 * Notes:
794 * (1) This is a convenient wrapper for displaying image files.
795 * (2) Set %scale = 0 to disable display.
796 * (3) This downscales 1 bpp to gray.
797 * </pre>
798 */
799 l_int32
l_fileDisplay(const char * fname,l_int32 x,l_int32 y,l_float32 scale)800 l_fileDisplay(const char *fname,
801 l_int32 x,
802 l_int32 y,
803 l_float32 scale)
804 {
805 PIX *pixs, *pixd;
806
807 PROCNAME("l_fileDisplay");
808
809 if (scale == 0.0)
810 return 0;
811
812 if (scale < 0.0)
813 return ERROR_INT("invalid scale factor", procName, 1);
814 if ((pixs = pixRead(fname)) == NULL)
815 return ERROR_INT("pixs not read", procName, 1);
816
817 if (scale == 1.0) {
818 pixd = pixClone(pixs);
819 } else {
820 if (scale < 1.0 && pixGetDepth(pixs) == 1)
821 pixd = pixScaleToGray(pixs, scale);
822 else
823 pixd = pixScale(pixs, scale, scale);
824 }
825 pixDisplay(pixd, x, y);
826 pixDestroy(&pixs);
827 pixDestroy(&pixd);
828 return 0;
829 }
830
831
832 /*!
833 * \brief pixDisplay()
834 *
835 * \param[in] pix 1, 2, 4, 8, 16, 32 bpp
836 * \param[in] x, y location of display frame on the screen
837 * \return 0 if OK; 1 on error
838 *
839 * <pre>
840 * Notes:
841 * (1) This is debugging code that displays an image on the screen.
842 * It uses a static internal variable to number the output files
843 * written by a single process. Behavior with a shared library
844 * may be unpredictable.
845 * (2) It uses these programs to display the image:
846 * On Unix: xzgv, xli or xv
847 * On Windows: i_view
848 * The display program must be on your $PATH variable. It is
849 * chosen by setting the global var_DISPLAY_PROG, using
850 * l_chooseDisplayProg(). Default on Unix is xzgv.
851 * (3) Images with dimensions larger than MAX_DISPLAY_WIDTH or
852 * MAX_DISPLAY_HEIGHT are downscaled to fit those constraints.
853 * This is particularly important for displaying 1 bpp images
854 * with xv, because xv automatically downscales large images
855 * by subsampling, which looks poor. For 1 bpp, we use
856 * scale-to-gray to get decent-looking anti-aliased images.
857 * In all cases, we write a temporary file to /tmp/lept/disp,
858 * that is read by the display program.
859 * (4) The temporary file is written as png if, after initial
860 * processing for special cases, any of these obtain:
861 * * pix dimensions are smaller than some thresholds
862 * * pix depth is less than 8 bpp
863 * * pix is colormapped
864 * (5) For spp == 4, we call pixDisplayLayersRGBA() to show 3
865 * versions of the image: the image with a fully opaque
866 * alpha, the alpha, and the image as it would appear with
867 * a white background.
868 * </pre>
869 */
870 l_int32
pixDisplay(PIX * pixs,l_int32 x,l_int32 y)871 pixDisplay(PIX *pixs,
872 l_int32 x,
873 l_int32 y)
874 {
875 return pixDisplayWithTitle(pixs, x, y, NULL, 1);
876 }
877
878
879 /*!
880 * \brief pixDisplayWithTitle()
881 *
882 * \param[in] pix 1, 2, 4, 8, 16, 32 bpp
883 * \param[in] x, y location of display frame
884 * \param[in] title [optional] on frame; can be NULL;
885 * \param[in] dispflag 1 to write, else disabled
886 * \return 0 if OK; 1 on error
887 *
888 * <pre>
889 * Notes:
890 * (1) See notes for pixDisplay().
891 * (2) This displays the image if dispflag == 1; otherwise it punts.
892 * </pre>
893 */
894 l_int32
pixDisplayWithTitle(PIX * pixs,l_int32 x,l_int32 y,const char * title,l_int32 dispflag)895 pixDisplayWithTitle(PIX *pixs,
896 l_int32 x,
897 l_int32 y,
898 const char *title,
899 l_int32 dispflag)
900 {
901 char *tempname;
902 char buffer[L_BUFSIZE];
903 static l_int32 index = 0; /* caution: not .so or thread safe */
904 l_int32 w, h, d, spp, maxheight, opaque, threeviews, ignore;
905 l_float32 ratw, rath, ratmin;
906 PIX *pix0, *pix1, *pix2;
907 PIXCMAP *cmap;
908 #ifndef _WIN32
909 l_int32 wt, ht;
910 #else
911 char *pathname;
912 char fullpath[_MAX_PATH];
913 #endif /* _WIN32 */
914
915 PROCNAME("pixDisplayWithTitle");
916
917 if (!LeptDebugOK) {
918 L_INFO("displaying files is disabled\n", procName);
919 return 0;
920 }
921
922 if (dispflag != 1) return 0;
923 if (!pixs)
924 return ERROR_INT("pixs not defined", procName, 1);
925 if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV &&
926 var_DISPLAY_PROG != L_DISPLAY_WITH_XLI &&
927 var_DISPLAY_PROG != L_DISPLAY_WITH_XV &&
928 var_DISPLAY_PROG != L_DISPLAY_WITH_IV &&
929 var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) {
930 return ERROR_INT("no program chosen for display", procName, 1);
931 }
932
933 /* Display with three views if either spp = 4 or if colormapped
934 * and the alpha component is not fully opaque */
935 opaque = TRUE;
936 if ((cmap = pixGetColormap(pixs)) != NULL)
937 pixcmapIsOpaque(cmap, &opaque);
938 spp = pixGetSpp(pixs);
939 threeviews = (spp == 4 || !opaque) ? TRUE : FALSE;
940
941 /* If colormapped and not opaque, remove the colormap to RGBA */
942 if (!opaque)
943 pix0 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA);
944 else
945 pix0 = pixClone(pixs);
946
947 /* Scale if necessary; this will also remove a colormap */
948 pixGetDimensions(pix0, &w, &h, &d);
949 maxheight = (threeviews) ? MAX_DISPLAY_HEIGHT / 3 : MAX_DISPLAY_HEIGHT;
950 if (w <= MAX_DISPLAY_WIDTH && h <= maxheight) {
951 if (d == 16) /* take MSB */
952 pix1 = pixConvert16To8(pix0, 1);
953 else
954 pix1 = pixClone(pix0);
955 } else {
956 ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w;
957 rath = (l_float32)maxheight / (l_float32)h;
958 ratmin = L_MIN(ratw, rath);
959 if (ratmin < 0.125 && d == 1)
960 pix1 = pixScaleToGray8(pix0);
961 else if (ratmin < 0.25 && d == 1)
962 pix1 = pixScaleToGray4(pix0);
963 else if (ratmin < 0.33 && d == 1)
964 pix1 = pixScaleToGray3(pix0);
965 else if (ratmin < 0.5 && d == 1)
966 pix1 = pixScaleToGray2(pix0);
967 else
968 pix1 = pixScale(pix0, ratmin, ratmin);
969 }
970 pixDestroy(&pix0);
971 if (!pix1)
972 return ERROR_INT("pix1 not made", procName, 1);
973
974 /* Generate the three views if required */
975 if (threeviews)
976 pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0);
977 else
978 pix2 = pixClone(pix1);
979
980 if (index == 0) { /* erase any existing images */
981 lept_rmdir("lept/disp");
982 lept_mkdir("lept/disp");
983 }
984
985 index++;
986 if (pixGetDepth(pix2) < 8 || pixGetColormap(pix2) ||
987 (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) {
988 snprintf(buffer, L_BUFSIZE, "/tmp/lept/disp/write.%03d.png", index);
989 pixWrite(buffer, pix2, IFF_PNG);
990 } else {
991 snprintf(buffer, L_BUFSIZE, "/tmp/lept/disp/write.%03d.jpg", index);
992 pixWrite(buffer, pix2, IFF_JFIF_JPEG);
993 }
994 tempname = genPathname(buffer, NULL);
995
996 #ifndef _WIN32
997
998 /* Unix */
999 if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) {
1000 /* no way to display title */
1001 pixGetDimensions(pix2, &wt, &ht, NULL);
1002 snprintf(buffer, L_BUFSIZE,
1003 "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10,
1004 x, y, tempname);
1005 } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) {
1006 if (title) {
1007 snprintf(buffer, L_BUFSIZE,
1008 "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &",
1009 x, y, title, tempname);
1010 } else {
1011 snprintf(buffer, L_BUFSIZE,
1012 "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &",
1013 x, y, tempname);
1014 }
1015 } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) {
1016 if (title) {
1017 snprintf(buffer, L_BUFSIZE,
1018 "xv -quit -geometry +%d+%d -name \"%s\" %s &",
1019 x, y, title, tempname);
1020 } else {
1021 snprintf(buffer, L_BUFSIZE,
1022 "xv -quit -geometry +%d+%d %s &", x, y, tempname);
1023 }
1024 } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_OPEN) {
1025 snprintf(buffer, L_BUFSIZE, "open %s &", tempname);
1026 }
1027 #ifndef OS_IOS /* iOS 11 does not support system() */
1028 ignore = system(buffer);
1029 #endif /* !OS_IOS */
1030
1031 #else /* _WIN32 */
1032
1033 /* Windows: L_DISPLAY_WITH_IV */
1034 pathname = genPathname(tempname, NULL);
1035 _fullpath(fullpath, pathname, sizeof(fullpath));
1036 if (title) {
1037 snprintf(buffer, L_BUFSIZE,
1038 "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"",
1039 fullpath, x, y, title);
1040 } else {
1041 snprintf(buffer, L_BUFSIZE, "i_view32.exe \"%s\" /pos=(%d,%d)",
1042 fullpath, x, y);
1043 }
1044 ignore = system(buffer);
1045 LEPT_FREE(pathname);
1046
1047 #endif /* _WIN32 */
1048
1049 pixDestroy(&pix1);
1050 pixDestroy(&pix2);
1051 LEPT_FREE(tempname);
1052 return 0;
1053 }
1054
1055
1056 /*!
1057 * \brief pixSaveTiled()
1058 *
1059 * \param[in] pixs 1, 2, 4, 8, 32 bpp
1060 * \param[in] pixa the pix are accumulated here
1061 * \param[in] scalefactor 0.0 to disable; otherwise this is a scale factor
1062 * \param[in] newrow 0 if placed on the same row as previous; 1 otherwise
1063 * \param[in] space horizontal and vertical spacing, in pixels
1064 * \param[in] dp depth of pixa; 8 or 32 bpp; only used on first call
1065 * \return 0 if OK, 1 on error.
1066 */
1067 l_int32
pixSaveTiled(PIX * pixs,PIXA * pixa,l_float32 scalefactor,l_int32 newrow,l_int32 space,l_int32 dp)1068 pixSaveTiled(PIX *pixs,
1069 PIXA *pixa,
1070 l_float32 scalefactor,
1071 l_int32 newrow,
1072 l_int32 space,
1073 l_int32 dp)
1074 {
1075 /* Save without an outline */
1076 return pixSaveTiledOutline(pixs, pixa, scalefactor, newrow, space, 0, dp);
1077 }
1078
1079
1080 /*!
1081 * \brief pixSaveTiledOutline()
1082 *
1083 * \param[in] pixs 1, 2, 4, 8, 32 bpp
1084 * \param[in] pixa the pix are accumulated here
1085 * \param[in] scalefactor 0.0 to disable; otherwise this is a scale factor
1086 * \param[in] newrow 0 if placed on the same row as previous; 1 otherwise
1087 * \param[in] space horizontal and vertical spacing, in pixels
1088 * \param[in] linewidth width of added outline for image; 0 for no outline
1089 * \param[in] dp depth of pixa; 8 or 32 bpp; only used on first call
1090 * \return 0 if OK, 1 on error.
1091 *
1092 * <pre>
1093 * Notes:
1094 * (1) Before calling this function for the first time, use
1095 * pixaCreate() to make the %pixa that will accumulate the pix.
1096 * This is passed in each time pixSaveTiled() is called.
1097 * (2) %scalefactor scales the input image. After scaling and
1098 * possible depth conversion, the image is saved in the input
1099 * pixa, along with a box that specifies the location to
1100 * place it when tiled later. Disable saving the pix by
1101 * setting %scalefactor == 0.0.
1102 * (3) %newrow and %space specify the location of the new pix
1103 * with respect to the last one(s) that were entered.
1104 * (4) %dp specifies the depth at which all pix are saved. It can
1105 * be only 8 or 32 bpp. Any colormap is removed. This is only
1106 * used at the first invocation.
1107 * (5) This function uses two variables from call to call.
1108 * If they were static, the function would not be .so or thread
1109 * safe, and furthermore, there would be interference with two or
1110 * more pixa accumulating images at a time. Consequently,
1111 * we use the first pix in the pixa to store and obtain both
1112 * the depth and the current position of the bottom (one pixel
1113 * below the lowest image raster line when laid out using
1114 * the boxa). The bottom variable is stored in the input format
1115 * field, which is the only field available for storing an int.
1116 * </pre>
1117 */
1118 l_int32
pixSaveTiledOutline(PIX * pixs,PIXA * pixa,l_float32 scalefactor,l_int32 newrow,l_int32 space,l_int32 linewidth,l_int32 dp)1119 pixSaveTiledOutline(PIX *pixs,
1120 PIXA *pixa,
1121 l_float32 scalefactor,
1122 l_int32 newrow,
1123 l_int32 space,
1124 l_int32 linewidth,
1125 l_int32 dp)
1126 {
1127 l_int32 n, top, left, bx, by, bw, w, h, depth, bottom;
1128 BOX *box;
1129 PIX *pix1, *pix2, *pix3, *pix4;
1130
1131 PROCNAME("pixSaveTiledOutline");
1132
1133 if (scalefactor == 0.0) return 0;
1134
1135 if (!pixs)
1136 return ERROR_INT("pixs not defined", procName, 1);
1137 if (!pixa)
1138 return ERROR_INT("pixa not defined", procName, 1);
1139
1140 n = pixaGetCount(pixa);
1141 if (n == 0) {
1142 bottom = 0;
1143 if (dp != 8 && dp != 32) {
1144 L_WARNING("dp not 8 or 32 bpp; using 32\n", procName);
1145 depth = 32;
1146 } else {
1147 depth = dp;
1148 }
1149 } else { /* extract the depth and bottom params from the first pix */
1150 pix1 = pixaGetPix(pixa, 0, L_CLONE);
1151 depth = pixGetDepth(pix1);
1152 bottom = pixGetInputFormat(pix1); /* not typical usage! */
1153 pixDestroy(&pix1);
1154 }
1155
1156 /* Remove colormap if it exists; otherwise a copy. This
1157 * guarantees that pix4 is not a clone of pixs. */
1158 pix1 = pixRemoveColormapGeneral(pixs, REMOVE_CMAP_BASED_ON_SRC, L_COPY);
1159
1160 /* Scale and convert to output depth */
1161 if (scalefactor == 1.0) {
1162 pix2 = pixClone(pix1);
1163 } else if (scalefactor > 1.0) {
1164 pix2 = pixScale(pix1, scalefactor, scalefactor);
1165 } else { /* scalefactor < 1.0) */
1166 if (pixGetDepth(pix1) == 1)
1167 pix2 = pixScaleToGray(pix1, scalefactor);
1168 else
1169 pix2 = pixScale(pix1, scalefactor, scalefactor);
1170 }
1171 pixDestroy(&pix1);
1172 if (depth == 8)
1173 pix3 = pixConvertTo8(pix2, 0);
1174 else
1175 pix3 = pixConvertTo32(pix2);
1176 pixDestroy(&pix2);
1177
1178 /* Add black outline */
1179 if (linewidth > 0)
1180 pix4 = pixAddBorder(pix3, linewidth, 0);
1181 else
1182 pix4 = pixClone(pix3);
1183 pixDestroy(&pix3);
1184
1185 /* Find position of current pix (UL corner plus size) */
1186 if (n == 0) {
1187 top = 0;
1188 left = 0;
1189 } else if (newrow == 1) {
1190 top = bottom + space;
1191 left = 0;
1192 } else { /* n > 0 */
1193 pixaGetBoxGeometry(pixa, n - 1, &bx, &by, &bw, NULL);
1194 top = by;
1195 left = bx + bw + space;
1196 }
1197
1198 pixGetDimensions(pix4, &w, &h, NULL);
1199 bottom = L_MAX(bottom, top + h);
1200 box = boxCreate(left, top, w, h);
1201 pixaAddPix(pixa, pix4, L_INSERT);
1202 pixaAddBox(pixa, box, L_INSERT);
1203
1204 /* Save the new bottom value */
1205 pix1 = pixaGetPix(pixa, 0, L_CLONE);
1206 pixSetInputFormat(pix1, bottom); /* not typical usage! */
1207 pixDestroy(&pix1);
1208 return 0;
1209 }
1210
1211
1212 /*!
1213 * \brief pixSaveTiledWithText()
1214 *
1215 * \param[in] pixs 1, 2, 4, 8, 32 bpp
1216 * \param[in] pixa the pix are accumulated here; as 32 bpp
1217 * \param[in] outwidth in pixels; use 0 to disable entirely
1218 * \param[in] newrow 1 to start a new row; 0 to go on same row as previous
1219 * \param[in] space horizontal and vertical spacing, in pixels
1220 * \param[in] linewidth width of added outline for image; 0 for no outline
1221 * \param[in] bmf [optional] font struct
1222 * \param[in] textstr [optional] text string to be added
1223 * \param[in] val color to set the text
1224 * \param[in] location L_ADD_ABOVE, L_ADD_AT_TOP, L_ADD_AT_BOT, L_ADD_BELOW
1225 * \return 0 if OK, 1 on error.
1226 *
1227 * <pre>
1228 * Notes:
1229 * (1) Before calling this function for the first time, use
1230 * pixaCreate() to make the %pixa that will accumulate the pix.
1231 * This is passed in each time pixSaveTiled() is called.
1232 * (2) %outwidth is the scaled width. After scaling, the image is
1233 * saved in the input pixa, along with a box that specifies
1234 * the location to place it when tiled later. Disable saving
1235 * the pix by setting %outwidth == 0.
1236 * (3) %newrow and %space specify the location of the new pix
1237 * with respect to the last one(s) that were entered.
1238 * (4) All pix are saved as 32 bpp RGB.
1239 * (5) If both %bmf and %textstr are defined, this generates a pix
1240 * with the additional text; otherwise, no text is written.
1241 * (6) The text is written before scaling, so it is properly
1242 * antialiased in the scaled pix. However, if the pix on
1243 * different calls have different widths, the size of the
1244 * text will vary.
1245 * (7) See pixSaveTiledOutline() for other implementation details.
1246 * </pre>
1247 */
1248 l_int32
pixSaveTiledWithText(PIX * pixs,PIXA * pixa,l_int32 outwidth,l_int32 newrow,l_int32 space,l_int32 linewidth,L_BMF * bmf,const char * textstr,l_uint32 val,l_int32 location)1249 pixSaveTiledWithText(PIX *pixs,
1250 PIXA *pixa,
1251 l_int32 outwidth,
1252 l_int32 newrow,
1253 l_int32 space,
1254 l_int32 linewidth,
1255 L_BMF *bmf,
1256 const char *textstr,
1257 l_uint32 val,
1258 l_int32 location)
1259 {
1260 PIX *pix1, *pix2, *pix3, *pix4;
1261
1262 PROCNAME("pixSaveTiledWithText");
1263
1264 if (outwidth == 0) return 0;
1265
1266 if (!pixs)
1267 return ERROR_INT("pixs not defined", procName, 1);
1268 if (!pixa)
1269 return ERROR_INT("pixa not defined", procName, 1);
1270
1271 pix1 = pixConvertTo32(pixs);
1272 if (linewidth > 0)
1273 pix2 = pixAddBorder(pix1, linewidth, 0);
1274 else
1275 pix2 = pixClone(pix1);
1276 if (bmf && textstr)
1277 pix3 = pixAddSingleTextblock(pix2, bmf, textstr, val, location, NULL);
1278 else
1279 pix3 = pixClone(pix2);
1280 pix4 = pixScaleToSize(pix3, outwidth, 0);
1281 pixSaveTiled(pix4, pixa, 1.0, newrow, space, 32);
1282 pixDestroy(&pix1);
1283 pixDestroy(&pix2);
1284 pixDestroy(&pix3);
1285 pixDestroy(&pix4);
1286 return 0;
1287 }
1288
1289
1290 void
l_chooseDisplayProg(l_int32 selection)1291 l_chooseDisplayProg(l_int32 selection)
1292 {
1293 if (selection == L_DISPLAY_WITH_XLI ||
1294 selection == L_DISPLAY_WITH_XZGV ||
1295 selection == L_DISPLAY_WITH_XV ||
1296 selection == L_DISPLAY_WITH_IV ||
1297 selection == L_DISPLAY_WITH_OPEN) {
1298 var_DISPLAY_PROG = selection;
1299 } else {
1300 L_ERROR("invalid display program\n", "l_chooseDisplayProg");
1301 }
1302 return;
1303 }
1304
1305
1306 /*---------------------------------------------------------------------*
1307 * Deprecated pix output for debugging *
1308 *---------------------------------------------------------------------*/
1309 /*!
1310 * \brief pixDisplayWrite()
1311 *
1312 * \param[in] pix 1, 2, 4, 8, 16, 32 bpp
1313 * \param[in] reduction -1 to reset/erase; 0 to disable;
1314 * otherwise this is a reduction factor
1315 * \return 0 if OK; 1 on error
1316 *
1317 * <pre>
1318 * Notes:
1319 * (0) Deprecated.
1320 * (1) This is a simple interface for writing a set of files.
1321 * (2) This uses jpeg output for pix that are 32 bpp or 8 bpp
1322 * without a colormap; otherwise, it uses png.
1323 * (3) To erase any previously written files in the output directory:
1324 * pixDisplayWrite(NULL, -1);
1325 * (4) If reduction > 1 and depth == 1, this does a scale-to-gray
1326 * reduction.
1327 * (5) This function uses a static internal variable to number
1328 * output files written by a single process. Behavior
1329 * with a shared library may be unpredictable.
1330 * (6) For 16 bpp, this displays the full dynamic range with log scale.
1331 * Alternative image transforms to generate 8 bpp pix are:
1332 * pix8 = pixMaxDynamicRange(pixt, L_LINEAR_SCALE);
1333 * pix8 = pixConvert16To8(pixt, 0); // low order byte
1334 * pix8 = pixConvert16To8(pixt, 1); // high order byte
1335 * </pre>
1336 */
1337 l_int32
pixDisplayWrite(PIX * pixs,l_int32 reduction)1338 pixDisplayWrite(PIX *pixs,
1339 l_int32 reduction)
1340 {
1341 char buf[L_BUFSIZE];
1342 char *fname;
1343 l_float32 scale;
1344 PIX *pix1, *pix2;
1345 static l_int32 index = 0; /* caution: not .so or thread safe */
1346
1347 PROCNAME("pixDisplayWrite");
1348
1349 if (reduction == 0) return 0;
1350 if (reduction < 0) { /* initialize */
1351 lept_rmdir("lept/display");
1352 index = 0;
1353 return 0;
1354 }
1355 if (!pixs)
1356 return ERROR_INT("pixs not defined", procName, 1);
1357 if (index == 0)
1358 lept_mkdir("lept/display");
1359 index++;
1360
1361 if (reduction == 1) {
1362 pix1 = pixClone(pixs);
1363 } else {
1364 scale = 1. / (l_float32)reduction;
1365 if (pixGetDepth(pixs) == 1)
1366 pix1 = pixScaleToGray(pixs, scale);
1367 else
1368 pix1 = pixScale(pixs, scale, scale);
1369 }
1370
1371 if (pixGetDepth(pix1) == 16) {
1372 pix2 = pixMaxDynamicRange(pix1, L_LOG_SCALE);
1373 snprintf(buf, L_BUFSIZE, "file.%03d.png", index);
1374 fname = pathJoin("/tmp/lept/display", buf);
1375 pixWrite(fname, pix2, IFF_PNG);
1376 pixDestroy(&pix2);
1377 } else if (pixGetDepth(pix1) < 8 || pixGetColormap(pix1)) {
1378 snprintf(buf, L_BUFSIZE, "file.%03d.png", index);
1379 fname = pathJoin("/tmp/lept/display", buf);
1380 pixWrite(fname, pix1, IFF_PNG);
1381 } else {
1382 snprintf(buf, L_BUFSIZE, "file.%03d.jpg", index);
1383 fname = pathJoin("/tmp/lept/display", buf);
1384 pixWrite(fname, pix1, IFF_JFIF_JPEG);
1385 }
1386 LEPT_FREE(fname);
1387 pixDestroy(&pix1);
1388 return 0;
1389 }
1390