Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
