1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -
4  -  Redistribution and use in source and binary forms, with or without
5  -  modification, are permitted provided that the following conditions
6  -  are met:
7  -  1. Redistributions of source code must retain the above copyright
8  -     notice, this list of conditions and the following disclaimer.
9  -  2. Redistributions in binary form must reproduce the above
10  -     copyright notice, this list of conditions and the following
11  -     disclaimer in the documentation and/or other materials
12  -     provided with the distribution.
13  -
14  -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18  -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
27 /*!
28  * \file psio2.c
29  * <pre>
30  *
31  *    |=============================================================|
32  *    |                         Important note                      |
33  *    |=============================================================|
34  *    | Some of these functions require libtiff, libjpeg and libz.  |
35  *    | If you do not have these libraries, you must set            |
36  *    |     #define  USE_PSIO     0                                 |
37  *    | in environ.h.  This will link psio2stub.c                   |
38  *    |=============================================================|
39  *
40  *     These are lower-level functions that implement a PostScript
41  *     "device driver" for wrapping images in PostScript.  The images
42  *     can be rendered by a PostScript interpreter for viewing,
43  *     using evince or gv.  They can also be rasterized for printing,
44  *     using gs or an embedded interpreter in a PostScript printer.
45  *     And they can be converted to a pdf using gs (ps2pdf).
46  *
47  *     For uncompressed images
48  *          l_int32              pixWritePSEmbed()
49  *          l_int32              pixWriteStreamPS()
50  *          char                *pixWriteStringPS()
51  *          char                *generateUncompressedPS()
52  *          void                 getScaledParametersPS()
53  *          l_int32              convertByteToHexAscii()
54  *
55  *     For jpeg compressed images (use dct compression)
56  *          l_int32              convertJpegToPSEmbed()
57  *          l_int32              convertJpegToPS()
58  *          l_int32              convertJpegToPSString()
59  *          char                *generateJpegPS()
60  *
61  *     For g4 fax compressed images (use ccitt g4 compression)
62  *          l_int32              convertG4ToPSEmbed()
63  *          l_int32              convertG4ToPS()
64  *          l_int32              convertG4ToPSString()
65  *          char                *generateG4PS()
66  *
67  *     For multipage tiff images
68  *          l_int32              convertTiffMultipageToPS()
69  *
70  *     For flate (gzip) compressed images (e.g., png)
71  *          l_int32              convertFlateToPSEmbed()
72  *          l_int32              convertFlateToPS()
73  *          l_int32              convertFlateToPSString()
74  *          char                *generateFlatePS()
75  *
76  *     Write to memory
77  *          l_int32              pixWriteMemPS()
78  *
79  *     Converting resolution
80  *          l_int32              getResLetterPage()
81  *          l_int32              getResA4Page()
82  *
83  *     Setting flag for writing bounding box hint
84  *          void                 l_psWriteBoundingBox()
85  *
86  *  See psio1.c for higher-level functions and their usage.
87  * </pre>
88  */
89 
90 #include <string.h>
91 #include "allheaders.h"
92 
93 /* --------------------------------------------*/
94 #if  USE_PSIO   /* defined in environ.h */
95  /* --------------------------------------------*/
96 
97     /* Set default for writing bounding box hint */
98 static l_int32  var_PS_WRITE_BOUNDING_BOX = 1;
99 
100 static const l_int32  L_BUF_SIZE = 512;
101 static const l_int32  DEFAULT_INPUT_RES   = 300;  /* typical scan res, ppi */
102 static const l_int32  MIN_RES             = 5;
103 static const l_int32  MAX_RES             = 3000;
104 
105     /* For computing resolution that fills page to desired amount */
106 static const l_int32  LETTER_WIDTH            = 612;   /* points */
107 static const l_int32  LETTER_HEIGHT           = 792;   /* points */
108 static const l_int32  A4_WIDTH                = 595;   /* points */
109 static const l_int32  A4_HEIGHT               = 842;   /* points */
110 static const l_float32  DEFAULT_FILL_FRACTION = 0.95;
111 
112 #ifndef  NO_CONSOLE_IO
113 #define  DEBUG_JPEG       0
114 #define  DEBUG_G4         0
115 #define  DEBUG_FLATE      0
116 #endif  /* ~NO_CONSOLE_IO */
117 
118 /* Note that the bounding box hint at the top of the generated PostScript
119  * file is required for the "*Embed" functions.  These generate a
120  * PostScript file for an individual image that can be translated and
121  * scaled by an application that embeds the image in its output
122  * (e.g., in the PS output from a TeX file).
123  * However, bounding box hints should not be embedded in any
124  * PostScript image that will be composited with other images,
125  * where more than one image may be placed in an arbitrary location
126  * on a page.  */
127 
128 
129 /*-------------------------------------------------------------*
130  *                  For uncompressed images                    *
131  *-------------------------------------------------------------*/
132 /*!
133  * \brief   pixWritePSEmbed()
134  *
135  * \param[in]    filein input file, all depths, colormap OK
136  * \param[in]    fileout output ps file
137  * \return  0 if OK, 1 on error
138  *
139  * <pre>
140  * Notes:
141  *      (1) This is a simple wrapper function that generates an
142  *          uncompressed PS file, with a bounding box.
143  *      (2) The bounding box is required when a program such as TeX
144  *          (through epsf) places and rescales the image.
145  *      (3) The bounding box is sized for fitting the image to an
146  *          8.5 x 11.0 inch page.
147  * </pre>
148  */
149 l_int32
pixWritePSEmbed(const char * filein,const char * fileout)150 pixWritePSEmbed(const char  *filein,
151                 const char  *fileout)
152 {
153 l_int32    w, h;
154 l_float32  scale;
155 FILE      *fp;
156 PIX       *pix;
157 
158     PROCNAME("pixWritePSEmbed");
159 
160     if (!filein)
161         return ERROR_INT("filein not defined", procName, 1);
162     if (!fileout)
163         return ERROR_INT("fileout not defined", procName, 1);
164 
165     if ((pix = pixRead(filein)) == NULL)
166         return ERROR_INT("image not read from file", procName, 1);
167     w = pixGetWidth(pix);
168     h = pixGetHeight(pix);
169     if (w * 11.0 > h * 8.5)
170         scale = 8.5 * 300. / (l_float32)w;
171     else
172         scale = 11.0 * 300. / (l_float32)h;
173 
174     if ((fp = fopenWriteStream(fileout, "wb")) == NULL)
175         return ERROR_INT("file not opened for write", procName, 1);
176     pixWriteStreamPS(fp, pix, NULL, 0, scale);
177     fclose(fp);
178 
179     pixDestroy(&pix);
180     return 0;
181 }
182 
183 
184 /*!
185  * \brief   pixWriteStreamPS()
186  *
187  * \param[in]    fp file stream
188  * \param[in]    pix
189  * \param[in]    box  [optional]
190  * \param[in]    res  can use 0 for default of 300 ppi
191  * \param[in]    scale to prevent scaling, use either 1.0 or 0.0
192  * \return  0 if OK; 1 on error
193  *
194  * <pre>
195  * Notes:
196  *      (1) This writes image in PS format, optionally scaled,
197  *          adjusted for the printer resolution, and with
198  *          a bounding box.
199  *      (2) For details on use of parameters, see pixWriteStringPS().
200  * </pre>
201  */
202 l_int32
pixWriteStreamPS(FILE * fp,PIX * pix,BOX * box,l_int32 res,l_float32 scale)203 pixWriteStreamPS(FILE      *fp,
204                  PIX       *pix,
205                  BOX       *box,
206                  l_int32    res,
207                  l_float32  scale)
208 {
209 char    *outstr;
210 l_int32  length;
211 PIX     *pixc;
212 
213     PROCNAME("pixWriteStreamPS");
214 
215     if (!fp)
216         return (l_int32)ERROR_INT("stream not open", procName, 1);
217     if (!pix)
218         return (l_int32)ERROR_INT("pix not defined", procName, 1);
219 
220     if ((pixc = pixConvertForPSWrap(pix)) == NULL)
221         return (l_int32)ERROR_INT("pixc not made", procName, 1);
222 
223     outstr = pixWriteStringPS(pixc, box, res, scale);
224     length = strlen(outstr);
225     fwrite(outstr, 1, length, fp);
226     LEPT_FREE(outstr);
227     pixDestroy(&pixc);
228 
229     return 0;
230 }
231 
232 
233 /*!
234  * \brief   pixWriteStringPS()
235  *
236  * \param[in]    pixs   all depths, colormap OK
237  * \param[in]    box    bounding box; can be NULL
238  * \param[in]    res    resolution, in printer ppi.  Use 0 for default 300 ppi.
239  * \param[in]    scale  scale factor.  If no scaling is desired, use
240  *                      either 1.0 or 0.0.   Scaling just resets the resolution
241  *                      parameter; the actual scaling is done in the
242  *                      interpreter at rendering time.  This is important:
243  *                      it allows you to scale the image up without
244  *                      increasing the file size.
245  * \return  ps string if OK, or NULL on error
246  *
247  * <pre>
248  * a) If %box == NULL, image is placed, optionally scaled,
249  *      in a standard b.b. at the center of the page.
250  *      This is to be used when another program like
251  *      TeX through epsf places the image.
252  * b) If %box != NULL, image is placed without a
253  *      b.b. at the specified page location and with
254  *      optional scaling.  This is to be used when
255  *      you want to specify exactly where and optionally
256  *      how big you want the image to be.
257  *      Note that all coordinates are in PS convention,
258  *      with 0,0 at LL corner of the page:
259  *          x,y    location of LL corner of image, in mils.
260  *          w,h    scaled size, in mils.  Use 0 to
261  *                 scale with "scale" and "res" input.
262  *
263  * %scale: If no scaling is desired, use either 1.0 or 0.0.
264  * Scaling just resets the resolution parameter; the actual
265  * scaling is done in the interpreter at rendering time.
266  * This is important: * it allows you to scale the image up
267  * without increasing the file size.
268  *
269  * Notes:
270  *      (1) OK, this seems a bit complicated, because there are various
271  *          ways to scale and not to scale.  Here's a summary:
272  *      (2) If you don't want any scaling at all:
273  *           * if you are using a box:
274  *               set w = 0, h = 0, and use scale = 1.0; it will print
275  *               each pixel unscaled at printer resolution
276  *           * if you are not using a box:
277  *               set scale = 1.0; it will print at printer resolution
278  *      (3) If you want the image to be a certain size in inches:
279  *           * you must use a box and set the box (w,h) in mils
280  *      (4) If you want the image to be scaled by a scale factor != 1.0:
281  *           * if you are using a box:
282  *               set w = 0, h = 0, and use the desired scale factor;
283  *               the higher the printer resolution, the smaller the
284  *               image will actually appear.
285  *           * if you are not using a box:
286  *               set the desired scale factor; the higher the printer
287  *               resolution, the smaller the image will actually appear.
288  *      (5) Another complication is the proliferation of distance units:
289  *           * The interface distances are in milli-inches.
290  *           * Three different units are used internally:
291  *              ~ pixels  (units of 1/res inch)
292  *              ~ printer pts (units of 1/72 inch)
293  *              ~ inches
294  *           * Here is a quiz on volume units from a reviewer:
295  *             How many UK milli-cups in a US kilo-teaspoon?
296  *               (Hint: 1.0 US cup = 0.75 UK cup + 0.2 US gill;
297  *                      1.0 US gill = 24.0 US teaspoons)
298  * </pre>
299  */
300 char *
pixWriteStringPS(PIX * pixs,BOX * box,l_int32 res,l_float32 scale)301 pixWriteStringPS(PIX       *pixs,
302                  BOX       *box,
303                  l_int32    res,
304                  l_float32  scale)
305 {
306 char       nib1, nib2;
307 char      *hexdata, *outstr;
308 l_uint8    byteval;
309 l_int32    i, j, k, w, h, d;
310 l_float32  wpt, hpt, xpt, ypt;
311 l_int32    wpl, psbpl, hexbytes, boxflag, bps;
312 l_uint32  *line, *data;
313 PIX       *pix;
314 
315     PROCNAME("pixWriteStringPS");
316 
317     if (!pixs)
318         return (char *)ERROR_PTR("pixs not defined", procName, NULL);
319 
320     if ((pix = pixConvertForPSWrap(pixs)) == NULL)
321         return (char *)ERROR_PTR("pix not made", procName, NULL);
322     pixGetDimensions(pix, &w, &h, &d);
323 
324         /* Get the factors by which PS scales and translates, in pts */
325     if (!box)
326         boxflag = 0;  /* no scaling; b.b. at center */
327     else
328         boxflag = 1;  /* no b.b., specify placement and optional scaling */
329     getScaledParametersPS(box, w, h, res, scale, &xpt, &ypt, &wpt, &hpt);
330 
331     if (d == 1)
332         bps = 1;  /* bits/sample */
333     else  /* d == 8 || d == 32 */
334         bps = 8;
335 
336         /* Convert image data to hex string.  psbpl is the number of
337          * bytes in each raster line when it is packed to the byte
338          * boundary (not the 32 bit word boundary, as with the pix).
339          * When converted to hex, the hex string has 2 bytes for
340          * every byte of raster data. */
341     wpl = pixGetWpl(pix);
342     if (d == 1 || d == 8)
343         psbpl = (w * d + 7) / 8;
344     else /* d == 32 */
345         psbpl = 3 * w;
346     data = pixGetData(pix);
347     hexbytes = 2 * psbpl * h;  /* size of ps hex array */
348     if ((hexdata = (char *)LEPT_CALLOC(hexbytes + 1, sizeof(char))) == NULL)
349         return (char *)ERROR_PTR("hexdata not made", procName, NULL);
350     if (d == 1 || d == 8) {
351         for (i = 0, k = 0; i < h; i++) {
352             line = data + i * wpl;
353             for (j = 0; j < psbpl; j++) {
354                 byteval = GET_DATA_BYTE(line, j);
355                 convertByteToHexAscii(byteval, &nib1, &nib2);
356                 hexdata[k++] = nib1;
357                 hexdata[k++] = nib2;
358             }
359         }
360     } else  {  /* d == 32; hexdata bytes packed RGBRGB..., 2 per sample */
361         for (i = 0, k = 0; i < h; i++) {
362             line = data + i * wpl;
363             for (j = 0; j < w; j++) {
364                 byteval = GET_DATA_BYTE(line + j, 0);  /* red */
365                 convertByteToHexAscii(byteval, &nib1, &nib2);
366                 hexdata[k++] = nib1;
367                 hexdata[k++] = nib2;
368                 byteval = GET_DATA_BYTE(line + j, 1);  /* green */
369                 convertByteToHexAscii(byteval, &nib1, &nib2);
370                 hexdata[k++] = nib1;
371                 hexdata[k++] = nib2;
372                 byteval = GET_DATA_BYTE(line + j, 2);  /* blue */
373                 convertByteToHexAscii(byteval, &nib1, &nib2);
374                 hexdata[k++] = nib1;
375                 hexdata[k++] = nib2;
376             }
377         }
378     }
379     hexdata[k] = '\0';
380 
381     outstr = generateUncompressedPS(hexdata, w, h, d, psbpl, bps,
382                                     xpt, ypt, wpt, hpt, boxflag);
383     if (!outstr)
384         return (char *)ERROR_PTR("outstr not made", procName, NULL);
385     pixDestroy(&pix);
386     return outstr;
387 }
388 
389 
390 /*!
391  * \brief   generateUncompressedPS()
392  *
393  * \param[in]    hexdata
394  * \param[in]    w, h  raster image size in pixels
395  * \param[in]    d image depth in bpp; rgb is 32
396  * \param[in]    psbpl raster bytes/line, when packed to the byte boundary
397  * \param[in]    bps bits/sample: either 1 or 8
398  * \param[in]    xpt, ypt location of LL corner of image, in pts, relative
399  *                    to the PostScript origin (0,0) at the LL corner
400  *                    of the page
401  * \param[in]    wpt, hpt rendered image size in pts
402  * \param[in]    boxflag 1 to print out bounding box hint; 0 to skip
403  * \return  PS string, or NULL on error
404  *
405  * <pre>
406  * Notes:
407  *      (1) Low-level function.
408  * </pre>
409  */
410 char *
generateUncompressedPS(char * hexdata,l_int32 w,l_int32 h,l_int32 d,l_int32 psbpl,l_int32 bps,l_float32 xpt,l_float32 ypt,l_float32 wpt,l_float32 hpt,l_int32 boxflag)411 generateUncompressedPS(char      *hexdata,
412                        l_int32    w,
413                        l_int32    h,
414                        l_int32    d,
415                        l_int32    psbpl,
416                        l_int32    bps,
417                        l_float32  xpt,
418                        l_float32  ypt,
419                        l_float32  wpt,
420                        l_float32  hpt,
421                        l_int32    boxflag)
422 {
423 char    *outstr;
424 char     bigbuf[L_BUF_SIZE];
425 SARRAY  *sa;
426 
427     PROCNAME("generateUncompressedPS");
428 
429     if (!hexdata)
430         return (char *)ERROR_PTR("hexdata not defined", procName, NULL);
431 
432     if ((sa = sarrayCreate(0)) == NULL)
433         return (char *)ERROR_PTR("sa not made", procName, NULL);
434     sarrayAddString(sa, (char *)"%!Adobe-PS", L_COPY);
435     if (boxflag == 0) {
436         snprintf(bigbuf, sizeof(bigbuf),
437                  "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
438                  xpt, ypt, xpt + wpt, ypt + hpt);
439         sarrayAddString(sa, bigbuf, L_COPY);
440     } else {  /* boxflag == 1 */
441         sarrayAddString(sa, (char *)"gsave", L_COPY);
442     }
443 
444     if (d == 1)
445         sarrayAddString(sa,
446               (char *)"{1 exch sub} settransfer    %invert binary", L_COPY);
447 
448     snprintf(bigbuf, sizeof(bigbuf),
449             "/bpl %d string def         %%bpl as a string", psbpl);
450     sarrayAddString(sa, bigbuf, L_COPY);
451     snprintf(bigbuf, sizeof(bigbuf),
452            "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
453     sarrayAddString(sa, bigbuf, L_COPY);
454     snprintf(bigbuf, sizeof(bigbuf),
455             "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
456     sarrayAddString(sa, bigbuf, L_COPY);
457     snprintf(bigbuf, sizeof(bigbuf),
458             "%d %d %d                 %%image dimensions in pixels", w, h, bps);
459     sarrayAddString(sa, bigbuf, L_COPY);
460     snprintf(bigbuf, sizeof(bigbuf),
461             "[%d %d %d %d %d %d]     %%mapping matrix: [w 0 0 -h 0 h]",
462             w, 0, 0, -h, 0, h);
463     sarrayAddString(sa, bigbuf, L_COPY);
464 
465     if (boxflag == 0) {
466         if (d == 1 || d == 8)
467             sarrayAddString(sa,
468                 (char *)"{currentfile bpl readhexstring pop} image", L_COPY);
469         else  /* d == 32 */
470             sarrayAddString(sa,
471               (char *)"{currentfile bpl readhexstring pop} false 3 colorimage",
472               L_COPY);
473     } else {  /* boxflag == 1 */
474         if (d == 1 || d == 8)
475             sarrayAddString(sa,
476               (char *)"{currentfile bpl readhexstring pop} bind image", L_COPY);
477         else  /* d == 32 */
478             sarrayAddString(sa,
479           (char *)"{currentfile bpl readhexstring pop} bind false 3 colorimage",
480                  L_COPY);
481     }
482 
483     sarrayAddString(sa, hexdata, L_INSERT);
484 
485     if (boxflag == 0)
486         sarrayAddString(sa, (char *)"\nshowpage", L_COPY);
487     else  /* boxflag == 1 */
488         sarrayAddString(sa, (char *)"\ngrestore", L_COPY);
489 
490     outstr = sarrayToString(sa, 1);
491     sarrayDestroy(&sa);
492     if (!outstr) L_ERROR("outstr not made\n", procName);
493     return outstr;
494 }
495 
496 
497 /*!
498  * \brief   getScaledParametersPS()
499  *
500  * \param[in]    box [optional] location of image in mils; with
501  *                   x,y being the LL corner
502  * \param[in]    wpix pix width in pixels
503  * \param[in]    hpix pix height in pixels
504  * \param[in]    res of printer; use 0 for default
505  * \param[in]    scale use 1.0 or 0.0 for no scaling
506  * \param[out]   pxpt location of llx in pts
507  * \param[out]   pypt location of lly in pts
508  * \param[out]   pwpt image width in pts
509  * \param[out]   phpt image height in pts
510  * \return  void no arg checking
511  *
512  * <pre>
513  * Notes:
514  *      (1) The image is always scaled, depending on res and scale.
515  *      (2) If no box, the image is centered on the page.
516  *      (3) If there is a box, the image is placed within it.
517  * </pre>
518  */
519 void
getScaledParametersPS(BOX * box,l_int32 wpix,l_int32 hpix,l_int32 res,l_float32 scale,l_float32 * pxpt,l_float32 * pypt,l_float32 * pwpt,l_float32 * phpt)520 getScaledParametersPS(BOX        *box,
521                       l_int32     wpix,
522                       l_int32     hpix,
523                       l_int32     res,
524                       l_float32   scale,
525                       l_float32  *pxpt,
526                       l_float32  *pypt,
527                       l_float32  *pwpt,
528                       l_float32  *phpt)
529 {
530 l_int32    bx, by, bw, bh;
531 l_float32  winch, hinch, xinch, yinch, fres;
532 
533     PROCNAME("getScaledParametersPS");
534 
535     if (res == 0)
536         res = DEFAULT_INPUT_RES;
537     fres = (l_float32)res;
538 
539         /* Allow the PS interpreter to scale the resolution */
540     if (scale == 0.0)
541         scale = 1.0;
542     if (scale != 1.0) {
543         fres = (l_float32)res / scale;
544         res = (l_int32)fres;
545     }
546 
547         /* Limit valid resolution interval */
548     if (res < MIN_RES || res > MAX_RES) {
549         L_WARNING("res %d out of bounds; using default res; no scaling\n",
550                   procName, res);
551         res = DEFAULT_INPUT_RES;
552         fres = (l_float32)res;
553     }
554 
555     if (!box) {  /* center on page */
556         winch = (l_float32)wpix / fres;
557         hinch = (l_float32)hpix / fres;
558         xinch = (8.5 - winch) / 2.;
559         yinch = (11.0 - hinch) / 2.;
560     } else {
561         boxGetGeometry(box, &bx, &by, &bw, &bh);
562         if (bw == 0)
563             winch = (l_float32)wpix / fres;
564         else
565             winch = (l_float32)bw / 1000.;
566         if (bh == 0)
567             hinch = (l_float32)hpix / fres;
568         else
569             hinch = (l_float32)bh / 1000.;
570         xinch = (l_float32)bx / 1000.;
571         yinch = (l_float32)by / 1000.;
572     }
573 
574     if (xinch < 0)
575         L_WARNING("left edge < 0.0 inch\n", procName);
576     if (xinch + winch > 8.5)
577         L_WARNING("right edge > 8.5 inch\n", procName);
578     if (yinch < 0.0)
579         L_WARNING("bottom edge < 0.0 inch\n", procName);
580     if (yinch + hinch > 11.0)
581         L_WARNING("top edge > 11.0 inch\n", procName);
582 
583     *pwpt = 72. * winch;
584     *phpt = 72. * hinch;
585     *pxpt = 72. * xinch;
586     *pypt = 72. * yinch;
587     return;
588 }
589 
590 
591 /*!
592  * \brief   convertByteToHexAscii()
593  *
594  * \param[in]    byteval  input byte
595  * \param[out]   pnib1, pnib2  two hex ascii characters
596  * \return  void
597  */
598 void
convertByteToHexAscii(l_uint8 byteval,char * pnib1,char * pnib2)599 convertByteToHexAscii(l_uint8  byteval,
600                       char    *pnib1,
601                       char    *pnib2)
602 {
603 l_uint8  nib;
604 
605     nib = byteval >> 4;
606     if (nib < 10)
607         *pnib1 = '0' + nib;
608     else
609         *pnib1 = 'a' + (nib - 10);
610     nib = byteval & 0xf;
611     if (nib < 10)
612         *pnib2 = '0' + nib;
613     else
614         *pnib2 = 'a' + (nib - 10);
615 
616     return;
617 }
618 
619 
620 /*-------------------------------------------------------------*
621  *                  For jpeg compressed images                 *
622  *-------------------------------------------------------------*/
623 /*!
624  * \brief   convertJpegToPSEmbed()
625  *
626  * \param[in]    filein input jpeg file
627  * \param[in]    fileout output ps file
628  * \return  0 if OK, 1 on error
629  *
630  * <pre>
631  * Notes:
632  *      (1) This function takes a jpeg file as input and generates a DCT
633  *          compressed, ascii85 encoded PS file, with a bounding box.
634  *      (2) The bounding box is required when a program such as TeX
635  *          (through epsf) places and rescales the image.
636  *      (3) The bounding box is sized for fitting the image to an
637  *          8.5 x 11.0 inch page.
638  * </pre>
639  */
640 l_int32
convertJpegToPSEmbed(const char * filein,const char * fileout)641 convertJpegToPSEmbed(const char  *filein,
642                      const char  *fileout)
643 {
644 char         *outstr;
645 l_int32       w, h, nbytes, ret;
646 l_float32     xpt, ypt, wpt, hpt;
647 L_COMP_DATA  *cid;
648 
649     PROCNAME("convertJpegToPSEmbed");
650 
651     if (!filein)
652         return ERROR_INT("filein not defined", procName, 1);
653     if (!fileout)
654         return ERROR_INT("fileout not defined", procName, 1);
655 
656         /* Generate the ascii encoded jpeg data */
657     if ((cid = l_generateJpegData(filein, 1)) == NULL)
658         return ERROR_INT("jpeg data not made", procName, 1);
659     w = cid->w;
660     h = cid->h;
661 
662         /* Scale for 20 pt boundary and otherwise full filling
663          * in one direction on 8.5 x 11 inch device */
664     xpt = 20.0;
665     ypt = 20.0;
666     if (w * 11.0 > h * 8.5) {
667         wpt = 572.0;   /* 612 - 2 * 20 */
668         hpt = wpt * (l_float32)h / (l_float32)w;
669     } else {
670         hpt = 752.0;   /* 792 - 2 * 20 */
671         wpt = hpt * (l_float32)w / (l_float32)h;
672     }
673 
674         /* Generate the PS.
675          * The bounding box information should be inserted (default). */
676     outstr = generateJpegPS(NULL, cid, xpt, ypt, wpt, hpt, 1, 1);
677     l_CIDataDestroy(&cid);
678     if (!outstr)
679         return ERROR_INT("outstr not made", procName, 1);
680     nbytes = strlen(outstr);
681 
682     ret = l_binaryWrite(fileout, "w", outstr, nbytes);
683     LEPT_FREE(outstr);
684     if (ret) L_ERROR("ps string not written to file\n", procName);
685     return ret;
686 }
687 
688 
689 /*!
690  * \brief   convertJpegToPS()
691  *
692  * \param[in]    filein input jpeg file
693  * \param[in]    fileout output ps file
694  * \param[in]    operation "w" for write; "a" for append
695  * \param[in]    x, y location of LL corner of image, in pixels, relative
696  *                    to the PostScript origin (0,0) at the LL corner
697  *                    of the page
698  * \param[in]    res resolution of the input image, in ppi; use 0 for default
699  * \param[in]    scale scaling by printer; use 0.0 or 1.0 for no scaling
700  * \param[in]    pageno page number; must start with 1; you can use 0
701  *                      if there is only one page
702  * \param[in]    endpage boolean: use TRUE if this is the last image to be
703  *                       added to the page; FALSE otherwise
704  * \return  0 if OK, 1 on error
705  *
706  * <pre>
707  * Notes:
708  *      (1) This is simpler to use than pixWriteStringPS(), and
709  *          it outputs in level 2 PS as compressed DCT (overlaid
710  *          with ascii85 encoding).
711  *      (2) An output file can contain multiple pages, each with
712  *          multiple images.  The arguments to convertJpegToPS()
713  *          allow you to control placement of jpeg images on multiple
714  *          pages within a PostScript file.
715  *      (3) For the first image written to a file, use "w", which
716  *          opens for write and clears the file.  For all subsequent
717  *          images written to that file, use "a".
718  *      (4) The (x, y) parameters give the LL corner of the image
719  *          relative to the LL corner of the page.  They are in
720  *          units of pixels if scale = 1.0.  If you use (e.g.)
721  *          scale = 2.0, the image is placed at (2x, 2y) on the page,
722  *          and the image dimensions are also doubled.
723  *      (5) Display vs printed resolution:
724  *           * If your display is 75 ppi and your image was created
725  *             at a resolution of 300 ppi, you can get the image
726  *             to print at the same size as it appears on your display
727  *             by either setting scale = 4.0 or by setting  res = 75.
728  *             Both tell the printer to make a 4x enlarged image.
729  *           * If your image is generated at 150 ppi and you use scale = 1,
730  *             it will be rendered such that 150 pixels correspond
731  *             to 72 pts (1 inch on the printer).  This function does
732  *             the conversion from pixels (with or without scaling) to
733  *             pts, which are the units that the printer uses.
734  *           * The printer will choose its own resolution to use
735  *             in rendering the image, which will not affect the size
736  *             of the rendered image.  That is because the output
737  *             PostScript file describes the geometry in terms of pts,
738  *             which are defined to be 1/72 inch.  The printer will
739  *             only see the size of the image in pts, through the
740  *             scale and translate parameters and the affine
741  *             transform (the ImageMatrix) of the image.
742  *      (6) To render multiple images on the same page, set
743  *          endpage = FALSE for each image until you get to the
744  *          last, for which you set endpage = TRUE.  This causes the
745  *          "showpage" command to be invoked.  Showpage outputs
746  *          the entire page and clears the raster buffer for the
747  *          next page to be added.  Without a "showpage",
748  *          subsequent images from the next page will overlay those
749  *          previously put down.
750  *      (7) For multiple pages, increment the page number, starting
751  *          with page 1.  This allows PostScript (and PDF) to build
752  *          a page directory, which viewers use for navigation.
753  * </pre>
754  */
755 l_int32
convertJpegToPS(const char * filein,const char * fileout,const char * operation,l_int32 x,l_int32 y,l_int32 res,l_float32 scale,l_int32 pageno,l_int32 endpage)756 convertJpegToPS(const char  *filein,
757                 const char  *fileout,
758                 const char  *operation,
759                 l_int32      x,
760                 l_int32      y,
761                 l_int32      res,
762                 l_float32    scale,
763                 l_int32      pageno,
764                 l_int32      endpage)
765 {
766 char    *outstr;
767 l_int32  nbytes;
768 
769     PROCNAME("convertJpegToPS");
770 
771     if (!filein)
772         return ERROR_INT("filein not defined", procName, 1);
773     if (!fileout)
774         return ERROR_INT("fileout not defined", procName, 1);
775     if (strcmp(operation, "w") && strcmp(operation, "a"))
776         return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1);
777 
778     if (convertJpegToPSString(filein, &outstr, &nbytes, x, y, res, scale,
779                           pageno, endpage))
780         return ERROR_INT("ps string not made", procName, 1);
781 
782     if (l_binaryWrite(fileout, operation, outstr, nbytes))
783         return ERROR_INT("ps string not written to file", procName, 1);
784 
785     LEPT_FREE(outstr);
786     return 0;
787 }
788 
789 
790 /*!
791  * \brief   convertJpegToPSString()
792  *
793  *      Generates PS string in jpeg format from jpeg file
794  *
795  * \param[in]    filein input jpeg file
796  * \param[out]   poutstr PS string
797  * \param[out]   pnbytes number of bytes in PS string
798  * \param[in]    x, y location of LL corner of image, in pixels, relative
799  *                    to the PostScript origin (0,0) at the LL corner
800  *                     of the page
801  * \param[in]    res resolution of the input image, in ppi; use 0 for default
802  * \param[in]    scale scaling by printer; use 0.0 or 1.0 for no scaling
803  * \param[in]    pageno page number; must start with 1; you can use 0
804  *                      if there is only one page
805  * \param[in]    endpage boolean: use TRUE if this is the last image to be
806  *                       added to the page; FALSE otherwise
807  * \return  0 if OK, 1 on error
808  *
809  * <pre>
810  * Notes:
811  *      (1) For usage, see convertJpegToPS()
812  * </pre>
813  */
814 l_int32
convertJpegToPSString(const char * filein,char ** poutstr,l_int32 * pnbytes,l_int32 x,l_int32 y,l_int32 res,l_float32 scale,l_int32 pageno,l_int32 endpage)815 convertJpegToPSString(const char  *filein,
816                       char       **poutstr,
817                       l_int32     *pnbytes,
818                       l_int32      x,
819                       l_int32      y,
820                       l_int32      res,
821                       l_float32    scale,
822                       l_int32      pageno,
823                       l_int32      endpage)
824 {
825 char         *outstr;
826 l_float32     xpt, ypt, wpt, hpt;
827 L_COMP_DATA  *cid;
828 
829     PROCNAME("convertJpegToPSString");
830 
831     if (!poutstr)
832         return ERROR_INT("&outstr not defined", procName, 1);
833     if (!pnbytes)
834         return ERROR_INT("&nbytes not defined", procName, 1);
835     *poutstr = NULL;
836     *pnbytes = 0;
837     if (!filein)
838         return ERROR_INT("filein not defined", procName, 1);
839 
840         /* Generate the ascii encoded jpeg data */
841     if ((cid = l_generateJpegData(filein, 1)) == NULL)
842         return ERROR_INT("jpeg data not made", procName, 1);
843 
844         /* Get scaled location in pts.  Guess the input scan resolution
845          * based on the input parameter %res, the resolution data in
846          * the pix, and the size of the image. */
847     if (scale == 0.0)
848         scale = 1.0;
849     if (res <= 0) {
850         if (cid->res > 0)
851             res = cid->res;
852         else
853             res = DEFAULT_INPUT_RES;
854     }
855 
856         /* Get scaled location in pts */
857     if (scale == 0.0)
858         scale = 1.0;
859     xpt = scale * x * 72. / res;
860     ypt = scale * y * 72. / res;
861     wpt = scale * cid->w * 72. / res;
862     hpt = scale * cid->h * 72. / res;
863 
864     if (pageno == 0)
865         pageno = 1;
866 
867 #if  DEBUG_JPEG
868     fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n",
869             cid->w, cid->h, cid->bps, cid->spp);
870     fprintf(stderr, "comp bytes = %ld, nbytes85 = %ld, ratio = %5.3f\n",
871             (unsigned long)cid->nbytescomp, (unsigned long)cid->nbytes85,
872            (l_float32)cid->nbytes85 / (l_float32)cid->nbytescomp);
873     fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n",
874              xpt, ypt, wpt, hpt);
875 #endif   /* DEBUG_JPEG */
876 
877         /* Generate the PS */
878     outstr = generateJpegPS(NULL, cid, xpt, ypt, wpt, hpt, pageno, endpage);
879     if (!outstr)
880         return ERROR_INT("outstr not made", procName, 1);
881     *poutstr = outstr;
882     *pnbytes = strlen(outstr);
883     l_CIDataDestroy(&cid);
884     return 0;
885 }
886 
887 
888 /*!
889  * \brief   generateJpegPS()
890  *
891  * \param[in]    filein [optional] input jpeg filename; can be null
892  * \param[in]    cid jpeg compressed image data
893  * \param[in]    xpt, ypt location of LL corner of image, in pts, relative
894  *                        to the PostScript origin (0,0) at the LL corner
895  *                        of the page
896  * \param[in]    wpt, hpt rendered image size in pts
897  * \param[in]    pageno page number; must start with 1; you can use 0
898  *                      if there is only one page.
899  * \param[in]    endpage boolean: use TRUE if this is the last image to be
900  *                       added to the page; FALSE otherwise
901  * \return  PS string, or NULL on error
902  *
903  * <pre>
904  * Notes:
905  *      (1) Low-level function.
906  * </pre>
907  */
908 char *
generateJpegPS(const char * filein,L_COMP_DATA * cid,l_float32 xpt,l_float32 ypt,l_float32 wpt,l_float32 hpt,l_int32 pageno,l_int32 endpage)909 generateJpegPS(const char   *filein,
910                L_COMP_DATA  *cid,
911                l_float32     xpt,
912                l_float32     ypt,
913                l_float32     wpt,
914                l_float32     hpt,
915                l_int32       pageno,
916                l_int32       endpage)
917 {
918 l_int32  w, h, bps, spp;
919 char    *outstr;
920 char     bigbuf[L_BUF_SIZE];
921 SARRAY  *sa;
922 
923     PROCNAME("generateJpegPS");
924 
925     if (!cid)
926         return (char *)ERROR_PTR("jpeg data not defined", procName, NULL);
927     w = cid->w;
928     h = cid->h;
929     bps = cid->bps;
930     spp = cid->spp;
931 
932     if ((sa = sarrayCreate(50)) == NULL)
933         return (char *)ERROR_PTR("sa not made", procName, NULL);
934 
935     sarrayAddString(sa, (char *)"%!PS-Adobe-3.0", L_COPY);
936     sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY);
937     if (filein)
938         snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: %s", filein);
939     else
940         snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: Jpeg compressed PS");
941     sarrayAddString(sa, bigbuf, L_COPY);
942     sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY);
943 
944     if (var_PS_WRITE_BOUNDING_BOX == 1) {
945         snprintf(bigbuf, sizeof(bigbuf),
946                  "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
947                  xpt, ypt, xpt + wpt, ypt + hpt);
948         sarrayAddString(sa, bigbuf, L_COPY);
949     }
950 
951     sarrayAddString(sa, (char *)"%%LanguageLevel: 2", L_COPY);
952     sarrayAddString(sa, (char *)"%%EndComments", L_COPY);
953     snprintf(bigbuf, sizeof(bigbuf), "%%%%Page: %d %d", pageno, pageno);
954     sarrayAddString(sa, bigbuf, L_COPY);
955 
956     sarrayAddString(sa, (char *)"save", L_COPY);
957     sarrayAddString(sa,
958            (char *)"/RawData currentfile /ASCII85Decode filter def", L_COPY);
959     sarrayAddString(sa,
960            (char *)"/Data RawData << >> /DCTDecode filter def", L_COPY);
961 
962     snprintf(bigbuf, sizeof(bigbuf),
963         "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
964     sarrayAddString(sa, bigbuf, L_COPY);
965 
966     snprintf(bigbuf, sizeof(bigbuf),
967         "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
968     sarrayAddString(sa, bigbuf, L_COPY);
969 
970     if (spp == 1)
971         sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY);
972     else if (spp == 3)
973         sarrayAddString(sa, (char *)"/DeviceRGB setcolorspace", L_COPY);
974     else  /*spp == 4 */
975         sarrayAddString(sa, (char *)"/DeviceCMYK setcolorspace", L_COPY);
976 
977     sarrayAddString(sa, (char *)"{ << /ImageType 1", L_COPY);
978     snprintf(bigbuf, sizeof(bigbuf), "     /Width %d", w);
979     sarrayAddString(sa, bigbuf, L_COPY);
980     snprintf(bigbuf, sizeof(bigbuf), "     /Height %d", h);
981     sarrayAddString(sa, bigbuf, L_COPY);
982     snprintf(bigbuf, sizeof(bigbuf),
983             "     /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
984     sarrayAddString(sa, bigbuf, L_COPY);
985     sarrayAddString(sa, (char *)"     /DataSource Data", L_COPY);
986     snprintf(bigbuf, sizeof(bigbuf), "     /BitsPerComponent %d", bps);
987     sarrayAddString(sa, bigbuf, L_COPY);
988 
989     if (spp == 1)
990         sarrayAddString(sa, (char *)"     /Decode [0 1]", L_COPY);
991     else if (spp == 3)
992         sarrayAddString(sa, (char *)"     /Decode [0 1 0 1 0 1]", L_COPY);
993     else   /* spp == 4 */
994         sarrayAddString(sa, (char *)"     /Decode [0 1 0 1 0 1 0 1]", L_COPY);
995 
996     sarrayAddString(sa, (char *)"  >> image", L_COPY);
997     sarrayAddString(sa, (char *)"  Data closefile", L_COPY);
998     sarrayAddString(sa, (char *)"  RawData flushfile", L_COPY);
999     if (endpage == TRUE)
1000         sarrayAddString(sa, (char *)"  showpage", L_COPY);
1001     sarrayAddString(sa, (char *)"  restore", L_COPY);
1002     sarrayAddString(sa, (char *)"} exec", L_COPY);
1003 
1004         /* Insert the ascii85 jpeg data; this is now owned by sa */
1005     sarrayAddString(sa, cid->data85, L_INSERT);
1006     cid->data85 = NULL;  /* it has been transferred and destroyed */
1007 
1008         /* Generate and return the output string */
1009     outstr = sarrayToString(sa, 1);
1010     sarrayDestroy(&sa);
1011     return outstr;
1012 }
1013 
1014 
1015 /*-------------------------------------------------------------*
1016  *                  For ccitt g4 compressed images             *
1017  *-------------------------------------------------------------*/
1018 /*!
1019  * \brief   convertG4ToPSEmbed()
1020  *
1021  * \param[in]    filein input tiff file
1022  * \param[in]    fileout output ps file
1023  * \return  0 if OK, 1 on error
1024  *
1025  * <pre>
1026  * Notes:
1027  *      (1) This function takes a g4 compressed tif file as input and
1028  *          generates a g4 compressed, ascii85 encoded PS file, with
1029  *          a bounding box.
1030  *      (2) The bounding box is required when a program such as TeX
1031  *          (through epsf) places and rescales the image.
1032  *      (3) The bounding box is sized for fitting the image to an
1033  *          8.5 x 11.0 inch page.
1034  *      (4) We paint this through a mask, over whatever is below.
1035  * </pre>
1036  */
1037 l_int32
convertG4ToPSEmbed(const char * filein,const char * fileout)1038 convertG4ToPSEmbed(const char  *filein,
1039                    const char  *fileout)
1040 {
1041 char         *outstr;
1042 l_int32       w, h, nbytes, ret;
1043 l_float32     xpt, ypt, wpt, hpt;
1044 L_COMP_DATA  *cid;
1045 
1046     PROCNAME("convertG4ToPSEmbed");
1047 
1048     if (!filein)
1049         return ERROR_INT("filein not defined", procName, 1);
1050     if (!fileout)
1051         return ERROR_INT("fileout not defined", procName, 1);
1052 
1053     if ((cid = l_generateG4Data(filein, 1)) == NULL)
1054         return ERROR_INT("g4 data not made", procName, 1);
1055     w = cid->w;
1056     h = cid->h;
1057 
1058         /* Scale for 20 pt boundary and otherwise full filling
1059          * in one direction on 8.5 x 11 inch device */
1060     xpt = 20.0;
1061     ypt = 20.0;
1062     if (w * 11.0 > h * 8.5) {
1063         wpt = 572.0;   /* 612 - 2 * 20 */
1064         hpt = wpt * (l_float32)h / (l_float32)w;
1065     } else {
1066         hpt = 752.0;   /* 792 - 2 * 20 */
1067         wpt = hpt * (l_float32)w / (l_float32)h;
1068     }
1069 
1070         /* Generate the PS, painting through the image mask.
1071          * The bounding box information should be inserted (default). */
1072     outstr = generateG4PS(NULL, cid, xpt, ypt, wpt, hpt, 1, 1, 1);
1073     l_CIDataDestroy(&cid);
1074     if (!outstr)
1075         return ERROR_INT("outstr not made", procName, 1);
1076     nbytes = strlen(outstr);
1077 
1078     ret = l_binaryWrite(fileout, "w", outstr, nbytes);
1079     LEPT_FREE(outstr);
1080     if (ret) L_ERROR("ps string not written to file\n", procName);
1081     return ret;
1082 }
1083 
1084 
1085 /*!
1086  * \brief   convertG4ToPS()
1087  *
1088  * \param[in]    filein input tiff g4 file
1089  * \param[in]    fileout output ps file
1090  * \param[in]    operation "w" for write; "a" for append
1091  * \param[in]    x, y location of LL corner of image, in pixels, relative
1092  *                    to the PostScript origin (0,0) at the LL corner
1093  *                    of the page
1094  * \param[in]    res resolution of the input image, in ppi; typ. values
1095  *                   are 300 and 600; use 0 for automatic determination
1096  *                   based on image size
1097  * \param[in]    scale scaling by printer; use 0.0 or 1.0 for no scaling
1098  * \param[in]    pageno page number; must start with 1; you can use 0
1099  *                      if there is only one page.
1100  * \param[in]    maskflag boolean: use TRUE if just painting through fg;
1101  *                        FALSE if painting both fg and bg.
1102  * \param[in]    endpage boolean: use TRUE if this is the last image to be
1103  *                       added to the page; FALSE otherwise
1104  * \return  0 if OK, 1 on error
1105  *
1106  * <pre>
1107  * Notes:
1108  *      (1) See the usage comments in convertJpegToPS(), some of
1109  *          which are repeated here.
1110  *      (2) This is a wrapper for tiff g4.  The PostScript that
1111  *          is generated is expanded by about 5/4 (due to the
1112  *          ascii85 encoding.  If you convert to pdf (ps2pdf), the
1113  *          ascii85 decoder is automatically invoked, so that the
1114  *          pdf wrapped g4 file is essentially the same size as
1115  *          the original g4 file.  It's useful to have the PS
1116  *          file ascii85 encoded, because many printers will not
1117  *          print binary PS files.
1118  *      (3) For the first image written to a file, use "w", which
1119  *          opens for write and clears the file.  For all subsequent
1120  *          images written to that file, use "a".
1121  *      (4) To render multiple images on the same page, set
1122  *          endpage = FALSE for each image until you get to the
1123  *          last, for which you set endpage = TRUE.  This causes the
1124  *          "showpage" command to be invoked.  Showpage outputs
1125  *          the entire page and clears the raster buffer for the
1126  *          next page to be added.  Without a "showpage",
1127  *          subsequent images from the next page will overlay those
1128  *          previously put down.
1129  *      (5) For multiple images to the same page, where you are writing
1130  *          both jpeg and tiff-g4, you have two options:
1131  *           (a) write the g4 first, as either image (maskflag == FALSE)
1132  *               or imagemask (maskflag == TRUE), and then write the
1133  *               jpeg over it.
1134  *           (b) write the jpeg first and as the last item, write
1135  *               the g4 as an imagemask (maskflag == TRUE), to paint
1136  *               through the foreground only.
1137  *          We have this flexibility with the tiff-g4 because it is 1 bpp.
1138  *      (6) For multiple pages, increment the page number, starting
1139  *          with page 1.  This allows PostScript (and PDF) to build
1140  *          a page directory, which viewers use for navigation.
1141  * </pre>
1142  */
1143 l_int32
convertG4ToPS(const char * filein,const char * fileout,const char * operation,l_int32 x,l_int32 y,l_int32 res,l_float32 scale,l_int32 pageno,l_int32 maskflag,l_int32 endpage)1144 convertG4ToPS(const char  *filein,
1145               const char  *fileout,
1146               const char  *operation,
1147               l_int32      x,
1148               l_int32      y,
1149               l_int32      res,
1150               l_float32    scale,
1151               l_int32      pageno,
1152               l_int32      maskflag,
1153               l_int32      endpage)
1154 {
1155 char    *outstr;
1156 l_int32  nbytes;
1157 
1158     PROCNAME("convertG4ToPS");
1159 
1160     if (!filein)
1161         return ERROR_INT("filein not defined", procName, 1);
1162     if (!fileout)
1163         return ERROR_INT("fileout not defined", procName, 1);
1164     if (strcmp(operation, "w") && strcmp(operation, "a"))
1165         return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1);
1166 
1167     if (convertG4ToPSString(filein, &outstr, &nbytes, x, y, res, scale,
1168                             pageno, maskflag, endpage))
1169         return ERROR_INT("ps string not made", procName, 1);
1170 
1171     if (l_binaryWrite(fileout, operation, outstr, nbytes))
1172         return ERROR_INT("ps string not written to file", procName, 1);
1173 
1174     LEPT_FREE(outstr);
1175     return 0;
1176 }
1177 
1178 
1179 /*!
1180  * \brief   convertG4ToPSString()
1181  *
1182  * \param[in]    filein input tiff g4 file
1183  * \param[out]   poutstr PS string
1184  * \param[out]   pnbytes number of bytes in PS string
1185  * \param[in]    x, y location of LL corner of image, in pixels, relative
1186  *                    to the PostScript origin (0,0) at the LL corner
1187  *                    of the page
1188  * \param[in]    res resolution of the input image, in ppi; typ. values
1189  *                   are 300 and 600; use 0 for automatic determination
1190  *                   based on image size
1191  * \param[in]    scale scaling by printer; use 0.0 or 1.0 for no scaling
1192  * \param[in]    pageno page number; must start with 1; you can use 0
1193  *                      if there is only one page.
1194  * \param[in]    maskflag boolean: use TRUE if just painting through fg;
1195  *                        FALSE if painting both fg and bg.
1196  * \param[in]    endpage boolean: use TRUE if this is the last image to be
1197  *                       added to the page; FALSE otherwise
1198  * \return  0 if OK, 1 on error
1199  *
1200  * <pre>
1201  * Notes:
1202  *      (1) Generates PS string in G4 compressed tiff format from G4 tiff file.
1203  *      (2) For usage, see convertG4ToPS().
1204  * </pre>
1205  */
1206 l_int32
convertG4ToPSString(const char * filein,char ** poutstr,l_int32 * pnbytes,l_int32 x,l_int32 y,l_int32 res,l_float32 scale,l_int32 pageno,l_int32 maskflag,l_int32 endpage)1207 convertG4ToPSString(const char  *filein,
1208                     char       **poutstr,
1209                     l_int32     *pnbytes,
1210                     l_int32      x,
1211                     l_int32      y,
1212                     l_int32      res,
1213                     l_float32    scale,
1214                     l_int32      pageno,
1215                     l_int32      maskflag,
1216                     l_int32      endpage)
1217 {
1218 char         *outstr;
1219 l_float32     xpt, ypt, wpt, hpt;
1220 L_COMP_DATA  *cid;
1221 
1222     PROCNAME("convertG4ToPSString");
1223 
1224     if (!poutstr)
1225         return ERROR_INT("&outstr not defined", procName, 1);
1226     if (!pnbytes)
1227         return ERROR_INT("&nbytes not defined", procName, 1);
1228     *poutstr = NULL;
1229     *pnbytes = 0;
1230     if (!filein)
1231         return ERROR_INT("filein not defined", procName, 1);
1232 
1233     if ((cid = l_generateG4Data(filein, 1)) == NULL)
1234         return ERROR_INT("g4 data not made", procName, 1);
1235 
1236         /* Get scaled location in pts.  Guess the input scan resolution
1237          * based on the input parameter %res, the resolution data in
1238          * the pix, and the size of the image. */
1239     if (scale == 0.0)
1240         scale = 1.0;
1241     if (res <= 0) {
1242         if (cid->res > 0) {
1243             res = cid->res;
1244         } else {
1245             if (cid->h <= 3509)  /* A4 height at 300 ppi */
1246                 res = 300;
1247             else
1248                 res = 600;
1249         }
1250     }
1251     xpt = scale * x * 72. / res;
1252     ypt = scale * y * 72. / res;
1253     wpt = scale * cid->w * 72. / res;
1254     hpt = scale * cid->h * 72. / res;
1255 
1256     if (pageno == 0)
1257         pageno = 1;
1258 
1259 #if  DEBUG_G4
1260     fprintf(stderr, "w = %d, h = %d, minisblack = %d\n",
1261             cid->w, cid->h, cid->minisblack);
1262     fprintf(stderr, "comp bytes = %ld, nbytes85 = %ld\n",
1263             (unsigned long)cid->nbytescomp, (unsigned long)cid->nbytes85);
1264     fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n",
1265              xpt, ypt, wpt, hpt);
1266 #endif   /* DEBUG_G4 */
1267 
1268         /* Generate the PS */
1269     outstr = generateG4PS(NULL, cid, xpt, ypt, wpt, hpt,
1270                           maskflag, pageno, endpage);
1271     if (!outstr)
1272         return ERROR_INT("outstr not made", procName, 1);
1273     *poutstr = outstr;
1274     *pnbytes = strlen(outstr);
1275     l_CIDataDestroy(&cid);
1276     return 0;
1277 }
1278 
1279 
1280 /*!
1281  * \brief   generateG4PS()
1282  *
1283  * \param[in]    filein [optional] input tiff g4 file; can be null
1284  * \param[in]    cid g4 compressed image data
1285  * \param[in]    xpt, ypt location of LL corner of image, in pts, relative
1286  *                        to the PostScript origin (0,0) at the LL corner
1287  *                        of the page
1288  * \param[in]    wpt, hpt rendered image size in pts
1289  * \param[in]    maskflag boolean: use TRUE if just painting through fg;
1290  *                        FALSE if painting both fg and bg.
1291  * \param[in]    pageno page number; must start with 1; you can use 0
1292  *                      if there is only one page.
1293  * \param[in]    endpage boolean: use TRUE if this is the last image to be
1294  *                       added to the page; FALSE otherwise
1295  * \return  PS string, or NULL on error
1296  *
1297  * <pre>
1298  * Notes:
1299  *      (1) Low-level function.
1300  * </pre>
1301  */
1302 char *
generateG4PS(const char * filein,L_COMP_DATA * cid,l_float32 xpt,l_float32 ypt,l_float32 wpt,l_float32 hpt,l_int32 maskflag,l_int32 pageno,l_int32 endpage)1303 generateG4PS(const char   *filein,
1304              L_COMP_DATA  *cid,
1305              l_float32     xpt,
1306              l_float32     ypt,
1307              l_float32     wpt,
1308              l_float32     hpt,
1309              l_int32       maskflag,
1310              l_int32       pageno,
1311              l_int32       endpage)
1312 {
1313 l_int32  w, h;
1314 char    *outstr;
1315 char     bigbuf[L_BUF_SIZE];
1316 SARRAY  *sa;
1317 
1318     PROCNAME("generateG4PS");
1319 
1320     if (!cid)
1321         return (char *)ERROR_PTR("g4 data not defined", procName, NULL);
1322     w = cid->w;
1323     h = cid->h;
1324 
1325     if ((sa = sarrayCreate(50)) == NULL)
1326         return (char *)ERROR_PTR("sa not made", procName, NULL);
1327 
1328     sarrayAddString(sa, (char *)"%!PS-Adobe-3.0", L_COPY);
1329     sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY);
1330     if (filein)
1331         snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: %s", filein);
1332     else
1333         snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: G4 compressed PS");
1334     sarrayAddString(sa, bigbuf, L_COPY);
1335     sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY);
1336 
1337     if (var_PS_WRITE_BOUNDING_BOX == 1) {
1338         snprintf(bigbuf, sizeof(bigbuf),
1339             "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
1340                     xpt, ypt, xpt + wpt, ypt + hpt);
1341         sarrayAddString(sa, bigbuf, L_COPY);
1342     }
1343 
1344     sarrayAddString(sa, (char *)"%%LanguageLevel: 2", L_COPY);
1345     sarrayAddString(sa, (char *)"%%EndComments", L_COPY);
1346     snprintf(bigbuf, sizeof(bigbuf), "%%%%Page: %d %d", pageno, pageno);
1347     sarrayAddString(sa, bigbuf, L_COPY);
1348 
1349     sarrayAddString(sa, (char *)"save", L_COPY);
1350     sarrayAddString(sa, (char *)"100 dict begin", L_COPY);
1351 
1352     snprintf(bigbuf, sizeof(bigbuf),
1353         "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
1354     sarrayAddString(sa, bigbuf, L_COPY);
1355 
1356     snprintf(bigbuf, sizeof(bigbuf),
1357         "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
1358     sarrayAddString(sa, bigbuf, L_COPY);
1359 
1360     sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY);
1361 
1362     sarrayAddString(sa, (char *)"{", L_COPY);
1363     sarrayAddString(sa,
1364           (char *)"  /RawData currentfile /ASCII85Decode filter def", L_COPY);
1365     sarrayAddString(sa, (char *)"  << ", L_COPY);
1366     sarrayAddString(sa, (char *)"    /ImageType 1", L_COPY);
1367     snprintf(bigbuf, sizeof(bigbuf), "    /Width %d", w);
1368     sarrayAddString(sa, bigbuf, L_COPY);
1369     snprintf(bigbuf, sizeof(bigbuf), "    /Height %d", h);
1370     sarrayAddString(sa, bigbuf, L_COPY);
1371     snprintf(bigbuf, sizeof(bigbuf),
1372              "    /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
1373     sarrayAddString(sa, bigbuf, L_COPY);
1374     sarrayAddString(sa, (char *)"    /BitsPerComponent 1", L_COPY);
1375     sarrayAddString(sa, (char *)"    /Interpolate true", L_COPY);
1376     if (cid->minisblack)
1377         sarrayAddString(sa, (char *)"    /Decode [1 0]", L_COPY);
1378     else  /* miniswhite; typical for 1 bpp */
1379         sarrayAddString(sa, (char *)"    /Decode [0 1]", L_COPY);
1380     sarrayAddString(sa, (char *)"    /DataSource RawData", L_COPY);
1381     sarrayAddString(sa, (char *)"        <<", L_COPY);
1382     sarrayAddString(sa, (char *)"          /K -1", L_COPY);
1383     snprintf(bigbuf, sizeof(bigbuf), "          /Columns %d", w);
1384     sarrayAddString(sa, bigbuf, L_COPY);
1385     snprintf(bigbuf, sizeof(bigbuf), "          /Rows %d", h);
1386     sarrayAddString(sa, bigbuf, L_COPY);
1387     sarrayAddString(sa, (char *)"        >> /CCITTFaxDecode filter", L_COPY);
1388     if (maskflag == TRUE)  /* just paint through the fg */
1389         sarrayAddString(sa, (char *)"  >> imagemask", L_COPY);
1390     else  /* Paint full image */
1391         sarrayAddString(sa, (char *)"  >> image", L_COPY);
1392     sarrayAddString(sa, (char *)"  RawData flushfile", L_COPY);
1393     if (endpage == TRUE)
1394         sarrayAddString(sa, (char *)"  showpage", L_COPY);
1395     sarrayAddString(sa, (char *)"}", L_COPY);
1396 
1397     sarrayAddString(sa, (char *)"%%BeginData:", L_COPY);
1398     sarrayAddString(sa, (char *)"exec", L_COPY);
1399 
1400         /* Insert the ascii85 ccittg4 data; this is now owned by sa */
1401     sarrayAddString(sa, cid->data85, L_INSERT);
1402 
1403         /* Concat the trailing data */
1404     sarrayAddString(sa, (char *)"%%EndData", L_COPY);
1405     sarrayAddString(sa, (char *)"end", L_COPY);
1406     sarrayAddString(sa, (char *)"restore", L_COPY);
1407 
1408     outstr = sarrayToString(sa, 1);
1409     sarrayDestroy(&sa);
1410     cid->data85 = NULL;  /* it has been transferred and destroyed */
1411     return outstr;
1412 }
1413 
1414 
1415 /*-------------------------------------------------------------*
1416  *                     For tiff multipage files                *
1417  *-------------------------------------------------------------*/
1418 /*!
1419  * \brief   convertTiffMultipageToPS()
1420  *
1421  * \param[in]    filein input tiff multipage file
1422  * \param[in]    fileout output ps file
1423  * \param[in]    fillfract factor for filling 8.5 x 11 inch page;
1424  *                      use 0.0 for DEFAULT_FILL_FRACTION
1425  * \return  0 if OK, 1 on error
1426  *
1427  * <pre>
1428  * Notes:
1429  *      (1) This converts a multipage tiff file of binary page images
1430  *          into a ccitt g4 compressed PS file.
1431  *      (2) If the images are generated from a standard resolution fax,
1432  *          the vertical resolution is doubled to give a normal-looking
1433  *          aspect ratio.
1434  * </pre>
1435  */
1436 l_int32
convertTiffMultipageToPS(const char * filein,const char * fileout,l_float32 fillfract)1437 convertTiffMultipageToPS(const char  *filein,
1438                          const char  *fileout,
1439                          l_float32    fillfract)
1440 {
1441 char      *tempfile;
1442 l_int32    i, npages, w, h, istiff;
1443 l_float32  scale;
1444 PIX       *pix, *pixs;
1445 FILE      *fp;
1446 
1447     PROCNAME("convertTiffMultipageToPS");
1448 
1449     if (!filein)
1450         return ERROR_INT("filein not defined", procName, 1);
1451     if (!fileout)
1452         return ERROR_INT("fileout not defined", procName, 1);
1453 
1454     if ((fp = fopenReadStream(filein)) == NULL)
1455         return ERROR_INT("file not found", procName, 1);
1456     istiff = fileFormatIsTiff(fp);
1457     if (!istiff) {
1458         fclose(fp);
1459         return ERROR_INT("file not tiff format", procName, 1);
1460     }
1461     tiffGetCount(fp, &npages);
1462     fclose(fp);
1463 
1464     if (fillfract == 0.0)
1465         fillfract = DEFAULT_FILL_FRACTION;
1466 
1467     for (i = 0; i < npages; i++) {
1468         if ((pix = pixReadTiff(filein, i)) == NULL)
1469             return ERROR_INT("pix not made", procName, 1);
1470 
1471         pixGetDimensions(pix, &w, &h, NULL);
1472         if (w == 1728 && h < w)   /* it's a std res fax */
1473             pixs = pixScale(pix, 1.0, 2.0);
1474         else
1475             pixs = pixClone(pix);
1476 
1477         tempfile = l_makeTempFilename();
1478         pixWrite(tempfile, pixs, IFF_TIFF_G4);
1479         scale = L_MIN(fillfract * 2550 / w, fillfract * 3300 / h);
1480         if (i == 0)
1481             convertG4ToPS(tempfile, fileout, "w", 0, 0, 300, scale,
1482                           i + 1, FALSE, TRUE);
1483         else
1484             convertG4ToPS(tempfile, fileout, "a", 0, 0, 300, scale,
1485                           i + 1, FALSE, TRUE);
1486         lept_rmfile(tempfile);
1487         LEPT_FREE(tempfile);
1488         pixDestroy(&pix);
1489         pixDestroy(&pixs);
1490     }
1491 
1492     return 0;
1493 }
1494 
1495 
1496 /*---------------------------------------------------------------------*
1497  *            For flate (gzip) compressed images (e.g., png)           *
1498  *---------------------------------------------------------------------*/
1499 /*!
1500  * \brief   convertFlateToPSEmbed()
1501  *
1502  * \param[in]    filein input file -- any format
1503  * \param[in]    fileout output ps file
1504  * \return  0 if OK, 1 on error
1505  *
1506  * <pre>
1507  * Notes:
1508  *      (1) This function takes any image file as input and generates a
1509  *          flate-compressed, ascii85 encoded PS file, with a bounding box.
1510  *      (2) The bounding box is required when a program such as TeX
1511  *          (through epsf) places and rescales the image.
1512  *      (3) The bounding box is sized for fitting the image to an
1513  *          8.5 x 11.0 inch page.
1514  * </pre>
1515  */
1516 l_int32
convertFlateToPSEmbed(const char * filein,const char * fileout)1517 convertFlateToPSEmbed(const char  *filein,
1518                       const char  *fileout)
1519 {
1520 char         *outstr;
1521 l_int32       w, h, nbytes, ret;
1522 l_float32     xpt, ypt, wpt, hpt;
1523 L_COMP_DATA  *cid;
1524 
1525     PROCNAME("convertFlateToPSEmbed");
1526 
1527     if (!filein)
1528         return ERROR_INT("filein not defined", procName, 1);
1529     if (!fileout)
1530         return ERROR_INT("fileout not defined", procName, 1);
1531 
1532     if ((cid = l_generateFlateData(filein, 1)) == NULL)
1533         return ERROR_INT("flate data not made", procName, 1);
1534     w = cid->w;
1535     h = cid->h;
1536 
1537         /* Scale for 20 pt boundary and otherwise full filling
1538          * in one direction on 8.5 x 11 inch device */
1539     xpt = 20.0;
1540     ypt = 20.0;
1541     if (w * 11.0 > h * 8.5) {
1542         wpt = 572.0;   /* 612 - 2 * 20 */
1543         hpt = wpt * (l_float32)h / (l_float32)w;
1544     } else {
1545         hpt = 752.0;   /* 792 - 2 * 20 */
1546         wpt = hpt * (l_float32)w / (l_float32)h;
1547     }
1548 
1549         /* Generate the PS.
1550          * The bounding box information should be inserted (default). */
1551     outstr = generateFlatePS(NULL, cid, xpt, ypt, wpt, hpt, 1, 1);
1552     l_CIDataDestroy(&cid);
1553     if (!outstr)
1554         return ERROR_INT("outstr not made", procName, 1);
1555     nbytes = strlen(outstr);
1556 
1557     ret = l_binaryWrite(fileout, "w", outstr, nbytes);
1558     LEPT_FREE(outstr);
1559     if (ret) L_ERROR("ps string not written to file\n", procName);
1560     return ret;
1561 }
1562 
1563 
1564 /*!
1565  * \brief   convertFlateToPS()
1566  *
1567  * \param[in]    filein input file -- any format
1568  * \param[in]    fileout output ps file
1569  * \param[in]    operation "w" for write; "a" for append
1570  * \param[in]    x, y location of LL corner of image, in pixels, relative
1571  *                    to the PostScript origin (0,0) at the LL corner
1572  *                    of the page
1573  * \param[in]    res resolution of the input image, in ppi; use 0 for default
1574  * \param[in]    scale scaling by printer; use 0.0 or 1.0 for no scaling
1575  * \param[in]    pageno page number; must start with 1; you can use 0
1576  *                      if there is only one page.
1577  * \param[in]    endpage boolean: use TRUE if this is the last image to be
1578  *                       added to the page; FALSE otherwise
1579  * \return  0 if OK, 1 on error
1580  *
1581  * <pre>
1582  * Notes:
1583  *      (1) This outputs level 3 PS as flate compressed (overlaid
1584  *          with ascii85 encoding).
1585  *      (2) An output file can contain multiple pages, each with
1586  *          multiple images.  The arguments to convertFlateToPS()
1587  *          allow you to control placement of png images on multiple
1588  *          pages within a PostScript file.
1589  *      (3) For the first image written to a file, use "w", which
1590  *          opens for write and clears the file.  For all subsequent
1591  *          images written to that file, use "a".
1592  *      (4) The (x, y) parameters give the LL corner of the image
1593  *          relative to the LL corner of the page.  They are in
1594  *          units of pixels if scale = 1.0.  If you use (e.g.)
1595  *          scale = 2.0, the image is placed at (2x, 2y) on the page,
1596  *          and the image dimensions are also doubled.
1597  *      (5) Display vs printed resolution:
1598  *           * If your display is 75 ppi and your image was created
1599  *             at a resolution of 300 ppi, you can get the image
1600  *             to print at the same size as it appears on your display
1601  *             by either setting scale = 4.0 or by setting  res = 75.
1602  *             Both tell the printer to make a 4x enlarged image.
1603  *           * If your image is generated at 150 ppi and you use scale = 1,
1604  *             it will be rendered such that 150 pixels correspond
1605  *             to 72 pts (1 inch on the printer).  This function does
1606  *             the conversion from pixels (with or without scaling) to
1607  *             pts, which are the units that the printer uses.
1608  *           * The printer will choose its own resolution to use
1609  *             in rendering the image, which will not affect the size
1610  *             of the rendered image.  That is because the output
1611  *             PostScript file describes the geometry in terms of pts,
1612  *             which are defined to be 1/72 inch.  The printer will
1613  *             only see the size of the image in pts, through the
1614  *             scale and translate parameters and the affine
1615  *             transform (the ImageMatrix) of the image.
1616  *      (6) To render multiple images on the same page, set
1617  *          endpage = FALSE for each image until you get to the
1618  *          last, for which you set endpage = TRUE.  This causes the
1619  *          "showpage" command to be invoked.  Showpage outputs
1620  *          the entire page and clears the raster buffer for the
1621  *          next page to be added.  Without a "showpage",
1622  *          subsequent images from the next page will overlay those
1623  *          previously put down.
1624  *      (7) For multiple pages, increment the page number, starting
1625  *          with page 1.  This allows PostScript (and PDF) to build
1626  *          a page directory, which viewers use for navigation.
1627  * </pre>
1628  */
1629 l_int32
convertFlateToPS(const char * filein,const char * fileout,const char * operation,l_int32 x,l_int32 y,l_int32 res,l_float32 scale,l_int32 pageno,l_int32 endpage)1630 convertFlateToPS(const char  *filein,
1631                  const char  *fileout,
1632                  const char  *operation,
1633                  l_int32      x,
1634                  l_int32      y,
1635                  l_int32      res,
1636                  l_float32    scale,
1637                  l_int32      pageno,
1638                  l_int32      endpage)
1639 {
1640 char    *outstr;
1641 l_int32  nbytes, ret;
1642 
1643     PROCNAME("convertFlateToPS");
1644 
1645     if (!filein)
1646         return ERROR_INT("filein not defined", procName, 1);
1647     if (!fileout)
1648         return ERROR_INT("fileout not defined", procName, 1);
1649     if (strcmp(operation, "w") && strcmp(operation, "a"))
1650         return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1);
1651 
1652     if (convertFlateToPSString(filein, &outstr, &nbytes, x, y, res, scale,
1653                                pageno, endpage))
1654         return ERROR_INT("ps string not made", procName, 1);
1655 
1656     ret = l_binaryWrite(fileout, operation, outstr, nbytes);
1657     LEPT_FREE(outstr);
1658     if (ret) L_ERROR("ps string not written to file\n", procName);
1659     return ret;
1660 }
1661 
1662 
1663 /*!
1664  * \brief   convertFlateToPSString()
1665  *
1666  *      Generates level 3 PS string in flate compressed format.
1667  *
1668  * \param[in]    filein input image file
1669  * \param[out]   poutstr PS string
1670  * \param[out]   pnbytes number of bytes in PS string
1671  * \param[in]    x, y location of LL corner of image, in pixels, relative
1672  *                    to the PostScript origin (0,0) at the LL corner
1673  *                    of the page
1674  * \param[in]    res resolution of the input image, in ppi; use 0 for default
1675  * \param[in]    scale scaling by printer; use 0.0 or 1.0 for no scaling
1676  * \param[in]    pageno page number; must start with 1; you can use 0
1677  *                      if there is only one page.
1678  * \param[in]    endpage boolean: use TRUE if this is the last image to be
1679  *                       added to the page; FALSE otherwise
1680  * \return  0 if OK, 1 on error
1681  *
1682  * <pre>
1683  * Notes:
1684  *      (1) The returned PS character array is a null-terminated
1685  *          ascii string.  All the raster data is ascii85 encoded, so
1686  *          there are no null bytes embedded in it.
1687  *      (2) The raster encoding is made with gzip, the same as that
1688  *          in a png file that is compressed without prediction.
1689  *          The raster data itself is 25% larger than that in the
1690  *          binary form, due to the ascii85 encoding.
1691  *
1692  *  Usage:  See convertFlateToPS()
1693  * </pre>
1694  */
1695 l_int32
convertFlateToPSString(const char * filein,char ** poutstr,l_int32 * pnbytes,l_int32 x,l_int32 y,l_int32 res,l_float32 scale,l_int32 pageno,l_int32 endpage)1696 convertFlateToPSString(const char  *filein,
1697                        char       **poutstr,
1698                        l_int32     *pnbytes,
1699                        l_int32      x,
1700                        l_int32      y,
1701                        l_int32      res,
1702                        l_float32    scale,
1703                        l_int32      pageno,
1704                        l_int32      endpage)
1705 {
1706 char         *outstr;
1707 l_float32     xpt, ypt, wpt, hpt;
1708 L_COMP_DATA  *cid;
1709 
1710     PROCNAME("convertFlateToPSString");
1711 
1712     if (!poutstr)
1713         return ERROR_INT("&outstr not defined", procName, 1);
1714     if (!pnbytes)
1715         return ERROR_INT("&nbytes not defined", procName, 1);
1716     *pnbytes = 0;
1717     *poutstr = NULL;
1718     if (!filein)
1719         return ERROR_INT("filein not defined", procName, 1);
1720 
1721     if ((cid = l_generateFlateData(filein, 1)) == NULL)
1722         return ERROR_INT("flate data not made", procName, 1);
1723 
1724         /* Get scaled location in pts.  Guess the input scan resolution
1725          * based on the input parameter %res, the resolution data in
1726          * the pix, and the size of the image. */
1727     if (scale == 0.0)
1728         scale = 1.0;
1729     if (res <= 0) {
1730         if (cid->res > 0)
1731             res = cid->res;
1732         else
1733             res = DEFAULT_INPUT_RES;
1734     }
1735     xpt = scale * x * 72. / res;
1736     ypt = scale * y * 72. / res;
1737     wpt = scale * cid->w * 72. / res;
1738     hpt = scale * cid->h * 72. / res;
1739 
1740     if (pageno == 0)
1741         pageno = 1;
1742 
1743 #if  DEBUG_FLATE
1744     fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n",
1745             cid->w, cid->h, cid->bps, cid->spp);
1746     fprintf(stderr, "uncomp bytes = %ld, comp bytes = %ld, nbytes85 = %ld\n",
1747             (unsigned long)cid->nbytes, (unsigned long)cid->nbytescomp,
1748             (unsigned long)cid->nbytes85);
1749     fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n",
1750              xpt, ypt, wpt, hpt);
1751 #endif   /* DEBUG_FLATE */
1752 
1753         /* Generate the PS */
1754     outstr = generateFlatePS(NULL, cid, xpt, ypt, wpt, hpt, pageno, endpage);
1755     if (!outstr)
1756         return ERROR_INT("outstr not made", procName, 1);
1757     *poutstr = outstr;
1758     *pnbytes = strlen(outstr);
1759     l_CIDataDestroy(&cid);
1760     return 0;
1761 }
1762 
1763 
1764 /*!
1765  * \brief   generateFlatePS()
1766  *
1767  * \param[in]    filein [optional] input filename; can be null
1768  * \param[in]    cid flate compressed image data
1769  * \param[in]    xpt, ypt location of LL corner of image, in pts, relative
1770  *                        to the PostScript origin (0,0) at the LL corner
1771  *                        of the page
1772  * \param[in]    wpt, hpt rendered image size in pts
1773  * \param[in]    pageno page number; must start with 1; you can use 0
1774  *                      if there is only one page
1775  * \param[in]    endpage boolean: use TRUE if this is the last image to be
1776  *                       added to the page; FALSE otherwise
1777  * \return  PS string, or NULL on error
1778  */
1779 char *
generateFlatePS(const char * filein,L_COMP_DATA * cid,l_float32 xpt,l_float32 ypt,l_float32 wpt,l_float32 hpt,l_int32 pageno,l_int32 endpage)1780 generateFlatePS(const char   *filein,
1781                 L_COMP_DATA  *cid,
1782                 l_float32     xpt,
1783                 l_float32     ypt,
1784                 l_float32     wpt,
1785                 l_float32     hpt,
1786                 l_int32       pageno,
1787                 l_int32       endpage)
1788 {
1789 l_int32  w, h, bps, spp;
1790 char    *outstr;
1791 char     bigbuf[L_BUF_SIZE];
1792 SARRAY  *sa;
1793 
1794     PROCNAME("generateFlatePS");
1795 
1796     if (!cid)
1797         return (char *)ERROR_PTR("flate data not defined", procName, NULL);
1798     w = cid->w;
1799     h = cid->h;
1800     bps = cid->bps;
1801     spp = cid->spp;
1802 
1803     if ((sa = sarrayCreate(50)) == NULL)
1804         return (char *)ERROR_PTR("sa not made", procName, NULL);
1805 
1806     sarrayAddString(sa, (char *)"%!PS-Adobe-3.0 EPSF-3.0", L_COPY);
1807     sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY);
1808     if (filein)
1809         snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: %s", filein);
1810     else
1811         snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: Flate compressed PS");
1812     sarrayAddString(sa, bigbuf, L_COPY);
1813     sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY);
1814 
1815     if (var_PS_WRITE_BOUNDING_BOX == 1) {
1816         snprintf(bigbuf, sizeof(bigbuf),
1817                  "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
1818                  xpt, ypt, xpt + wpt, ypt + hpt);
1819         sarrayAddString(sa, bigbuf, L_COPY);
1820     }
1821 
1822     sarrayAddString(sa, (char *)"%%LanguageLevel: 3", L_COPY);
1823     sarrayAddString(sa, (char *)"%%EndComments", L_COPY);
1824     snprintf(bigbuf, sizeof(bigbuf), "%%%%Page: %d %d", pageno, pageno);
1825     sarrayAddString(sa, bigbuf, L_COPY);
1826 
1827     sarrayAddString(sa, (char *)"save", L_COPY);
1828     snprintf(bigbuf, sizeof(bigbuf),
1829            "%7.2f %7.2f translate         %%set image origin in pts", xpt, ypt);
1830     sarrayAddString(sa, bigbuf, L_COPY);
1831 
1832     snprintf(bigbuf, sizeof(bigbuf),
1833              "%7.2f %7.2f scale             %%set image size in pts", wpt, hpt);
1834     sarrayAddString(sa, bigbuf, L_COPY);
1835 
1836         /* If there is a colormap, add the data; it is now owned by sa */
1837     if (cid->cmapdata85) {
1838         snprintf(bigbuf, sizeof(bigbuf),
1839                  "[ /Indexed /DeviceRGB %d          %%set colormap type/size",
1840                  cid->ncolors - 1);
1841         sarrayAddString(sa, bigbuf, L_COPY);
1842         sarrayAddString(sa, (char *)"  <~", L_COPY);
1843         sarrayAddString(sa, cid->cmapdata85, L_INSERT);
1844         sarrayAddString(sa, (char *)"  ] setcolorspace", L_COPY);
1845     } else if (spp == 1) {
1846         sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY);
1847     } else {  /* spp == 3 */
1848         sarrayAddString(sa, (char *)"/DeviceRGB setcolorspace", L_COPY);
1849     }
1850 
1851     sarrayAddString(sa,
1852               (char *)"/RawData currentfile /ASCII85Decode filter def", L_COPY);
1853     sarrayAddString(sa,
1854               (char *)"/Data RawData << >> /FlateDecode filter def", L_COPY);
1855 
1856     sarrayAddString(sa, (char *)"{ << /ImageType 1", L_COPY);
1857     snprintf(bigbuf, sizeof(bigbuf), "     /Width %d", w);
1858     sarrayAddString(sa, bigbuf, L_COPY);
1859     snprintf(bigbuf, sizeof(bigbuf), "     /Height %d", h);
1860     sarrayAddString(sa, bigbuf, L_COPY);
1861     snprintf(bigbuf, sizeof(bigbuf), "     /BitsPerComponent %d", bps);
1862     sarrayAddString(sa, bigbuf, L_COPY);
1863     snprintf(bigbuf, sizeof(bigbuf),
1864             "     /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
1865     sarrayAddString(sa, bigbuf, L_COPY);
1866 
1867     if (cid->cmapdata85) {
1868         sarrayAddString(sa, (char *)"     /Decode [0 255]", L_COPY);
1869     } else if (spp == 1) {
1870         if (bps == 1)  /* miniswhite photometry */
1871             sarrayAddString(sa, (char *)"     /Decode [1 0]", L_COPY);
1872         else  /* bps > 1 */
1873             sarrayAddString(sa, (char *)"     /Decode [0 1]", L_COPY);
1874     } else {  /* spp == 3 */
1875         sarrayAddString(sa, (char *)"     /Decode [0 1 0 1 0 1]", L_COPY);
1876     }
1877 
1878     sarrayAddString(sa, (char *)"     /DataSource Data", L_COPY);
1879     sarrayAddString(sa, (char *)"  >> image", L_COPY);
1880     sarrayAddString(sa, (char *)"  Data closefile", L_COPY);
1881     sarrayAddString(sa, (char *)"  RawData flushfile", L_COPY);
1882     if (endpage == TRUE)
1883         sarrayAddString(sa, (char *)"  showpage", L_COPY);
1884     sarrayAddString(sa, (char *)"  restore", L_COPY);
1885     sarrayAddString(sa, (char *)"} exec", L_COPY);
1886 
1887         /* Insert the ascii85 gzipped data; this is now owned by sa */
1888     sarrayAddString(sa, cid->data85, L_INSERT);
1889 
1890         /* Generate and return the output string */
1891     outstr = sarrayToString(sa, 1);
1892     sarrayDestroy(&sa);
1893     cid->cmapdata85 = NULL;  /* it has been transferred to sa and destroyed */
1894     cid->data85 = NULL;  /* it has been transferred to sa and destroyed */
1895     return outstr;
1896 }
1897 
1898 
1899 /*---------------------------------------------------------------------*
1900  *                          Write to memory                            *
1901  *---------------------------------------------------------------------*/
1902 /*!
1903  * \brief   pixWriteMemPS()
1904  *
1905  * \param[out]   pdata data of tiff compressed image
1906  * \param[out]   psize size of returned data
1907  * \param[in]    pix
1908  * \param[in]    box  [optional]
1909  * \param[in]    res  can use 0 for default of 300 ppi
1910  * \param[in]    scale to prevent scaling, use either 1.0 or 0.0
1911  * \return  0 if OK, 1 on error
1912  *
1913  * <pre>
1914  * Notes:
1915  *      (1) See pixWriteStringPS() for usage.
1916  *      (2) This is just a wrapper for pixWriteStringPS(), which
1917  *          writes uncompressed image data to memory.
1918  * </pre>
1919  */
1920 l_int32
pixWriteMemPS(l_uint8 ** pdata,size_t * psize,PIX * pix,BOX * box,l_int32 res,l_float32 scale)1921 pixWriteMemPS(l_uint8  **pdata,
1922               size_t    *psize,
1923               PIX       *pix,
1924               BOX       *box,
1925               l_int32    res,
1926               l_float32  scale)
1927 {
1928     PROCNAME("pixWriteMemPS");
1929 
1930     if (!pdata)
1931         return ERROR_INT("&data not defined", procName, 1 );
1932     if (!psize)
1933         return ERROR_INT("&size not defined", procName, 1 );
1934     if (!pix)
1935         return ERROR_INT("&pix not defined", procName, 1 );
1936 
1937     *pdata = (l_uint8 *)pixWriteStringPS(pix, box, res, scale);
1938     *psize = strlen((char *)(*pdata));
1939     return 0;
1940 }
1941 
1942 
1943 /*-------------------------------------------------------------*
1944  *                    Converting resolution                    *
1945  *-------------------------------------------------------------*/
1946 /*!
1947  * \brief   getResLetterPage()
1948  *
1949  * \param[in]    w image width, pixels
1950  * \param[in]    h image height, pixels
1951  * \param[in]    fillfract fraction in linear dimension of full page, not
1952  *                         to be exceeded; use 0 for default
1953  * \return  0 if OK, 1 on error
1954  */
1955 l_int32
getResLetterPage(l_int32 w,l_int32 h,l_float32 fillfract)1956 getResLetterPage(l_int32    w,
1957                  l_int32    h,
1958                  l_float32  fillfract)
1959 {
1960 l_int32  resw, resh, res;
1961 
1962     if (fillfract == 0.0)
1963         fillfract = DEFAULT_FILL_FRACTION;
1964     resw = (l_int32)((w * 72.) / (LETTER_WIDTH * fillfract));
1965     resh = (l_int32)((h * 72.) / (LETTER_HEIGHT * fillfract));
1966     res = L_MAX(resw, resh);
1967     return res;
1968 }
1969 
1970 
1971 /*!
1972  * \brief   getResA4Page()
1973  *
1974  * \param[in]    w image width, pixels
1975  * \param[in]    h image height, pixels
1976  * \param[in]    fillfract fraction in linear dimension of full page, not
1977  *                        to be exceeded; use 0 for default
1978  * \return  0 if OK, 1 on error
1979  */
1980 l_int32
getResA4Page(l_int32 w,l_int32 h,l_float32 fillfract)1981 getResA4Page(l_int32    w,
1982              l_int32    h,
1983              l_float32  fillfract)
1984 {
1985 l_int32  resw, resh, res;
1986 
1987     if (fillfract == 0.0)
1988         fillfract = DEFAULT_FILL_FRACTION;
1989     resw = (l_int32)((w * 72.) / (A4_WIDTH * fillfract));
1990     resh = (l_int32)((h * 72.) / (A4_HEIGHT * fillfract));
1991     res = L_MAX(resw, resh);
1992     return res;
1993 }
1994 
1995 
1996 /*-------------------------------------------------------------*
1997  *           Setting flag for writing bounding box hint        *
1998  *-------------------------------------------------------------*/
1999 void
l_psWriteBoundingBox(l_int32 flag)2000 l_psWriteBoundingBox(l_int32  flag)
2001 {
2002     var_PS_WRITE_BOUNDING_BOX = flag;
2003 }
2004 
2005 
2006 /* --------------------------------------------*/
2007 #endif  /* USE_PSIO */
2008 /* --------------------------------------------*/
2009