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