Leptonica 1.68
C Image Processing Library

writefile.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  * writefile.c
00018  *
00019  *     High-level procedures for writing images to file:
00020  *        l_int32     pixaWriteFiles()
00021  *        l_int32     pixWrite()    [behavior depends on WRITE_AS_NAMED]
00022  *        l_int32     pixWriteStream()
00023  *        l_int32     pixWriteImpliedFormat()
00024  *        l_int32     pixWriteTempfile()
00025  *
00026  *     Selection of output format if default is requested
00027  *        l_int32     pixChooseOutputFormat()
00028  *        l_int32     getImpliedFileFormat()
00029  *        const char *getFormatExtension()
00030  *
00031  *     Write to memory
00032  *        l_int32     pixWriteMem()
00033  *
00034  *     Image display for debugging
00035  *        l_int32     pixDisplay()
00036  *        l_int32     pixDisplayWithTitle()
00037  *        l_int32     pixDisplayMultiple()
00038  *        l_int32     pixDisplayWrite()
00039  *        l_int32     pixDisplayWriteFormat()
00040  *        l_int32     pixSaveTiled()
00041  *        l_int32     pixSaveTiledOutline()
00042  *        l_int32     pixSaveTiledWithText()
00043  *        void        l_chooseDisplayProg()
00044  */
00045 
00046 #include <string.h>
00047 #include "allheaders.h"
00048 
00049     /*   Special flag for pixWrite().  The default for both unix and     */
00050     /*   windows is to use whatever filename is given, as opposed to     */
00051     /*   insuring the filename extension matches the image compression.  */
00052 #define  WRITE_AS_NAMED    1
00053 
00054     /* MS VC++ can't handle array initialization with static consts !   */
00055 #define L_BUF_SIZE   512
00056 
00057     /* Display program (xv, xli or xzgv) to be invoked by pixDisplay()  */
00058 #ifdef _WIN32
00059 static l_int32  var_DISPLAY_PROG = L_DISPLAY_WITH_IV;  /* default */
00060 #else
00061 static l_int32  var_DISPLAY_PROG = L_DISPLAY_WITH_XZGV;  /* default */
00062 #endif  /* _WIN32 */
00063 static const l_int32  MAX_DISPLAY_WIDTH = 1000;
00064 static const l_int32  MAX_DISPLAY_HEIGHT = 800;
00065 static const l_int32  MAX_SIZE_FOR_PNG = 200;
00066 
00067     /* PostScript output for printing */
00068 static const l_float32  DEFAULT_SCALING = 1.0;
00069 
00070     /* Global array of image file format extension names.                */
00071     /* This is in 1-1 corrspondence with format enum in imageio.h.       */
00072     /* The empty string at the end represents the serialized format,     */
00073     /* which has no recognizable extension name, but the array must      */
00074     /* be padded to agree with the format enum.                          */
00075     /* (Note on 'const': The size of the array can't be defined 'const'  */
00076     /* because that makes it static.  The 'const' in the definition of   */
00077     /* the array refers to the strings in the array; the ptr to the      */
00078     /* array is not const and can be used 'extern' in other files.)      */
00079 LEPT_DLL l_int32  NumImageFileFormatExtensions = 19;  /* array size */
00080 LEPT_DLL const char *ImageFileFormatExtensions[] =
00081          {"unknown",
00082           "bmp",
00083           "jpg",
00084           "png",
00085           "tif",
00086           "tif",
00087           "tif",
00088           "tif",
00089           "tif",
00090           "tif",
00091           "tif",
00092           "pnm",
00093           "ps",
00094           "gif",
00095           "jp2",
00096           "webp",
00097           "pdf",
00098           "default",
00099           ""};
00100 
00101     /* Local map of image file name extension to output format */
00102 struct ExtensionMap
00103 {
00104     char     extension[8];
00105     l_int32  format;
00106 };
00107 static const struct ExtensionMap extension_map[] =
00108                             { { ".bmp",  IFF_BMP       },
00109                               { ".jpg",  IFF_JFIF_JPEG },
00110                               { ".jpeg", IFF_JFIF_JPEG },
00111                               { ".png",  IFF_PNG       },
00112                               { ".tif",  IFF_TIFF      },
00113                               { ".tiff", IFF_TIFF      },
00114                               { ".pnm",  IFF_PNM       },
00115                               { ".gif",  IFF_GIF       },
00116                               { ".jp2",  IFF_JP2       },
00117                               { ".ps",   IFF_PS        },
00118                               { ".pdf",  IFF_LPDF      },
00119                               { ".webp", IFF_WEBP      } };
00120 
00121 
00122 /*---------------------------------------------------------------------*
00123  *           Top-level procedures for writing images to file           *
00124  *---------------------------------------------------------------------*/
00125 /*!
00126  *  pixaWriteFiles()
00127  *
00128  *      Input:  rootname
00129  *              pixa
00130  *              format  (defined in imageio.h)
00131  *      Return: 0 if OK; 1 on error
00132  */
00133 l_int32
00134 pixaWriteFiles(const char  *rootname,
00135                PIXA        *pixa,
00136                l_int32      format)
00137 {
00138 char     bigbuf[L_BUF_SIZE];
00139 l_int32  i, n;
00140 PIX     *pix;
00141 
00142     PROCNAME("pixaWriteFiles");
00143 
00144     if (!rootname)
00145         return ERROR_INT("rootname not defined", procName, 1);
00146     if (!pixa)
00147         return ERROR_INT("pixa not defined", procName, 1);
00148     if (format < 0 || format >= NumImageFileFormatExtensions)
00149         return ERROR_INT("invalid format", procName, 1);
00150 
00151     n = pixaGetCount(pixa);
00152     for (i = 0; i < n; i++) {
00153         snprintf(bigbuf, L_BUF_SIZE, "%s%03d.%s", rootname, i,
00154                  ImageFileFormatExtensions[format]);
00155         pix = pixaGetPix(pixa, i, L_CLONE);
00156         pixWrite(bigbuf, pix, format);
00157         pixDestroy(&pix);
00158     }
00159 
00160     return 0;
00161 }
00162 
00163 
00164 /*!
00165  *  pixWrite()
00166  *
00167  *      Input:  filename
00168  *              pix
00169  *              format  (defined in imageio.h)
00170  *      Return: 0 if OK; 1 on error
00171  *
00172  *  Notes:
00173  *      (1) Open for write using binary mode (with the "b" flag)
00174  *          to avoid having Windows automatically translate the NL
00175  *          into CRLF, which corrupts image files.  On non-windows
00176  *          systems this flag should be ignored, per ISO C90.
00177  *          Thanks to Dave Bryan for pointing this out.
00178  *      (2) If the default image format is requested, we use the input format;
00179  *          if the input format is unknown, a lossless format is assigned.
00180  *      (3) There are two modes with respect to file naming.
00181  *          (a) The default code writes to @filename.
00182  *          (b) If WRITE_AS_NAMED is defined to 0, it's a bit fancier.
00183  *              Then, if @filename does not have a file extension, one is
00184  *              automatically appended, depending on the requested format.
00185  *          The original intent for providing option (b) was to insure
00186  *          that filenames on Windows have an extension that matches
00187  *          the image compression.  However, this is not the default.
00188  */
00189 l_int32
00190 pixWrite(const char  *filename,
00191          PIX         *pix,
00192          l_int32      format)
00193 {
00194 char  *fname;
00195 FILE  *fp;
00196 
00197     PROCNAME("pixWrite");
00198 
00199     if (!pix)
00200         return ERROR_INT("pix not defined", procName, 1);
00201     if (!filename)
00202         return ERROR_INT("filename not defined", procName, 1);
00203     if (format == IFF_JP2)
00204         return ERROR_INT("jp2 not supported", procName, 1);
00205 
00206     fname = genPathname(filename, NULL);
00207 
00208 #if  WRITE_AS_NAMED  /* Default */
00209 
00210     if ((fp = fopen(fname, "wb+")) == NULL) {
00211         FREE(fname);
00212         return ERROR_INT("stream not opened", procName, 1);
00213     }
00214 
00215 #else  /* Add an extension to the output name if none exists */
00216 
00217     {l_int32  extlen;
00218      char    *extension, *filebuf;
00219         splitPathAtExtension(fname, NULL, &extension);
00220         extlen = strlen(extension);
00221         FREE(extension);
00222         if (extlen == 0) {
00223             if (format == IFF_DEFAULT || format == IFF_UNKNOWN)
00224                 format = pixChooseOutputFormat(pix);
00225 
00226             filebuf = (char *)CALLOC(strlen(fname) + 10, sizeof(char));
00227             if (!filebuf) {
00228                 return ERROR_INT("filebuf not made", procName, 1);
00229                 FREE(fname);
00230             }
00231             strncpy(filebuf, fname, strlen(fname));
00232             strcat(filebuf, ".");
00233             strcat(filebuf, ImageFileFormatExtensions[format]);
00234         }
00235         else
00236             filebuf = (char *)fname;
00237 
00238         fp = fopen(filebuf, "wb+");
00239         if (filebuf != fname)
00240             FREE(filebuf);
00241         if (fp == NULL) {
00242             FREE(fname);
00243             return ERROR_INT("stream not opened", procName, 1);
00244         }
00245     }
00246 
00247 #endif  /* WRITE_AS_NAMED */
00248 
00249     FREE(fname);
00250     if (pixWriteStream(fp, pix, format)) {
00251         fclose(fp);
00252         return ERROR_INT("pix not written to stream", procName, 1);
00253     }
00254 
00255         /* Close the stream except if GIF under windows, because
00256          * EGifCloseFile() closes the windows file stream! */
00257     if (format != IFF_GIF)
00258         fclose(fp);
00259 #ifndef _WIN32
00260     else  /* gif file */
00261         fclose(fp);
00262 #endif  /* ! _WIN32 */
00263 
00264     return 0;
00265 }
00266 
00267 
00268 /*!
00269  *  pixWriteStream()
00270  *
00271  *      Input:  stream
00272  *              pix
00273  *              format
00274  *      Return: 0 if OK; 1 on error.
00275  */
00276 l_int32
00277 pixWriteStream(FILE    *fp,
00278                PIX     *pix,
00279                l_int32  format)
00280 {
00281     PROCNAME("pixWriteStream");
00282 
00283     if (!fp)
00284         return ERROR_INT("stream not defined", procName, 1);
00285     if (!pix)
00286         return ERROR_INT("pix not defined", procName, 1);
00287 
00288     if (format == IFF_DEFAULT)
00289         format = pixChooseOutputFormat(pix);
00290 
00291     switch(format)
00292     {
00293     case IFF_BMP:
00294         pixWriteStreamBmp(fp, pix);
00295         break;
00296 
00297     case IFF_JFIF_JPEG:   /* default quality; baseline sequential */
00298         return pixWriteStreamJpeg(fp, pix, 75, 0);
00299         break;
00300 
00301     case IFF_PNG:   /* no gamma value stored */
00302         return pixWriteStreamPng(fp, pix, 0.0);
00303         break;
00304 
00305     case IFF_TIFF:           /* uncompressed */
00306     case IFF_TIFF_PACKBITS:  /* compressed, binary only */
00307     case IFF_TIFF_RLE:       /* compressed, binary only */
00308     case IFF_TIFF_G3:        /* compressed, binary only */
00309     case IFF_TIFF_G4:        /* compressed, binary only */
00310     case IFF_TIFF_LZW:       /* compressed, all depths */
00311     case IFF_TIFF_ZIP:       /* compressed, all depths */
00312         return pixWriteStreamTiff(fp, pix, format);
00313         break;
00314 
00315     case IFF_PNM:
00316         return pixWriteStreamPnm(fp, pix);
00317         break;
00318 
00319     case IFF_GIF:
00320         return pixWriteStreamGif(fp, pix);
00321         break;
00322 
00323     case IFF_PS:
00324         return pixWriteStreamPS(fp, pix, NULL, 0, DEFAULT_SCALING);
00325         break;
00326 
00327     case IFF_JP2:
00328         return ERROR_INT("jp2 format not supported", procName, 1);
00329         break;
00330 
00331     case IFF_WEBP:
00332         return pixWriteStreamWebP(fp, pix, 80);
00333         break;
00334 
00335     case IFF_LPDF:
00336         return pixWriteStreamPdf(fp, pix, 0, NULL);
00337         break;
00338 
00339     case IFF_SPIX:
00340         return pixWriteStreamSpix(fp, pix);
00341         break;
00342 
00343     default:
00344         return ERROR_INT("unknown format", procName, 1);
00345         break;
00346     }
00347 
00348     return 0;
00349 }
00350 
00351 
00352 /*!
00353  *  pixWriteImpliedFormat()
00354  *
00355  *      Input:  filename
00356  *              pix
00357  *              quality (iff JPEG; 1 - 100, 0 for default)
00358  *              progressive (iff JPEG; 0 for baseline seq., 1 for progressive)
00359  *      Return: 0 if OK; 1 on error
00360  *
00361  *  Notes:
00362  *      (1) This determines the output format from the filename extension.
00363  *      (2) The last two args are ignored except for requests for jpeg files.
00364  *      (3) The jpeg default quality is 75.
00365  */
00366 l_int32
00367 pixWriteImpliedFormat(const char  *filename,
00368                       PIX         *pix,
00369                       l_int32      quality,
00370                       l_int32      progressive)
00371 {
00372 l_int32  format;
00373 
00374     PROCNAME("pixWriteImpliedFormat");
00375 
00376     if (!filename)
00377         return ERROR_INT("filename not defined", procName, 1);
00378     if (!pix)
00379         return ERROR_INT("pix not defined", procName, 1);
00380 
00381         /* Determine output format */
00382     format = getImpliedFileFormat(filename);
00383     if (format == IFF_UNKNOWN)
00384         format = IFF_PNG;
00385     else if (format == IFF_TIFF) {
00386         if (pixGetDepth(pix) == 1)
00387             format = IFF_TIFF_G4;
00388         else
00389 #ifdef _WIN32
00390             format = IFF_TIFF_LZW;  /* poor compression */
00391 #else
00392             format = IFF_TIFF_ZIP;  /* native windows tools can't handle this */
00393 #endif  /* _WIN32 */
00394     }
00395 
00396     if (format == IFF_JFIF_JPEG) {
00397         quality = L_MIN(quality, 100);
00398         quality = L_MAX(quality, 0);
00399         if (progressive != 0 && progressive != 1) {
00400             progressive = 0;
00401             L_WARNING("invalid progressive; setting to baseline", procName);
00402         }
00403         if (quality == 0)
00404             quality = 75;
00405         pixWriteJpeg (filename, pix, quality, progressive);
00406     }
00407     else
00408         pixWrite(filename, pix, format);
00409 
00410     return 0;
00411 }
00412 
00413 
00414 /*!
00415  *  pixWriteTempfile()
00416  *
00417  *      Input:  dir (directory name; use '.' for local dir; no trailing '/')
00418  *              tail (<optional> tailname, including extension if any)
00419  *              pix
00420  *              format
00421  *              &filename (<optional> return actual filename used; use
00422  *                         null to skip)
00423  *      Return: 0 if OK; 1 on error
00424  *
00425  *  Notes:
00426  *      (1) This generates a temp filename, writes the pix to it,
00427  *          and optionally returns the temp filename.
00428  *      (2) If the filename is returned to a windows program from a DLL,
00429  *          use lept_free() to free it.
00430  *      (3) See genTempFilename() for details.  We omit the time and pid
00431  *          here.
00432  */
00433 l_int32
00434 pixWriteTempfile(const char  *dir,
00435                  const char  *tail,
00436                  PIX         *pix,
00437                  l_int32      format, 
00438                  char       **pfilename)
00439 {
00440 char    *filename;
00441 l_int32  ret;
00442 
00443     PROCNAME("pixWriteTempfile");
00444 
00445     if (!dir)
00446         return ERROR_INT("filename not defined", procName, 1);
00447     if (!pix)
00448         return ERROR_INT("pix not defined", procName, 1);
00449 
00450     if ((filename = genTempFilename(dir, tail, 0, 0)) == NULL)
00451         return ERROR_INT("temp filename not made", procName, 1);
00452 
00453     ret = pixWrite(filename, pix, format);
00454     if (pfilename)
00455         *pfilename = filename;
00456     else
00457         FREE(filename);
00458 
00459     return ret;
00460 }
00461 
00462 
00463 /*---------------------------------------------------------------------*
00464  *          Selection of output format if default is requested         *
00465  *---------------------------------------------------------------------*/
00466 /*!
00467  *  pixChooseOutputFormat()
00468  *
00469  *      Input:  pix
00470  *      Return: output format, or 0 on error
00471  *
00472  *  Notes:
00473  *      (1) This should only be called if the requested format is IFF_DEFAULT.
00474  *      (2) If the pix wasn't read from a file, its input format value
00475  *          will be IFF_UNKNOWN, and in that case it is written out
00476  *          in a compressed but lossless format.
00477  */
00478 l_int32
00479 pixChooseOutputFormat(PIX  *pix)
00480 {
00481 l_int32  d, format;
00482 
00483     PROCNAME("pixChooseOutputFormat");
00484 
00485     if (!pix)
00486         return ERROR_INT("pix not defined", procName, 0);
00487 
00488     d = pixGetDepth(pix);
00489     format = pixGetInputFormat(pix);
00490     if (format == IFF_UNKNOWN) {  /* output lossless */
00491         if (d == 1)
00492             format = IFF_TIFF_G4;
00493         else
00494             format = IFF_PNG;
00495     }
00496 
00497     return format;
00498 }
00499 
00500 
00501 /*!
00502  *  getImpliedFileFormat()
00503  *
00504  *      Input:  filename
00505  *      Return: output format, or IFF_UNKNOWN on error or invalid extension.
00506  *
00507  *  Notes:
00508  *      (1) This determines the output file format from the extension
00509  *          of the input filename.
00510  */
00511 l_int32
00512 getImpliedFileFormat(const char  *filename)
00513 {
00514 char    *extension;
00515 int      i, numext;
00516 l_int32  format = IFF_UNKNOWN;
00517 
00518     if (splitPathAtExtension (filename, NULL, &extension))
00519         return IFF_UNKNOWN;
00520 
00521     numext = sizeof(extension_map) / sizeof(extension_map[0]);
00522     for (i = 0; i < numext; i++) {
00523         if (!strcmp(extension, extension_map[i].extension)) {
00524             format = extension_map[i].format;
00525             break;
00526         }
00527     }
00528 
00529     FREE(extension);
00530     return format;
00531 }
00532 
00533 
00534 /*!
00535  *  getFormatExtension()
00536  *
00537  *      Input:  format (integer)
00538  *      Return: extension (string), or null if format is out of range
00539  *
00540  *  Notes:
00541  *      (1) This string is NOT owned by the caller; it is just a pointer
00542  *          to a global string.  Do not free it.
00543  */
00544 const char *
00545 getFormatExtension(l_int32  format)
00546 {
00547     PROCNAME("getFormatExtension");
00548 
00549     if (format < 0 || format >= NumImageFileFormatExtensions)
00550         return (const char *)ERROR_PTR("invalid format", procName, NULL);
00551 
00552     return ImageFileFormatExtensions[format];
00553 }
00554 
00555 
00556 /*---------------------------------------------------------------------*
00557  *                            Write to memory                          *
00558  *---------------------------------------------------------------------*/
00559 /*!
00560  *  pixWriteMem()
00561  *
00562  *      Input:  &data (<return> data of tiff compressed image)
00563  *              &size (<return> size of returned data)
00564  *              pix
00565  *              format  (defined in imageio.h)
00566  *      Return: 0 if OK, 1 on error
00567  *
00568  *  Notes:
00569  *      (1) On windows, this will only write tiff and PostScript to memory.
00570  *          For other formats, it requires open_memstream(3).
00571  *      (2) PostScript output is uncompressed, in hex ascii.
00572  *          Most printers support level 2 compression (tiff_g4 for 1 bpp,
00573  *          jpeg for 8 and 32 bpp).
00574  */
00575 l_int32
00576 pixWriteMem(l_uint8  **pdata,
00577             size_t    *psize,
00578             PIX       *pix,
00579             l_int32    format)
00580 {
00581 l_int32  ret;
00582 
00583     PROCNAME("pixWriteMem");
00584 
00585     if (!pdata)
00586         return ERROR_INT("&data not defined", procName, 1 );
00587     if (!psize)
00588         return ERROR_INT("&size not defined", procName, 1 );
00589     if (!pix)
00590         return ERROR_INT("&pix not defined", procName, 1 );
00591 
00592     if (format == IFF_DEFAULT)
00593         format = pixChooseOutputFormat(pix);
00594 
00595     switch(format)
00596     {
00597     case IFF_BMP:
00598         ret = pixWriteMemBmp(pdata, psize, pix);
00599         break;
00600 
00601     case IFF_JFIF_JPEG:   /* default quality; baseline sequential */
00602         ret = pixWriteMemJpeg(pdata, psize, pix, 75, 0);
00603         break;
00604 
00605     case IFF_PNG:   /* no gamma value stored */
00606         ret = pixWriteMemPng(pdata, psize, pix, 0.0);
00607         break;
00608 
00609     case IFF_TIFF:           /* uncompressed */
00610     case IFF_TIFF_PACKBITS:  /* compressed, binary only */
00611     case IFF_TIFF_RLE:       /* compressed, binary only */
00612     case IFF_TIFF_G3:        /* compressed, binary only */
00613     case IFF_TIFF_G4:        /* compressed, binary only */
00614     case IFF_TIFF_LZW:       /* compressed, all depths */
00615     case IFF_TIFF_ZIP:       /* compressed, all depths */
00616         ret = pixWriteMemTiff(pdata, psize, pix, format);
00617         break;
00618 
00619     case IFF_PNM:
00620         ret = pixWriteMemPnm(pdata, psize, pix);
00621         break;
00622 
00623     case IFF_PS:
00624         ret = pixWriteMemPS(pdata, psize, pix, NULL, 0, DEFAULT_SCALING);
00625         break;
00626 
00627     case IFF_GIF:
00628         ret = pixWriteMemGif(pdata, psize, pix);
00629         break;
00630 
00631     case IFF_JP2:
00632         return ERROR_INT("jp2 not supported", procName, 1);
00633         break;
00634 
00635     case IFF_SPIX:
00636         ret = pixWriteMemSpix(pdata, psize, pix);
00637         break;
00638 
00639     default:
00640         return ERROR_INT("unknown format", procName, 1);
00641         break;
00642     }
00643 
00644     return ret;
00645 }
00646 
00647 
00648 /*---------------------------------------------------------------------*
00649  *                       Image display for debugging                   *
00650  *---------------------------------------------------------------------*/
00651 /*!
00652  *  pixDisplay()
00653  *
00654  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
00655  *              x, y  (location of display frame on the screen)
00656  *      Return: 0 if OK; 1 on error
00657  *
00658  *  Notes:
00659  *      (1) This displays the image using xv, xli or xzgv on Unix,
00660  *          or i_view on Windows.  The display program must be on
00661  *          your $PATH variable.  It is chosen by setting the global
00662  *          var_DISPLAY_PROG, using l_chooseDisplayProg().
00663  *          Default on Unix is xv.
00664  *      (2) Images with dimensions larger than MAX_DISPLAY_WIDTH or
00665  *          MAX_DISPLAY_HEIGHT are downscaled to fit those constraints.
00666  *          This is particulary important for displaying 1 bpp images
00667  *          with xv, because xv automatically downscales large images
00668  *          by subsampling, which looks lousy.  For 1 bpp, we use
00669  *          scale-to-gray to get decent-looking anti-aliased images.
00670  *          In all cases, we write a temporary file to /tmp, that is
00671  *          read by the display program.
00672  *      (3) Note: this function uses a static internal variable to number
00673  *          output files written by a single process.  Behavior with a
00674  *          shared library may be unpredictable.
00675  */
00676 l_int32
00677 pixDisplay(PIX     *pixs,
00678            l_int32  x,
00679            l_int32  y)
00680 {
00681     return pixDisplayWithTitle(pixs, x, y, NULL, 1);
00682 }
00683 
00684 
00685 /*!
00686  *  pixDisplayWithTitle()
00687  *
00688  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
00689  *              x, y  (location of display frame)
00690  *              title (<optional> on frame; can be NULL);
00691  *              dispflag (1 to write, else disabled)
00692  *      Return: 0 if OK; 1 on error
00693  *
00694  *  Notes:
00695  *      (1) See notes for pixDisplay().
00696  *      (2) This displays the image if dispflag == 1.
00697  */
00698 l_int32
00699 pixDisplayWithTitle(PIX         *pixs,
00700                     l_int32      x,
00701                     l_int32      y,
00702                     const char  *title,
00703                     l_int32      dispflag)
00704 {
00705 char           *tempname;
00706 char            buffer[L_BUF_SIZE];
00707 static l_int32  index = 0;  /* caution: not .so or thread safe */
00708 l_int32         w, h, d, ignore;
00709 l_float32       ratw, rath, ratmin;
00710 PIX            *pixt;
00711 #ifndef _WIN32
00712 l_int32         wt, ht;
00713 #else
00714 char           *pathname;
00715 char            fullpath[_MAX_PATH];
00716 #endif  /* _WIN32 */
00717 
00718     PROCNAME("pixDisplayWithTitle");
00719 
00720     if (dispflag != 1) return 0;
00721     if (!pixs)
00722         return ERROR_INT("pixs not defined", procName, 1);
00723     if (var_DISPLAY_PROG != L_DISPLAY_WITH_XV &&
00724         var_DISPLAY_PROG != L_DISPLAY_WITH_XLI &&
00725         var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV &&
00726         var_DISPLAY_PROG != L_DISPLAY_WITH_IV)
00727         return ERROR_INT("no program chosen for display", procName, 1);
00728 
00729     pixGetDimensions(pixs, &w, &h, &d);
00730     if (w <= MAX_DISPLAY_WIDTH && h <= MAX_DISPLAY_HEIGHT) {
00731         if (d == 16)  /* take MSB */
00732             pixt = pixConvert16To8(pixs, 1);
00733         else
00734             pixt = pixClone(pixs);
00735     }
00736     else {
00737         ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w;
00738         rath = (l_float32)MAX_DISPLAY_HEIGHT / (l_float32)h;
00739         ratmin = L_MIN(ratw, rath);
00740         if (ratmin < 0.125 && d == 1)
00741             pixt = pixScaleToGray8(pixs);
00742         else if (ratmin < 0.25 && d == 1)
00743             pixt = pixScaleToGray4(pixs);
00744         else if (ratmin < 0.33 && d == 1)
00745             pixt = pixScaleToGray3(pixs);
00746         else if (ratmin < 0.5 && d == 1)
00747             pixt = pixScaleToGray2(pixs);
00748         else
00749             pixt = pixScale(pixs, ratmin, ratmin);
00750         if (!pixt)
00751             return ERROR_INT("pixt not made", procName, 1);
00752     }
00753 
00754     if (index == 0) {
00755         lept_rmdir("display");
00756         lept_mkdir("display");
00757     }
00758 
00759     index++;
00760     if (pixGetDepth(pixt) < 8 ||
00761         (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) {
00762         snprintf(buffer, L_BUF_SIZE, "/tmp/display/write.%03d.png", index);
00763         pixWrite(buffer, pixt, IFF_PNG);
00764     }
00765     else {
00766         snprintf(buffer, L_BUF_SIZE, "/tmp/display/write.%03d.jpg", index);
00767         pixWrite(buffer, pixt, IFF_JFIF_JPEG);
00768     }
00769     tempname = stringNew(buffer);
00770 
00771 #ifndef _WIN32
00772 
00773         /* Unix */
00774     if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) {
00775         if (title)
00776             snprintf(buffer, L_BUF_SIZE,
00777                      "xv -quit -geometry +%d+%d -name \"%s\" %s &",
00778                      x, y, title, tempname);
00779         else
00780             snprintf(buffer, L_BUF_SIZE,
00781                      "xv -quit -geometry +%d+%d %s &", x, y, tempname);
00782     }
00783     else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) {
00784         if (title)
00785             snprintf(buffer, L_BUF_SIZE,
00786                "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &",
00787                x, y, title, tempname);
00788         else
00789             snprintf(buffer, L_BUF_SIZE,
00790                "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &",
00791                x, y, tempname);
00792     }
00793     else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) {
00794             /* no way to display title */
00795         pixGetDimensions(pixt, &wt, &ht, NULL);
00796         snprintf(buffer, L_BUF_SIZE,
00797                  "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10,
00798                  x, y, tempname);
00799     }
00800     ignore = system(buffer);
00801 
00802 #else  /* _WIN32 */
00803 
00804         /* Windows: L_DISPLAY_WITH_IV */
00805     pathname = genPathname(tempname, NULL);
00806     _fullpath(fullpath, pathname, sizeof(fullpath));
00807     if (title)
00808         snprintf(buffer, L_BUF_SIZE,
00809                  "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"",
00810                  fullpath, x, y, title);
00811     else
00812         snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d)",
00813                  fullpath, x, y);
00814     ignore = system(buffer);
00815     FREE(pathname);
00816 
00817 #endif  /* _WIN32 */
00818 
00819     pixDestroy(&pixt);
00820     FREE(tempname);
00821     return 0;
00822 }
00823 
00824 
00825 /*!
00826  *  pixDisplayMultiple()
00827  *
00828  *      Input:  filepattern
00829  *      Return: 0 if OK; 1 on error
00830  *
00831  *  Notes:
00832  *      (1) This allows display of multiple images using gthumb on unix
00833  *          and i_view32 on windows.  The @filepattern is a regular
00834  *          expression that is expanded by the shell.
00835  *      (2) _fullpath automatically changes '/' to '\' if necessary.
00836  */
00837 l_int32
00838 pixDisplayMultiple(const char  *filepattern)
00839 {
00840 char     buffer[L_BUF_SIZE];
00841 l_int32  ignore;
00842 #ifdef _WIN32
00843 char    *pathname;
00844 char    *dir, *tail;
00845 char     fullpath[_MAX_PATH];
00846 #endif  /* _WIN32 */
00847 
00848     PROCNAME("pixDisplayMultiple");
00849 
00850     if (!filepattern || strlen(filepattern) == 0)
00851         return ERROR_INT("filepattern not defined", procName, 1);
00852 
00853 #ifndef _WIN32
00854     snprintf(buffer, L_BUF_SIZE, "gthumb %s &", filepattern);
00855 #else
00856         /* irFanView wants absolute path for directory */
00857     pathname = genPathname(filepattern, NULL);
00858     splitPathAtDirectory(pathname, &dir, &tail);
00859     _fullpath(fullpath, dir, sizeof(fullpath));
00860 
00861     snprintf(buffer, L_BUF_SIZE,
00862              "i_view32.exe \"%s\" /filepattern=\"%s\" /thumbs", fullpath, tail);
00863     FREE(pathname);
00864     FREE(dir);
00865     FREE(tail);
00866 #endif  /* _WIN32 */
00867 
00868     ignore = system(buffer);
00869     return 0;
00870 }
00871 
00872 
00873 /*!
00874  *  pixDisplayWrite()
00875  *
00876  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
00877  *              reduction (-1 to reset/erase; 0 to disable;
00878  *                         otherwise this is a reduction factor)
00879  *      Return: 0 if OK; 1 on error
00880  *
00881  *  Notes:
00882  *      (1) This defaults to jpeg output for pix that are 32 bpp or
00883  *          8 bpp without a colormap.  If you want to write all images
00884  *          losslessly, use format == IFF_PNG in pixDisplayWriteFormat().
00885  *      (2) See pixDisplayWriteFormat() for usage details.
00886  */
00887 l_int32
00888 pixDisplayWrite(PIX     *pixs,
00889                 l_int32  reduction)
00890 {
00891     return pixDisplayWriteFormat(pixs, reduction, IFF_JFIF_JPEG);
00892 }
00893 
00894 
00895 /*!
00896  *  pixDisplayWriteFormat()
00897  *
00898  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
00899  *              reduction (-1 to reset/erase; 0 to disable;
00900  *                         otherwise this is a reduction factor)
00901  *              format (IFF_PNG or IFF_JFIF_JPEG)
00902  *      Return: 0 if OK; 1 on error
00903  *
00904  *  Notes:
00905  *      (1) This writes files if reduction > 0.  These can be displayed using
00906  *            pixDisplayMultiple("/tmp/junk_write_display*");
00907  *      (2) All previously written files can be erased by calling with
00908  *          reduction < 0; the value of pixs is ignored.
00909  *      (3) If reduction > 1 and depth == 1, this does a scale-to-gray
00910  *          reduction.
00911  *      (4) This function uses a static internal variable to number
00912  *          output files written by a single process.  Behavior
00913  *          with a shared library may be unpredictable.
00914  *      (5) Output file format is as follows:
00915  *            format == IFF_JFIF_JPEG:
00916  *                png if d < 8 or d == 16 or if the output pix
00917  *                has a colormap.   Otherwise, output is jpg.
00918  *            format == IFF_PNG:
00919  *                png (lossless) on all images.
00920  *      (6) For 16 bpp, the choice of full dynamic range with log scale
00921  *          is the best for displaying these images.  Alternative outputs are
00922  *             pix8 = pixMaxDynamicRange(pixt, L_LINEAR_SCALE);
00923  *             pix8 = pixConvert16To8(pixt, 0);  // low order byte
00924  *             pix8 = pixConvert16To8(pixt, 1);  // high order byte
00925  */
00926 l_int32
00927 pixDisplayWriteFormat(PIX     *pixs,
00928                       l_int32  reduction,
00929                       l_int32  format)
00930 {
00931 char            buffer[L_BUF_SIZE];
00932 l_int32         ignore;
00933 l_float32       scale;
00934 PIX            *pixt, *pix8;
00935 static l_int32  index = 0;  /* caution: not .so or thread safe */
00936 
00937     PROCNAME("pixDisplayWriteFormat");
00938 
00939     if (reduction == 0) return 0;
00940 
00941     if (reduction < 0) {
00942         index = 0;  /* reset; this will cause erasure at next call to write */
00943         return 0;
00944     }
00945 
00946     if (format != IFF_JFIF_JPEG && format != IFF_PNG)
00947         return ERROR_INT("invalid format", procName, 1);
00948     if (!pixs)
00949         return ERROR_INT("pixs not defined", procName, 1);
00950 
00951     if (index == 0) {
00952         snprintf(buffer, L_BUF_SIZE,
00953            "rm -f /tmp/junk_write_display.*.png /tmp/junk_write_display.*.jpg");
00954         ignore = system(buffer);
00955     }
00956     index++;
00957 
00958     if (reduction == 1)
00959         pixt = pixClone(pixs);
00960     else {
00961         scale = 1. / (l_float32)reduction;
00962         if (pixGetDepth(pixs) == 1)
00963             pixt = pixScaleToGray(pixs, scale);
00964         else
00965             pixt = pixScale(pixs, scale, scale);
00966     }
00967 
00968     if (pixGetDepth(pixt) == 16) {
00969         pix8 = pixMaxDynamicRange(pixt, L_LOG_SCALE);
00970         snprintf(buffer, L_BUF_SIZE, "/tmp/junk_write_display.%03d.png", index);
00971         pixWrite(buffer, pix8, IFF_PNG);
00972         pixDestroy(&pix8);
00973     }
00974     else if (pixGetDepth(pixt) < 8 || pixGetColormap(pixt) ||
00975              format == IFF_PNG) {
00976         snprintf(buffer, L_BUF_SIZE, "/tmp/junk_write_display.%03d.png", index);
00977         pixWrite(buffer, pixt, IFF_PNG);
00978     }
00979     else {
00980         snprintf(buffer, L_BUF_SIZE, "/tmp/junk_write_display.%03d.jpg", index);
00981         pixWrite(buffer, pixt, format);
00982     }
00983     pixDestroy(&pixt);
00984 
00985     return 0;
00986 }
00987 
00988 
00989 /*!
00990  *  pixSaveTiled()
00991  *
00992  *      Input:  pixs (1, 2, 4, 8, 32 bpp)
00993  *              pixa (the pix are accumulated here)
00994  *              reduction (0 to disable; otherwise this is a reduction factor)
00995  *              newrow (0 if placed on the same row as previous; 1 otherwise)
00996  *              space (horizontal and vertical spacing, in pixels)
00997  *              dp (depth of pixa; 8 or 32 bpp; only used on first call)
00998  *      Return: 0 if OK, 1 on error.
00999  */
01000 l_int32
01001 pixSaveTiled(PIX     *pixs,
01002              PIXA    *pixa,
01003              l_int32  reduction,
01004              l_int32  newrow,
01005              l_int32  space,
01006              l_int32  dp)
01007 {
01008         /* Save without an outline */
01009     return pixSaveTiledOutline(pixs, pixa, reduction, newrow, space, 0, dp);
01010 }
01011 
01012 
01013 /*!
01014  *  pixSaveTiledOutline()
01015  *
01016  *      Input:  pixs (1, 2, 4, 8, 32 bpp)
01017  *              pixa (the pix are accumulated here)
01018  *              reduction (0 to disable; otherwise this is a reduction factor)
01019  *              newrow (0 if placed on the same row as previous; 1 otherwise)
01020  *              space (horizontal and vertical spacing, in pixels)
01021  *              linewidth (width of added outline for image; 0 for no outline)
01022  *              dp (depth of pixa; 8 or 32 bpp; only used on first call)
01023  *      Return: 0 if OK, 1 on error.
01024  *
01025  *  Notes:
01026  *      (1) Before calling this function for the first time, use
01027  *          pixaCreate() to make the @pixa that will accumulate the pix.
01028  *          This is passed in each time pixSaveTiled() is called.
01029  *      (2) @reduction is the integer reduction factor for the input
01030  *          image.  After reduction and possible depth conversion,
01031  *          the image is saved in the input pixa, along with a box
01032  *          that specifies the location to place it when tiled later.
01033  *          Disable saving the pix by setting reduction == 0.
01034  *      (3) @newrow and @space specify the location of the new pix
01035  *          with respect to the last one(s) that were entered.
01036  *      (4) @dp specifies the depth at which all pix are saved.  It can
01037  *          be only 8 or 32 bpp.  Any colormap is removed.  This is only
01038  *          used at the first invocation.
01039  *      (5) This function uses two variables from call to call.
01040  *          If they were static, the function would not be .so or thread
01041  *          safe, and furthermore, there would be interference with two or
01042  *          more pixa accumulating images at a time.  Consequently,
01043  *          we use the first pix in the pixa to store and obtain both
01044  *          the depth and the current position of the bottom (one pixel
01045  *          below the lowest image raster line when laid out using
01046  *          the boxa).  The bottom variable is stored in the input format
01047  *          field, which is the only field available for storing an int.
01048  */
01049 l_int32
01050 pixSaveTiledOutline(PIX     *pixs,
01051                     PIXA    *pixa,
01052                     l_int32  reduction,
01053                     l_int32  newrow,
01054                     l_int32  space,
01055                     l_int32  linewidth,
01056                     l_int32  dp)
01057 {
01058 l_int32         n, top, left, bx, by, bw, w, h, depth, bottom;
01059 l_float32       scale;
01060 BOX            *box;
01061 PIX            *pix, *pixt1, *pixt2, *pixt3;
01062 
01063     PROCNAME("pixSaveTiledOutline");
01064 
01065     if (reduction == 0) return 0;
01066 
01067     if (!pixs)
01068         return ERROR_INT("pixs not defined", procName, 1);
01069     if (!pixa)
01070         return ERROR_INT("pixa not defined", procName, 1);
01071 
01072     n = pixaGetCount(pixa);
01073     if (n == 0) {
01074         bottom = 0;
01075         if (dp != 8 && dp != 32) {
01076             L_WARNING("dp not 8 or 32 bpp; using 32", procName);
01077             depth = 32;
01078         } else
01079             depth = dp;
01080     }
01081     else {  /* extract the depth and bottom params from the first pix */
01082         pix = pixaGetPix(pixa, 0, L_CLONE);
01083         depth = pixGetDepth(pix);
01084         bottom = pixGetInputFormat(pix);  /* not typical usage! */
01085         pixDestroy(&pix);
01086     }
01087 
01088         /* Scale and convert to output depth */
01089     if (reduction == 1)
01090         pixt1 = pixClone(pixs);
01091     else {
01092         scale = 1. / (l_float32)reduction;
01093         if (pixGetDepth(pixs) == 1)
01094             pixt1 = pixScaleToGray(pixs, scale);
01095         else
01096             pixt1 = pixScale(pixs, scale, scale);
01097     }
01098     if (depth == 8)
01099         pixt2 = pixConvertTo8(pixt1, 0);
01100     else
01101         pixt2 = pixConvertTo32(pixt1);
01102     pixDestroy(&pixt1);
01103 
01104         /* Add black outline */
01105     if (linewidth > 0)
01106         pixt3 = pixAddBorder(pixt2, linewidth, 0);
01107     else
01108         pixt3 = pixClone(pixt2);
01109     pixDestroy(&pixt2);
01110 
01111         /* Find position of current pix (UL corner plus size) */
01112     if (n == 0) {
01113         top = 0;
01114         left = 0;
01115     }
01116     else if (newrow == 1) {
01117         top = bottom + space;
01118         left = 0;
01119     }
01120     else if (n > 0) {
01121         pixaGetBoxGeometry(pixa, n - 1, &bx, &by, &bw, NULL);
01122         top = by;
01123         left = bx + bw + space;
01124     }
01125 
01126     pixGetDimensions(pixt3, &w, &h, NULL);
01127     bottom = L_MAX(bottom, top + h);
01128     box = boxCreate(left, top, w, h);
01129     pixaAddPix(pixa, pixt3, L_INSERT);
01130     pixaAddBox(pixa, box, L_INSERT);
01131 
01132         /* Save the new bottom value */
01133     pix = pixaGetPix(pixa, 0, L_CLONE);
01134     pixSetInputFormat(pix, bottom);  /* not typical usage! */
01135     pixDestroy(&pix);
01136 
01137     return 0;
01138 }
01139 
01140 
01141 /*!
01142  *  pixSaveTiledWithText()
01143  *
01144  *      Input:  pixs (1, 2, 4, 8, 32 bpp)
01145  *              pixa (the pix are accumulated here; as 32 bpp)
01146  *              outwidth (in pixels; use 0 to disable entirely)
01147  *              newrow (1 to start a new row; 0 to go on same row as previous)
01148  *              space (horizontal and vertical spacing, in pixels)
01149  *              linewidth (width of added outline for image; 0 for no outline)
01150  *              bmf (<optional> font struct)
01151  *              textstr (<optional> text string to be added)
01152  *              val (color to set the text)
01153  *              location (L_ADD_ABOVE, L_ADD_AT_TOP, L_ADD_AT_BOTTOM,
01154  *                        L_ADD_BELOW)
01155  *      Return: 0 if OK, 1 on error.
01156  *
01157  *  Notes:
01158  *      (1) Before calling this function for the first time, use
01159  *          pixaCreate() to make the @pixa that will accumulate the pix.
01160  *          This is passed in each time pixSaveTiled() is called.
01161  *      (2) @outwidth is the scaled width.  After scaling, the image is
01162  *          saved in the input pixa, along with a box that specifies
01163  *          the location to place it when tiled later.  Disable saving
01164  *          the pix by setting @outwidth == 0.
01165  *      (3) @newrow and @space specify the location of the new pix
01166  *          with respect to the last one(s) that were entered.
01167  *      (4) All pix are saved as 32 bpp RGB.
01168  *      (5) If both @bmf and @textstr are defined, this generates a pix
01169  *          with the additional text; otherwise, no text is written.
01170  *      (6) The text is written before scaling, so it is properly
01171  *          antialiased in the scaled pix.  However, if the pix on
01172  *          different calls have different widths, the size of the
01173  *          text will vary.
01174  *      (7) See pixSaveTiledOutline() for other implementation details.
01175  */
01176 l_int32
01177 pixSaveTiledWithText(PIX         *pixs,
01178                      PIXA        *pixa,
01179                      l_int32      outwidth,
01180                      l_int32      newrow,
01181                      l_int32      space,
01182                      l_int32      linewidth,
01183                      L_BMF       *bmf,
01184                      const char  *textstr,
01185                      l_uint32     val,
01186                      l_int32      location)
01187 {
01188 PIX  *pixt1, *pixt2, *pixt3, *pixt4;
01189 
01190     PROCNAME("pixSaveTiledWithText");
01191 
01192     if (outwidth == 0) return 0;
01193 
01194     if (!pixs)
01195         return ERROR_INT("pixs not defined", procName, 1);
01196     if (!pixa)
01197         return ERROR_INT("pixa not defined", procName, 1);
01198 
01199     pixt1 = pixConvertTo32(pixs);
01200     if (linewidth > 0)
01201         pixt2 = pixAddBorder(pixt1, linewidth, 0);
01202     else
01203         pixt2 = pixClone(pixt1);
01204     if (bmf && textstr)
01205         pixt3 = pixAddSingleTextblock(pixt2, bmf, textstr, val, location, NULL);
01206     else
01207         pixt3 = pixClone(pixt2);
01208     pixt4 = pixScaleToSize(pixt3, outwidth, 0);
01209     pixSaveTiled(pixt4, pixa, 1, newrow, space, 32);
01210     pixDestroy(&pixt1);
01211     pixDestroy(&pixt2);
01212     pixDestroy(&pixt3);
01213     pixDestroy(&pixt4);
01214     return 0;
01215 }
01216 
01217 
01218 void
01219 l_chooseDisplayProg(l_int32  selection)
01220 {
01221     if (selection == L_DISPLAY_WITH_XLI ||
01222         selection == L_DISPLAY_WITH_XZGV ||
01223         selection == L_DISPLAY_WITH_XV)
01224         var_DISPLAY_PROG = selection;
01225     else
01226         L_ERROR("invalid unix display program", "l_chooseDisplayProg");
01227     return;
01228 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines