Leptonica 1.68
C Image Processing Library

psio2.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  *  psio2.c
00018  *
00019  *    |=============================================================|
00020  *    |                         Important note                      |
00021  *    |=============================================================|
00022  *    | Some of these functions require libtiff, libjpeg and libz.  |
00023  *    | If you do not have these libraries, you must set            |
00024  *    |     #define  USE_PSIO     0                                 |
00025  *    | in environ.h.  This will link psio2stub.c                   |
00026  *    |=============================================================|
00027  *
00028  *     These are lower-level functions that implement a PostScript
00029  *     "device driver" for wrapping images in PostScript.  The images
00030  *     can be rendered by a PostScript interpreter for viewing,
00031  *     using evince or gv.  They can also be rasterized for printing,
00032  *     using gs or an embedded interpreter in a PostScript printer.
00033  *     And they can be converted to a pdf using gs (ps2pdf).
00034  *
00035  *     For uncompressed images
00036  *          l_int32              pixWritePSEmbed()
00037  *          l_int32              pixWriteStreamPS()
00038  *          char                *pixWriteStringPS()
00039  *          char                *generateUncompressedPS()
00040  *          void                 getScaledParametersPS()
00041  *          l_int32              convertByteToHexAscii()
00042  *
00043  *     For jpeg compressed images (use dct compression)
00044  *          l_int32              convertJpegToPSEmbed()
00045  *          l_int32              convertJpegToPS()
00046  *          l_int32              convertJpegToPSString()
00047  *          char                *generateJpegPS()
00048  *          L_COMPRESSED_DATA   *pixGenerateJpegData()
00049  *          L_COMPRESSED_DATA   *l_generateJpegData()
00050  *          void                 compressed_dataDestroy()
00051  *
00052  *     For g4 fax compressed images (use ccitt g4 compression)
00053  *          l_int32              convertG4ToPSEmbed()
00054  *          l_int32              convertG4ToPS()
00055  *          l_int32              convertG4ToPSString()
00056  *          char                *generateG4PS()
00057  *          L_COMPRESSED_DATA   *pixGenerateG4Data()
00058  *          L_COMPRESSED_DATA   *l_generateG4Data()
00059  *
00060  *     For multipage tiff images
00061  *          l_int32              convertTiffMultipageToPS()
00062  *
00063  *     For flate (gzip) compressed images (e.g., png)
00064  *          l_int32              convertFlateToPSEmbed()
00065  *          l_int32              convertFlateToPS()
00066  *          l_int32              convertFlateToPSString()
00067  *          char                *generateFlatePS()
00068  *          L_COMPRESSED_DATA   *l_generateFlateData()
00069  *          L_COMPRESSED_DATA   *pixGenerateFlateData()
00070  *
00071  *     Write to memory
00072  *          l_int32              pixWriteMemPS()
00073  *
00074  *     Converting resolution
00075  *          l_int32              getResLetterPage()
00076  *          l_int32              getResA4Page()
00077  *
00078  *     Utility for encoding and decoding data with ascii85
00079  *          char                *encodeAscii85()
00080  *          l_int32             *convertChunkToAscii85()
00081  *          l_uint8             *decodeAscii85()
00082  *
00083  *     Setting flag for writing bounding box hint
00084  *          void                 l_psWriteBoundingBox()
00085  *
00086  *  See psio1.c for higher-level functions and their usage.
00087  */
00088 
00089 #include <string.h>
00090 #include "allheaders.h"
00091 
00092 /* --------------------------------------------*/
00093 #if  USE_PSIO   /* defined in environ.h */
00094  /* --------------------------------------------*/
00095  
00096     /* Set default for writing bounding box hint */
00097 static l_int32  var_PS_WRITE_BOUNDING_BOX = 1;
00098 
00099     /* MS VC++ can't handle array initialization with static consts ! */
00100 #define L_BUF_SIZE      512
00101 
00102 static const l_int32  DEFAULT_INPUT_RES   = 300;  /* typical scan res, ppi */
00103 static const l_int32  MIN_RES             = 5;
00104 static const l_int32  MAX_RES             = 3000;
00105 static const l_int32  MAX_85_LINE_COUNT   = 64;  /* max line length ascii85 */
00106 
00107     /* For computing resolution that fills page to desired amount */
00108 static const l_int32  LETTER_WIDTH            = 612;   /* points */
00109 static const l_int32  LETTER_HEIGHT           = 792;   /* points */
00110 static const l_int32  A4_WIDTH                = 595;   /* points */
00111 static const l_int32  A4_HEIGHT               = 842;   /* points */
00112 static const l_float32  DEFAULT_FILL_FRACTION = 0.95;
00113 
00114 static const l_uint32  power85[5] = {1,
00115                                      85,
00116                                      85 * 85,
00117                                      85 * 85 * 85,
00118                                      85 * 85 * 85 * 85};
00119 
00120 static l_int32  convertChunkToAscii85(l_uint8 *inarray, l_int32 insize,
00121                                       l_int32 *pindex, char *outbuf,
00122                                       l_int32 *pnbout);
00123 
00124 #ifndef  NO_CONSOLE_IO
00125 #define  DEBUG_JPEG       0
00126 #define  DEBUG_G4         0
00127 #define  DEBUG_FLATE      0
00128 #endif  /* ~NO_CONSOLE_IO */
00129 
00130 /* Note that the bounding box hint at the top of the generated PostScript
00131  * file is required for the "*Embed" functions.  These generate a
00132  * PostScript file for an individual image that can be translated and
00133  * scaled by an application that embeds the image in its output
00134  * (e.g., in the PS output from a TeX file).
00135  * However, bounding box hints should not be embedded in any
00136  * PostScript image that will be composited with other images,
00137  * where more than one image may be placed in an arbitrary location
00138  * on a page.  */
00139 
00140 
00141 /*-------------------------------------------------------------*
00142  *                  For uncompressed images                    *
00143  *-------------------------------------------------------------*/
00144 /*!
00145  *  pixWritePSEmbed()
00146  *
00147  *      Input:  filein (input file, all depths, colormap OK)
00148  *              fileout (output ps file)
00149  *      Return: 0 if OK, 1 on error
00150  *
00151  *  Notes:
00152  *      (1) This is a simple wrapper function that generates an
00153  *          uncompressed PS file, with a bounding box.
00154  *      (2) The bounding box is required when a program such as TeX
00155  *          (through epsf) places and rescales the image.
00156  *      (3) The bounding box is sized for fitting the image to an
00157  *          8.5 x 11.0 inch page.
00158  */
00159 l_int32
00160 pixWritePSEmbed(const char  *filein,
00161                 const char  *fileout)
00162 {
00163 l_int32    w, h;
00164 l_float32  scale;
00165 FILE      *fp;
00166 PIX       *pix;
00167 
00168     PROCNAME("pixWritePSEmbed");
00169 
00170     if (!filein)
00171         return ERROR_INT("filein not defined", procName, 1);
00172     if (!fileout)
00173         return ERROR_INT("fileout not defined", procName, 1);
00174 
00175     if ((pix = pixRead(filein)) == NULL)
00176         return ERROR_INT("image not read from file", procName, 1);
00177     w = pixGetWidth(pix);
00178     h = pixGetHeight(pix);
00179     if (w * 11.0 > h * 8.5)
00180         scale = 8.5 * 300. / (l_float32)w;
00181     else
00182         scale = 11.0 * 300. / (l_float32)h;
00183 
00184     if ((fp = fopenWriteStream(fileout, "wb")) == NULL)
00185         return ERROR_INT("file not opened for write", procName, 1);
00186     pixWriteStreamPS(fp, pix, NULL, 0, scale);
00187     fclose(fp);
00188 
00189     pixDestroy(&pix);
00190     return 0;
00191 }
00192 
00193 
00194 /*!
00195  *  pixWriteStreamPS()
00196  *
00197  *      Input:  stream
00198  *              pix
00199  *              box  (<optional>)
00200  *              res  (can use 0 for default of 300 ppi)
00201  *              scale (to prevent scaling, use either 1.0 or 0.0)
00202  *      Return: 0 if OK; 1 on error
00203  *
00204  *  Notes:
00205  *      (1) This writes image in PS format, optionally scaled,
00206  *          adjusted for the printer resolution, and with
00207  *          a bounding box.
00208  *      (2) For details on use of parameters, see pixWriteStringPS().
00209  */
00210 l_int32
00211 pixWriteStreamPS(FILE      *fp,
00212                  PIX       *pix,
00213                  BOX       *box,
00214                  l_int32    res,
00215                  l_float32  scale)
00216 {
00217 char    *outstr;
00218 l_int32  length;
00219 PIX     *pixc;
00220 
00221     PROCNAME("pixWriteStreamPS");
00222 
00223     if (!fp)
00224         return (l_int32)ERROR_INT("stream not open", procName, 1);
00225     if (!pix)
00226         return (l_int32)ERROR_INT("pix not defined", procName, 1);
00227 
00228     if ((pixc = pixConvertForPSWrap(pix)) == NULL)
00229         return (l_int32)ERROR_INT("pixc not made", procName, 1);
00230 
00231     outstr = pixWriteStringPS(pixc, box, res, scale);
00232     length = strlen(outstr);
00233     fwrite(outstr, 1, length, fp);
00234     FREE(outstr);
00235     pixDestroy(&pixc);
00236 
00237     return 0;
00238 }
00239 
00240 
00241 /*!
00242  *  pixWriteStringPS()
00243  *
00244  *      Input:  pixs:  all depths, colormap OK
00245  *              box:  (a) If box == null, image is placed, optionally scaled,
00246  *                        in a standard b.b. at the center of the page.
00247  *                        This is to be used when another program like
00248  *                        TeX (through epsf) places the image.
00249  *                    (b) If box != null, image is placed without a
00250  *                        b.b. at the specified page location and with
00251  *                        (optional) scaling.  This is to be used when
00252  *                        you want to specify exactly where (and optionally
00253  *                        how big) you want the image to be.
00254  *                        Note that all coordinates are in PS convention,
00255  *                        with (0,0) at LL corner of the page:
00256  *                            (x,y)    location of LL corner of image, in mils.
00257  *                            (w,h)    scaled size, in mils.  Use 0 to
00258  *                                     scale with "scale" and "res" input.
00259  *              res:  resolution, in printer ppi.  Use 0 for default (300 ppi).
00260  *              scale: scale factor.  If no scaling is desired, use
00261  *                     either 1.0 or 0.0.   Scaling just resets the resolution
00262  *                     parameter; the actual scaling is done in the
00263  *                     interpreter at rendering time.  This is important:
00264  *                     it allows you to scale the image up without
00265  *                     increasing the file size.
00266  *      Return: ps string if OK, or null on error
00267  *
00268  *  Notes:
00269  *      (1) OK, this seems a bit complicated, because there are various
00270  *          ways to scale and not to scale.  Here's a summary:
00271  *      (2) If you don't want any scaling at all:
00272  *           * if you are using a box:
00273  *               set w = 0, h = 0, and use scale = 1.0; it will print
00274  *               each pixel unscaled at printer resolution
00275  *           * if you are not using a box:
00276  *               set scale = 1.0; it will print at printer resolution
00277  *      (3) If you want the image to be a certain size in inches:
00278  *           * you must use a box and set the box (w,h) in mils
00279  *      (4) If you want the image to be scaled by a scale factor != 1.0:
00280  *           * if you are using a box:
00281  *               set w = 0, h = 0, and use the desired scale factor;
00282  *               the higher the printer resolution, the smaller the
00283  *               image will actually appear.
00284  *           * if you are not using a box:
00285  *               set the desired scale factor; the higher the printer
00286  *               resolution, the smaller the image will actually appear.
00287  *      (5) Another complication is the proliferation of distance units:
00288  *           * The interface distances are in milli-inches.
00289  *           * Three different units are used internally:
00290  *              - pixels  (units of 1/res inch)
00291  *              - printer pts (units of 1/72 inch)
00292  *              - inches
00293  *           * Here is a quiz on volume units from a reviewer:
00294  *             How many UK milli-cups in a US kilo-teaspoon?
00295  *               (Hint: 1.0 US cup = 0.75 UK cup + 0.2 US gill;
00296  *                      1.0 US gill = 24.0 US teaspoons)
00297  */
00298 char *
00299 pixWriteStringPS(PIX       *pixs,
00300                  BOX       *box,
00301                  l_int32    res,
00302                  l_float32  scale)
00303 {
00304 char       nib1, nib2;
00305 char      *hexdata, *outstr;
00306 l_uint8    byteval;
00307 l_int32    i, j, k, w, h, d;
00308 l_float32  wpt, hpt, xpt, ypt;
00309 l_int32    wpl, psbpl, hexbytes, boxflag, bps;
00310 l_uint32  *line, *data;
00311 PIX       *pix;
00312 
00313     PROCNAME("pixWriteStringPS");
00314 
00315     if (!pixs)
00316         return (char *)ERROR_PTR("pixs not defined", procName, NULL);
00317 
00318     if ((pix = pixConvertForPSWrap(pixs)) == NULL)
00319         return (char *)ERROR_PTR("pix not made", procName, NULL);
00320     pixGetDimensions(pix, &w, &h, &d);
00321 
00322         /* Get the factors by which PS scales and translates, in pts */
00323     if (!box)
00324         boxflag = 0;  /* no scaling; b.b. at center */
00325     else
00326         boxflag = 1;  /* no b.b., specify placement and optional scaling */
00327     getScaledParametersPS(box, w, h, res, scale, &xpt, &ypt, &wpt, &hpt);
00328 
00329     if (d == 1)
00330         bps = 1;  /* bits/sample */
00331     else  /* d == 8 || d == 32 */
00332         bps = 8;
00333 
00334         /* Convert image data to hex string.  psbpl is the number of
00335          * bytes in each raster line when it is packed to the byte
00336          * boundary (not the 32 bit word boundary, as with the pix).
00337          * When converted to hex, the hex string has 2 bytes for
00338          * every byte of raster data. */
00339     wpl = pixGetWpl(pix);
00340     if (d == 1 || d == 8)
00341         psbpl = (w * d + 7) / 8;
00342     else /* d == 32 */
00343         psbpl = 3 * w;
00344     data = pixGetData(pix);
00345     hexbytes = 2 * psbpl * h;  /* size of ps hex array */
00346     if ((hexdata = (char *)CALLOC(hexbytes + 1, sizeof(char))) == NULL)
00347         return (char *)ERROR_PTR("hexdata not made", procName, NULL);
00348     if (d == 1 || d == 8) {
00349         for (i = 0, k = 0; i < h; i++) {
00350             line = data + i * wpl;
00351             for (j = 0; j < psbpl; j++) {
00352                 byteval = GET_DATA_BYTE(line, j);
00353                 convertByteToHexAscii(byteval, &nib1, &nib2);
00354                 hexdata[k++] = nib1;
00355                 hexdata[k++] = nib2;
00356             }
00357         }
00358     }
00359     else  {  /* d == 32; hexdata bytes packed RGBRGB..., 2 per sample */
00360         for (i = 0, k = 0; i < h; i++) {
00361             line = data + i * wpl;
00362             for (j = 0; j < w; j++) {
00363                 byteval = GET_DATA_BYTE(line + j, 0);  /* red */
00364                 convertByteToHexAscii(byteval, &nib1, &nib2);
00365                 hexdata[k++] = nib1;
00366                 hexdata[k++] = nib2;
00367                 byteval = GET_DATA_BYTE(line + j, 1);  /* green */
00368                 convertByteToHexAscii(byteval, &nib1, &nib2);
00369                 hexdata[k++] = nib1;
00370                 hexdata[k++] = nib2;
00371                 byteval = GET_DATA_BYTE(line + j, 2);  /* blue */
00372                 convertByteToHexAscii(byteval, &nib1, &nib2);
00373                 hexdata[k++] = nib1;
00374                 hexdata[k++] = nib2;
00375             }
00376         }
00377     }
00378     hexdata[k] = '\0';
00379 
00380     outstr = generateUncompressedPS(hexdata, w, h, d, psbpl, bps,
00381                                     xpt, ypt, wpt, hpt, boxflag);
00382     if (!outstr)
00383         return (char *)ERROR_PTR("outstr not made", procName, NULL);
00384     pixDestroy(&pix);
00385     return outstr;
00386 }
00387 
00388 
00389 /*!
00390  *  generateUncompressedPS()
00391  *
00392  *      Input:  hexdata
00393  *              w, h  (raster image size in pixels)
00394  *              d (image depth in bpp; rgb is 32)
00395  *              psbpl (raster bytes/line, when packed to the byte boundary)
00396  *              bps (bits/sample: either 1 or 8)
00397  *              xpt, ypt (location of LL corner of image, in pts, relative
00398  *                    to the PostScript origin (0,0) at the LL corner
00399  *                    of the page)
00400  *              wpt, hpt (rendered image size in pts)
00401  *              boxflag (1 to print out bounding box hint; 0 to skip)
00402  *      Return: PS string, or null on error
00403  *
00404  *  Notes:
00405  *      (1) Low-level function.
00406  */
00407 char *
00408 generateUncompressedPS(char      *hexdata,
00409                        l_int32    w,
00410                        l_int32    h,
00411                        l_int32    d,
00412                        l_int32    psbpl,
00413                        l_int32    bps,
00414                        l_float32  xpt,
00415                        l_float32  ypt,
00416                        l_float32  wpt,
00417                        l_float32  hpt,
00418                        l_int32    boxflag)
00419 {
00420 char    *outstr;
00421 char     bigbuf[L_BUF_SIZE];
00422 SARRAY  *sa;
00423 
00424     PROCNAME("generateUncompressedPS");
00425 
00426     if (!hexdata)
00427         return (char *)ERROR_PTR("hexdata not defined", procName, NULL);
00428 
00429     if ((sa = sarrayCreate(0)) == NULL)
00430         return (char *)ERROR_PTR("sa not made", procName, NULL);
00431     sarrayAddString(sa, (char *)"%!Adobe-PS", L_COPY);
00432     if (boxflag == 0) {
00433         sprintf(bigbuf,
00434             "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
00435             xpt, ypt, xpt + wpt, ypt + hpt);
00436         sarrayAddString(sa, bigbuf, L_COPY);
00437     }
00438     else    /* boxflag == 1 */
00439         sarrayAddString(sa, (char *)"gsave", L_COPY);
00440 
00441     if (d == 1)
00442         sarrayAddString(sa,
00443               (char *)"{1 exch sub} settransfer    %invert binary", L_COPY);
00444 
00445     sprintf(bigbuf, "/bpl %d string def         %%bpl as a string", psbpl);
00446     sarrayAddString(sa, bigbuf, L_COPY);
00447     sprintf(bigbuf,
00448            "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
00449     sarrayAddString(sa, bigbuf, L_COPY);
00450     sprintf(bigbuf,
00451             "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
00452     sarrayAddString(sa, bigbuf, L_COPY);
00453     sprintf(bigbuf,
00454             "%d %d %d                 %%image dimensions in pixels", w, h, bps);
00455     sarrayAddString(sa, bigbuf, L_COPY);
00456     sprintf(bigbuf,
00457             "[%d %d %d %d %d %d]     %%mapping matrix: [w 0 0 -h 0 h]",
00458             w, 0, 0, -h, 0, h);
00459     sarrayAddString(sa, bigbuf, L_COPY);
00460 
00461     if (boxflag == 0) {
00462         if (d == 1 || d == 8)
00463             sarrayAddString(sa,
00464                 (char *)"{currentfile bpl readhexstring pop} image", L_COPY);
00465         else  /* d == 32 */
00466             sarrayAddString(sa,
00467               (char *)"{currentfile bpl readhexstring pop} false 3 colorimage",
00468               L_COPY);
00469     }
00470     else {  /* boxflag == 1 */
00471         if (d == 1 || d == 8)
00472             sarrayAddString(sa,
00473               (char *)"{currentfile bpl readhexstring pop} bind image", L_COPY);
00474         else  /* d == 32 */
00475             sarrayAddString(sa,
00476           (char *)"{currentfile bpl readhexstring pop} bind false 3 colorimage",
00477                  L_COPY);
00478     }
00479 
00480     sarrayAddString(sa, hexdata, L_INSERT);
00481 
00482     if (boxflag == 0)
00483         sarrayAddString(sa, (char *)"\nshowpage", L_COPY);
00484     else  /* boxflag == 1 */
00485         sarrayAddString(sa, (char *)"\ngrestore", L_COPY);
00486 
00487     if ((outstr = sarrayToString(sa, 1)) == NULL)
00488         return (char *)ERROR_PTR("outstr not made", procName, NULL);
00489 
00490     sarrayDestroy(&sa);
00491     return outstr;
00492 }
00493 
00494 
00495 /*!
00496  *  getScaledParametersPS()
00497  *
00498  *      Input:  box (<optional> location of image in mils; with
00499  *                   (x,y) being the LL corner)
00500  *              wpix (pix width in pixels)
00501  *              hpix (pix height in pixels)
00502  *              res (of printer; use 0 for default)
00503  *              scale (use 1.0 or 0.0 for no scaling) 
00504  *              &xpt (location of llx in pts)
00505  *              &ypt (location of lly in pts)
00506  *              &wpt (image width in pts)
00507  *              &hpt (image height in pts)
00508  *      Return: void (no arg checking)
00509  *
00510  *  Notes:
00511  *      (1) The image is always scaled, depending on res and scale.
00512  *      (2) If no box, the image is centered on the page.
00513  *      (3) If there is a box, the image is placed within it.
00514  */
00515 void
00516 getScaledParametersPS(BOX        *box,
00517                       l_int32     wpix,
00518                       l_int32     hpix,
00519                       l_int32     res,
00520                       l_float32   scale,
00521                       l_float32  *pxpt,
00522                       l_float32  *pypt,
00523                       l_float32  *pwpt,
00524                       l_float32  *phpt)
00525 {
00526 l_int32    bx, by, bw, bh;
00527 l_float32  winch, hinch, xinch, yinch, fres;
00528 
00529     PROCNAME("getScaledParametersPS");
00530 
00531     if (res == 0)
00532         res = DEFAULT_INPUT_RES;
00533     fres = (l_float32)res;
00534 
00535         /* Allow the PS interpreter to scale the resolution */
00536     if (scale == 0.0)
00537         scale = 1.0;
00538     if (scale != 1.0) {
00539         fres = (l_float32)res / scale;
00540         res = (l_int32)fres;
00541     }
00542 
00543         /* Limit valid resolution interval */
00544     if (res < MIN_RES || res > MAX_RES) {
00545         L_WARNING_INT("res %d out of bounds; using default res; no scaling",
00546                       procName, res);
00547         res = DEFAULT_INPUT_RES;
00548         fres = (l_float32)res;
00549     }
00550 
00551     if (!box) {  /* center on page */
00552         winch = (l_float32)wpix / fres;
00553         hinch = (l_float32)hpix / fres;
00554         xinch = (8.5 - winch) / 2.;
00555         yinch = (11.0 - hinch) / 2.;
00556     }
00557     else {
00558         boxGetGeometry(box, &bx, &by, &bw, &bh);
00559         if (bw == 0)
00560             winch = (l_float32)wpix / fres;
00561         else
00562             winch = (l_float32)bw / 1000.;
00563         if (bh == 0)
00564             hinch = (l_float32)hpix / fres;
00565         else
00566             hinch = (l_float32)bh / 1000.;
00567         xinch = (l_float32)bx / 1000.;
00568         yinch = (l_float32)by / 1000.;
00569     }
00570 
00571     if (xinch < 0)
00572         L_WARNING("left edge < 0.0 inch", procName);
00573     if (xinch + winch > 8.5)
00574         L_WARNING("right edge > 8.5 inch", procName);
00575     if (yinch < 0.0)
00576         L_WARNING("bottom edge < 0.0 inch", procName);
00577     if (yinch + hinch > 11.0)
00578         L_WARNING("top edge > 11.0 inch", procName);
00579 
00580     *pwpt = 72. * winch;
00581     *phpt = 72. * hinch;
00582     *pxpt = 72. * xinch;
00583     *pypt = 72. * yinch;
00584     return;
00585 }
00586     
00587 
00588 /*!
00589  *  convertByteToHexAscii()
00590  *
00591  *      Input:  byteval  (input byte)
00592  *              &nib1, &nib2  (<return> two hex ascii characters)
00593  *      Return: void
00594  */
00595 void
00596 convertByteToHexAscii(l_uint8  byteval,
00597                       char    *pnib1,
00598                       char    *pnib2)
00599 {
00600 l_uint8  nib;
00601 
00602     nib = byteval >> 4;
00603     if (nib < 10)
00604         *pnib1 = '0' + nib;
00605     else
00606         *pnib1 = 'a' + (nib - 10);
00607     nib = byteval & 0xf;
00608     if (nib < 10)
00609         *pnib2 = '0' + nib;
00610     else
00611         *pnib2 = 'a' + (nib - 10);
00612 
00613     return;
00614 }
00615 
00616 
00617 /*-------------------------------------------------------------*
00618  *                  For jpeg compressed images                 *
00619  *-------------------------------------------------------------*/
00620 /*!
00621  *  convertJpegToPSEmbed()
00622  *
00623  *      Input:  filein (input jpeg file)
00624  *              fileout (output ps file)
00625  *      Return: 0 if OK, 1 on error
00626  *
00627  *  Notes:
00628  *      (1) This function takes a jpeg file as input and generates a DCT
00629  *          compressed, ascii85 encoded PS file, with a bounding box.
00630  *      (2) The bounding box is required when a program such as TeX
00631  *          (through epsf) places and rescales the image.
00632  *      (3) The bounding box is sized for fitting the image to an
00633  *          8.5 x 11.0 inch page.
00634  */
00635 l_int32
00636 convertJpegToPSEmbed(const char  *filein,
00637                      const char  *fileout)
00638 {
00639 char               *outstr;
00640 l_int32             w, h, nbytes;
00641 l_float32           xpt, ypt, wpt, hpt;
00642 L_COMPRESSED_DATA  *cid;
00643 
00644     PROCNAME("convertJpegToPSEmbed");
00645 
00646     if (!filein)
00647         return ERROR_INT("filein not defined", procName, 1);
00648     if (!fileout)
00649         return ERROR_INT("fileout not defined", procName, 1);
00650 
00651         /* Generate the ascii encoded jpeg data */
00652     if ((cid = l_generateJpegData(filein, 1)) == NULL)
00653         return ERROR_INT("jpeg data not made", procName, 1);
00654     w = cid->w;
00655     h = cid->h;
00656 
00657         /* Scale for 20 pt boundary and otherwise full filling
00658          * in one direction on 8.5 x 11 inch device */
00659     xpt = 20.0;
00660     ypt = 20.0;
00661     if (w * 11.0 > h * 8.5) {
00662         wpt = 572.0;   /* 612 - 2 * 20 */
00663         hpt = wpt * (l_float32)h / (l_float32)w;
00664     }
00665     else {
00666         hpt = 752.0;   /* 792 - 2 * 20 */
00667         wpt = hpt * (l_float32)w / (l_float32)h;
00668     }
00669 
00670         /* Generate the PS.
00671          * The bounding box information should be inserted (default). */
00672     outstr = generateJpegPS(filein, cid, xpt, ypt, wpt, hpt, 1, 1);
00673     if (!outstr)
00674         return ERROR_INT("outstr not made", procName, 1);
00675     nbytes = strlen(outstr);
00676 
00677     if (l_binaryWrite(fileout, "w", outstr, nbytes))
00678         return ERROR_INT("ps string not written to file", procName, 1);
00679     FREE(outstr);
00680     compressed_dataDestroy(&cid);
00681     return 0;
00682 }
00683 
00684 
00685 /*!
00686  *  convertJpegToPS()
00687  *
00688  *      Input:  filein (input jpeg file)
00689  *              fileout (output ps file)
00690  *              operation ("w" for write; "a" for append)
00691  *              x, y (location of LL corner of image, in pixels, relative
00692  *                    to the PostScript origin (0,0) at the LL corner
00693  *                    of the page)
00694  *              res (resolution of the input image, in ppi; use 0 for default)
00695  *              scale (scaling by printer; use 0.0 or 1.0 for no scaling)
00696  *              pageno (page number; must start with 1; you can use 0
00697  *                      if there is only one page)
00698  *              endpage (boolean: use TRUE if this is the last image to be
00699  *                       added to the page; FALSE otherwise)
00700  *      Return: 0 if OK, 1 on error
00701  *
00702  *  Notes:
00703  *      (1) This is simpler to use than pixWriteStringPS(), and
00704  *          it outputs in level 2 PS as compressed DCT (overlaid
00705  *          with ascii85 encoding).
00706  *      (2) An output file can contain multiple pages, each with
00707  *          multiple images.  The arguments to convertJpegToPS()
00708  *          allow you to control placement of jpeg images on multiple
00709  *          pages within a PostScript file.
00710  *      (3) For the first image written to a file, use "w", which
00711  *          opens for write and clears the file.  For all subsequent
00712  *          images written to that file, use "a".
00713  *      (4) The (x, y) parameters give the LL corner of the image
00714  *          relative to the LL corner of the page.  They are in
00715  *          units of pixels if scale = 1.0.  If you use (e.g.)
00716  *          scale = 2.0, the image is placed at (2x, 2y) on the page,
00717  *          and the image dimensions are also doubled.
00718  *      (5) Display vs printed resolution:
00719  *           * If your display is 75 ppi and your image was created
00720  *             at a resolution of 300 ppi, you can get the image
00721  *             to print at the same size as it appears on your display
00722  *             by either setting scale = 4.0 or by setting  res = 75.
00723  *             Both tell the printer to make a 4x enlarged image.
00724  *           * If your image is generated at 150 ppi and you use scale = 1,
00725  *             it will be rendered such that 150 pixels correspond
00726  *             to 72 pts (1 inch on the printer).  This function does
00727  *             the conversion from pixels (with or without scaling) to
00728  *             pts, which are the units that the printer uses.
00729  *           * The printer will choose its own resolution to use
00730  *             in rendering the image, which will not affect the size
00731  *             of the rendered image.  That is because the output
00732  *             PostScript file describes the geometry in terms of pts,
00733  *             which are defined to be 1/72 inch.  The printer will
00734  *             only see the size of the image in pts, through the
00735  *             scale and translate parameters and the affine
00736  *             transform (the ImageMatrix) of the image.
00737  *      (6) To render multiple images on the same page, set
00738  *          endpage = FALSE for each image until you get to the
00739  *          last, for which you set endpage = TRUE.  This causes the
00740  *          "showpage" command to be invoked.  Showpage outputs
00741  *          the entire page and clears the raster buffer for the
00742  *          next page to be added.  Without a "showpage",
00743  *          subsequent images from the next page will overlay those
00744  *          previously put down.
00745  *      (7) For multiple pages, increment the page number, starting
00746  *          with page 1.  This allows PostScript (and PDF) to build
00747  *          a page directory, which viewers use for navigation.
00748  */
00749 l_int32
00750 convertJpegToPS(const char  *filein,
00751                 const char  *fileout,
00752                 const char  *operation,
00753                 l_int32      x,
00754                 l_int32      y,
00755                 l_int32      res,
00756                 l_float32    scale,
00757                 l_int32      pageno,
00758                 l_int32      endpage)
00759 {
00760 char    *outstr;
00761 l_int32  nbytes;
00762 
00763     PROCNAME("convertJpegToPS");
00764 
00765     if (!filein)
00766         return ERROR_INT("filein not defined", procName, 1);
00767     if (!fileout)
00768         return ERROR_INT("fileout not defined", procName, 1);
00769     if (strcmp(operation, "w") && strcmp(operation, "a"))
00770         return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1);
00771 
00772     if (convertJpegToPSString(filein, &outstr, &nbytes, x, y, res, scale,
00773                           pageno, endpage))
00774         return ERROR_INT("ps string not made", procName, 1);
00775 
00776     if (l_binaryWrite(fileout, operation, outstr, nbytes))
00777         return ERROR_INT("ps string not written to file", procName, 1);
00778 
00779     FREE(outstr);
00780     return 0;
00781 }
00782 
00783 
00784 /*!
00785  *  convertJpegToPSString()
00786  *
00787  *      Generates PS string in jpeg format from jpeg file
00788  *
00789  *      Input:  filein (input jpeg file)
00790  *              &poutstr (<return> PS string)
00791  *              &nbytes (<return> number of bytes in PS string)
00792  *              x, y (location of LL corner of image, in pixels, relative
00793  *                    to the PostScript origin (0,0) at the LL corner
00794  *                    of the page)
00795  *              res (resolution of the input image, in ppi; use 0 for default)
00796  *              scale (scaling by printer; use 0.0 or 1.0 for no scaling)
00797  *              pageno (page number; must start with 1; you can use 0
00798  *                      if there is only one page)
00799  *              endpage (boolean: use TRUE if this is the last image to be
00800  *                       added to the page; FALSE otherwise)
00801  *      Return: 0 if OK, 1 on error
00802  *
00803  *  Notes:
00804  *      (1) For usage, see convertJpegToPS()
00805  */
00806 l_int32
00807 convertJpegToPSString(const char  *filein,
00808                       char       **poutstr,
00809                       l_int32     *pnbytes,
00810                       l_int32      x,
00811                       l_int32      y,
00812                       l_int32      res,
00813                       l_float32    scale,
00814                       l_int32      pageno,
00815                       l_int32      endpage)
00816 {
00817 char               *outstr;
00818 l_float32           xpt, ypt, wpt, hpt;
00819 L_COMPRESSED_DATA  *cid;
00820 
00821     PROCNAME("convertJpegToPSString");
00822 
00823     if (!poutstr)
00824         return ERROR_INT("&outstr not defined", procName, 1);
00825     if (!pnbytes)
00826         return ERROR_INT("&nbytes not defined", procName, 1);
00827     *poutstr = NULL;
00828     *pnbytes = 0;
00829     if (!filein)
00830         return ERROR_INT("filein not defined", procName, 1);
00831 
00832         /* Generate the ascii encoded jpeg data */
00833     if ((cid = l_generateJpegData(filein, 1)) == NULL)
00834         return ERROR_INT("jpeg data not made", procName, 1);
00835 
00836         /* Get scaled location in pts.  Guess the input scan resolution
00837          * based on the input parameter @res, the resolution data in
00838          * the pix, and the size of the image. */
00839     if (scale == 0.0)
00840         scale = 1.0;
00841     if (res <= 0) {
00842         if (cid->res > 0)
00843             res = cid->res;
00844         else
00845             res = DEFAULT_INPUT_RES;
00846     }
00847 
00848         /* Get scaled location in pts */
00849     if (scale == 0.0)
00850         scale = 1.0;
00851     if (res == 0)
00852         res = DEFAULT_INPUT_RES;
00853     xpt = scale * x * 72. / res;
00854     ypt = scale * y * 72. / res;
00855     wpt = scale * cid->w * 72. / res;
00856     hpt = scale * cid->h * 72. / res;
00857 
00858     if (pageno == 0)
00859         pageno = 1;
00860 
00861 #if  DEBUG_JPEG
00862     fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n",
00863             cid->w, cid->h, cid->bps, cid->spp);
00864     fprintf(stderr, "comp bytes = %d, nbytes85 = %d, ratio = %5.3f\n",
00865            cid->nbytescomp, cid->nbytes85,
00866            (l_float32)cid->nbytes85 / (l_float32)cid->nbytescomp);
00867     fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n",
00868              xpt, ypt, wpt, hpt);
00869 #endif   /* DEBUG_JPEG */
00870 
00871         /* Generate the PS */
00872     outstr = generateJpegPS(filein, cid, xpt, ypt, wpt, hpt, pageno, endpage);
00873     if (!outstr)
00874         return ERROR_INT("outstr not made", procName, 1);
00875     *poutstr = outstr;
00876     *pnbytes = strlen(outstr);
00877     compressed_dataDestroy(&cid);
00878     return 0;
00879 }
00880 
00881 
00882 /*!
00883  *  generateJpegPS()
00884  *
00885  *      Input:  filein (<optional> input jpeg filename; can be null)
00886  *              cid (jpeg compressed image data)
00887  *              xpt, ypt (location of LL corner of image, in pts, relative
00888  *                        to the PostScript origin (0,0) at the LL corner
00889  *                        of the page)
00890  *              wpt, hpt (rendered image size in pts)
00891  *              pageno (page number; must start with 1; you can use 0
00892  *                      if there is only one page.)
00893  *              endpage (boolean: use TRUE if this is the last image to be
00894  *                       added to the page; FALSE otherwise)
00895  *      Return: PS string, or null on error
00896  *
00897  *  Notes:
00898  *      (1) Low-level function.
00899  */
00900 char *
00901 generateJpegPS(const char         *filein,
00902                L_COMPRESSED_DATA  *cid,
00903                l_float32           xpt,
00904                l_float32           ypt,
00905                l_float32           wpt,
00906                l_float32           hpt,
00907                l_int32             pageno,
00908                l_int32             endpage)
00909 {
00910 l_int32  w, h, bps, spp;
00911 char    *outstr;
00912 char     bigbuf[L_BUF_SIZE];
00913 SARRAY  *sa;
00914 
00915     PROCNAME("generateJpegPS");
00916 
00917     if (!cid)
00918         return (char *)ERROR_PTR("jpeg data not defined", procName, NULL);
00919     w = cid->w;
00920     h = cid->h;
00921     bps = cid->bps;
00922     spp = cid->spp;
00923 
00924     if ((sa = sarrayCreate(50)) == NULL)
00925         return (char *)ERROR_PTR("sa not made", procName, NULL);
00926 
00927     sarrayAddString(sa, (char *)"%!PS-Adobe-3.0", L_COPY);
00928     sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY);
00929     if (filein) {
00930         sprintf(bigbuf, "%%%%Title: %s", filein);
00931         sarrayAddString(sa, bigbuf, L_COPY);
00932     }
00933     sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY);
00934 
00935     if (var_PS_WRITE_BOUNDING_BOX == 1) {
00936         sprintf(bigbuf,
00937             "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
00938                        xpt, ypt, xpt + wpt, ypt + hpt);
00939         sarrayAddString(sa, bigbuf, L_COPY);
00940     }
00941 
00942     sarrayAddString(sa, (char *)"%%LanguageLevel: 2", L_COPY);
00943     sarrayAddString(sa, (char *)"%%EndComments", L_COPY);
00944     sprintf(bigbuf, "%%%%Page: %d %d", pageno, pageno);
00945     sarrayAddString(sa, bigbuf, L_COPY);
00946 
00947     sarrayAddString(sa, (char *)"save", L_COPY);
00948     sarrayAddString(sa,
00949            (char *)"/RawData currentfile /ASCII85Decode filter def", L_COPY);
00950     sarrayAddString(sa,
00951            (char *)"/Data RawData << >> /DCTDecode filter def", L_COPY);
00952 
00953     sprintf(bigbuf,
00954         "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
00955     sarrayAddString(sa, bigbuf, L_COPY);
00956 
00957     sprintf(bigbuf,
00958         "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
00959     sarrayAddString(sa, bigbuf, L_COPY);
00960 
00961     if (spp == 1)
00962         sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY);
00963     else if (spp == 3)
00964         sarrayAddString(sa, (char *)"/DeviceRGB setcolorspace", L_COPY);
00965     else  /*spp == 4 */
00966         sarrayAddString(sa, (char *)"/DeviceCMYK setcolorspace", L_COPY);
00967 
00968     sarrayAddString(sa, (char *)"{ << /ImageType 1", L_COPY);
00969     sprintf(bigbuf, "     /Width %d", w);
00970     sarrayAddString(sa, bigbuf, L_COPY);
00971     sprintf(bigbuf, "     /Height %d", h);
00972     sarrayAddString(sa, bigbuf, L_COPY);
00973     sprintf(bigbuf, "     /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
00974     sarrayAddString(sa, bigbuf, L_COPY);
00975     sarrayAddString(sa, (char *)"     /DataSource Data", L_COPY);
00976     sprintf(bigbuf, "     /BitsPerComponent %d", bps);
00977     sarrayAddString(sa, bigbuf, L_COPY);
00978 
00979     if (spp == 1)
00980         sarrayAddString(sa, (char *)"     /Decode [0 1]", L_COPY);
00981     else if (spp == 3)
00982         sarrayAddString(sa, (char *)"     /Decode [0 1 0 1 0 1]", L_COPY);
00983     else   /* spp == 4 */
00984         sarrayAddString(sa, (char *)"     /Decode [0 1 0 1 0 1 0 1]", L_COPY);
00985 
00986     sarrayAddString(sa, (char *)"  >> image", L_COPY);
00987     sarrayAddString(sa, (char *)"  Data closefile", L_COPY);
00988     sarrayAddString(sa, (char *)"  RawData flushfile", L_COPY);
00989     if (endpage == TRUE)
00990         sarrayAddString(sa, (char *)"  showpage", L_COPY);
00991     sarrayAddString(sa, (char *)"  restore", L_COPY);
00992     sarrayAddString(sa, (char *)"} exec", L_COPY);
00993 
00994         /* Insert the ascii85 jpeg data; this is now owned by sa */
00995     sarrayAddString(sa, cid->data85, L_INSERT);
00996     cid->data85 = NULL;  /* it has been transferred and destroyed */
00997 
00998         /* Generate and return the output string */
00999     outstr = sarrayToString(sa, 1);
01000     sarrayDestroy(&sa);
01001     return outstr;
01002 }
01003 
01004 
01005 /*!
01006  *  pixGenerateJpegData()
01007  *
01008  *      Input:  pixs (8 or 32 bpp, no colormap)
01009  *              ascii85flag (0 for jpeg; 1 for ascii85-encoded jpeg)
01010  *              quality (0 for default, which is 75)
01011  *      Return: cid (jpeg compressed data), or null on error
01012  *
01013  *  Notes:
01014  *      (1) Set ascii85flag:
01015  *           - 0 for binary data (not permitted in PostScript)
01016  *           - 1 for ascii85 (5 for 4) encoded binary data
01017  */
01018 L_COMPRESSED_DATA *
01019 pixGenerateJpegData(PIX     *pixs,
01020                     l_int32  ascii85flag,
01021                     l_int32  quality)
01022 {
01023 l_int32             d;
01024 char               *tname;
01025 L_COMPRESSED_DATA  *cid;
01026 
01027     PROCNAME("pixGenerateJpegData");
01028 
01029     if (!pixs)
01030         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not defined",
01031                                               procName, NULL);
01032     if (pixGetColormap(pixs))
01033         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs has colormap",
01034                                               procName, NULL);
01035     d = pixGetDepth(pixs);
01036     if (d != 8 && d != 32)
01037         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not 8 or 32 bpp",
01038                                               procName, NULL);
01039 
01040         /* Compress to a temp jpeg file */
01041     tname = genTempFilename("/tmp", "temp.jpg", 1, 1);
01042     pixWriteJpeg(tname, pixs, quality, 0);
01043 
01044     cid = l_generateJpegData(tname, ascii85flag);
01045     FREE(tname);
01046     return cid;
01047 }
01048 
01049 
01050 /*!
01051  *  l_generateJpegData()
01052  *
01053  *      Input:  fname (of jpeg file)
01054  *              ascii85flag (0 for jpeg; 1 for ascii85-encoded jpeg)
01055  *      Return: cid (containing jpeg data), or null on error
01056  *
01057  *  Notes:
01058  *      (1) Set ascii85flag:
01059  *           - 0 for binary data (not permitted in PostScript)
01060  *           - 1 for ascii85 (5 for 4) encoded binary data
01061  */
01062 L_COMPRESSED_DATA *
01063 l_generateJpegData(const char  *fname,
01064                    l_int32      ascii85flag)
01065 {
01066 l_uint8            *datacomp = NULL;  /* entire jpeg compressed file */
01067 char               *data85 = NULL;  /* ascii85 encoded jpeg compressed file */
01068 l_int32             w, h, xres, yres, bps, spp;
01069 l_int32             nbytes85;
01070 size_t              nbytescomp;
01071 FILE               *fp;
01072 L_COMPRESSED_DATA  *cid;
01073 
01074     PROCNAME("l_generateJpegData");
01075 
01076     if (!fname)
01077         return (L_COMPRESSED_DATA *)ERROR_PTR("fname not defined",
01078                                               procName, NULL);
01079 
01080         /* The returned jpeg data in memory is the entire jpeg file,
01081          * which starts with ffd8 and ends with ffd9 */
01082     if ((datacomp = l_binaryRead(fname, &nbytescomp)) == NULL)
01083         return (L_COMPRESSED_DATA *)ERROR_PTR("datacomp not extracted",
01084                                               procName, NULL);
01085 
01086         /* Read the metadata */
01087     if ((fp = fopenReadStream(fname)) == NULL)
01088         return (L_COMPRESSED_DATA *)ERROR_PTR("stream not opened",
01089                                               procName, NULL);
01090     freadHeaderJpeg(fp, &w, &h, &spp, NULL, NULL);
01091     bps = 8;
01092     fgetJpegResolution(fp, &xres, &yres);
01093     fclose(fp);
01094 
01095         /* Optionally, encode the compressed data */
01096     if (ascii85flag == 1) {
01097         data85 = encodeAscii85(datacomp, nbytescomp, &nbytes85);
01098         FREE(datacomp);
01099         if (!data85)
01100             return (L_COMPRESSED_DATA *)ERROR_PTR("data85 not made",
01101                                                   procName, NULL);
01102         else
01103             data85[nbytes85 - 1] = '\0';  /* remove the newline */
01104     }
01105 
01106     cid = (L_COMPRESSED_DATA *)CALLOC(1, sizeof(L_COMPRESSED_DATA));
01107     if (!cid)
01108         return (L_COMPRESSED_DATA *)ERROR_PTR("cid not made", procName, NULL);
01109     if (ascii85flag == 0)
01110         cid->datacomp = datacomp;
01111     else {  /* ascii85 */
01112         cid->data85 = data85;
01113         cid->nbytes85 = nbytes85;
01114     }
01115     cid->type = L_JPEG_ENCODE;
01116     cid->nbytescomp = nbytescomp;
01117     cid->w = w;
01118     cid->h = h;
01119     cid->bps = bps;
01120     cid->spp = spp;
01121     cid->res = xres;
01122     return cid;
01123 }
01124 
01125 
01126 /*!
01127  *  compressed_dataDestroy()
01128  *
01129  *      Input:  &cid (<will be set to null before returning>)
01130  *      Return: void
01131  */
01132 void
01133 compressed_dataDestroy(L_COMPRESSED_DATA  **pcid)
01134 {
01135 L_COMPRESSED_DATA  *cid;
01136 
01137     PROCNAME("compressed_dataDestroy");
01138 
01139     if (pcid == NULL) {
01140         L_WARNING("ptr address is null!", procName);
01141         return;
01142     }
01143     if ((cid = *pcid) == NULL)
01144         return;
01145 
01146     if (cid->datacomp) FREE(cid->datacomp);
01147     if (cid->data85) FREE(cid->data85);
01148     if (cid->cmapdata85) FREE(cid->cmapdata85);
01149     if (cid->cmapdatahex) FREE(cid->cmapdatahex);
01150     FREE(cid);
01151     *pcid = NULL;
01152     return;
01153 }
01154 
01155 
01156 /*-------------------------------------------------------------*
01157  *                  For ccitt g4 compressed images             *
01158  *-------------------------------------------------------------*/
01159 /*!
01160  *  convertG4ToPSEmbed()
01161  *
01162  *      Input:  filein (input tiff file)
01163  *              fileout (output ps file)
01164  *      Return: 0 if OK, 1 on error
01165  *
01166  *  Notes:
01167  *      (1) This function takes a g4 compressed tif file as input and
01168  *          generates a g4 compressed, ascii85 encoded PS file, with
01169  *          a bounding box.
01170  *      (2) The bounding box is required when a program such as TeX
01171  *          (through epsf) places and rescales the image.
01172  *      (3) The bounding box is sized for fitting the image to an
01173  *          8.5 x 11.0 inch page.
01174  *      (4) We paint this through a mask, over whatever is below.
01175  */
01176 l_int32
01177 convertG4ToPSEmbed(const char  *filein,
01178                    const char  *fileout)
01179 {
01180 char               *outstr;
01181 l_int32             w, h, nbytes;
01182 l_float32           xpt, ypt, wpt, hpt;
01183 L_COMPRESSED_DATA  *cid;
01184 
01185     PROCNAME("convertG4ToPSEmbed");
01186 
01187     if (!filein)
01188         return ERROR_INT("filein not defined", procName, 1);
01189     if (!fileout)
01190         return ERROR_INT("fileout not defined", procName, 1);
01191 
01192     if ((cid = l_generateG4Data(filein, 1)) == NULL)
01193         return ERROR_INT("g4 data not made", procName, 1);
01194     w = cid->w;
01195     h = cid->h;
01196 
01197         /* Scale for 20 pt boundary and otherwise full filling
01198          * in one direction on 8.5 x 11 inch device */
01199     xpt = 20.0;
01200     ypt = 20.0;
01201     if (w * 11.0 > h * 8.5) {
01202         wpt = 572.0;   /* 612 - 2 * 20 */
01203         hpt = wpt * (l_float32)h / (l_float32)w;
01204     }
01205     else {
01206         hpt = 752.0;   /* 792 - 2 * 20 */
01207         wpt = hpt * (l_float32)w / (l_float32)h;
01208     }
01209 
01210         /* Generate the PS, painting through the image mask.
01211          * The bounding box information should be inserted (default). */
01212     outstr = generateG4PS(filein, cid, xpt, ypt, wpt, hpt, 1, 1, 1);
01213     if (!outstr)
01214         return ERROR_INT("outstr not made", procName, 1);
01215     nbytes = strlen(outstr);
01216 
01217     if (l_binaryWrite(fileout, "w", outstr, nbytes))
01218         return ERROR_INT("ps string not written to file", procName, 1);
01219     FREE(outstr);
01220     compressed_dataDestroy(&cid);
01221     return 0;
01222 }
01223     
01224 
01225 /*!
01226  *  convertG4ToPS()
01227  *
01228  *      Input:  filein (input tiff g4 file)
01229  *              fileout (output ps file)
01230  *              operation ("w" for write; "a" for append)
01231  *              x, y (location of LL corner of image, in pixels, relative
01232  *                    to the PostScript origin (0,0) at the LL corner
01233  *                    of the page)
01234  *              res (resolution of the input image, in ppi; typ. values
01235  *                   are 300 and 600; use 0 for automatic determination
01236  *                   based on image size)
01237  *              scale (scaling by printer; use 0.0 or 1.0 for no scaling)
01238  *              pageno (page number; must start with 1; you can use 0
01239  *                      if there is only one page.)
01240  *              maskflag (boolean: use TRUE if just painting through fg;
01241  *                        FALSE if painting both fg and bg.
01242  *              endpage (boolean: use TRUE if this is the last image to be
01243  *                       added to the page; FALSE otherwise)
01244  *      Return: 0 if OK, 1 on error
01245  *
01246  *  Notes:
01247  *      (1) See the usage comments in convertJpegToPS(), some of
01248  *          which are repeated here.
01249  *      (2) This is a wrapper for tiff g4.  The PostScript that
01250  *          is generated is expanded by about 5/4 (due to the
01251  *          ascii85 encoding.  If you convert to pdf (ps2pdf), the
01252  *          ascii85 decoder is automatically invoked, so that the
01253  *          pdf wrapped g4 file is essentially the same size as
01254  *          the original g4 file.  It's useful to have the PS
01255  *          file ascii85 encoded, because many printers will not
01256  *          print binary PS files.
01257  *      (3) For the first image written to a file, use "w", which
01258  *          opens for write and clears the file.  For all subsequent
01259  *          images written to that file, use "a".
01260  *      (4) To render multiple images on the same page, set
01261  *          endpage = FALSE for each image until you get to the
01262  *          last, for which you set endpage = TRUE.  This causes the
01263  *          "showpage" command to be invoked.  Showpage outputs
01264  *          the entire page and clears the raster buffer for the
01265  *          next page to be added.  Without a "showpage",
01266  *          subsequent images from the next page will overlay those
01267  *          previously put down.
01268  *      (5) For multiple images to the same page, where you are writing
01269  *          both jpeg and tiff-g4, you have two options:
01270  *           (a) write the g4 first, as either image (maskflag == FALSE)
01271  *               or imagemask (maskflag == TRUE), and then write the
01272  *               jpeg over it.
01273  *           (b) write the jpeg first and as the last item, write
01274  *               the g4 as an imagemask (maskflag == TRUE), to paint
01275  *               through the foreground only.  
01276  *          We have this flexibility with the tiff-g4 because it is 1 bpp.
01277  *      (6) For multiple pages, increment the page number, starting
01278  *          with page 1.  This allows PostScript (and PDF) to build
01279  *          a page directory, which viewers use for navigation.
01280  */
01281 l_int32
01282 convertG4ToPS(const char  *filein,
01283               const char  *fileout,
01284               const char  *operation,
01285               l_int32      x,
01286               l_int32      y,
01287               l_int32      res,
01288               l_float32    scale,
01289               l_int32      pageno,
01290               l_int32      maskflag,
01291               l_int32      endpage)
01292 {
01293 char    *outstr;
01294 l_int32  nbytes;
01295 
01296     PROCNAME("convertG4ToPS");
01297 
01298     if (!filein)
01299         return ERROR_INT("filein not defined", procName, 1);
01300     if (!fileout)
01301         return ERROR_INT("fileout not defined", procName, 1);
01302     if (strcmp(operation, "w") && strcmp(operation, "a"))
01303         return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1);
01304 
01305     if (convertG4ToPSString(filein, &outstr, &nbytes, x, y, res, scale,
01306                             pageno, maskflag, endpage))
01307         return ERROR_INT("ps string not made", procName, 1);
01308 
01309     if (l_binaryWrite(fileout, operation, outstr, nbytes))
01310         return ERROR_INT("ps string not written to file", procName, 1);
01311 
01312     FREE(outstr);
01313     return 0;
01314 }
01315 
01316 
01317 /*!
01318  *  convertG4ToPSString()
01319  *
01320  *      Input:  filein (input tiff g4 file)
01321  *              &poutstr (<return> PS string)
01322  *              &nbytes (<return> number of bytes in PS string)
01323  *              x, y (location of LL corner of image, in pixels, relative
01324  *                    to the PostScript origin (0,0) at the LL corner
01325  *                    of the page)
01326  *              res (resolution of the input image, in ppi; typ. values
01327  *                   are 300 and 600; use 0 for automatic determination
01328  *                   based on image size)
01329  *              scale (scaling by printer; use 0.0 or 1.0 for no scaling)
01330  *              pageno (page number; must start with 1; you can use 0
01331  *                      if there is only one page.)
01332  *              maskflag (boolean: use TRUE if just painting through fg;
01333  *                        FALSE if painting both fg and bg.
01334  *              endpage (boolean: use TRUE if this is the last image to be
01335  *                       added to the page; FALSE otherwise)
01336  *      Return: 0 if OK, 1 on error
01337  *
01338  *  Notes:
01339  *      (1) Generates PS string in G4 compressed tiff format from G4 tiff file.
01340  *      (2) For usage, see convertG4ToPS().
01341  */
01342 l_int32
01343 convertG4ToPSString(const char  *filein,
01344                     char       **poutstr,
01345                     l_int32     *pnbytes,
01346                     l_int32      x,
01347                     l_int32      y,
01348                     l_int32      res,
01349                     l_float32    scale,
01350                     l_int32      pageno,
01351                     l_int32      maskflag,
01352                     l_int32      endpage)
01353 {
01354 char               *outstr;
01355 l_float32           xpt, ypt, wpt, hpt;
01356 L_COMPRESSED_DATA  *cid;
01357 
01358     PROCNAME("convertG4ToPSString");
01359 
01360     if (!poutstr)
01361         return ERROR_INT("&outstr not defined", procName, 1);
01362     if (!pnbytes)
01363         return ERROR_INT("&nbytes not defined", procName, 1);
01364     *poutstr = NULL;
01365     *pnbytes = 0;
01366     if (!filein)
01367         return ERROR_INT("filein not defined", procName, 1);
01368 
01369     if ((cid = l_generateG4Data(filein, 1)) == NULL)
01370         return ERROR_INT("g4 data not made", procName, 1);
01371 
01372         /* Get scaled location in pts.  Guess the input scan resolution
01373          * based on the input parameter @res, the resolution data in
01374          * the pix, and the size of the image. */
01375     if (scale == 0.0)
01376         scale = 1.0;
01377     if (res <= 0) {
01378         if (cid->res > 0)
01379             res = cid->res;
01380         else {
01381             if (cid->h <= 3509)  /* A4 height at 300 ppi */
01382                 res = 300;
01383             else
01384                 res = 600;
01385         }
01386     }
01387     xpt = scale * x * 72. / res;
01388     ypt = scale * y * 72. / res;
01389     wpt = scale * cid->w * 72. / res;
01390     hpt = scale * cid->h * 72. / res;
01391 
01392     if (pageno == 0)
01393         pageno = 1;
01394 
01395 #if  DEBUG_G4
01396     fprintf(stderr, "w = %d, h = %d, minisblack = %d\n",
01397             cid->w, cid->h, cid->minisblack);
01398     fprintf(stderr, "comp bytes = %d, nbytes85 = %d\n",
01399             cid->nbytescomp, cid->nbytes85);
01400     fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n",
01401              xpt, ypt, wpt, hpt);
01402 #endif   /* DEBUG_G4 */
01403 
01404         /* Generate the PS */
01405     outstr = generateG4PS(filein, cid, xpt, ypt, wpt, hpt,
01406                           maskflag, pageno, endpage);
01407     if (!outstr)
01408         return ERROR_INT("outstr not made", procName, 1);
01409     *poutstr = outstr;
01410     *pnbytes = strlen(outstr);
01411     compressed_dataDestroy(&cid);
01412     return 0;
01413 }
01414 
01415 
01416 /*!
01417  *  generateG4PS()
01418  *
01419  *      Input:  filein (<optional> input tiff g4 file; can be null)
01420  *              cid (g4 compressed image data)
01421  *              xpt, ypt (location of LL corner of image, in pts, relative
01422  *                        to the PostScript origin (0,0) at the LL corner
01423  *                        of the page)
01424  *              wpt, hpt (rendered image size in pts)
01425  *              maskflag (boolean: use TRUE if just painting through fg;
01426  *                        FALSE if painting both fg and bg.
01427  *              pageno (page number; must start with 1; you can use 0
01428  *                      if there is only one page.)
01429  *              endpage (boolean: use TRUE if this is the last image to be
01430  *                       added to the page; FALSE otherwise)
01431  *      Return: PS string, or null on error
01432  *
01433  *  Notes:
01434  *      (1) Low-level function.
01435  */
01436 char *
01437 generateG4PS(const char         *filein,
01438              L_COMPRESSED_DATA  *cid,
01439              l_float32           xpt,
01440              l_float32           ypt,
01441              l_float32           wpt,
01442              l_float32           hpt,
01443              l_int32             maskflag,
01444              l_int32             pageno,
01445              l_int32             endpage)
01446 {
01447 l_int32  w, h;
01448 char    *outstr;
01449 char     bigbuf[L_BUF_SIZE];
01450 SARRAY  *sa;
01451 
01452     PROCNAME("generateG4PS");
01453 
01454     if (!cid)
01455         return (char *)ERROR_PTR("g4 data not defined", procName, NULL);
01456     w = cid->w;
01457     h = cid->h;
01458 
01459     if ((sa = sarrayCreate(50)) == NULL)
01460         return (char *)ERROR_PTR("sa not made", procName, NULL);
01461 
01462     sarrayAddString(sa, (char *)"%!PS-Adobe-3.0", L_COPY);
01463     sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY);
01464     if (filein) {
01465         sprintf(bigbuf, "%%%%Title: %s", filein);
01466         sarrayAddString(sa, bigbuf, L_COPY);
01467     }
01468     sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY);
01469 
01470     if (var_PS_WRITE_BOUNDING_BOX == 1) {
01471         sprintf(bigbuf,
01472             "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
01473                     xpt, ypt, xpt + wpt, ypt + hpt);
01474         sarrayAddString(sa, bigbuf, L_COPY);
01475     }
01476 
01477     sarrayAddString(sa, (char *)"%%LanguageLevel: 2", L_COPY);
01478     sarrayAddString(sa, (char *)"%%EndComments", L_COPY);
01479     sprintf(bigbuf, "%%%%Page: %d %d", pageno, pageno);
01480     sarrayAddString(sa, bigbuf, L_COPY);
01481 
01482     sarrayAddString(sa, (char *)"save", L_COPY);
01483     sarrayAddString(sa, (char *)"100 dict begin", L_COPY);
01484 
01485     sprintf(bigbuf,
01486         "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
01487     sarrayAddString(sa, bigbuf, L_COPY);
01488 
01489     sprintf(bigbuf,
01490         "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
01491     sarrayAddString(sa, bigbuf, L_COPY);
01492 
01493     sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY);
01494 
01495     sarrayAddString(sa, (char *)"{", L_COPY);
01496     sarrayAddString(sa,
01497           (char *)"  /RawData currentfile /ASCII85Decode filter def", L_COPY);
01498     sarrayAddString(sa, (char *)"  << ", L_COPY);
01499     sarrayAddString(sa, (char *)"    /ImageType 1", L_COPY);
01500     sprintf(bigbuf, "    /Width %d", w);
01501     sarrayAddString(sa, bigbuf, L_COPY);
01502     sprintf(bigbuf, "    /Height %d", h);
01503     sarrayAddString(sa, bigbuf, L_COPY);
01504     sprintf(bigbuf, "    /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
01505     sarrayAddString(sa, bigbuf, L_COPY);
01506     sarrayAddString(sa, (char *)"    /BitsPerComponent 1", L_COPY);
01507     sarrayAddString(sa, (char *)"    /Interpolate true", L_COPY);
01508     if (cid->minisblack)
01509         sarrayAddString(sa, (char *)"    /Decode [1 0]", L_COPY);
01510     else  /* miniswhite; typical for 1 bpp */
01511         sarrayAddString(sa, (char *)"    /Decode [0 1]", L_COPY);
01512     sarrayAddString(sa, (char *)"    /DataSource RawData", L_COPY);
01513     sarrayAddString(sa, (char *)"        <<", L_COPY);
01514     sarrayAddString(sa, (char *)"          /K -1", L_COPY);
01515     sprintf(bigbuf, "          /Columns %d", w);
01516     sarrayAddString(sa, bigbuf, L_COPY);
01517     sprintf(bigbuf, "          /Rows %d", h);
01518     sarrayAddString(sa, bigbuf, L_COPY);
01519     sarrayAddString(sa, (char *)"        >> /CCITTFaxDecode filter", L_COPY);
01520     if (maskflag == TRUE)  /* just paint through the fg */
01521         sarrayAddString(sa, (char *)"  >> imagemask", L_COPY);
01522     else  /* Paint full image */
01523         sarrayAddString(sa, (char *)"  >> image", L_COPY);
01524     sarrayAddString(sa, (char *)"  RawData flushfile", L_COPY);
01525     if (endpage == TRUE)
01526         sarrayAddString(sa, (char *)"  showpage", L_COPY);
01527     sarrayAddString(sa, (char *)"}", L_COPY);
01528 
01529     sarrayAddString(sa, (char *)"%%BeginData:", L_COPY);
01530     sarrayAddString(sa, (char *)"exec", L_COPY);
01531 
01532         /* Insert the ascii85 ccittg4 data; this is now owned by sa */
01533     sarrayAddString(sa, cid->data85, L_INSERT);
01534 
01535         /* Concat the trailing data */
01536     sarrayAddString(sa, (char *)"%%EndData", L_COPY);
01537     sarrayAddString(sa, (char *)"end", L_COPY);
01538     sarrayAddString(sa, (char *)"restore", L_COPY);
01539 
01540     outstr = sarrayToString(sa, 1);
01541     sarrayDestroy(&sa);
01542     cid->data85 = NULL;  /* it has been transferred and destroyed */
01543     return outstr;
01544 }
01545 
01546 
01547 /*!
01548  *  pixGenerateG4Data()
01549  *
01550  *      Input:  pixs (1 bpp)
01551  *              ascii85flag (0 for gzipped; 1 for ascii85-encoded gzipped)
01552  *      Return: cid (g4 compressed image data), or null on error
01553  *
01554  *  Notes:
01555  *      (1) Set ascii85flag:
01556  *           - 0 for binary data (not permitted in PostScript)
01557  *           - 1 for ascii85 (5 for 4) encoded binary data
01558  */
01559 L_COMPRESSED_DATA *
01560 pixGenerateG4Data(PIX     *pixs,
01561                   l_int32  ascii85flag)
01562 {
01563 char               *tname;
01564 L_COMPRESSED_DATA  *cid;
01565 
01566     PROCNAME("pixGenerateG4Data");
01567 
01568     if (!pixs)
01569         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not defined",
01570                                               procName, NULL);
01571     if (pixGetDepth(pixs) != 1)
01572         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not 1 bpp",
01573                                               procName, NULL);
01574 
01575         /* Compress to a temp tiff g4 file */
01576     tname = genTempFilename("/tmp", "temp.tif", 1, 1);
01577     pixWrite(tname, pixs, IFF_TIFF_G4);
01578 
01579     cid = l_generateG4Data(tname, ascii85flag);
01580     FREE(tname);
01581     return cid;
01582 }
01583 
01584 
01585 /*!
01586  *  l_generateG4Data()
01587  *
01588  *      Input:  fname (of g4 compressed file)
01589  *              ascii85flag (0 for g4 compressed; 1 for ascii85-encoded g4)
01590  *      Return: cid (g4 compressed image data), or null on error
01591  *
01592  *  Notes:
01593  *      (1) Set ascii85flag:
01594  *           - 0 for binary data (not permitted in PostScript)
01595  *           - 1 for ascii85 (5 for 4) encoded binary data
01596  */
01597 L_COMPRESSED_DATA *
01598 l_generateG4Data(const char  *fname,
01599                  l_int32      ascii85flag)
01600 {
01601 l_uint8            *datacomp = NULL;  /* g4 compressed raster data */
01602 char               *data85 = NULL;  /* ascii85 encoded g4 compressed data */
01603 l_int32             w, h, xres, yres;
01604 l_int32             minisblack;  /* TRUE or FALSE */
01605 l_int32             nbytes85;
01606 size_t              nbytescomp;
01607 L_COMPRESSED_DATA  *cid;
01608 FILE               *fp;
01609 
01610     PROCNAME("l_generateG4Data");
01611 
01612     if (!fname)
01613         return (L_COMPRESSED_DATA *)ERROR_PTR("fname not defined",
01614                                               procName, NULL);
01615 
01616         /* The returned ccitt g4 data in memory is the block of
01617          * bytes in the tiff file, starting after 8 bytes and
01618          * ending before the directory. */
01619     if (extractG4DataFromFile(fname, &datacomp, &nbytescomp,
01620                               &w, &h, &minisblack)) {
01621         return (L_COMPRESSED_DATA *)ERROR_PTR("datacomp not extracted",
01622                                               procName, NULL);
01623     }
01624 
01625         /* Read the resolution */
01626     if ((fp = fopenReadStream(fname)) == NULL)
01627         return (L_COMPRESSED_DATA *)ERROR_PTR("stream not opened",
01628                                               procName, NULL);
01629     getTiffResolution(fp, &xres, &yres);
01630     fclose(fp);
01631 
01632         /* Optionally, encode the compressed data */
01633     if (ascii85flag == 1) {
01634         data85 = encodeAscii85(datacomp, nbytescomp, &nbytes85);
01635         FREE(datacomp);
01636         if (!data85)
01637             return (L_COMPRESSED_DATA *)ERROR_PTR("data85 not made",
01638                                                   procName, NULL);
01639         else
01640             data85[nbytes85 - 1] = '\0';  /* remove the newline */
01641     }
01642 
01643     cid = (L_COMPRESSED_DATA *)CALLOC(1, sizeof(L_COMPRESSED_DATA));
01644     if (!cid)
01645         return (L_COMPRESSED_DATA *)ERROR_PTR("cid not made", procName, NULL);
01646     if (ascii85flag == 0)
01647         cid->datacomp = datacomp;
01648     else {  /* ascii85 */
01649         cid->data85 = data85;
01650         cid->nbytes85 = nbytes85;
01651     }
01652     cid->type = L_G4_ENCODE;
01653     cid->nbytescomp = nbytescomp;
01654     cid->w = w;
01655     cid->h = h;
01656     cid->minisblack = minisblack;
01657     cid->res = xres;
01658     return cid;
01659 }
01660 
01661 
01662 /*-------------------------------------------------------------*
01663  *                     For tiff multipage files                *
01664  *-------------------------------------------------------------*/
01665 /*!
01666  *  convertTiffMultipageToPS()
01667  *
01668  *      Input:  filein (input tiff multipage file)
01669  *              fileout (output ps file)
01670  *              tempfile (<optional> for temporary g4 tiffs;
01671  *                        use NULL for default)
01672  *              factor (for filling 8.5 x 11 inch page;
01673  *                      use 0.0 for DEFAULT_FILL_FRACTION)
01674  *      Return: 0 if OK, 1 on error
01675  *
01676  *  Notes:
01677  *      (1) This converts a multipage tiff file of binary page images
01678  *          into a ccitt g4 compressed PS file.
01679  *      (2) If the images are generated from a standard resolution fax,
01680  *          the vertical resolution is doubled to give a normal-looking
01681  *          aspect ratio.
01682  */
01683 l_int32
01684 convertTiffMultipageToPS(const char  *filein,
01685                          const char  *fileout,
01686                          const char  *tempfile,
01687                          l_float32    fillfract)
01688 {
01689 const char   tempdefault[] = "/tmp/junk_temp_g4.tif";
01690 const char  *tempname;
01691 l_int32      i, npages, w, h, istiff;
01692 l_float32    scale;
01693 PIX         *pix, *pixs;
01694 FILE        *fp;
01695 
01696     PROCNAME("convertTiffMultipageToPS");
01697 
01698     if (!filein)
01699         return ERROR_INT("filein not defined", procName, 1);
01700     if (!fileout)
01701         return ERROR_INT("fileout not defined", procName, 1);
01702 
01703     if ((fp = fopenReadStream(filein)) == NULL)
01704         return ERROR_INT("file not found", procName, 1);
01705     istiff = fileFormatIsTiff(fp);
01706     if (!istiff) {
01707         fclose(fp);
01708         return ERROR_INT("file not tiff format", procName, 1);
01709     }
01710     tiffGetCount(fp, &npages);
01711     fclose(fp);
01712 
01713     if (tempfile)
01714         tempname = tempfile;
01715     else
01716         tempname = tempdefault;
01717 
01718     if (fillfract == 0.0)
01719         fillfract = DEFAULT_FILL_FRACTION;
01720 
01721     for (i = 0; i < npages; i++) {
01722         if ((pix = pixReadTiff(filein, i)) == NULL)
01723              return ERROR_INT("pix not made", procName, 1);
01724 
01725         w = pixGetWidth(pix);
01726         h = pixGetHeight(pix);
01727         if (w == 1728 && h < w)   /* it's a std res fax */
01728             pixs = pixScale(pix, 1.0, 2.0);
01729         else
01730             pixs = pixClone(pix);
01731 
01732         pixWrite(tempname, pixs, IFF_TIFF_G4);
01733         scale = L_MIN(fillfract * 2550 / w, fillfract * 3300 / h);
01734         if (i == 0)
01735             convertG4ToPS(tempname, fileout, "w", 0, 0, 300, scale,
01736                           i + 1, FALSE, TRUE);
01737         else
01738             convertG4ToPS(tempname, fileout, "a", 0, 0, 300, scale,
01739                           i + 1, FALSE, TRUE);
01740         pixDestroy(&pix);
01741         pixDestroy(&pixs);
01742     }
01743 
01744     return 0;
01745 }
01746 
01747 
01748 /*---------------------------------------------------------------------*
01749  *            For flate (gzip) compressed images (e.g., png)           *
01750  *---------------------------------------------------------------------*/
01751 /*!
01752  *  convertFlateToPSEmbed()
01753  *
01754  *      Input:  filein (input file -- any format)
01755  *              fileout (output ps file)
01756  *      Return: 0 if OK, 1 on error
01757  *
01758  *  Notes:
01759  *      (1) This function takes any image file as input and generates a
01760  *          flate-compressed, ascii85 encoded PS file, with a bounding box.
01761  *      (2) The bounding box is required when a program such as TeX
01762  *          (through epsf) places and rescales the image.
01763  *      (3) The bounding box is sized for fitting the image to an
01764  *          8.5 x 11.0 inch page.
01765  */
01766 l_int32
01767 convertFlateToPSEmbed(const char  *filein,
01768                       const char  *fileout)
01769 {
01770 char               *outstr;
01771 l_int32             w, h, nbytes;
01772 l_float32           xpt, ypt, wpt, hpt;
01773 L_COMPRESSED_DATA  *cid;
01774 
01775     PROCNAME("convertFlateToPSEmbed");
01776 
01777     if (!filein)
01778         return ERROR_INT("filein not defined", procName, 1);
01779     if (!fileout)
01780         return ERROR_INT("fileout not defined", procName, 1);
01781 
01782     if ((cid = l_generateFlateData(filein, 1)) == NULL)
01783         return ERROR_INT("flate data not made", procName, 1);
01784     w = cid->w;
01785     h = cid->h;
01786 
01787         /* Scale for 20 pt boundary and otherwise full filling
01788          * in one direction on 8.5 x 11 inch device */
01789     xpt = 20.0;
01790     ypt = 20.0;
01791     if (w * 11.0 > h * 8.5) {
01792         wpt = 572.0;   /* 612 - 2 * 20 */
01793         hpt = wpt * (l_float32)h / (l_float32)w;
01794     }
01795     else {
01796         hpt = 752.0;   /* 792 - 2 * 20 */
01797         wpt = hpt * (l_float32)w / (l_float32)h;
01798     }
01799 
01800         /* Generate the PS.
01801          * The bounding box information should be inserted (default). */
01802     outstr = generateFlatePS(filein, cid, xpt, ypt, wpt, hpt, 1, 1);
01803     if (!outstr)
01804         return ERROR_INT("outstr not made", procName, 1);
01805     nbytes = strlen(outstr);
01806 
01807     if (l_binaryWrite(fileout, "w", outstr, nbytes))
01808         return ERROR_INT("ps string not written to file", procName, 1);
01809     FREE(outstr);
01810     compressed_dataDestroy(&cid);
01811     return 0;
01812 }
01813 
01814 
01815 /*!
01816  *  convertFlateToPS()
01817  *
01818  *      Input:  filein (input file -- any format)
01819  *              fileout (output ps file)
01820  *              operation ("w" for write; "a" for append)
01821  *              x, y (location of LL corner of image, in pixels, relative
01822  *                    to the PostScript origin (0,0) at the LL corner
01823  *                    of the page)
01824  *              res (resolution of the input image, in ppi; use 0 for default)
01825  *              scale (scaling by printer; use 0.0 or 1.0 for no scaling)
01826  *              pageno (page number; must start with 1; you can use 0
01827  *                      if there is only one page.)
01828  *              endpage (boolean: use TRUE if this is the last image to be
01829  *                       added to the page; FALSE otherwise)
01830  *      Return: 0 if OK, 1 on error
01831  *
01832  *  Notes:
01833  *      (1) This outputs level 3 PS as flate compressed (overlaid
01834  *          with ascii85 encoding).
01835  *      (2) An output file can contain multiple pages, each with
01836  *          multiple images.  The arguments to convertFlateToPS()
01837  *          allow you to control placement of png images on multiple
01838  *          pages within a PostScript file.
01839  *      (3) For the first image written to a file, use "w", which
01840  *          opens for write and clears the file.  For all subsequent
01841  *          images written to that file, use "a".
01842  *      (4) The (x, y) parameters give the LL corner of the image
01843  *          relative to the LL corner of the page.  They are in
01844  *          units of pixels if scale = 1.0.  If you use (e.g.)
01845  *          scale = 2.0, the image is placed at (2x, 2y) on the page,
01846  *          and the image dimensions are also doubled.
01847  *      (5) Display vs printed resolution:
01848  *           * If your display is 75 ppi and your image was created
01849  *             at a resolution of 300 ppi, you can get the image
01850  *             to print at the same size as it appears on your display
01851  *             by either setting scale = 4.0 or by setting  res = 75.
01852  *             Both tell the printer to make a 4x enlarged image.
01853  *           * If your image is generated at 150 ppi and you use scale = 1,
01854  *             it will be rendered such that 150 pixels correspond
01855  *             to 72 pts (1 inch on the printer).  This function does
01856  *             the conversion from pixels (with or without scaling) to
01857  *             pts, which are the units that the printer uses.
01858  *           * The printer will choose its own resolution to use
01859  *             in rendering the image, which will not affect the size
01860  *             of the rendered image.  That is because the output
01861  *             PostScript file describes the geometry in terms of pts,
01862  *             which are defined to be 1/72 inch.  The printer will
01863  *             only see the size of the image in pts, through the
01864  *             scale and translate parameters and the affine
01865  *             transform (the ImageMatrix) of the image.
01866  *      (6) To render multiple images on the same page, set
01867  *          endpage = FALSE for each image until you get to the
01868  *          last, for which you set endpage = TRUE.  This causes the
01869  *          "showpage" command to be invoked.  Showpage outputs
01870  *          the entire page and clears the raster buffer for the
01871  *          next page to be added.  Without a "showpage",
01872  *          subsequent images from the next page will overlay those
01873  *          previously put down.
01874  *      (7) For multiple pages, increment the page number, starting
01875  *          with page 1.  This allows PostScript (and PDF) to build
01876  *          a page directory, which viewers use for navigation.
01877  */
01878 l_int32
01879 convertFlateToPS(const char  *filein,
01880                  const char  *fileout,
01881                  const char  *operation,
01882                  l_int32      x,
01883                  l_int32      y,
01884                  l_int32      res,
01885                  l_float32    scale,
01886                  l_int32      pageno,
01887                  l_int32      endpage)
01888 {
01889 char    *outstr;
01890 l_int32  nbytes;
01891 
01892     PROCNAME("convertFlateToPS");
01893 
01894     if (!filein)
01895         return ERROR_INT("filein not defined", procName, 1);
01896     if (!fileout)
01897         return ERROR_INT("fileout not defined", procName, 1);
01898     if (strcmp(operation, "w") && strcmp(operation, "a"))
01899         return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1);
01900 
01901     if (convertFlateToPSString(filein, &outstr, &nbytes, x, y, res, scale,
01902                                pageno, endpage))
01903         return ERROR_INT("ps string not made", procName, 1);
01904 
01905     if (l_binaryWrite(fileout, operation, outstr, nbytes))
01906         return ERROR_INT("ps string not written to file", procName, 1);
01907 
01908     FREE(outstr);
01909     return 0;
01910 }
01911 
01912 
01913 /*!
01914  *  convertFlateToPSString()
01915  *
01916  *      Generates level 3 PS string in flate compressed format.
01917  *
01918  *      Input:  filein (input image file)
01919  *              &poutstr (<return> PS string)
01920  *              &nbytes (<return> number of bytes in PS string)
01921  *              x, y (location of LL corner of image, in pixels, relative
01922  *                    to the PostScript origin (0,0) at the LL corner
01923  *                    of the page)
01924  *              res (resolution of the input image, in ppi; use 0 for default)
01925  *              scale (scaling by printer; use 0.0 or 1.0 for no scaling)
01926  *              pageno (page number; must start with 1; you can use 0
01927  *                      if there is only one page.)
01928  *              endpage (boolean: use TRUE if this is the last image to be
01929  *                       added to the page; FALSE otherwise)
01930  *      Return: 0 if OK, 1 on error
01931  *
01932  *  Notes:
01933  *      (1) The returned PS character array is a null-terminated
01934  *          ascii string.  All the raster data is ascii85 encoded, so
01935  *          there are no null bytes embedded in it.
01936  *      (2) The raster encoding is made with gzip, the same as that
01937  *          in a png file that is compressed without prediction.
01938  *          The raster data itself is 25% larger than that in the
01939  *          binary form, due to the ascii85 encoding.
01940  *
01941  *  Usage:  See convertFlateToPS()
01942  */
01943 l_int32
01944 convertFlateToPSString(const char  *filein,
01945                        char       **poutstr,
01946                        l_int32     *pnbytes,
01947                        l_int32      x,
01948                        l_int32      y,
01949                        l_int32      res,
01950                        l_float32    scale,
01951                        l_int32      pageno,
01952                        l_int32      endpage)
01953 {
01954 char               *outstr;
01955 l_float32           xpt, ypt, wpt, hpt;
01956 L_COMPRESSED_DATA  *cid;
01957 
01958     PROCNAME("convertFlateToPSString");
01959 
01960     if (!poutstr)
01961         return ERROR_INT("&outstr not defined", procName, 1);
01962     if (!pnbytes)
01963         return ERROR_INT("&nbytes not defined", procName, 1);
01964     *pnbytes = 0;
01965     *poutstr = NULL;
01966     if (!filein)
01967         return ERROR_INT("filein not defined", procName, 1);
01968 
01969     if ((cid = l_generateFlateData(filein, 1)) == NULL)
01970         return ERROR_INT("flate data not made", procName, 1);
01971 
01972         /* Get scaled location in pts.  Guess the input scan resolution
01973          * based on the input parameter @res, the resolution data in
01974          * the pix, and the size of the image. */
01975     if (scale == 0.0)
01976         scale = 1.0;
01977     if (res <= 0) {
01978         if (cid->res > 0)
01979             res = cid->res;
01980         else
01981             res = DEFAULT_INPUT_RES;
01982     }
01983     xpt = scale * x * 72. / res;
01984     ypt = scale * y * 72. / res;
01985     wpt = scale * cid->w * 72. / res;
01986     hpt = scale * cid->h * 72. / res;
01987 
01988     if (pageno == 0)
01989         pageno = 1;
01990 
01991 #if  DEBUG_FLATE
01992     fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n",
01993             cid->w, cid->h, cid->bps, cid->spp);
01994     fprintf(stderr, "uncomp bytes = %d, comp bytes = %d, nbytes85 = %d\n",
01995             cid->nbytes, cid->nbytescomp, cid->nbytes85);
01996     fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n",
01997              xpt, ypt, wpt, hpt);
01998 #endif   /* DEBUG_FLATE */
01999 
02000         /* Generate the PS */
02001     outstr = generateFlatePS(filein, cid, xpt, ypt, wpt, hpt, pageno, endpage);
02002     if (!outstr)
02003         return ERROR_INT("outstr not made", procName, 1);
02004     *poutstr = outstr;
02005     *pnbytes = strlen(outstr);
02006     compressed_dataDestroy(&cid);
02007     return 0;
02008 }
02009 
02010 
02011 /*!
02012  *  generateFlatePS()
02013  *
02014  *      Input:  filein (<optional> input filename; can be null)
02015  *              cid (flate compressed image data)
02016  *              xpt, ypt (location of LL corner of image, in pts, relative
02017  *                        to the PostScript origin (0,0) at the LL corner
02018  *                        of the page)
02019  *              wpt, hpt (rendered image size in pts)
02020  *              pageno (page number; must start with 1; you can use 0
02021  *                      if there is only one page)
02022  *              endpage (boolean: use TRUE if this is the last image to be
02023  *                       added to the page; FALSE otherwise)
02024  *      Return: PS string, or null on error
02025  */
02026 char *
02027 generateFlatePS(const char         *filein,
02028                 L_COMPRESSED_DATA  *cid,
02029                 l_float32           xpt,
02030                 l_float32           ypt,
02031                 l_float32           wpt,
02032                 l_float32           hpt,
02033                 l_int32             pageno,
02034                 l_int32             endpage)
02035 {
02036 l_int32  w, h, bps, spp;
02037 char    *outstr;
02038 char     bigbuf[L_BUF_SIZE];
02039 SARRAY  *sa;
02040 
02041     PROCNAME("generateFlatePS");
02042 
02043     if (!cid)
02044         return (char *)ERROR_PTR("flate data not defined", procName, NULL);
02045     w = cid->w;
02046     h = cid->h;
02047     bps = cid->bps;
02048     spp = cid->spp;
02049 
02050     if ((sa = sarrayCreate(50)) == NULL)
02051         return (char *)ERROR_PTR("sa not made", procName, NULL);
02052 
02053     sarrayAddString(sa, (char *)"%!PS-Adobe-3.0 EPSF-3.0", L_COPY);
02054     sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY);
02055     if (filein) {
02056         sprintf(bigbuf, "%%%%Title: %s", filein);
02057         sarrayAddString(sa, bigbuf, L_COPY);
02058     }
02059     sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY);
02060 
02061     if (var_PS_WRITE_BOUNDING_BOX == 1) {
02062         sprintf(bigbuf,
02063             "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
02064                        xpt, ypt, xpt + wpt, ypt + hpt);
02065         sarrayAddString(sa, bigbuf, L_COPY);
02066     }
02067 
02068     sarrayAddString(sa, (char *)"%%LanguageLevel: 3", L_COPY);
02069     sarrayAddString(sa, (char *)"%%EndComments", L_COPY);
02070     sprintf(bigbuf, "%%%%Page: %d %d", pageno, pageno);
02071     sarrayAddString(sa, bigbuf, L_COPY);
02072 
02073     sarrayAddString(sa, (char *)"save", L_COPY);
02074     sprintf(bigbuf,
02075         "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
02076     sarrayAddString(sa, bigbuf, L_COPY);
02077 
02078     sprintf(bigbuf,
02079         "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
02080     sarrayAddString(sa, bigbuf, L_COPY);
02081 
02082         /* If there is a colormap, add the data; it is now owned by sa */
02083     if (cid->cmapdata85) {
02084         sprintf(bigbuf,
02085              "[ /Indexed /DeviceRGB %d          %%set colormap type/size",
02086              cid->ncolors - 1);
02087         sarrayAddString(sa, bigbuf, L_COPY);
02088         sarrayAddString(sa, (char *)"  <~", L_COPY);
02089         sarrayAddString(sa, cid->cmapdata85, L_INSERT);
02090         sarrayAddString(sa, (char *)"  ] setcolorspace", L_COPY);
02091     }
02092     else if (spp == 1)
02093         sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY);
02094     else   /* spp == 3 */
02095         sarrayAddString(sa, (char *)"/DeviceRGB setcolorspace", L_COPY);
02096 
02097     sarrayAddString(sa,
02098               (char *)"/RawData currentfile /ASCII85Decode filter def", L_COPY);
02099     sarrayAddString(sa,
02100               (char *)"/Data RawData << >> /FlateDecode filter def", L_COPY);
02101 
02102     sarrayAddString(sa, (char *)"{ << /ImageType 1", L_COPY);
02103     sprintf(bigbuf, "     /Width %d", w);
02104     sarrayAddString(sa, bigbuf, L_COPY);
02105     sprintf(bigbuf, "     /Height %d", h);
02106     sarrayAddString(sa, bigbuf, L_COPY);
02107     sprintf(bigbuf, "     /BitsPerComponent %d", bps);
02108     sarrayAddString(sa, bigbuf, L_COPY);
02109     sprintf(bigbuf, "     /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
02110     sarrayAddString(sa, bigbuf, L_COPY);
02111 
02112     if (cid->cmapdata85)
02113         sarrayAddString(sa, (char *)"     /Decode [0 255]", L_COPY);
02114     else if (spp == 1) {
02115         if (bps == 1)  /* miniswhite photometry */
02116             sarrayAddString(sa, (char *)"     /Decode [1 0]", L_COPY);
02117         else  /* bps > 1 */
02118             sarrayAddString(sa, (char *)"     /Decode [0 1]", L_COPY);
02119     }
02120     else  /* spp == 3 */
02121         sarrayAddString(sa, (char *)"     /Decode [0 1 0 1 0 1]", L_COPY);
02122 
02123     sarrayAddString(sa, (char *)"     /DataSource Data", L_COPY);
02124     sarrayAddString(sa, (char *)"  >> image", L_COPY);
02125     sarrayAddString(sa, (char *)"  Data closefile", L_COPY);
02126     sarrayAddString(sa, (char *)"  RawData flushfile", L_COPY);
02127     if (endpage == TRUE)
02128         sarrayAddString(sa, (char *)"  showpage", L_COPY);
02129     sarrayAddString(sa, (char *)"  restore", L_COPY);
02130     sarrayAddString(sa, (char *)"} exec", L_COPY);
02131 
02132         /* Insert the ascii85 gzipped data; this is now owned by sa */
02133     sarrayAddString(sa, cid->data85, L_INSERT);
02134 
02135         /* Generate and return the output string */
02136     outstr = sarrayToString(sa, 1);
02137     sarrayDestroy(&sa);
02138     cid->cmapdata85 = NULL;  /* it has been transferred to sa and destroyed */
02139     cid->data85 = NULL;  /* it has been transferred to sa and destroyed */
02140     return outstr;
02141 }
02142 
02143 
02144 /*!
02145  *  l_generateFlateData()
02146  *
02147  *      Input:  fname
02148  *              ascii85flag (0 for gzipped; 1 for ascii85-encoded gzipped)
02149  *      Return: cid (flate compressed image data), or null on error
02150  *
02151  *  Notes:
02152  *      (1) The input image is converted to one of these 4 types:
02153  *           - 1 bpp
02154  *           - 8 bpp, no colormap
02155  *           - 8 bpp, colormap
02156  *           - 32 bpp rgb
02157  *      (2) Set ascii85flag:
02158  *           - 0 for binary data (not permitted in PostScript)
02159  *           - 1 for ascii85 (5 for 4) encoded binary data
02160  */
02161 L_COMPRESSED_DATA *
02162 l_generateFlateData(const char  *fname,
02163                     l_int32      ascii85flag)
02164 {
02165 L_COMPRESSED_DATA  *cid;
02166 PIX                *pixs;
02167 
02168     PROCNAME("l_generateFlateData");
02169 
02170     if (!fname)
02171         return (L_COMPRESSED_DATA *)ERROR_PTR("fname not defined",
02172                                               procName, NULL);
02173 
02174     if ((pixs = pixRead(fname)) == NULL)
02175         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not made",
02176                                               procName, NULL);
02177     cid = pixGenerateFlateData(pixs, ascii85flag);
02178     pixDestroy(&pixs);
02179     return cid;
02180 }
02181 
02182 
02183 /*!
02184  *  pixGenerateFlateData()
02185  *
02186  *      Input:  pixs
02187  *              ascii85flag (0 for gzipped; 1 for ascii85-encoded gzipped)
02188  *      Return: cid (flate compressed image data), or null on error
02189  */
02190 L_COMPRESSED_DATA *
02191 pixGenerateFlateData(PIX     *pixs,
02192                      l_int32  ascii85flag)
02193 {
02194 l_uint8       *data = NULL;  /* uncompressed raster data in required format */
02195 l_uint8       *datacomp = NULL;  /* gzipped raster data */
02196 char          *data85 = NULL;  /* ascii85 encoded gzipped raster data */
02197 l_uint8       *cmapdata = NULL;  /* uncompressed colormap */
02198 char          *cmapdata85 = NULL;  /* ascii85 encoded uncompressed colormap */
02199 char          *cmapdatahex = NULL;  /* hex ascii uncompressed colormap */
02200 l_int32        ncolors;  /* in colormap; not used if cmapdata85 is null */
02201 l_int32        bps;  /* bits/sample: usually 8 */
02202 l_int32        spp;  /* samples/pixel: 1-grayscale); 3-rgb; 4-rgba */
02203 l_int32        w, h, d, cmapflag;
02204 l_int32        ncmapbytes, ncmapbytes85, nbytes85;
02205 size_t         nbytes, nbytescomp;
02206 L_COMPRESSED_DATA  *cid;
02207 PIX           *pixt;
02208 PIXCMAP       *cmap;
02209 
02210     PROCNAME("pixGenerateFlateData");
02211 
02212     if (!pixs)
02213         return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not defined",
02214                                               procName, NULL);
02215 
02216         /* Convert the image to one of these 4 types:
02217          *     1 bpp
02218          *     8 bpp, no colormap
02219          *     8 bpp, colormap
02220          *     32 bpp rgb    */
02221     pixGetDimensions(pixs, &w, &h, &d);
02222     cmap = pixGetColormap(pixs);
02223     cmapflag = (cmap) ? 1 : 0;
02224     if (d == 2 || d == 4 || d == 16) {
02225         pixt = pixConvertTo8(pixs, cmapflag);
02226         cmap = pixGetColormap(pixt);
02227         d = pixGetDepth(pixt);
02228     }
02229     else
02230         pixt = pixClone(pixs);
02231     spp = (d == 32) ? 3 : 1;
02232     bps = (d == 32) ? 8 : d;
02233 
02234         /* Extract and encode the colormap data as both ascii85 and hexascii  */
02235     ncolors = 0;
02236     if (cmap) {
02237         pixcmapSerializeToMemory(cmap, 3, &ncolors, &cmapdata, &ncmapbytes);
02238         if (!cmapdata)
02239             return (L_COMPRESSED_DATA *)ERROR_PTR("cmapdata not made",
02240                                                   procName, NULL);
02241 
02242         cmapdata85 = encodeAscii85(cmapdata, ncmapbytes, &ncmapbytes85);
02243         cmapdatahex = pixcmapConvertToHex(cmapdata, ncmapbytes, ncolors);
02244         FREE(cmapdata);
02245     }
02246 
02247         /* Extract and compress the raster data */
02248     pixGetRasterData(pixt, &data, &nbytes);
02249     pixDestroy(&pixt);
02250     datacomp = zlibCompress(data, nbytes, &nbytescomp);
02251     if (!datacomp) {
02252         if (cmapdata85) FREE(cmapdata85);
02253         if (cmapdatahex) FREE(cmapdatahex);
02254         return (L_COMPRESSED_DATA *)ERROR_PTR("datacomp not made",
02255                                               procName, NULL);
02256     }
02257     FREE(data);
02258 
02259         /* Optionally, encode the compressed data */
02260     if (ascii85flag == 1) {
02261         data85 = encodeAscii85(datacomp, nbytescomp, &nbytes85);
02262         FREE(datacomp);
02263         if (!data85) {
02264             FREE(cmapdata85);
02265             return (L_COMPRESSED_DATA *)ERROR_PTR("data85 not made",
02266                                                   procName, NULL);
02267         }
02268         else
02269             data85[nbytes85 - 1] = '\0';  /* remove the newline */
02270     }
02271 
02272     cid = (L_COMPRESSED_DATA *)CALLOC(1, sizeof(L_COMPRESSED_DATA));
02273     if (!cid)
02274         return (L_COMPRESSED_DATA *)ERROR_PTR("cid not made", procName, NULL);
02275     if (ascii85flag == 0)
02276         cid->datacomp = datacomp;
02277     else {  /* ascii85 */
02278         cid->data85 = data85;
02279         cid->nbytes85 = nbytes85;
02280     }
02281     cid->type = L_FLATE_ENCODE;
02282     cid->cmapdatahex = cmapdatahex;
02283     cid->cmapdata85 = cmapdata85;
02284     cid->nbytescomp = nbytescomp;
02285     cid->ncolors = ncolors;
02286     cid->w = w;
02287     cid->h = h;
02288     cid->bps = bps;
02289     cid->spp = spp;
02290     cid->res = pixGetXRes(pixs);
02291     cid->nbytes = nbytes;  /* only for debugging */
02292     return cid;
02293 }
02294 
02295 
02296 /*---------------------------------------------------------------------*
02297  *                          Write to memory                            *
02298  *---------------------------------------------------------------------*/
02299 /*!
02300  *  pixWriteMemPS()
02301  *
02302  *      Input:  &data (<return> data of tiff compressed image)
02303  *              &size (<return> size of returned data)
02304  *              pix
02305  *              box  (<optional>)
02306  *              res  (can use 0 for default of 300 ppi)
02307  *              scale (to prevent scaling, use either 1.0 or 0.0)
02308  *      Return: 0 if OK, 1 on error
02309  *
02310  *  Notes:
02311  *      (1) See pixWriteStringPS() for usage.
02312  *      (2) This is just a wrapper for pixWriteStringPS(), which
02313  *          writes uncompressed image data to memory.
02314  */
02315 l_int32
02316 pixWriteMemPS(l_uint8  **pdata,
02317               size_t    *psize,
02318               PIX       *pix,
02319               BOX       *box,
02320               l_int32    res,
02321               l_float32  scale)
02322 {
02323     PROCNAME("pixWriteMemPS");
02324 
02325     if (!pdata)
02326         return ERROR_INT("&data not defined", procName, 1 );
02327     if (!psize)
02328         return ERROR_INT("&size not defined", procName, 1 );
02329     if (!pix)
02330         return ERROR_INT("&pix not defined", procName, 1 );
02331 
02332     *pdata = (l_uint8 *)pixWriteStringPS(pix, box, res, scale);
02333     *psize = strlen((char *)(*pdata));
02334     return 0;
02335 }
02336 
02337 
02338 /*-------------------------------------------------------------*
02339  *                    Converting resolution                    *
02340  *-------------------------------------------------------------*/
02341 /*!
02342  *  getResLetterPage()
02343  *
02344  *      Input:  w (image width, pixels)
02345  *              h (image height, pixels)
02346  *              fillfract (fraction in linear dimension of full page, not
02347  *                         to be exceeded; use 0 for default)
02348  *      Return: 0 if OK, 1 on error
02349  */
02350 l_int32
02351 getResLetterPage(l_int32    w,
02352                  l_int32    h,
02353                  l_float32  fillfract)
02354 {
02355 l_int32  resw, resh, res;
02356 
02357     if (fillfract == 0.0)
02358         fillfract = DEFAULT_FILL_FRACTION;
02359     resw = (l_int32)((w * 72.) / (LETTER_WIDTH * fillfract));
02360     resh = (l_int32)((h * 72.) / (LETTER_HEIGHT * fillfract));
02361     res = L_MAX(resw, resh);
02362     return res;
02363 }
02364 
02365 
02366 /*!
02367  *  getResA4Page()
02368  *
02369  *      Input:  w (image width, pixels)
02370  *              h (image height, pixels)
02371  *              fillfract (fraction in linear dimension of full page, not
02372  *                        to be exceeded; use 0 for default)
02373  *      Return: 0 if OK, 1 on error
02374  */
02375 l_int32
02376 getResA4Page(l_int32    w,
02377              l_int32    h,
02378              l_float32  fillfract)
02379 {
02380 l_int32  resw, resh, res;
02381 
02382     if (fillfract == 0.0)
02383         fillfract = DEFAULT_FILL_FRACTION;
02384     resw = (l_int32)((w * 72.) / (A4_WIDTH * fillfract));
02385     resh = (l_int32)((h * 72.) / (A4_HEIGHT * fillfract));
02386     res = L_MAX(resw, resh);
02387     return res;
02388 }
02389 
02390 
02391 
02392 /*-------------------------------------------------------------*
02393  *      Utility for encoding and decoding data with ascii85    *
02394  *-------------------------------------------------------------*/
02395 /*!
02396  *  encodeAscii85()
02397  *
02398  *      Input:  inarray (input data)
02399  *              insize (number of bytes in input array)
02400  *              &outsize (<return> number of bytes in output char array)
02401  *      Return: chara (with 64 characters + \n in each line)
02402  *
02403  *  Notes:
02404  *      (1) Ghostscript has a stack break if the last line of
02405  *          data only has a '>', so we avoid the problem by
02406  *          always putting '~>' on the last line.
02407  */
02408 char *
02409 encodeAscii85(l_uint8  *inarray,
02410               l_int32   insize,
02411               l_int32  *poutsize)
02412 {
02413 char    *chara;
02414 char    *outbuf;
02415 l_int32  maxsize, i, index, outindex, linecount, nbout, eof;
02416 
02417     PROCNAME("encodeAscii85");
02418 
02419     if (!inarray)
02420         return (char *)ERROR_PTR("inarray not defined", procName, NULL);
02421 
02422         /* Accumulate results in char array */
02423     maxsize = (l_int32)(80. + (insize * 5. / 4.) *
02424                         (1. + 2. / MAX_85_LINE_COUNT));
02425     if ((chara = (char *)CALLOC(maxsize, sizeof(char))) == NULL)
02426         return (char *)ERROR_PTR("chara not made", procName, NULL);
02427 
02428     if ((outbuf = (char *)CALLOC(8, sizeof(char))) == NULL)
02429         return (char *)ERROR_PTR("outbuf not made", procName, NULL);
02430 
02431     linecount = 0;
02432     index = 0;
02433     outindex = 0;
02434     while (1) {
02435         eof = convertChunkToAscii85(inarray, insize, &index, outbuf, &nbout);
02436         for (i = 0; i < nbout; i++) {
02437             chara[outindex++] = outbuf[i];
02438             linecount++;
02439             if (linecount >= MAX_85_LINE_COUNT) {
02440                 chara[outindex++] = '\n';
02441                 linecount = 0;
02442             }
02443         }
02444         if (eof == TRUE) {
02445             if (linecount != 0)
02446                 chara[outindex++] = '\n';
02447             chara[outindex++] = '~';
02448             chara[outindex++] = '>';
02449             chara[outindex++] = '\n';
02450             break;
02451         }
02452     }
02453 
02454     FREE(outbuf);
02455     *poutsize = outindex;
02456     return chara;
02457 }
02458 
02459 
02460 /*!
02461  *  convertChunkToAscii85()
02462  *
02463  *      Input:  inarray (input data)
02464  *              insize  (number of bytes in input array)
02465  *              &index (use and <return> -- ptr)
02466  *              outbuf (holds 8 ascii chars; we use no more than 7)
02467  *              &nbsout (<return> number of bytes written to outbuf)
02468  *      Return: boolean for eof (0 if more data, 1 if end of file)
02469  *
02470  *  Notes:
02471  *      (1) Attempts to read 4 bytes and write 5.
02472  *      (2) Writes 1 byte if the value is 0.
02473  */
02474 static l_int32
02475 convertChunkToAscii85(l_uint8  *inarray,
02476                       l_int32   insize,
02477                       l_int32  *pindex,
02478                       char     *outbuf,
02479                       l_int32  *pnbout)
02480 {
02481 l_uint8   inbyte;
02482 l_uint32  inword, val;
02483 l_int32   eof, index, nread, nbout, i;
02484 
02485     eof = FALSE;
02486     index = *pindex;
02487     nread = L_MIN(4, (insize - index));
02488     if (insize == index + nread)
02489         eof = TRUE;
02490     *pindex += nread;  /* save new index */
02491 
02492         /* Read input data and save in l_uint32 */
02493     inword = 0;
02494     for (i = 0; i < nread; i++) {
02495         inbyte = inarray[index + i];
02496         inword += inbyte << (8 * (3 - i));
02497     }
02498 
02499 #if 0
02500     fprintf(stderr, "index = %d, nread = %d\n", index, nread);
02501     fprintf(stderr, "inword = %x\n", inword);
02502     fprintf(stderr, "eof = %d\n", eof);
02503 #endif
02504 
02505         /* Special case: output 1 byte only */
02506     if (inword == 0) {
02507         outbuf[0] = 'z';
02508         nbout = 1;
02509     }
02510     else { /* output nread + 1 bytes */
02511         for (i = 4; i >= 4 - nread; i--) {
02512             val = inword / power85[i];
02513             outbuf[4 - i] = (l_uint8)(val + '!');
02514             inword -= val * power85[i];
02515         }
02516         nbout = nread + 1;
02517     }
02518     *pnbout = nbout;
02519 
02520     return eof;
02521 }
02522 
02523 
02524 /*!
02525  *  decodeAscii85()
02526  *
02527  *      Input:  inarray (ascii85 input data)
02528  *              insize (number of bytes in input array)
02529  *              &outsize (<return> number of bytes in output l_uint8 array)
02530  *      Return: outarray (binary)
02531  *
02532  *  Notes:
02533  *      (1) We assume the data is properly encoded, so we do not check
02534  *          for invalid characters or the final '>' character.
02535  *      (2) We permit whitespace to be added to the encoding in an
02536  *          arbitrary way.
02537  */
02538 l_uint8 *
02539 decodeAscii85(char     *ina,
02540               l_int32   insize,
02541               l_int32  *poutsize)
02542 {
02543 char      inc;
02544 char     *pin;
02545 l_uint8   val;
02546 l_uint8  *outa;
02547 l_int32   maxsize, ocount, bytecount, index;
02548 l_uint32  oword;
02549 
02550     PROCNAME("decodeAscii85");
02551 
02552     if (!ina)
02553         return (l_uint8 *)ERROR_PTR("ina not defined", procName, NULL);
02554 
02555         /* Accumulate results in outa */
02556     maxsize = (l_int32)(80. + (insize * 4. / 5.));  /* plenty big */
02557     if ((outa = (l_uint8 *)CALLOC(maxsize, sizeof(l_uint8))) == NULL)
02558         return (l_uint8 *)ERROR_PTR("outa not made", procName, NULL);
02559 
02560     pin = ina;
02561     ocount = 0;  /* byte index into outa */
02562     oword = 0;
02563     for (index = 0, bytecount = 0; index < insize; index++, pin++) {
02564         inc = *pin;
02565 
02566         if (inc == ' ' || inc == '\t' || inc == '\n' ||
02567             inc == '\f' || inc == '\r' || inc == '\v')  /* ignore white space */
02568             continue;
02569 
02570         val = inc - '!';
02571         if (val < 85) {
02572             oword = oword * 85 + val;
02573             if (bytecount < 4)
02574                 bytecount++;
02575             else {  /* we have all 5 input chars for the oword */
02576                 outa[ocount] = (oword >> 24) & 0xff;
02577                 outa[ocount + 1] = (oword >> 16) & 0xff;
02578                 outa[ocount + 2] = (oword >> 8) & 0xff;
02579                 outa[ocount + 3] = oword & 0xff;
02580                 ocount += 4;
02581                 bytecount = 0;
02582                 oword = 0;
02583             }
02584         }
02585         else if (inc == 'z' && bytecount == 0) {
02586             outa[ocount] = 0;
02587             outa[ocount + 1] = 0;
02588             outa[ocount + 2] = 0;
02589             outa[ocount + 3] = 0;
02590             ocount += 4;
02591         }
02592         else if (inc == '~') {  /* end of data */
02593             fprintf(stderr, " %d extra bytes output\n", bytecount - 1);
02594             switch (bytecount) {
02595             case 0:   /* normal eof */
02596             case 1:   /* error */
02597                 break;
02598             case 2:   /* 1 extra byte */
02599                 oword = oword * (85 * 85 * 85) + 0xffffff;
02600                 outa[ocount] = (oword >> 24) & 0xff; 
02601                 break;
02602             case 3:   /* 2 extra bytes */
02603                 oword = oword * (85 * 85) + 0xffff;
02604                 outa[ocount] = (oword >> 24) & 0xff; 
02605                 outa[ocount + 1] = (oword >> 16) & 0xff; 
02606                 break;
02607             case 4:   /* 3 extra bytes */
02608                 oword = oword * 85 + 0xff;
02609                 outa[ocount] = (oword >> 24) & 0xff; 
02610                 outa[ocount + 1] = (oword >> 16) & 0xff; 
02611                 outa[ocount + 2] = (oword >> 8) & 0xff; 
02612                 break;
02613             }
02614             if (bytecount > 1)
02615                 ocount += (bytecount - 1);
02616             break;
02617         }
02618     }
02619     *poutsize = ocount;
02620 
02621     return outa;
02622 }
02623 
02624 
02625 /*-------------------------------------------------------------*
02626  *           Setting flag for writing bounding box hint        *
02627  *-------------------------------------------------------------*/
02628 void
02629 l_psWriteBoundingBox(l_int32  flag)
02630 {
02631     var_PS_WRITE_BOUNDING_BOX = flag;
02632 }
02633 
02634 
02635 /* --------------------------------------------*/
02636 #endif  /* USE_PSIO */
02637 /* --------------------------------------------*/
02638 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines