comparison mupdf-source/thirdparty/leptonica/src/writefile.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 getFormatFromExtension()
48 * l_int32 pixGetAutoFormat()
49 * const char *getFormatExtension()
50 *
51 * Write to memory
52 * l_int32 pixWriteMem()
53 *
54 * Image display for debugging
55 * l_int32 l_fileDisplay()
56 * l_int32 pixDisplay()
57 * l_int32 pixDisplayWithTitle()
58 * PIX *pixMakeColorSquare()
59 * void l_chooseDisplayProg()
60 *
61 * Change format for missing library
62 * void changeFormatForMissingLib()
63 *
64 * Nonfunctional stub of pix output for debugging
65 * l_int32 pixDisplayWrite()
66 *
67 * Supported file formats:
68 * (1) Writing is supported without any external libraries:
69 * bmp
70 * pnm (including pbm, pgm, etc)
71 * spix (raw serialized)
72 * (2) Writing is supported with installation of external libraries:
73 * png
74 * jpg (standard jfif version)
75 * tiff (including most varieties of compression)
76 * gif
77 * webp
78 * jp2 (jpeg2000)
79 * (3) Writing is supported through special interfaces:
80 * ps (PostScript, in psio1.c, psio2.c):
81 * level 1 (uncompressed)
82 * level 2 (g4 and dct encoding: requires tiff, jpg)
83 * level 3 (g4, dct and flate encoding: requires tiff, jpg, zlib)
84 * pdf (PDF, in pdfio.c):
85 * level 1 (g4 and dct encoding: requires tiff, jpg)
86 * level 2 (g4, dct and flate encoding: requires tiff, jpg, zlib)
87 */
88
89 #ifdef HAVE_CONFIG_H
90 #include <config_auto.h>
91 #endif /* HAVE_CONFIG_H */
92
93 #include <string.h>
94 #include "allheaders.h"
95
96 /* Set defaults for the display program (xv, xli, xzgv, open, irfanview)
97 * that is invoked by pixDisplay() */
98 #ifdef _WIN32
99 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_IV; /* default */
100 #elif defined(__APPLE__)
101 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_OPEN; /* default */
102 #else
103 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_XZGV; /* default */
104 #endif /* _WIN32 */
105
106 #define Bufsize 512
107 static const l_int32 MaxDisplayWidth = 1000;
108 static const l_int32 MaxDisplayHeight = 800;
109 static const l_int32 MaxSizeForPng = 200;
110
111 /* PostScript output for printing */
112 static const l_float32 DefaultScaling = 1.0;
113
114 /* Global array of image file format extension names. */
115 /* This is in 1-1 correspondence with format enum in imageio.h. */
116 /* The empty string at the end represents the serialized format, */
117 /* which has no recognizable extension name, but the array must */
118 /* be padded to agree with the format enum. */
119 /* (Note on 'const': The size of the array can't be defined 'const' */
120 /* because that makes it static. The 'const' in the definition of */
121 /* the array refers to the strings in the array; the ptr to the */
122 /* array is not const and can be used 'extern' in other files.) */
123 LEPT_DLL l_int32 NumImageFileFormatExtensions = 20; /* array size */
124 LEPT_DLL const char *ImageFileFormatExtensions[] =
125 {"unknown",
126 "bmp",
127 "jpg",
128 "png",
129 "tif",
130 "tif",
131 "tif",
132 "tif",
133 "tif",
134 "tif",
135 "tif",
136 "pnm",
137 "ps",
138 "gif",
139 "jp2",
140 "webp",
141 "pdf",
142 "tif",
143 "default",
144 ""};
145
146 /* Local map of image file name extension to output format.
147 * Note that the extension string always includes a '.' */
148 struct ExtensionMap
149 {
150 char extension[16];
151 l_int32 format;
152 };
153 static const struct ExtensionMap extension_map[] =
154 { { ".bmp", IFF_BMP },
155 { ".jpg", IFF_JFIF_JPEG },
156 { ".jpeg", IFF_JFIF_JPEG },
157 { ".JPG", IFF_JFIF_JPEG },
158 { ".png", IFF_PNG },
159 { ".tif", IFF_TIFF },
160 { ".tiff", IFF_TIFF },
161 { ".tiffg4", IFF_TIFF_G4 },
162 { ".pbm", IFF_PNM },
163 { ".pgm", IFF_PNM },
164 { ".pnm", IFF_PNM },
165 { ".gif", IFF_GIF },
166 { ".jp2", IFF_JP2 },
167 { ".j2k", IFF_JP2 },
168 { ".ps", IFF_PS },
169 { ".pdf", IFF_LPDF },
170 { ".webp", IFF_WEBP } };
171
172
173 /*---------------------------------------------------------------------*
174 * Set jpeg quality for pixWrite() and pixWriteMem() *
175 *---------------------------------------------------------------------*/
176 /* Parameter that controls jpeg quality for high-level calls. */
177 static l_int32 var_JPEG_QUALITY = 75; /* default */
178
179 /*!
180 * \brief l_jpegSetQuality()
181 *
182 * \param[in] new_quality 1 - 100; 75 is default; 0 defaults to 75
183 * \return prev previous quality
184 *
185 * <pre>
186 * Notes:
187 * (1) This variable is used in pixWriteStream() and pixWriteMem(),
188 * to control the jpeg quality. The default is 75.
189 * (2) It returns the previous quality, so for example:
190 * l_int32 prev = l_jpegSetQuality(85); //sets to 85
191 * pixWriteStream(...);
192 * l_jpegSetQuality(prev); // resets to previous value
193 * (3) On error, logs a message and does not change the variable.
194 */
195 l_int32
196 l_jpegSetQuality(l_int32 new_quality)
197 {
198 l_int32 prevq, newq;
199
200 prevq = var_JPEG_QUALITY;
201 newq = (new_quality == 0) ? 75 : new_quality;
202 if (newq < 1 || newq > 100)
203 L_ERROR("invalid jpeg quality; unchanged\n", __func__);
204 else
205 var_JPEG_QUALITY = newq;
206 return prevq;
207 }
208
209
210 /*----------------------------------------------------------------------*
211 * Set global variable LeptDebugOK for writing to named temp files *
212 *----------------------------------------------------------------------*/
213 LEPT_DLL l_int32 LeptDebugOK = 0; /* default value */
214 /*!
215 * \brief setLeptDebugOK()
216 *
217 * \param[in] allow TRUE (1) or FALSE (0)
218 * \return void
219 *
220 * <pre>
221 * Notes:
222 * (1) This sets or clears the global variable LeptDebugOK, to
223 * control writing files in a temp directory with names that
224 * are compiled in.
225 * (2) The default in the library distribution is 0. Call with
226 * %allow = 1 for development and debugging.
227 */
228 void
229 setLeptDebugOK(l_int32 allow)
230 {
231 if (allow != 0) allow = 1;
232 LeptDebugOK = allow;
233 }
234
235
236 /*---------------------------------------------------------------------*
237 * Top-level procedures for writing images to file *
238 *---------------------------------------------------------------------*/
239 /*!
240 * \brief pixaWriteFiles()
241 *
242 * \param[in] rootname
243 * \param[in] pixa
244 * \param[in] format defined in imageio.h; see notes for default
245 * \return 0 if OK; 1 on error
246 *
247 * <pre>
248 * Notes:
249 * (1) Use %format = IFF_DEFAULT to decide the output format
250 * individually for each pix.
251 * </pre>
252 */
253 l_ok
254 pixaWriteFiles(const char *rootname,
255 PIXA *pixa,
256 l_int32 format)
257 {
258 char bigbuf[Bufsize];
259 l_int32 i, n, pixformat;
260 PIX *pix;
261
262 if (!rootname)
263 return ERROR_INT("rootname not defined", __func__, 1);
264 if (!pixa)
265 return ERROR_INT("pixa not defined", __func__, 1);
266 if (format < 0 || format == IFF_UNKNOWN ||
267 format >= NumImageFileFormatExtensions)
268 return ERROR_INT("invalid format", __func__, 1);
269
270 n = pixaGetCount(pixa);
271 for (i = 0; i < n; i++) {
272 pix = pixaGetPix(pixa, i, L_CLONE);
273 if (format == IFF_DEFAULT)
274 pixformat = pixChooseOutputFormat(pix);
275 else
276 pixformat = format;
277 snprintf(bigbuf, Bufsize, "%s%03d.%s", rootname, i,
278 ImageFileFormatExtensions[pixformat]);
279 pixWrite(bigbuf, pix, pixformat);
280 pixDestroy(&pix);
281 }
282
283 return 0;
284 }
285
286
287 /*!
288 * \brief pixWriteDebug()
289 *
290 * \param[in] fname
291 * \param[in] pix
292 * \param[in] format defined in imageio.h
293 * \return 0 if OK; 1 on error
294 *
295 * <pre>
296 * Notes:
297 * (1) Debug version, intended for use in the library when writing
298 * to files in a temp directory with names that are compiled in.
299 * This is used instead of pixWrite() for all such library calls.
300 * (2) The global variable LeptDebugOK defaults to 0, and can be set
301 * or cleared by the function setLeptDebugOK().
302 * </pre>
303 */
304 l_ok
305 pixWriteDebug(const char *fname,
306 PIX *pix,
307 l_int32 format)
308 {
309 if (LeptDebugOK) {
310 return pixWrite(fname, pix, format);
311 } else {
312 L_INFO("write to named temp file %s is disabled\n", __func__, fname);
313 return 0;
314 }
315 }
316
317
318 /*!
319 * \brief pixWrite()
320 *
321 * \param[in] fname
322 * \param[in] pix
323 * \param[in] format defined in imageio.h
324 * \return 0 if OK; 1 on error
325 *
326 * <pre>
327 * Notes:
328 * (1) Open for write using binary mode (with the "b" flag)
329 * to avoid having Windows automatically translate the NL
330 * into CRLF, which corrupts image files. On non-Windows
331 * systems this flag should be ignored, per ISO C90.
332 * Thanks to Dave Bryan for pointing this out.
333 * (2) If the default image format IFF_DEFAULT is requested:
334 * use the input format if known; otherwise, use a lossless format.
335 * (3) The default jpeg quality is 75. For some other value,
336 * Use l_jpegSetQuality().
337 * </pre>
338 */
339 l_ok
340 pixWrite(const char *fname,
341 PIX *pix,
342 l_int32 format)
343 {
344 l_int32 ret;
345 FILE *fp;
346
347 if (!pix)
348 return ERROR_INT("pix not defined", __func__, 1);
349 if (!fname)
350 return ERROR_INT("fname not defined", __func__, 1);
351
352 if ((fp = fopenWriteStream(fname, "wb+")) == NULL)
353 return ERROR_INT_1("stream not opened", fname, __func__, 1);
354
355 ret = pixWriteStream(fp, pix, format);
356 fclose(fp);
357 if (ret)
358 return ERROR_INT_1("pix not written to stream", fname, __func__, 1);
359 return 0;
360 }
361
362
363 /*!
364 * \brief pixWriteAutoFormat()
365 *
366 * \param[in] filename
367 * \param[in] pix
368 * \return 0 if OK; 1 on error
369 */
370 l_ok
371 pixWriteAutoFormat(const char *filename,
372 PIX *pix)
373 {
374 l_int32 format;
375
376 if (!pix)
377 return ERROR_INT("pix not defined", __func__, 1);
378 if (!filename)
379 return ERROR_INT("filename not defined", __func__, 1);
380
381 if (pixGetAutoFormat(pix, &format))
382 return ERROR_INT("auto format not returned", __func__, 1);
383 return pixWrite(filename, pix, format);
384 }
385
386
387 /*!
388 * \brief pixWriteStream()
389 *
390 * \param[in] fp file stream
391 * \param[in] pix
392 * \param[in] format
393 * \return 0 if OK; 1 on error.
394 */
395 l_ok
396 pixWriteStream(FILE *fp,
397 PIX *pix,
398 l_int32 format)
399 {
400 if (!fp)
401 return ERROR_INT("stream not defined", __func__, 1);
402 if (!pix)
403 return ERROR_INT("pix not defined", __func__, 1);
404
405 if (format == IFF_DEFAULT)
406 format = pixChooseOutputFormat(pix);
407
408 /* Use bmp format for testing if library for requested
409 * format for jpeg, png or tiff is not available */
410 changeFormatForMissingLib(&format);
411
412 switch(format)
413 {
414 case IFF_BMP:
415 pixWriteStreamBmp(fp, pix);
416 break;
417
418 case IFF_JFIF_JPEG: /* default quality; baseline sequential */
419 return pixWriteStreamJpeg(fp, pix, var_JPEG_QUALITY, 0);
420
421 case IFF_PNG: /* no gamma value stored */
422 return pixWriteStreamPng(fp, pix, 0.0);
423
424 case IFF_TIFF: /* uncompressed */
425 case IFF_TIFF_PACKBITS: /* compressed, binary only */
426 case IFF_TIFF_RLE: /* compressed, binary only */
427 case IFF_TIFF_G3: /* compressed, binary only */
428 case IFF_TIFF_G4: /* compressed, binary only */
429 case IFF_TIFF_LZW: /* compressed, all depths */
430 case IFF_TIFF_ZIP: /* compressed, all depths */
431 case IFF_TIFF_JPEG: /* compressed, 8 bpp gray and 32 bpp rgb */
432 return pixWriteStreamTiff(fp, pix, format);
433
434 case IFF_PNM:
435 return pixWriteStreamPnm(fp, pix);
436
437 case IFF_PS:
438 return pixWriteStreamPS(fp, pix, NULL, 0, DefaultScaling);
439
440 case IFF_GIF:
441 return pixWriteStreamGif(fp, pix);
442
443 case IFF_JP2:
444 return pixWriteStreamJp2k(fp, pix, 34, 0, L_JP2_CODEC, 0, 0);
445
446 case IFF_WEBP:
447 return pixWriteStreamWebP(fp, pix, 80, 0);
448
449 case IFF_LPDF:
450 return pixWriteStreamPdf(fp, pix, 0, NULL);
451
452 case IFF_SPIX:
453 return pixWriteStreamSpix(fp, pix);
454
455 default:
456 return ERROR_INT("unknown format", __func__, 1);
457 }
458
459 return 0;
460 }
461
462
463 /*!
464 * \brief pixWriteImpliedFormat()
465 *
466 * \param[in] filename
467 * \param[in] pix
468 * \param[in] quality iff JPEG; 1 - 100, 0 for default
469 * \param[in] progressive iff JPEG; 0 for baseline seq., 1 for progressive
470 * \return 0 if OK; 1 on error
471 *
472 * <pre>
473 * Notes:
474 * (1) This determines the output format from the filename extension.
475 * (2) The last two args are ignored except for requests for jpeg files.
476 * (3) The jpeg default quality is 75.
477 * </pre>
478 */
479 l_ok
480 pixWriteImpliedFormat(const char *filename,
481 PIX *pix,
482 l_int32 quality,
483 l_int32 progressive)
484 {
485 l_int32 format;
486
487 if (!filename)
488 return ERROR_INT("filename not defined", __func__, 1);
489 if (!pix)
490 return ERROR_INT("pix not defined", __func__, 1);
491
492 /* Determine output format */
493 format = getImpliedFileFormat(filename);
494 if (format == IFF_UNKNOWN) {
495 format = IFF_PNG;
496 } else if (format == IFF_TIFF) {
497 if (pixGetDepth(pix) == 1)
498 format = IFF_TIFF_G4;
499 else
500 #ifdef _WIN32
501 format = IFF_TIFF_LZW; /* poor compression */
502 #else
503 format = IFF_TIFF_ZIP; /* native Windows tools can't handle this */
504 #endif /* _WIN32 */
505 }
506
507 if (format == IFF_JFIF_JPEG) {
508 quality = L_MIN(quality, 100);
509 quality = L_MAX(quality, 0);
510 if (progressive != 0 && progressive != 1) {
511 progressive = 0;
512 L_WARNING("invalid progressive; setting to baseline\n", __func__);
513 }
514 if (quality == 0)
515 quality = 75;
516 pixWriteJpeg (filename, pix, quality, progressive);
517 } else {
518 pixWrite(filename, pix, format);
519 }
520
521 return 0;
522 }
523
524
525 /*---------------------------------------------------------------------*
526 * Selection of output format if default is requested *
527 *---------------------------------------------------------------------*/
528 /*!
529 * \brief pixChooseOutputFormat()
530 *
531 * \param[in] pix
532 * \return output format, or 0 on error
533 *
534 * <pre>
535 * Notes:
536 * (1) This should only be called if the requested format is IFF_DEFAULT.
537 * (2) If the pix wasn't read from a file, its input format value
538 * will be IFF_UNKNOWN, and in that case it is written out
539 * in a compressed but lossless format.
540 * </pre>
541 */
542 l_int32
543 pixChooseOutputFormat(PIX *pix)
544 {
545 l_int32 d, format;
546
547 if (!pix)
548 return ERROR_INT("pix not defined", __func__, 0);
549
550 d = pixGetDepth(pix);
551 format = pixGetInputFormat(pix);
552 if (format == IFF_UNKNOWN) { /* output lossless */
553 if (d == 1)
554 format = IFF_TIFF_G4;
555 else
556 format = IFF_PNG;
557 }
558
559 return format;
560 }
561
562
563 /*!
564 * \brief getImpliedFileFormat()
565 *
566 * \param[in] filename
567 * \return output format, or IFF_UNKNOWN on error or invalid extension.
568 *
569 * <pre>
570 * Notes:
571 * (1) This determines the output file format from the extension
572 * of the input filename.
573 * </pre>
574 */
575 l_int32
576 getImpliedFileFormat(const char *filename)
577 {
578 char *extension;
579 l_int32 format = IFF_UNKNOWN;
580
581 if (!filename)
582 return ERROR_INT("extension not defined", __func__, IFF_UNKNOWN);
583
584 if (splitPathAtExtension (filename, NULL, &extension))
585 return IFF_UNKNOWN;
586
587 format = getFormatFromExtension(extension);
588 LEPT_FREE(extension);
589 return format;
590 }
591
592
593 /*!
594 * \brief getFormatFromExtension()
595 *
596 * \param[in] extension
597 * \return output format, or IFF_UNKNOWN on error or invalid extension.
598 *
599 * <pre>
600 * Notes:
601 * (1) This determines the integer for writing in a format that
602 * corresponds to the image file type extension. For example,
603 * the integer code corresponding to the extension "jpg" is 2;
604 * it is used to write with jpeg encoding.
605 * </pre>
606 */
607 l_int32
608 getFormatFromExtension(const char *extension)
609 {
610 int i, numext;
611 l_int32 format = IFF_UNKNOWN;
612
613 if (!extension)
614 return ERROR_INT("extension not defined", __func__, IFF_UNKNOWN);
615
616 numext = sizeof(extension_map) / sizeof(extension_map[0]);
617 for (i = 0; i < numext; i++) {
618 if (!strcmp(extension, extension_map[i].extension)) {
619 format = extension_map[i].format;
620 break;
621 }
622 }
623 return format;
624 }
625
626
627 /*!
628 * \brief pixGetAutoFormat()
629 *
630 * \param[in] pix
631 * \param[in] &format
632 * \return 0 if OK, 1 on error
633 *
634 * <pre>
635 * Notes:
636 * (1) The output formats are restricted to tiff, jpeg and png
637 * because these are the most commonly used image formats and
638 * the ones that are typically installed with leptonica.
639 * (2) This decides what compression to use based on the pix.
640 * It chooses tiff-g4 if 1 bpp without a colormap, jpeg with
641 * quality 75 if grayscale, rgb or rgba (where it loses
642 * the alpha layer), and lossless png for all other situations.
643 * </pre>
644 */
645 l_ok
646 pixGetAutoFormat(PIX *pix,
647 l_int32 *pformat)
648 {
649 l_int32 d;
650 PIXCMAP *cmap;
651
652 if (!pformat)
653 return ERROR_INT("&format not defined", __func__, 0);
654 *pformat = IFF_UNKNOWN;
655 if (!pix)
656 return ERROR_INT("pix not defined", __func__, 0);
657
658 d = pixGetDepth(pix);
659 cmap = pixGetColormap(pix);
660 if (d == 1 && !cmap) {
661 *pformat = IFF_TIFF_G4;
662 } else if ((d == 8 && !cmap) || d == 24 || d == 32) {
663 *pformat = IFF_JFIF_JPEG;
664 } else {
665 *pformat = IFF_PNG;
666 }
667
668 return 0;
669 }
670
671
672 /*!
673 * \brief getFormatExtension()
674 *
675 * \param[in] format integer
676 * \return extension string, or NULL if format is out of range
677 *
678 * <pre>
679 * Notes:
680 * (1) This string is NOT owned by the caller; it is just a pointer
681 * to a global string. Do not free it.
682 * </pre>
683 */
684 const char *
685 getFormatExtension(l_int32 format)
686 {
687 if (format < 0 || format >= NumImageFileFormatExtensions)
688 return (const char *)ERROR_PTR("invalid format", __func__, NULL);
689
690 return ImageFileFormatExtensions[format];
691 }
692
693
694 /*---------------------------------------------------------------------*
695 * Write to memory *
696 *---------------------------------------------------------------------*/
697 /*!
698 * \brief pixWriteMem()
699 *
700 * \param[out] pdata data of tiff compressed image
701 * \param[out] psize size of returned data
702 * \param[in] pix
703 * \param[in] format defined in imageio.h
704 * \return 0 if OK, 1 on error
705 *
706 * <pre>
707 * Notes:
708 * (1) On Windows, this will only write tiff and PostScript to memory.
709 * For other formats, it requires open_memstream(3).
710 * (2) PostScript output is uncompressed, in hex ascii.
711 * Most printers support level 2 compression (tiff_g4 for 1 bpp,
712 * jpeg for 8 and 32 bpp).
713 * (3) The default jpeg quality is 75. For some other value,
714 * Use l_jpegSetQuality().
715 * </pre>
716 */
717 l_ok
718 pixWriteMem(l_uint8 **pdata,
719 size_t *psize,
720 PIX *pix,
721 l_int32 format)
722 {
723 l_int32 ret;
724
725 if (!pdata)
726 return ERROR_INT("&data not defined", __func__, 1 );
727 if (!psize)
728 return ERROR_INT("&size not defined", __func__, 1 );
729 if (!pix)
730 return ERROR_INT("&pix not defined", __func__, 1 );
731
732 if (format == IFF_DEFAULT)
733 format = pixChooseOutputFormat(pix);
734
735 /* Use bmp format for testing if library for requested
736 * format for jpeg, png or tiff is not available */
737 changeFormatForMissingLib(&format);
738
739 switch(format)
740 {
741 case IFF_BMP:
742 ret = pixWriteMemBmp(pdata, psize, pix);
743 break;
744
745 case IFF_JFIF_JPEG: /* default quality; baseline sequential */
746 ret = pixWriteMemJpeg(pdata, psize, pix, var_JPEG_QUALITY, 0);
747 break;
748
749 case IFF_PNG: /* no gamma value stored */
750 ret = pixWriteMemPng(pdata, psize, pix, 0.0);
751 break;
752
753 case IFF_TIFF: /* uncompressed */
754 case IFF_TIFF_PACKBITS: /* compressed, binary only */
755 case IFF_TIFF_RLE: /* compressed, binary only */
756 case IFF_TIFF_G3: /* compressed, binary only */
757 case IFF_TIFF_G4: /* compressed, binary only */
758 case IFF_TIFF_LZW: /* compressed, all depths */
759 case IFF_TIFF_ZIP: /* compressed, all depths */
760 case IFF_TIFF_JPEG: /* compressed, 8 bpp gray or 32 bpp rgb */
761 ret = pixWriteMemTiff(pdata, psize, pix, format);
762 break;
763
764 case IFF_PNM:
765 ret = pixWriteMemPnm(pdata, psize, pix);
766 break;
767
768 case IFF_PS:
769 ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DefaultScaling);
770 break;
771
772 case IFF_GIF:
773 ret = pixWriteMemGif(pdata, psize, pix);
774 break;
775
776 case IFF_JP2:
777 ret = pixWriteMemJp2k(pdata, psize, pix, 34, 0, 0, 0);
778 break;
779
780 case IFF_WEBP:
781 ret = pixWriteMemWebP(pdata, psize, pix, 80, 0);
782 break;
783
784 case IFF_LPDF:
785 ret = pixWriteMemPdf(pdata, psize, pix, 0, NULL);
786 break;
787
788 case IFF_SPIX:
789 ret = pixWriteMemSpix(pdata, psize, pix);
790 break;
791
792 default:
793 return ERROR_INT("unknown format", __func__, 1);
794 }
795
796 return ret;
797 }
798
799
800 /*---------------------------------------------------------------------*
801 * Image display for debugging *
802 *---------------------------------------------------------------------*/
803 /*!
804 * \brief l_fileDisplay()
805 *
806 * \param[in] fname
807 * \param[in] x, y location of display frame on the screen
808 * \param[in] scale scale factor (use 0 to skip display)
809 * \return 0 if OK; 1 on error
810 *
811 * <pre>
812 * Notes:
813 * (1) This is a convenient wrapper for displaying image files.
814 * (2) It does nothing unless LeptDebugOK == TRUE.
815 * (2) Set %scale = 0 to disable display.
816 * (3) This downscales 1 bpp to gray.
817 * </pre>
818 */
819 l_ok
820 l_fileDisplay(const char *fname,
821 l_int32 x,
822 l_int32 y,
823 l_float32 scale)
824 {
825 PIX *pixs, *pixd;
826
827 if (!LeptDebugOK) {
828 L_INFO("displaying files is disabled; "
829 "use setLeptDebugOK(1) to enable\n", __func__);
830 return 0;
831 }
832 if (scale == 0.0)
833 return 0;
834 if (scale < 0.0)
835 return ERROR_INT("invalid scale factor", __func__, 1);
836 if ((pixs = pixRead(fname)) == NULL)
837 return ERROR_INT("pixs not read", __func__, 1);
838
839 if (scale == 1.0) {
840 pixd = pixClone(pixs);
841 } else {
842 if (scale < 1.0 && pixGetDepth(pixs) == 1)
843 pixd = pixScaleToGray(pixs, scale);
844 else
845 pixd = pixScale(pixs, scale, scale);
846 }
847 pixDisplay(pixd, x, y);
848 pixDestroy(&pixs);
849 pixDestroy(&pixd);
850 return 0;
851 }
852
853
854 /*!
855 * \brief pixDisplay()
856 *
857 * \param[in] pix 1, 2, 4, 8, 16, 32 bpp
858 * \param[in] x, y location of display frame on the screen
859 * \return 0 if OK; 1 on error
860 *
861 * <pre>
862 * Notes:
863 * (1) This is debugging code that displays an image on the screen.
864 * It uses a static internal variable to number the output files
865 * written by a single process. Behavior with a shared library
866 * may be unpredictable.
867 * (2) It does nothing unless LeptDebugOK == TRUE.
868 * (3) It uses these programs to display the image:
869 * On Unix: xzgv, xli, xv or (for apple) open
870 * On Windows: i_view or the application currently registered
871 * as the default viewer (the browser 'open' action
872 * based on the extension of the image file).
873 * The display program must be on your $PATH variable. It is
874 * chosen by setting the global var_DISPLAY_PROG, using
875 * l_chooseDisplayProg(). Default on Unix is xzgv.
876 * (4) Images with dimensions larger than MaxDisplayWidth or
877 * MaxDisplayHeight are downscaled to fit those constraints.
878 * This is particularly important for displaying 1 bpp images
879 * with xv, because xv automatically downscales large images
880 * by subsampling, which looks poor. For 1 bpp, we use
881 * scale-to-gray to get decent-looking anti-aliased images.
882 * In all cases, we write a temporary file to /tmp/lept/disp,
883 * that is read by the display program.
884 * (5) The temporary file is written as png if, after initial
885 * processing for special cases, any of these obtain:
886 * * pix dimensions are smaller than some thresholds
887 * * pix depth is less than 8 bpp
888 * * pix is colormapped
889 * (6) For spp == 4, we call pixDisplayLayersRGBA() to show 3
890 * versions of the image: the image with a fully opaque
891 * alpha, the alpha, and the image as it would appear with
892 * a white background.
893 * (7) pixDisplay() can be inactivated at runtime by calling:
894 * l_chooseDisplayProg(L_DISPLAY_WITH_NONE);
895 * </pre>
896 */
897 l_ok
898 pixDisplay(PIX *pixs,
899 l_int32 x,
900 l_int32 y)
901 {
902 return pixDisplayWithTitle(pixs, x, y, NULL, 1);
903 }
904
905
906 /*!
907 * \brief pixDisplayWithTitle()
908 *
909 * \param[in] pix 1, 2, 4, 8, 16, 32 bpp
910 * \param[in] x, y location of display frame
911 * \param[in] title [optional] on frame; can be NULL;
912 * \param[in] dispflag 1 to write, else disabled
913 * \return 0 if OK; 1 on error
914 *
915 * <pre>
916 * Notes:
917 * (1) See notes for pixDisplay().
918 * (2) This displays the image if dispflag == 1 and the global
919 * var_DISPLAY_PROG != L_DISPLAY_WITH_NONE; otherwise it punts.
920 * </pre>
921 */
922 l_ok
923 pixDisplayWithTitle(PIX *pixs,
924 l_int32 x,
925 l_int32 y,
926 const char *title,
927 l_int32 dispflag)
928 {
929 char *tempname;
930 char buffer[Bufsize];
931 static l_atomic index = 0; /* caution: not .so safe */
932 l_int32 w, h, d, spp, maxheight, opaque, threeviews;
933 l_float32 ratw, rath, ratmin;
934 PIX *pix0, *pix1, *pix2;
935 PIXCMAP *cmap;
936 #ifndef _WIN32
937 l_int32 wt, ht;
938 #else
939 char *pathname;
940 char fullpath[_MAX_PATH];
941 #endif /* _WIN32 */
942
943 if (!LeptDebugOK) {
944 L_INFO("displaying images is disabled;\n "
945 "use setLeptDebugOK(1) to enable\n", __func__);
946 return 0;
947 }
948
949 #ifdef OS_IOS /* iOS 11 does not support system() */
950 return ERROR_INT("iOS 11 does not support system()", __func__, 1);
951 #endif /* OS_IOS */
952
953 if (dispflag != 1 || var_DISPLAY_PROG == L_DISPLAY_WITH_NONE)
954 return 0;
955 if (!pixs)
956 return ERROR_INT("pixs not defined", __func__, 1);
957
958 #ifndef _WIN32 /* unix */
959 if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV &&
960 var_DISPLAY_PROG != L_DISPLAY_WITH_XLI &&
961 var_DISPLAY_PROG != L_DISPLAY_WITH_XV &&
962 var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN)
963 return ERROR_INT("invalid unix program chosen for display",
964 __func__, 1);
965 #else /* _WIN32 */
966 if (var_DISPLAY_PROG != L_DISPLAY_WITH_IV &&
967 var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN)
968 return ERROR_INT("invalid windows program chosen for display",
969 __func__, 1);
970 #endif /* _WIN32 */
971
972 /* Display with three views if either spp = 4 or if colormapped
973 * and the alpha component is not fully opaque */
974 opaque = TRUE;
975 if ((cmap = pixGetColormap(pixs)) != NULL)
976 pixcmapIsOpaque(cmap, &opaque);
977 spp = pixGetSpp(pixs);
978 threeviews = (spp == 4 || !opaque) ? TRUE : FALSE;
979
980 /* If colormapped and not opaque, remove the colormap to RGBA */
981 if (!opaque)
982 pix0 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA);
983 else
984 pix0 = pixClone(pixs);
985
986 /* Scale if necessary; this will also remove a colormap */
987 pixGetDimensions(pix0, &w, &h, &d);
988 maxheight = (threeviews) ? MaxDisplayHeight / 3 : MaxDisplayHeight;
989 if (w <= MaxDisplayWidth && h <= maxheight) {
990 if (d == 16) /* take MSB */
991 pix1 = pixConvert16To8(pix0, L_MS_BYTE);
992 else
993 pix1 = pixClone(pix0);
994 } else {
995 ratw = (l_float32)MaxDisplayWidth / (l_float32)w;
996 rath = (l_float32)maxheight / (l_float32)h;
997 ratmin = L_MIN(ratw, rath);
998 if (ratmin < 0.125 && d == 1)
999 pix1 = pixScaleToGray8(pix0);
1000 else if (ratmin < 0.25 && d == 1)
1001 pix1 = pixScaleToGray4(pix0);
1002 else if (ratmin < 0.33 && d == 1)
1003 pix1 = pixScaleToGray3(pix0);
1004 else if (ratmin < 0.5 && d == 1)
1005 pix1 = pixScaleToGray2(pix0);
1006 else
1007 pix1 = pixScale(pix0, ratmin, ratmin);
1008 }
1009 pixDestroy(&pix0);
1010 if (!pix1)
1011 return ERROR_INT("pix1 not made", __func__, 1);
1012
1013 /* Generate the three views if required */
1014 if (threeviews)
1015 pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0);
1016 else
1017 pix2 = pixClone(pix1);
1018
1019 if (index == 0) { /* erase any existing images */
1020 lept_rmdir("lept/disp");
1021 lept_mkdir("lept/disp");
1022 }
1023
1024 index++;
1025 if (pixGetDepth(pix2) < 8 || pixGetColormap(pix2) ||
1026 (w < MaxSizeForPng && h < MaxSizeForPng)) {
1027 snprintf(buffer, Bufsize, "/tmp/lept/disp/write.%03d.png", index);
1028 pixWrite(buffer, pix2, IFF_PNG);
1029 } else {
1030 snprintf(buffer, Bufsize, "/tmp/lept/disp/write.%03d.jpg", index);
1031 pixWrite(buffer, pix2, IFF_JFIF_JPEG);
1032 }
1033 tempname = genPathname(buffer, NULL);
1034
1035 #ifndef _WIN32
1036
1037 /* Unix */
1038 if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) {
1039 /* no way to display title */
1040 pixGetDimensions(pix2, &wt, &ht, NULL);
1041 snprintf(buffer, Bufsize,
1042 "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10,
1043 x, y, tempname);
1044 } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) {
1045 if (title) {
1046 snprintf(buffer, Bufsize,
1047 "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &",
1048 x, y, title, tempname);
1049 } else {
1050 snprintf(buffer, Bufsize,
1051 "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &",
1052 x, y, tempname);
1053 }
1054 } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) {
1055 if (title) {
1056 snprintf(buffer, Bufsize,
1057 "xv -quit -geometry +%d+%d -name \"%s\" %s &",
1058 x, y, title, tempname);
1059 } else {
1060 snprintf(buffer, Bufsize,
1061 "xv -quit -geometry +%d+%d %s &", x, y, tempname);
1062 }
1063 } else { /* L_DISPLAY_WITH_OPEN */
1064 snprintf(buffer, Bufsize, "open %s &", tempname);
1065 }
1066 callSystemDebug(buffer);
1067
1068 #else /* _WIN32 */
1069
1070 /* Windows: L_DISPLAY_WITH_IV || L_DISPLAY_WITH_OPEN */
1071 pathname = genPathname(tempname, NULL);
1072 _fullpath(fullpath, pathname, sizeof(fullpath));
1073 if (var_DISPLAY_PROG == L_DISPLAY_WITH_IV) {
1074 if (title) {
1075 snprintf(buffer, Bufsize,
1076 "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"",
1077 fullpath, x, y, title);
1078 } else {
1079 snprintf(buffer, Bufsize, "i_view32.exe \"%s\" /pos=(%d,%d)",
1080 fullpath, x, y);
1081 }
1082 } else { /* L_DISPLAY_WITH_OPEN */
1083 snprintf(buffer, Bufsize, "explorer.exe /open,\"%s\"", fullpath);
1084 }
1085 callSystemDebug(buffer);
1086 LEPT_FREE(pathname);
1087
1088 #endif /* _WIN32 */
1089
1090 pixDestroy(&pix1);
1091 pixDestroy(&pix2);
1092 LEPT_FREE(tempname);
1093 return 0;
1094 }
1095
1096
1097 /*!
1098 * \brief pixMakeColorSquare()
1099 *
1100 * \param[in] color in 0xrrggbb00 format
1101 * \param[in] size in pixels; >= 100; use 0 for default (min size)
1102 * \param[in] addlabel use 1 to display the color component values
1103 * \param[in] location of text: L_ADD_ABOVE, etc; ignored if %addlabel == 0
1104 * \param[in] textcolor of text label; in 0xrrggbb00 format
1105 * \return 32 bpp rgb pixd if OK; NULL on error
1106 *
1107 * <pre>
1108 * Notes:
1109 * (1) If %addlabel == 0, %location and %textcolor are ignored.
1110 * (2) To make an array of color squares, use pixDisplayColorArray().
1111 * </pre>
1112 */
1113 PIX *
1114 pixMakeColorSquare(l_uint32 color,
1115 l_int32 size,
1116 l_int32 addlabel,
1117 l_int32 location,
1118 l_uint32 textcolor)
1119 {
1120 char buf[32];
1121 l_int32 w, rval, gval, bval;
1122 L_BMF *bmf;
1123 PIX *pix1, *pix2;
1124
1125 w = (size <= 0) ? 100 : size;
1126 if (addlabel && w < 100) {
1127 L_WARNING("size too small for label; omitting label\n", __func__);
1128 addlabel = 0;
1129 }
1130
1131 if ((pix1 = pixCreate(w, w, 32)) == NULL)
1132 return (PIX *)ERROR_PTR("pix1 not madel", __func__, NULL);
1133 pixSetAllArbitrary(pix1, color);
1134 if (!addlabel)
1135 return pix1;
1136
1137 /* Adding text of color component values */
1138 if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP &&
1139 location != L_ADD_AT_BOT && location != L_ADD_BELOW) {
1140 L_ERROR("invalid location: adding below\n", __func__);
1141 location = L_ADD_BELOW;
1142 }
1143 bmf = bmfCreate(NULL, 4);
1144 extractRGBValues(color, &rval, &gval, &bval);
1145 snprintf(buf, sizeof(buf), "%d,%d,%d", rval, gval, bval);
1146 pix2 = pixAddSingleTextblock(pix1, bmf, buf, textcolor, location, NULL);
1147 pixDestroy(&pix1);
1148 bmfDestroy(&bmf);
1149 return pix2;
1150 }
1151
1152
1153 void
1154 l_chooseDisplayProg(l_int32 selection)
1155 {
1156 if (selection == L_DISPLAY_WITH_XLI ||
1157 selection == L_DISPLAY_WITH_XZGV ||
1158 selection == L_DISPLAY_WITH_XV ||
1159 selection == L_DISPLAY_WITH_IV ||
1160 selection == L_DISPLAY_WITH_OPEN) {
1161 var_DISPLAY_PROG = selection;
1162 } else {
1163 L_ERROR("invalid display program\n", "l_chooseDisplayProg");
1164 }
1165 }
1166
1167
1168 /*---------------------------------------------------------------------*
1169 * Change format for missing lib *
1170 *---------------------------------------------------------------------*/
1171 /*!
1172 * \brief changeFormatForMissingLib()
1173 *
1174 * \param[in,out] pformat addr of requested output image format
1175 * \return void
1176 *
1177 * <pre>
1178 * Notes:
1179 * (1) This is useful for testing functionality when the library for
1180 * the requested output format (jpeg, png or tiff) is not linked.
1181 * In that case, the output format is changed to bmp.
1182 * </pre>
1183 */
1184 void
1185 changeFormatForMissingLib(l_int32 *pformat)
1186 {
1187 #if !defined(HAVE_LIBJPEG)
1188 if (*pformat == IFF_JFIF_JPEG) {
1189 L_WARNING("jpeg library missing; output bmp format\n", __func__);
1190 *pformat = IFF_BMP;
1191 }
1192 #endif /* !defined(HAVE_LIBJPEG) */
1193 #if !defined(HAVE_LIBPNG)
1194 if (*pformat == IFF_PNG) {
1195 L_WARNING("png library missing; output bmp format\n", __func__);
1196 *pformat = IFF_BMP;
1197 }
1198 #endif /* !defined(HAVE_LIBPNG) */
1199 #if !defined(HAVE_LIBTIFF)
1200 if (L_FORMAT_IS_TIFF(*pformat)) {
1201 L_WARNING("tiff library missing; output bmp format\n", __func__);
1202 *pformat = IFF_BMP;
1203 }
1204 #endif /* !defined(HAVE_LIBTIFF) */
1205 }
1206
1207
1208 /*---------------------------------------------------------------------*
1209 * Deprecated pix output for debugging *
1210 *---------------------------------------------------------------------*/
1211 /*!
1212 * \brief pixDisplayWrite()
1213 *
1214 * \param[in] pix
1215 * \param[in] reduction
1216 * \return 1 (error)
1217 *
1218 * <pre>
1219 * Notes:
1220 * As of 1.80, this is a non-functional stub.
1221 * </pre>
1222 */
1223 l_ok
1224 pixDisplayWrite(PIX *pixs,
1225 l_int32 reduction)
1226 {
1227 lept_stderr("\n########################################################\n"
1228 " pixDisplayWrite() was last used in tesseract 3.04,"
1229 " in Feb 2016. As of 1.80, it is a non-functional stub\n"
1230 "########################################################"
1231 "\n\n\n");
1232 return 1;
1233 }