/*====================================================================* - Copyright (C) 2001-2016 Leptonica. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *====================================================================*/ /* * writefile.c * * Set jpeg quality for pixWrite() and pixWriteMem() * l_int32 l_jpegSetQuality() * * Set global variable LeptDebugOK for writing to named temp files * l_int32 setLeptDebugOK() * * High-level procedures for writing images to file: * l_int32 pixaWriteFiles() * l_int32 pixWriteDebug() * l_int32 pixWrite() * l_int32 pixWriteAutoFormat() * l_int32 pixWriteStream() * l_int32 pixWriteImpliedFormat() * * Selection of output format if default is requested * l_int32 pixChooseOutputFormat() * l_int32 getImpliedFileFormat() * l_int32 pixGetAutoFormat() * const char *getFormatExtension() * * Write to memory * l_int32 pixWriteMem() * * Image display for debugging * l_int32 l_fileDisplay() * l_int32 pixDisplay() * l_int32 pixDisplayWithTitle() * PIX *pixMakeColorSquare() * void l_chooseDisplayProg() * * Change format for missing library * void changeFormatForMissingLib() * * Nonfunctional stub of pix output for debugging * l_int32 pixDisplayWrite() * * Supported file formats: * (1) Writing is supported without any external libraries: * bmp * pnm (including pbm, pgm, etc) * spix (raw serialized) * (2) Writing is supported with installation of external libraries: * png * jpg (standard jfif version) * tiff (including most varieties of compression) * gif * webp * jp2 (jpeg2000) * (3) Writing is supported through special interfaces: * ps (PostScript, in psio1.c, psio2.c): * level 1 (uncompressed) * level 2 (g4 and dct encoding: requires tiff, jpg) * level 3 (g4, dct and flate encoding: requires tiff, jpg, zlib) * pdf (PDF, in pdfio.c): * level 1 (g4 and dct encoding: requires tiff, jpg) * level 2 (g4, dct and flate encoding: requires tiff, jpg, zlib) */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include "allheaders.h" /* Display program (xv, xli, xzgv, open) to be invoked by pixDisplay() */ #ifdef _WIN32 static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_IV; /* default */ #elif defined(__APPLE__) static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_OPEN; /* default */ #else static l_int32 var_DISPLAY_PROG = L_DISPLAY_WITH_XZGV; /* default */ #endif /* _WIN32 */ #define Bufsize 512 static const l_int32 MaxDisplayWidth = 1000; static const l_int32 MaxDisplayHeight = 800; static const l_int32 MaxSizeForPng = 200; /* PostScript output for printing */ static const l_float32 DefaultScaling = 1.0; /* Global array of image file format extension names. */ /* This is in 1-1 corrspondence with format enum in imageio.h. */ /* The empty string at the end represents the serialized format, */ /* which has no recognizable extension name, but the array must */ /* be padded to agree with the format enum. */ /* (Note on 'const': The size of the array can't be defined 'const' */ /* because that makes it static. The 'const' in the definition of */ /* the array refers to the strings in the array; the ptr to the */ /* array is not const and can be used 'extern' in other files.) */ LEPT_DLL l_int32 NumImageFileFormatExtensions = 20; /* array size */ LEPT_DLL const char *ImageFileFormatExtensions[] = {"unknown", "bmp", "jpg", "png", "tif", "tif", "tif", "tif", "tif", "tif", "tif", "pnm", "ps", "gif", "jp2", "webp", "pdf", "tif", "default", ""}; /* Local map of image file name extension to output format */ struct ExtensionMap { char extension[8]; l_int32 format; }; static const struct ExtensionMap extension_map[] = { { ".bmp", IFF_BMP }, { ".jpg", IFF_JFIF_JPEG }, { ".jpeg", IFF_JFIF_JPEG }, { ".png", IFF_PNG }, { ".tif", IFF_TIFF }, { ".tiff", IFF_TIFF }, { ".pnm", IFF_PNM }, { ".gif", IFF_GIF }, { ".jp2", IFF_JP2 }, { ".ps", IFF_PS }, { ".pdf", IFF_LPDF }, { ".webp", IFF_WEBP } }; /*---------------------------------------------------------------------* * Set jpeg quality for pixWrite() and pixWriteMem() * *---------------------------------------------------------------------*/ /* Parameter that controls jpeg quality for high-level calls. */ static l_int32 var_JPEG_QUALITY = 75; /* default */ /*! * \brief l_jpegSetQuality() * * \param[in] new_quality 1 - 100; 75 is default; 0 defaults to 75 * \return prev previous quality * *
 * Notes:
 *      (1) This variable is used in pixWriteStream() and pixWriteMem(),
 *          to control the jpeg quality.  The default is 75.
 *      (2) It returns the previous quality, so for example:
 *           l_int32  prev = l_jpegSetQuality(85);  //sets to 85
 *           pixWriteStream(...);
 *           l_jpegSetQuality(prev);   // resets to previous value
 *      (3) On error, logs a message and does not change the variable.
 */
l_int32
l_jpegSetQuality(l_int32  new_quality)
{
l_int32  prevq, newq;

    PROCNAME("l_jpeqSetQuality");

    prevq = var_JPEG_QUALITY;
    newq = (new_quality == 0) ? 75 : new_quality;
    if (newq < 1 || newq > 100)
        L_ERROR("invalid jpeg quality; unchanged\n", procName);
    else
        var_JPEG_QUALITY = newq;
    return prevq;
}


/*----------------------------------------------------------------------*
 *    Set global variable LeptDebugOK for writing to named temp files   *
 *----------------------------------------------------------------------*/
LEPT_DLL l_int32 LeptDebugOK = 0;  /* default value */
/*!
 * \brief   setLeptDebugOK()
 *
 * \param[in]    allow     TRUE (1) or FALSE (0)
 * \return       void
 *
 * 
 * Notes:
 *      (1) This sets or clears the global variable LeptDebugOK, to
 *          control writing files in a temp directory with names that
 *          are compiled in.
 *      (2) The default in the library distribution is 0.  Call with
 *          %allow = 1 for development and debugging.
 */
void
setLeptDebugOK(l_int32  allow)
{
    if (allow != 0) allow = 1;
    LeptDebugOK = allow;
}


/*---------------------------------------------------------------------*
 *           Top-level procedures for writing images to file           *
 *---------------------------------------------------------------------*/
/*!
 * \brief   pixaWriteFiles()
 *
 * \param[in]    rootname
 * \param[in]    pixa
 * \param[in]    format  defined in imageio.h; see notes for default
 * \return  0 if OK; 1 on error
 *
 * 
 * Notes:
 *      (1) Use %format = IFF_DEFAULT to decide the output format
 *          individually for each pix.
 * 
*/ l_ok pixaWriteFiles(const char *rootname, PIXA *pixa, l_int32 format) { char bigbuf[Bufsize]; l_int32 i, n, pixformat; PIX *pix; PROCNAME("pixaWriteFiles"); if (!rootname) return ERROR_INT("rootname not defined", procName, 1); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); if (format < 0 || format == IFF_UNKNOWN || format >= NumImageFileFormatExtensions) return ERROR_INT("invalid format", procName, 1); n = pixaGetCount(pixa); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa, i, L_CLONE); if (format == IFF_DEFAULT) pixformat = pixChooseOutputFormat(pix); else pixformat = format; snprintf(bigbuf, Bufsize, "%s%03d.%s", rootname, i, ImageFileFormatExtensions[pixformat]); pixWrite(bigbuf, pix, pixformat); pixDestroy(&pix); } return 0; } /*! * \brief pixWriteDebug() * * \param[in] fname * \param[in] pix * \param[in] format defined in imageio.h * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) Debug version, intended for use in the library when writing
 *          to files in a temp directory with names that are compiled in.
 *          This is used instead of pixWrite() for all such library calls.
 *      (2) The global variable LeptDebugOK defaults to 0, and can be set
 *          or cleared by the function setLeptDebugOK().
 * 
*/ l_ok pixWriteDebug(const char *fname, PIX *pix, l_int32 format) { PROCNAME("pixWriteDebug"); if (LeptDebugOK) { return pixWrite(fname, pix, format); } else { L_INFO("write to named temp file %s is disabled\n", procName, fname); return 0; } } /*! * \brief pixWrite() * * \param[in] fname * \param[in] pix * \param[in] format defined in imageio.h * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) Open for write using binary mode (with the "b" flag)
 *          to avoid having Windows automatically translate the NL
 *          into CRLF, which corrupts image files.  On non-windows
 *          systems this flag should be ignored, per ISO C90.
 *          Thanks to Dave Bryan for pointing this out.
 *      (2) If the default image format IFF_DEFAULT is requested:
 *          use the input format if known; otherwise, use a lossless format.
 *      (3) The default jpeg quality is 75.  For some other value,
 *          Use l_jpegSetQuality().
 * 
*/ l_ok pixWrite(const char *fname, PIX *pix, l_int32 format) { l_int32 ret; FILE *fp; PROCNAME("pixWrite"); if (!pix) return ERROR_INT("pix not defined", procName, 1); if (!fname) return ERROR_INT("fname not defined", procName, 1); if ((fp = fopenWriteStream(fname, "wb+")) == NULL) return ERROR_INT("stream not opened", procName, 1); ret = pixWriteStream(fp, pix, format); fclose(fp); if (ret) return ERROR_INT("pix not written to stream", procName, 1); return 0; } /*! * \brief pixWriteAutoFormat() * * \param[in] filename * \param[in] pix * \return 0 if OK; 1 on error */ l_ok pixWriteAutoFormat(const char *filename, PIX *pix) { l_int32 format; PROCNAME("pixWriteAutoFormat"); if (!pix) return ERROR_INT("pix not defined", procName, 1); if (!filename) return ERROR_INT("filename not defined", procName, 1); if (pixGetAutoFormat(pix, &format)) return ERROR_INT("auto format not returned", procName, 1); return pixWrite(filename, pix, format); } /*! * \brief pixWriteStream() * * \param[in] fp file stream * \param[in] pix * \param[in] format * \return 0 if OK; 1 on error. */ l_ok pixWriteStream(FILE *fp, PIX *pix, l_int32 format) { PROCNAME("pixWriteStream"); if (!fp) return ERROR_INT("stream not defined", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); if (format == IFF_DEFAULT) format = pixChooseOutputFormat(pix); /* Use bmp format for testing if library for requested * format for jpeg, png or tiff is not available */ changeFormatForMissingLib(&format); switch(format) { case IFF_BMP: pixWriteStreamBmp(fp, pix); break; case IFF_JFIF_JPEG: /* default quality; baseline sequential */ return pixWriteStreamJpeg(fp, pix, var_JPEG_QUALITY, 0); case IFF_PNG: /* no gamma value stored */ return pixWriteStreamPng(fp, pix, 0.0); case IFF_TIFF: /* uncompressed */ case IFF_TIFF_PACKBITS: /* compressed, binary only */ case IFF_TIFF_RLE: /* compressed, binary only */ case IFF_TIFF_G3: /* compressed, binary only */ case IFF_TIFF_G4: /* compressed, binary only */ case IFF_TIFF_LZW: /* compressed, all depths */ case IFF_TIFF_ZIP: /* compressed, all depths */ case IFF_TIFF_JPEG: /* compressed, 8 bpp gray and 32 bpp rgb */ return pixWriteStreamTiff(fp, pix, format); case IFF_PNM: return pixWriteStreamPnm(fp, pix); case IFF_PS: return pixWriteStreamPS(fp, pix, NULL, 0, DefaultScaling); case IFF_GIF: return pixWriteStreamGif(fp, pix); case IFF_JP2: return pixWriteStreamJp2k(fp, pix, 34, 4, 0, 0); case IFF_WEBP: return pixWriteStreamWebP(fp, pix, 80, 0); case IFF_LPDF: return pixWriteStreamPdf(fp, pix, 0, NULL); case IFF_SPIX: return pixWriteStreamSpix(fp, pix); default: return ERROR_INT("unknown format", procName, 1); } return 0; } /*! * \brief pixWriteImpliedFormat() * * \param[in] filename * \param[in] pix * \param[in] quality iff JPEG; 1 - 100, 0 for default * \param[in] progressive iff JPEG; 0 for baseline seq., 1 for progressive * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) This determines the output format from the filename extension.
 *      (2) The last two args are ignored except for requests for jpeg files.
 *      (3) The jpeg default quality is 75.
 * 
*/ l_ok pixWriteImpliedFormat(const char *filename, PIX *pix, l_int32 quality, l_int32 progressive) { l_int32 format; PROCNAME("pixWriteImpliedFormat"); if (!filename) return ERROR_INT("filename not defined", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); /* Determine output format */ format = getImpliedFileFormat(filename); if (format == IFF_UNKNOWN) { format = IFF_PNG; } else if (format == IFF_TIFF) { if (pixGetDepth(pix) == 1) format = IFF_TIFF_G4; else #ifdef _WIN32 format = IFF_TIFF_LZW; /* poor compression */ #else format = IFF_TIFF_ZIP; /* native windows tools can't handle this */ #endif /* _WIN32 */ } if (format == IFF_JFIF_JPEG) { quality = L_MIN(quality, 100); quality = L_MAX(quality, 0); if (progressive != 0 && progressive != 1) { progressive = 0; L_WARNING("invalid progressive; setting to baseline\n", procName); } if (quality == 0) quality = 75; pixWriteJpeg (filename, pix, quality, progressive); } else { pixWrite(filename, pix, format); } return 0; } /*---------------------------------------------------------------------* * Selection of output format if default is requested * *---------------------------------------------------------------------*/ /*! * \brief pixChooseOutputFormat() * * \param[in] pix * \return output format, or 0 on error * *
 * Notes:
 *      (1) This should only be called if the requested format is IFF_DEFAULT.
 *      (2) If the pix wasn't read from a file, its input format value
 *          will be IFF_UNKNOWN, and in that case it is written out
 *          in a compressed but lossless format.
 * 
*/ l_int32 pixChooseOutputFormat(PIX *pix) { l_int32 d, format; PROCNAME("pixChooseOutputFormat"); if (!pix) return ERROR_INT("pix not defined", procName, 0); d = pixGetDepth(pix); format = pixGetInputFormat(pix); if (format == IFF_UNKNOWN) { /* output lossless */ if (d == 1) format = IFF_TIFF_G4; else format = IFF_PNG; } return format; } /*! * \brief getImpliedFileFormat() * * \param[in] filename * \return output format, or IFF_UNKNOWN on error or invalid extension. * *
 * Notes:
 *      (1) This determines the output file format from the extension
 *          of the input filename.
 * 
*/ l_int32 getImpliedFileFormat(const char *filename) { char *extension; int i, numext; l_int32 format = IFF_UNKNOWN; if (splitPathAtExtension (filename, NULL, &extension)) return IFF_UNKNOWN; numext = sizeof(extension_map) / sizeof(extension_map[0]); for (i = 0; i < numext; i++) { if (!strcmp(extension, extension_map[i].extension)) { format = extension_map[i].format; break; } } LEPT_FREE(extension); return format; } /*! * \brief pixGetAutoFormat() * * \param[in] pix * \param[in] &format * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) The output formats are restricted to tiff, jpeg and png
 *          because these are the most commonly used image formats and
 *          the ones that are typically installed with leptonica.
 *      (2) This decides what compression to use based on the pix.
 *          It chooses tiff-g4 if 1 bpp without a colormap, jpeg with
 *          quality 75 if grayscale, rgb or rgba (where it loses
 *          the alpha layer), and lossless png for all other situations.
 * 
*/ l_ok pixGetAutoFormat(PIX *pix, l_int32 *pformat) { l_int32 d; PIXCMAP *cmap; PROCNAME("pixGetAutoFormat"); if (!pformat) return ERROR_INT("&format not defined", procName, 0); *pformat = IFF_UNKNOWN; if (!pix) return ERROR_INT("pix not defined", procName, 0); d = pixGetDepth(pix); cmap = pixGetColormap(pix); if (d == 1 && !cmap) { *pformat = IFF_TIFF_G4; } else if ((d == 8 && !cmap) || d == 24 || d == 32) { *pformat = IFF_JFIF_JPEG; } else { *pformat = IFF_PNG; } return 0; } /*! * \brief getFormatExtension() * * \param[in] format integer * \return extension string, or NULL if format is out of range * *
 * Notes:
 *      (1) This string is NOT owned by the caller; it is just a pointer
 *          to a global string.  Do not free it.
 * 
*/ const char * getFormatExtension(l_int32 format) { PROCNAME("getFormatExtension"); if (format < 0 || format >= NumImageFileFormatExtensions) return (const char *)ERROR_PTR("invalid format", procName, NULL); return ImageFileFormatExtensions[format]; } /*---------------------------------------------------------------------* * Write to memory * *---------------------------------------------------------------------*/ /*! * \brief pixWriteMem() * * \param[out] pdata data of tiff compressed image * \param[out] psize size of returned data * \param[in] pix * \param[in] format defined in imageio.h * \return 0 if OK, 1 on error * *
 * Notes:
 *      (1) On windows, this will only write tiff and PostScript to memory.
 *          For other formats, it requires open_memstream(3).
 *      (2) PostScript output is uncompressed, in hex ascii.
 *          Most printers support level 2 compression (tiff_g4 for 1 bpp,
 *          jpeg for 8 and 32 bpp).
 *      (3) The default jpeg quality is 75.  For some other value,
 *          Use l_jpegSetQuality().
 * 
*/ l_ok pixWriteMem(l_uint8 **pdata, size_t *psize, PIX *pix, l_int32 format) { l_int32 ret; PROCNAME("pixWriteMem"); if (!pdata) return ERROR_INT("&data not defined", procName, 1 ); if (!psize) return ERROR_INT("&size not defined", procName, 1 ); if (!pix) return ERROR_INT("&pix not defined", procName, 1 ); if (format == IFF_DEFAULT) format = pixChooseOutputFormat(pix); /* Use bmp format for testing if library for requested * format for jpeg, png or tiff is not available */ changeFormatForMissingLib(&format); switch(format) { case IFF_BMP: ret = pixWriteMemBmp(pdata, psize, pix); break; case IFF_JFIF_JPEG: /* default quality; baseline sequential */ ret = pixWriteMemJpeg(pdata, psize, pix, var_JPEG_QUALITY, 0); break; case IFF_PNG: /* no gamma value stored */ ret = pixWriteMemPng(pdata, psize, pix, 0.0); break; case IFF_TIFF: /* uncompressed */ case IFF_TIFF_PACKBITS: /* compressed, binary only */ case IFF_TIFF_RLE: /* compressed, binary only */ case IFF_TIFF_G3: /* compressed, binary only */ case IFF_TIFF_G4: /* compressed, binary only */ case IFF_TIFF_LZW: /* compressed, all depths */ case IFF_TIFF_ZIP: /* compressed, all depths */ case IFF_TIFF_JPEG: /* compressed, 8 bpp gray or 32 bpp rgb */ ret = pixWriteMemTiff(pdata, psize, pix, format); break; case IFF_PNM: ret = pixWriteMemPnm(pdata, psize, pix); break; case IFF_PS: ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DefaultScaling); break; case IFF_GIF: ret = pixWriteMemGif(pdata, psize, pix); break; case IFF_JP2: ret = pixWriteMemJp2k(pdata, psize, pix, 34, 0, 0, 0); break; case IFF_WEBP: ret = pixWriteMemWebP(pdata, psize, pix, 80, 0); break; case IFF_LPDF: ret = pixWriteMemPdf(pdata, psize, pix, 0, NULL); break; case IFF_SPIX: ret = pixWriteMemSpix(pdata, psize, pix); break; default: return ERROR_INT("unknown format", procName, 1); } return ret; } /*---------------------------------------------------------------------* * Image display for debugging * *---------------------------------------------------------------------*/ /*! * \brief l_fileDisplay() * * \param[in] fname * \param[in] x, y location of display frame on the screen * \param[in] scale scale factor (use 0 to skip display) * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) This is a convenient wrapper for displaying image files.
 *      (2) It does nothing unless LeptDebugOK == TRUE.
 *      (2) Set %scale = 0 to disable display.
 *      (3) This downscales 1 bpp to gray.
 * 
*/ l_ok l_fileDisplay(const char *fname, l_int32 x, l_int32 y, l_float32 scale) { PIX *pixs, *pixd; PROCNAME("l_fileDisplay"); if (!LeptDebugOK) { L_INFO("displaying files is disabled; " "use setLeptDebugOK(1) to enable\n", procName); return 0; } if (scale == 0.0) return 0; if (scale < 0.0) return ERROR_INT("invalid scale factor", procName, 1); if ((pixs = pixRead(fname)) == NULL) return ERROR_INT("pixs not read", procName, 1); if (scale == 1.0) { pixd = pixClone(pixs); } else { if (scale < 1.0 && pixGetDepth(pixs) == 1) pixd = pixScaleToGray(pixs, scale); else pixd = pixScale(pixs, scale, scale); } pixDisplay(pixd, x, y); pixDestroy(&pixs); pixDestroy(&pixd); return 0; } /*! * \brief pixDisplay() * * \param[in] pix 1, 2, 4, 8, 16, 32 bpp * \param[in] x, y location of display frame on the screen * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) This is debugging code that displays an image on the screen.
 *          It uses a static internal variable to number the output files
 *          written by a single process.  Behavior with a shared library
 *          may be unpredictable.
 *      (2) It does nothing unless LeptDebugOK == TRUE.
 *      (3) It uses these programs to display the image:
 *             On Unix: xzgv, xli or xv
 *             On Windows: i_view
 *          The display program must be on your $PATH variable.  It is
 *          chosen by setting the global var_DISPLAY_PROG, using
 *          l_chooseDisplayProg().  Default on Unix is xzgv.
 *      (4) Images with dimensions larger than MaxDisplayWidth or
 *          MaxDisplayHeight are downscaled to fit those constraints.
 *          This is particularly important for displaying 1 bpp images
 *          with xv, because xv automatically downscales large images
 *          by subsampling, which looks poor.  For 1 bpp, we use
 *          scale-to-gray to get decent-looking anti-aliased images.
 *          In all cases, we write a temporary file to /tmp/lept/disp,
 *          that is read by the display program.
 *      (5) The temporary file is written as png if, after initial
 *          processing for special cases, any of these obtain:
 *            * pix dimensions are smaller than some thresholds
 *            * pix depth is less than 8 bpp
 *            * pix is colormapped
 *      (6) For spp == 4, we call pixDisplayLayersRGBA() to show 3
 *          versions of the image: the image with a fully opaque
 *          alpha, the alpha, and the image as it would appear with
 *          a white background.
 * 
*/ l_ok pixDisplay(PIX *pixs, l_int32 x, l_int32 y) { return pixDisplayWithTitle(pixs, x, y, NULL, 1); } /*! * \brief pixDisplayWithTitle() * * \param[in] pix 1, 2, 4, 8, 16, 32 bpp * \param[in] x, y location of display frame * \param[in] title [optional] on frame; can be NULL; * \param[in] dispflag 1 to write, else disabled * \return 0 if OK; 1 on error * *
 * Notes:
 *      (1) See notes for pixDisplay().
 *      (2) This displays the image if dispflag == 1; otherwise it punts.
 * 
*/ l_ok pixDisplayWithTitle(PIX *pixs, l_int32 x, l_int32 y, const char *title, l_int32 dispflag) { char *tempname; char buffer[Bufsize]; static l_int32 index = 0; /* caution: not .so or thread safe */ l_int32 w, h, d, spp, maxheight, opaque, threeviews; l_float32 ratw, rath, ratmin; PIX *pix0, *pix1, *pix2; PIXCMAP *cmap; #ifndef _WIN32 l_int32 wt, ht; #else char *pathname; char fullpath[_MAX_PATH]; #endif /* _WIN32 */ PROCNAME("pixDisplayWithTitle"); if (!LeptDebugOK) { L_INFO("displaying images is disabled;\n " "use setLeptDebugOK(1) to enable\n", procName); return 0; } #ifdef OS_IOS /* iOS 11 does not support system() */ return ERROR_INT("iOS 11 does not support system()", procName, 1); #endif /* OS_IOS */ if (dispflag != 1) return 0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV && var_DISPLAY_PROG != L_DISPLAY_WITH_XLI && var_DISPLAY_PROG != L_DISPLAY_WITH_XV && var_DISPLAY_PROG != L_DISPLAY_WITH_IV && var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) { return ERROR_INT("no program chosen for display", procName, 1); } /* Display with three views if either spp = 4 or if colormapped * and the alpha component is not fully opaque */ opaque = TRUE; if ((cmap = pixGetColormap(pixs)) != NULL) pixcmapIsOpaque(cmap, &opaque); spp = pixGetSpp(pixs); threeviews = (spp == 4 || !opaque) ? TRUE : FALSE; /* If colormapped and not opaque, remove the colormap to RGBA */ if (!opaque) pix0 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA); else pix0 = pixClone(pixs); /* Scale if necessary; this will also remove a colormap */ pixGetDimensions(pix0, &w, &h, &d); maxheight = (threeviews) ? MaxDisplayHeight / 3 : MaxDisplayHeight; if (w <= MaxDisplayWidth && h <= maxheight) { if (d == 16) /* take MSB */ pix1 = pixConvert16To8(pix0, L_MS_BYTE); else pix1 = pixClone(pix0); } else { ratw = (l_float32)MaxDisplayWidth / (l_float32)w; rath = (l_float32)maxheight / (l_float32)h; ratmin = L_MIN(ratw, rath); if (ratmin < 0.125 && d == 1) pix1 = pixScaleToGray8(pix0); else if (ratmin < 0.25 && d == 1) pix1 = pixScaleToGray4(pix0); else if (ratmin < 0.33 && d == 1) pix1 = pixScaleToGray3(pix0); else if (ratmin < 0.5 && d == 1) pix1 = pixScaleToGray2(pix0); else pix1 = pixScale(pix0, ratmin, ratmin); } pixDestroy(&pix0); if (!pix1) return ERROR_INT("pix1 not made", procName, 1); /* Generate the three views if required */ if (threeviews) pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0); else pix2 = pixClone(pix1); if (index == 0) { /* erase any existing images */ lept_rmdir("lept/disp"); lept_mkdir("lept/disp"); } index++; if (pixGetDepth(pix2) < 8 || pixGetColormap(pix2) || (w < MaxSizeForPng && h < MaxSizeForPng)) { snprintf(buffer, Bufsize, "/tmp/lept/disp/write.%03d.png", index); pixWrite(buffer, pix2, IFF_PNG); } else { snprintf(buffer, Bufsize, "/tmp/lept/disp/write.%03d.jpg", index); pixWrite(buffer, pix2, IFF_JFIF_JPEG); } tempname = genPathname(buffer, NULL); #ifndef _WIN32 /* Unix */ if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) { /* no way to display title */ pixGetDimensions(pix2, &wt, &ht, NULL); snprintf(buffer, Bufsize, "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10, x, y, tempname); } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) { if (title) { snprintf(buffer, Bufsize, "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &", x, y, title, tempname); } else { snprintf(buffer, Bufsize, "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &", x, y, tempname); } } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) { if (title) { snprintf(buffer, Bufsize, "xv -quit -geometry +%d+%d -name \"%s\" %s &", x, y, title, tempname); } else { snprintf(buffer, Bufsize, "xv -quit -geometry +%d+%d %s &", x, y, tempname); } } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_OPEN) { snprintf(buffer, Bufsize, "open %s &", tempname); } callSystemDebug(buffer); #else /* _WIN32 */ /* Windows: L_DISPLAY_WITH_IV */ pathname = genPathname(tempname, NULL); _fullpath(fullpath, pathname, sizeof(fullpath)); if (title) { snprintf(buffer, Bufsize, "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"", fullpath, x, y, title); } else { snprintf(buffer, Bufsize, "i_view32.exe \"%s\" /pos=(%d,%d)", fullpath, x, y); } callSystemDebug(buffer); LEPT_FREE(pathname); #endif /* _WIN32 */ pixDestroy(&pix1); pixDestroy(&pix2); LEPT_FREE(tempname); return 0; } /*! * \brief pixMakeColorSquare() * * \param[in] color in 0xrrggbb00 format * \param[in] size in pixels; >= 100; use 0 for default (min size) * \param[in] addlabel use 1 to display the color component values * \param[in] location of text: L_ADD_ABOVE, etc; ignored if %addlabel == 0 * \param[in] textcolor of text label; in 0xrrggbb00 format * \return 32 bpp rgb pixd if OK; NULL on error * *
 * Notes:
 *      (1) If %addlabel == 0, %location and %textcolor are ignored.
 *      (2) To make an array of color squares, use pixDisplayColorArray().
 * 
*/ PIX * pixMakeColorSquare(l_uint32 color, l_int32 size, l_int32 addlabel, l_int32 location, l_uint32 textcolor) { char buf[32]; l_int32 w, rval, gval, bval; L_BMF *bmf; PIX *pix1, *pix2; PROCNAME("pixMakeColorSquare"); w = (size <= 0) ? 100 : size; if (addlabel && w < 100) { L_WARNING("size too small for label; omitting label\n", procName); addlabel = 0; } if ((pix1 = pixCreate(w, w, 32)) == NULL) return (PIX *)ERROR_PTR("pix1 not madel", procName, NULL); pixSetAllArbitrary(pix1, color); if (!addlabel) return pix1; /* Adding text of color component values */ if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP && location != L_ADD_AT_BOT && location != L_ADD_BELOW) { L_ERROR("invalid location: adding below\n", procName); location = L_ADD_BELOW; } bmf = bmfCreate(NULL, 4); extractRGBValues(color, &rval, &gval, &bval); snprintf(buf, sizeof(buf), "%d,%d,%d", rval, gval, bval); pix2 = pixAddSingleTextblock(pix1, bmf, buf, textcolor, location, NULL); pixDestroy(&pix1); bmfDestroy(&bmf); return pix2; } void l_chooseDisplayProg(l_int32 selection) { if (selection == L_DISPLAY_WITH_XLI || selection == L_DISPLAY_WITH_XZGV || selection == L_DISPLAY_WITH_XV || selection == L_DISPLAY_WITH_IV || selection == L_DISPLAY_WITH_OPEN) { var_DISPLAY_PROG = selection; } else { L_ERROR("invalid display program\n", "l_chooseDisplayProg"); } } /*---------------------------------------------------------------------* * Change format for missing lib * *---------------------------------------------------------------------*/ /*! * \brief changeFormatForMissingLib() * * \param[in,out] pformat addr of requested output image format * \return void * *
 * Notes:
 *      (1) This is useful for testing functionality when the library for
 *          the requested output format (jpeg, png or tiff) is not linked.
 *          In that case, the output format is changed to bmp.
 * 
*/ void changeFormatForMissingLib(l_int32 *pformat) { PROCNAME("changeFormatForMissingLib"); #if !defined(HAVE_LIBJPEG) if (*pformat == IFF_JFIF_JPEG) { L_WARNING("jpeg library missing; output bmp format\n", procName); *pformat = IFF_BMP; } #endif /* !defined(HAVE_LIBJPEG) */ #if !defined(HAVE_LIBPNG) if (*pformat == IFF_PNG) { L_WARNING("png library missing; output bmp format\n", procName); *pformat = IFF_BMP; } #endif /* !defined(HAVE_LIBPNG) */ #if !defined(HAVE_LIBTIFF) if (L_FORMAT_IS_TIFF(*pformat)) { L_WARNING("tiff library missing; output bmp format\n", procName); *pformat = IFF_BMP; } #endif /* !defined(HAVE_LIBTIFF) */ } /*---------------------------------------------------------------------* * Deprecated pix output for debugging * *---------------------------------------------------------------------*/ /*! * \brief pixDisplayWrite() * * \param[in] pix * \param[in] reduction * \return 1 (error) * *
 * Notes:
 *      As of 1.80, this is a non-functional stub.
 * 
*/ l_ok pixDisplayWrite(PIX *pixs, l_int32 reduction) { lept_stderr("\n########################################################\n" " pixDisplayWrite() was last used in tesseract 3.04," " in Feb 2016. As of 1.80, it is a non-functional stub\n" "########################################################" "\n\n\n"); return 1; }