comparison mupdf-source/thirdparty/leptonica/src/psio2.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 {
191 l_int32 w, h, ret;
192 l_float32 scale;
193 FILE *fp;
194 PIX *pix;
195
196 if (!filein)
197 return ERROR_INT("filein not defined", __func__, 1);
198 if (!fileout)
199 return ERROR_INT("fileout not defined", __func__, 1);
200
201 if ((pix = pixRead(filein)) == NULL)
202 return ERROR_INT("image not read from file", __func__, 1);
203 w = pixGetWidth(pix);
204 h = pixGetHeight(pix);
205 if (w * 11.0 > h * 8.5)
206 scale = 8.5f * 300.f / (l_float32)w;
207 else
208 scale = 11.0f * 300.f / (l_float32)h;
209
210 if ((fp = fopenWriteStream(fileout, "wb")) == NULL)
211 return ERROR_INT_1("file not opened for write", fileout, __func__, 1);
212 ret = pixWriteStreamPS(fp, pix, NULL, 0, scale);
213 fclose(fp);
214
215 pixDestroy(&pix);
216 return ret;
217 }
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 {
245 char *outstr;
246 l_int32 length;
247 PIX *pixc;
248
249 if (!fp)
250 return (l_int32)ERROR_INT("stream not open", __func__, 1);
251 if (!pix)
252 return (l_int32)ERROR_INT("pix not defined", __func__, 1);
253
254 if ((pixc = pixConvertForPSWrap(pix)) == NULL)
255 return (l_int32)ERROR_INT("pixc not made", __func__, 1);
256
257 if ((outstr = pixWriteStringPS(pixc, box, res, scale)) == NULL) {
258 pixDestroy(&pixc);
259 return (l_int32)ERROR_INT("outstr not made", __func__, 1);
260 }
261 length = strlen(outstr);
262 fwrite(outstr, 1, length, fp);
263 LEPT_FREE(outstr);
264 pixDestroy(&pixc);
265 return 0;
266 }
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 {
342 char nib1, nib2;
343 char *hexdata, *outstr;
344 l_uint8 byteval;
345 l_int32 i, j, k, w, h, d;
346 l_float32 wpt, hpt, xpt, ypt;
347 l_int32 wpl, psbpl, hexbytes, boxflag, bps;
348 l_uint32 *line, *data;
349 PIX *pix;
350
351 if (!pixs)
352 return (char *)ERROR_PTR("pixs not defined", __func__, NULL);
353
354 if ((pix = pixConvertForPSWrap(pixs)) == NULL)
355 return (char *)ERROR_PTR("pix not made", __func__, NULL);
356 pixGetDimensions(pix, &w, &h, &d);
357
358 /* Get the factors by which PS scales and translates, in pts */
359 if (!box)
360 boxflag = 0; /* no scaling; b.b. at center */
361 else
362 boxflag = 1; /* no b.b., specify placement and optional scaling */
363 getScaledParametersPS(box, w, h, res, scale, &xpt, &ypt, &wpt, &hpt);
364
365 if (d == 1)
366 bps = 1; /* bits/sample */
367 else /* d == 8 || d == 32 */
368 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 wpl = pixGetWpl(pix);
376 if (d == 1 || d == 8)
377 psbpl = (w * d + 7) / 8;
378 else /* d == 32 */
379 psbpl = 3 * w;
380 data = pixGetData(pix);
381 hexbytes = 2 * psbpl * h; /* size of ps hex array */
382 if ((hexdata = (char *)LEPT_CALLOC(hexbytes + 1, sizeof(char))) == NULL)
383 return (char *)ERROR_PTR("hexdata not made", __func__, NULL);
384 if (d == 1 || d == 8) {
385 for (i = 0, k = 0; i < h; i++) {
386 line = data + i * wpl;
387 for (j = 0; j < psbpl; j++) {
388 byteval = GET_DATA_BYTE(line, j);
389 convertByteToHexAscii(byteval, &nib1, &nib2);
390 hexdata[k++] = nib1;
391 hexdata[k++] = nib2;
392 }
393 }
394 } else { /* d == 32; hexdata bytes packed RGBRGB..., 2 per sample */
395 for (i = 0, k = 0; i < h; i++) {
396 line = data + i * wpl;
397 for (j = 0; j < w; j++) {
398 byteval = GET_DATA_BYTE(line + j, 0); /* red */
399 convertByteToHexAscii(byteval, &nib1, &nib2);
400 hexdata[k++] = nib1;
401 hexdata[k++] = nib2;
402 byteval = GET_DATA_BYTE(line + j, 1); /* green */
403 convertByteToHexAscii(byteval, &nib1, &nib2);
404 hexdata[k++] = nib1;
405 hexdata[k++] = nib2;
406 byteval = GET_DATA_BYTE(line + j, 2); /* blue */
407 convertByteToHexAscii(byteval, &nib1, &nib2);
408 hexdata[k++] = nib1;
409 hexdata[k++] = nib2;
410 }
411 }
412 }
413 hexdata[k] = '\0';
414
415 outstr = generateUncompressedPS(hexdata, w, h, d, psbpl, bps,
416 xpt, ypt, wpt, hpt, boxflag);
417 pixDestroy(&pix);
418 if (!outstr)
419 return (char *)ERROR_PTR("outstr not made", __func__, NULL);
420 return outstr;
421 }
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 {
457 char *outstr;
458 char bigbuf[Bufsize];
459 SARRAY *sa;
460
461 if (!hexdata)
462 return (char *)ERROR_PTR("hexdata not defined", __func__, NULL);
463
464 sa = sarrayCreate(0);
465 sarrayAddString(sa, "%!Adobe-PS", L_COPY);
466 if (boxflag == 0) {
467 snprintf(bigbuf, sizeof(bigbuf),
468 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
469 xpt, ypt, xpt + wpt, ypt + hpt);
470 sarrayAddString(sa, bigbuf, L_COPY);
471 } else { /* boxflag == 1 */
472 sarrayAddString(sa, "gsave", L_COPY);
473 }
474
475 if (d == 1)
476 sarrayAddString(sa,
477 "{1 exch sub} settransfer %invert binary", L_COPY);
478
479 snprintf(bigbuf, sizeof(bigbuf),
480 "/bpl %d string def %%bpl as a string", psbpl);
481 sarrayAddString(sa, bigbuf, L_COPY);
482 snprintf(bigbuf, sizeof(bigbuf),
483 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt);
484 sarrayAddString(sa, bigbuf, L_COPY);
485 snprintf(bigbuf, sizeof(bigbuf),
486 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt);
487 sarrayAddString(sa, bigbuf, L_COPY);
488 snprintf(bigbuf, sizeof(bigbuf),
489 "%d %d %d %%image dimensions in pixels", w, h, bps);
490 sarrayAddString(sa, bigbuf, L_COPY);
491 snprintf(bigbuf, sizeof(bigbuf),
492 "[%d %d %d %d %d %d] %%mapping matrix: [w 0 0 -h 0 h]",
493 w, 0, 0, -h, 0, h);
494 sarrayAddString(sa, bigbuf, L_COPY);
495
496 if (boxflag == 0) {
497 if (d == 1 || d == 8)
498 sarrayAddString(sa,
499 "{currentfile bpl readhexstring pop} image", L_COPY);
500 else /* d == 32 */
501 sarrayAddString(sa,
502 "{currentfile bpl readhexstring pop} false 3 colorimage",
503 L_COPY);
504 } else { /* boxflag == 1 */
505 if (d == 1 || d == 8)
506 sarrayAddString(sa,
507 "{currentfile bpl readhexstring pop} bind image", L_COPY);
508 else /* d == 32 */
509 sarrayAddString(sa,
510 "{currentfile bpl readhexstring pop} bind false 3 colorimage",
511 L_COPY);
512 }
513
514 sarrayAddString(sa, hexdata, L_INSERT);
515
516 if (boxflag == 0)
517 sarrayAddString(sa, "\nshowpage", L_COPY);
518 else /* boxflag == 1 */
519 sarrayAddString(sa, "\ngrestore", L_COPY);
520
521 outstr = sarrayToString(sa, 1);
522 sarrayDestroy(&sa);
523 if (!outstr) L_ERROR("outstr not made\n", __func__);
524 return outstr;
525 }
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 {
560 l_int32 bx, by, bw, bh;
561 l_float32 winch, hinch, xinch, yinch, fres;
562
563 if (res == 0)
564 res = DefaultInputRes;
565 fres = (l_float32)res;
566
567 /* Allow the PS interpreter to scale the resolution */
568 if (scale == 0.0)
569 scale = 1.0;
570 if (scale != 1.0) {
571 fres = (l_float32)res / scale;
572 res = (l_int32)fres;
573 }
574
575 /* Limit valid resolution interval */
576 if (res < MinRes || res > MaxRes) {
577 L_WARNING("res %d out of bounds; using default res; no scaling\n",
578 __func__, res);
579 res = DefaultInputRes;
580 fres = (l_float32)res;
581 }
582
583 if (!box) { /* center on page */
584 winch = (l_float32)wpix / fres;
585 hinch = (l_float32)hpix / fres;
586 xinch = (8.5f - winch) / 2.f;
587 yinch = (11.0f - hinch) / 2.f;
588 } else {
589 boxGetGeometry(box, &bx, &by, &bw, &bh);
590 if (bw == 0)
591 winch = (l_float32)wpix / fres;
592 else
593 winch = (l_float32)bw / 1000.f;
594 if (bh == 0)
595 hinch = (l_float32)hpix / fres;
596 else
597 hinch = (l_float32)bh / 1000.f;
598 xinch = (l_float32)bx / 1000.f;
599 yinch = (l_float32)by / 1000.f;
600 }
601
602 if (xinch < 0)
603 L_WARNING("left edge < 0.0 inch\n", __func__);
604 if (xinch + winch > 8.5)
605 L_WARNING("right edge > 8.5 inch\n", __func__);
606 if (yinch < 0.0)
607 L_WARNING("bottom edge < 0.0 inch\n", __func__);
608 if (yinch + hinch > 11.0)
609 L_WARNING("top edge > 11.0 inch\n", __func__);
610
611 *pwpt = 72.f * winch;
612 *phpt = 72.f * hinch;
613 *pxpt = 72.f * xinch;
614 *pypt = 72.f * yinch;
615 return;
616 }
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 {
631 l_uint8 nib;
632
633 nib = byteval >> 4;
634 if (nib < 10)
635 *pnib1 = '0' + nib;
636 else
637 *pnib1 = 'a' + (nib - 10);
638 nib = byteval & 0xf;
639 if (nib < 10)
640 *pnib2 = '0' + nib;
641 else
642 *pnib2 = 'a' + (nib - 10);
643 return;
644 }
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 {
671 char *outstr;
672 l_int32 w, h, nbytes, ret;
673 l_float32 xpt, ypt, wpt, hpt;
674 L_COMP_DATA *cid;
675
676 if (!filein)
677 return ERROR_INT("filein not defined", __func__, 1);
678 if (!fileout)
679 return ERROR_INT("fileout not defined", __func__, 1);
680
681 /* Generate the ascii encoded jpeg data */
682 if ((cid = l_generateJpegData(filein, 1)) == NULL)
683 return ERROR_INT("jpeg data not made", __func__, 1);
684 w = cid->w;
685 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 xpt = 20.0;
690 ypt = 20.0;
691 if (w * 11.0 > h * 8.5) {
692 wpt = 572.0; /* 612 - 2 * 20 */
693 hpt = wpt * (l_float32)h / (l_float32)w;
694 } else {
695 hpt = 752.0; /* 792 - 2 * 20 */
696 wpt = hpt * (l_float32)w / (l_float32)h;
697 }
698
699 /* Generate the PS.
700 * The bounding box information should be inserted (default). */
701 outstr = generateJpegPS(NULL, cid, xpt, ypt, wpt, hpt, 1, 1);
702 l_CIDataDestroy(&cid);
703 if (!outstr)
704 return ERROR_INT("outstr not made", __func__, 1);
705 nbytes = strlen(outstr);
706
707 ret = l_binaryWrite(fileout, "w", outstr, nbytes);
708 LEPT_FREE(outstr);
709 if (ret) L_ERROR("ps string not written to file\n", __func__);
710 return ret;
711 }
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 {
792 char *outstr;
793 l_int32 nbytes;
794
795 if (!filein)
796 return ERROR_INT("filein not defined", __func__, 1);
797 if (!fileout)
798 return ERROR_INT("fileout not defined", __func__, 1);
799 if (strcmp(operation, "w") && strcmp(operation, "a"))
800 return ERROR_INT("operation must be \"w\" or \"a\"", __func__, 1);
801
802 if (convertJpegToPSString(filein, &outstr, &nbytes, x, y, res, scale,
803 pageno, endpage))
804 return ERROR_INT("ps string not made", __func__, 1);
805
806 if (l_binaryWrite(fileout, operation, outstr, nbytes)) {
807 LEPT_FREE(outstr);
808 return ERROR_INT("ps string not written to file", __func__, 1);
809 }
810
811 LEPT_FREE(outstr);
812 return 0;
813 }
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 {
852 char *outstr;
853 l_float32 xpt, ypt, wpt, hpt;
854 L_COMP_DATA *cid;
855
856 if (!poutstr)
857 return ERROR_INT("&outstr not defined", __func__, 1);
858 if (!pnbytes)
859 return ERROR_INT("&nbytes not defined", __func__, 1);
860 *poutstr = NULL;
861 *pnbytes = 0;
862 if (!filein)
863 return ERROR_INT("filein not defined", __func__, 1);
864
865 /* Generate the ascii encoded jpeg data */
866 if ((cid = l_generateJpegData(filein, 1)) == NULL)
867 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 if (scale == 0.0)
873 scale = 1.0;
874 if (res <= 0) {
875 if (cid->res > 0)
876 res = cid->res;
877 else
878 res = DefaultInputRes;
879 }
880
881 /* Get scaled location in pts */
882 if (scale == 0.0)
883 scale = 1.0;
884 xpt = scale * x * 72.f / res;
885 ypt = scale * y * 72.f / res;
886 wpt = scale * cid->w * 72.f / res;
887 hpt = scale * cid->h * 72.f / res;
888
889 if (pageno == 0)
890 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 outstr = generateJpegPS(NULL, cid, xpt, ypt, wpt, hpt, pageno, endpage);
904 l_CIDataDestroy(&cid);
905 if (!outstr)
906 return ERROR_INT("outstr not made", __func__, 1);
907 *poutstr = outstr;
908 *pnbytes = strlen(outstr);
909 return 0;
910 }
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 {
943 l_int32 w, h, bps, spp;
944 char *outstr;
945 char bigbuf[Bufsize];
946 SARRAY *sa;
947
948 if (!cid)
949 return (char *)ERROR_PTR("jpeg data not defined", __func__, NULL);
950 w = cid->w;
951 h = cid->h;
952 bps = cid->bps;
953 spp = cid->spp;
954
955 sa = sarrayCreate(50);
956 sarrayAddString(sa, "%!PS-Adobe-3.0", L_COPY);
957 sarrayAddString(sa, "%%Creator: leptonica", L_COPY);
958 if (filein)
959 snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: %s", filein);
960 else
961 snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: Jpeg compressed PS");
962 sarrayAddString(sa, bigbuf, L_COPY);
963 sarrayAddString(sa, "%%DocumentData: Clean7Bit", L_COPY);
964
965 if (var_PS_WRITE_BOUNDING_BOX == 1) {
966 snprintf(bigbuf, sizeof(bigbuf),
967 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
968 xpt, ypt, xpt + wpt, ypt + hpt);
969 sarrayAddString(sa, bigbuf, L_COPY);
970 }
971
972 sarrayAddString(sa, "%%LanguageLevel: 2", L_COPY);
973 sarrayAddString(sa, "%%EndComments", L_COPY);
974 snprintf(bigbuf, sizeof(bigbuf), "%%%%Page: %d %d", pageno, pageno);
975 sarrayAddString(sa, bigbuf, L_COPY);
976
977 sarrayAddString(sa, "save", L_COPY);
978 sarrayAddString(sa,
979 "/RawData currentfile /ASCII85Decode filter def", L_COPY);
980 sarrayAddString(sa, "/Data RawData << >> /DCTDecode filter def", L_COPY);
981
982 snprintf(bigbuf, sizeof(bigbuf),
983 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt);
984 sarrayAddString(sa, bigbuf, L_COPY);
985
986 snprintf(bigbuf, sizeof(bigbuf),
987 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt);
988 sarrayAddString(sa, bigbuf, L_COPY);
989
990 if (spp == 1)
991 sarrayAddString(sa, "/DeviceGray setcolorspace", L_COPY);
992 else if (spp == 3)
993 sarrayAddString(sa, "/DeviceRGB setcolorspace", L_COPY);
994 else /*spp == 4 */
995 sarrayAddString(sa, "/DeviceCMYK setcolorspace", L_COPY);
996
997 sarrayAddString(sa, "{ << /ImageType 1", L_COPY);
998 snprintf(bigbuf, sizeof(bigbuf), " /Width %d", w);
999 sarrayAddString(sa, bigbuf, L_COPY);
1000 snprintf(bigbuf, sizeof(bigbuf), " /Height %d", h);
1001 sarrayAddString(sa, bigbuf, L_COPY);
1002 snprintf(bigbuf, sizeof(bigbuf),
1003 " /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
1004 sarrayAddString(sa, bigbuf, L_COPY);
1005 sarrayAddString(sa, " /DataSource Data", L_COPY);
1006 snprintf(bigbuf, sizeof(bigbuf), " /BitsPerComponent %d", bps);
1007 sarrayAddString(sa, bigbuf, L_COPY);
1008
1009 if (spp == 1)
1010 sarrayAddString(sa, " /Decode [0 1]", L_COPY);
1011 else if (spp == 3)
1012 sarrayAddString(sa, " /Decode [0 1 0 1 0 1]", L_COPY);
1013 else /* spp == 4 */
1014 sarrayAddString(sa, " /Decode [0 1 0 1 0 1 0 1]", L_COPY);
1015
1016 sarrayAddString(sa, " >> image", L_COPY);
1017 sarrayAddString(sa, " Data closefile", L_COPY);
1018 sarrayAddString(sa, " RawData flushfile", L_COPY);
1019 if (endpage == TRUE)
1020 sarrayAddString(sa, " showpage", L_COPY);
1021 sarrayAddString(sa, " restore", L_COPY);
1022 sarrayAddString(sa, "} exec", L_COPY);
1023
1024 /* Insert the ascii85 jpeg data; this is now owned by sa */
1025 sarrayAddString(sa, cid->data85, L_INSERT);
1026 cid->data85 = NULL; /* it has been transferred and destroyed */
1027
1028 /* Generate and return the output string */
1029 outstr = sarrayToString(sa, 1);
1030 sarrayDestroy(&sa);
1031 return outstr;
1032 }
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 {
1061 char *outstr;
1062 l_int32 w, h, nbytes, ret;
1063 l_float32 xpt, ypt, wpt, hpt;
1064 L_COMP_DATA *cid;
1065
1066 if (!filein)
1067 return ERROR_INT("filein not defined", __func__, 1);
1068 if (!fileout)
1069 return ERROR_INT("fileout not defined", __func__, 1);
1070
1071 if ((cid = l_generateG4Data(filein, 1)) == NULL)
1072 return ERROR_INT("g4 data not made", __func__, 1);
1073 w = cid->w;
1074 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 xpt = 20.0;
1079 ypt = 20.0;
1080 if (w * 11.0 > h * 8.5) {
1081 wpt = 572.0; /* 612 - 2 * 20 */
1082 hpt = wpt * (l_float32)h / (l_float32)w;
1083 } else {
1084 hpt = 752.0; /* 792 - 2 * 20 */
1085 wpt = hpt * (l_float32)w / (l_float32)h;
1086 }
1087
1088 /* Generate the PS, painting through the image mask.
1089 * The bounding box information should be inserted (default). */
1090 outstr = generateG4PS(NULL, cid, xpt, ypt, wpt, hpt, 1, 1, 1);
1091 l_CIDataDestroy(&cid);
1092 if (!outstr)
1093 return ERROR_INT("outstr not made", __func__, 1);
1094 nbytes = strlen(outstr);
1095
1096 ret = l_binaryWrite(fileout, "w", outstr, nbytes);
1097 LEPT_FREE(outstr);
1098 if (ret) L_ERROR("ps string not written to file\n", __func__);
1099 return ret;
1100 }
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 {
1173 char *outstr;
1174 l_int32 nbytes, ret;
1175
1176 if (!filein)
1177 return ERROR_INT("filein not defined", __func__, 1);
1178 if (!fileout)
1179 return ERROR_INT("fileout not defined", __func__, 1);
1180 if (strcmp(operation, "w") && strcmp(operation, "a"))
1181 return ERROR_INT("operation must be \"w\" or \"a\"", __func__, 1);
1182
1183 if (convertG4ToPSString(filein, &outstr, &nbytes, x, y, res, scale,
1184 pageno, maskflag, endpage))
1185 return ERROR_INT("ps string not made", __func__, 1);
1186
1187 ret = l_binaryWrite(fileout, operation, outstr, nbytes);
1188 LEPT_FREE(outstr);
1189 if (ret)
1190 return ERROR_INT("ps string not written to file", __func__, 1);
1191 return 0;
1192 }
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 {
1234 char *outstr;
1235 l_float32 xpt, ypt, wpt, hpt;
1236 L_COMP_DATA *cid;
1237
1238 if (!poutstr)
1239 return ERROR_INT("&outstr not defined", __func__, 1);
1240 if (!pnbytes)
1241 return ERROR_INT("&nbytes not defined", __func__, 1);
1242 *poutstr = NULL;
1243 *pnbytes = 0;
1244 if (!filein)
1245 return ERROR_INT("filein not defined", __func__, 1);
1246
1247 if ((cid = l_generateG4Data(filein, 1)) == NULL)
1248 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 if (scale == 0.0)
1254 scale = 1.0;
1255 if (res <= 0) {
1256 if (cid->res > 0) {
1257 res = cid->res;
1258 } else {
1259 if (cid->h <= 3509) /* A4 height at 300 ppi */
1260 res = 300;
1261 else
1262 res = 600;
1263 }
1264 }
1265 xpt = scale * x * 72.f / res;
1266 ypt = scale * y * 72.f / res;
1267 wpt = scale * cid->w * 72.f / res;
1268 hpt = scale * cid->h * 72.f / res;
1269
1270 if (pageno == 0)
1271 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 outstr = generateG4PS(NULL, cid, xpt, ypt, wpt, hpt,
1284 maskflag, pageno, endpage);
1285 l_CIDataDestroy(&cid);
1286 if (!outstr)
1287 return ERROR_INT("outstr not made", __func__, 1);
1288 *poutstr = outstr;
1289 *pnbytes = strlen(outstr);
1290 return 0;
1291 }
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 {
1327 l_int32 w, h;
1328 char *outstr;
1329 char bigbuf[Bufsize];
1330 SARRAY *sa;
1331
1332 if (!cid)
1333 return (char *)ERROR_PTR("g4 data not defined", __func__, NULL);
1334 w = cid->w;
1335 h = cid->h;
1336
1337 sa = sarrayCreate(50);
1338 sarrayAddString(sa, "%!PS-Adobe-3.0", L_COPY);
1339 sarrayAddString(sa, "%%Creator: leptonica", L_COPY);
1340 if (filein)
1341 snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: %s", filein);
1342 else
1343 snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: G4 compressed PS");
1344 sarrayAddString(sa, bigbuf, L_COPY);
1345 sarrayAddString(sa, "%%DocumentData: Clean7Bit", L_COPY);
1346
1347 if (var_PS_WRITE_BOUNDING_BOX == 1) {
1348 snprintf(bigbuf, sizeof(bigbuf),
1349 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
1350 xpt, ypt, xpt + wpt, ypt + hpt);
1351 sarrayAddString(sa, bigbuf, L_COPY);
1352 }
1353
1354 sarrayAddString(sa, "%%LanguageLevel: 2", L_COPY);
1355 sarrayAddString(sa, "%%EndComments", L_COPY);
1356 snprintf(bigbuf, sizeof(bigbuf), "%%%%Page: %d %d", pageno, pageno);
1357 sarrayAddString(sa, bigbuf, L_COPY);
1358
1359 sarrayAddString(sa, "save", L_COPY);
1360 sarrayAddString(sa, "100 dict begin", L_COPY);
1361
1362 snprintf(bigbuf, sizeof(bigbuf),
1363 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt);
1364 sarrayAddString(sa, bigbuf, L_COPY);
1365
1366 snprintf(bigbuf, sizeof(bigbuf),
1367 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt);
1368 sarrayAddString(sa, bigbuf, L_COPY);
1369
1370 sarrayAddString(sa, "/DeviceGray setcolorspace", L_COPY);
1371
1372 sarrayAddString(sa, "{", L_COPY);
1373 sarrayAddString(sa,
1374 " /RawData currentfile /ASCII85Decode filter def", L_COPY);
1375 sarrayAddString(sa, " << ", L_COPY);
1376 sarrayAddString(sa, " /ImageType 1", L_COPY);
1377 snprintf(bigbuf, sizeof(bigbuf), " /Width %d", w);
1378 sarrayAddString(sa, bigbuf, L_COPY);
1379 snprintf(bigbuf, sizeof(bigbuf), " /Height %d", h);
1380 sarrayAddString(sa, bigbuf, L_COPY);
1381 snprintf(bigbuf, sizeof(bigbuf),
1382 " /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
1383 sarrayAddString(sa, bigbuf, L_COPY);
1384 sarrayAddString(sa, " /BitsPerComponent 1", L_COPY);
1385 sarrayAddString(sa, " /Interpolate true", L_COPY);
1386 if (cid->minisblack)
1387 sarrayAddString(sa, " /Decode [1 0]", L_COPY);
1388 else /* miniswhite; typical for 1 bpp */
1389 sarrayAddString(sa, " /Decode [0 1]", L_COPY);
1390 sarrayAddString(sa, " /DataSource RawData", L_COPY);
1391 sarrayAddString(sa, " <<", L_COPY);
1392 sarrayAddString(sa, " /K -1", L_COPY);
1393 snprintf(bigbuf, sizeof(bigbuf), " /Columns %d", w);
1394 sarrayAddString(sa, bigbuf, L_COPY);
1395 snprintf(bigbuf, sizeof(bigbuf), " /Rows %d", h);
1396 sarrayAddString(sa, bigbuf, L_COPY);
1397 sarrayAddString(sa, " >> /CCITTFaxDecode filter", L_COPY);
1398 if (maskflag == TRUE) /* just paint through the fg */
1399 sarrayAddString(sa, " >> imagemask", L_COPY);
1400 else /* Paint full image */
1401 sarrayAddString(sa, " >> image", L_COPY);
1402 sarrayAddString(sa, " RawData flushfile", L_COPY);
1403 if (endpage == TRUE)
1404 sarrayAddString(sa, " showpage", L_COPY);
1405 sarrayAddString(sa, "}", L_COPY);
1406
1407 sarrayAddString(sa, "%%BeginData:", L_COPY);
1408 sarrayAddString(sa, "exec", L_COPY);
1409
1410 /* Insert the ascii85 ccittg4 data; this is now owned by sa */
1411 sarrayAddString(sa, cid->data85, L_INSERT);
1412
1413 /* Concat the trailing data */
1414 sarrayAddString(sa, "%%EndData", L_COPY);
1415 sarrayAddString(sa, "end", L_COPY);
1416 sarrayAddString(sa, "restore", L_COPY);
1417
1418 outstr = sarrayToString(sa, 1);
1419 sarrayDestroy(&sa);
1420 cid->data85 = NULL; /* it has been transferred and destroyed */
1421 return outstr;
1422 }
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 {
1451 char *tempfile;
1452 l_int32 i, npages, w, h, istiff;
1453 l_float32 scale;
1454 PIX *pix, *pixs;
1455 FILE *fp;
1456
1457 if (!filein)
1458 return ERROR_INT("filein not defined", __func__, 1);
1459 if (!fileout)
1460 return ERROR_INT("fileout not defined", __func__, 1);
1461
1462 if ((fp = fopenReadStream(filein)) == NULL)
1463 return ERROR_INT_1("file not found", filein, __func__, 1);
1464 istiff = fileFormatIsTiff(fp);
1465 if (!istiff) {
1466 fclose(fp);
1467 return ERROR_INT_1("file not tiff format", filein, __func__, 1);
1468 }
1469 tiffGetCount(fp, &npages);
1470 fclose(fp);
1471
1472 if (fillfract == 0.0)
1473 fillfract = DefaultFillFraction;
1474
1475 for (i = 0; i < npages; i++) {
1476 if ((pix = pixReadTiff(filein, i)) == NULL)
1477 return ERROR_INT_1("pix not made", filein, __func__, 1);
1478
1479 pixGetDimensions(pix, &w, &h, NULL);
1480 if (w == 1728 && h < w) /* it's a std res fax */
1481 pixs = pixScale(pix, 1.0, 2.0);
1482 else
1483 pixs = pixClone(pix);
1484
1485 tempfile = l_makeTempFilename();
1486 pixWrite(tempfile, pixs, IFF_TIFF_G4);
1487 scale = L_MIN(fillfract * 2550 / w, fillfract * 3300 / h);
1488 if (i == 0)
1489 convertG4ToPS(tempfile, fileout, "w", 0, 0, 300, scale,
1490 i + 1, FALSE, TRUE);
1491 else
1492 convertG4ToPS(tempfile, fileout, "a", 0, 0, 300, scale,
1493 i + 1, FALSE, TRUE);
1494 lept_rmfile(tempfile);
1495 LEPT_FREE(tempfile);
1496 pixDestroy(&pix);
1497 pixDestroy(&pixs);
1498 }
1499
1500 return 0;
1501 }
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 {
1528 char *outstr;
1529 l_int32 w, h, nbytes, ret;
1530 l_float32 xpt, ypt, wpt, hpt;
1531 L_COMP_DATA *cid;
1532
1533 if (!filein)
1534 return ERROR_INT("filein not defined", __func__, 1);
1535 if (!fileout)
1536 return ERROR_INT("fileout not defined", __func__, 1);
1537
1538 if ((cid = l_generateFlateData(filein, 1)) == NULL)
1539 return ERROR_INT("flate data not made", __func__, 1);
1540 w = cid->w;
1541 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 xpt = 20.0;
1546 ypt = 20.0;
1547 if (w * 11.0 > h * 8.5) {
1548 wpt = 572.0; /* 612 - 2 * 20 */
1549 hpt = wpt * (l_float32)h / (l_float32)w;
1550 } else {
1551 hpt = 752.0; /* 792 - 2 * 20 */
1552 wpt = hpt * (l_float32)w / (l_float32)h;
1553 }
1554
1555 /* Generate the PS.
1556 * The bounding box information should be inserted (default). */
1557 outstr = generateFlatePS(NULL, cid, xpt, ypt, wpt, hpt, 1, 1);
1558 l_CIDataDestroy(&cid);
1559 if (!outstr)
1560 return ERROR_INT("outstr not made", __func__, 1);
1561 nbytes = strlen(outstr);
1562
1563 ret = l_binaryWrite(fileout, "w", outstr, nbytes);
1564 LEPT_FREE(outstr);
1565 if (ret) L_ERROR("ps string not written to file\n", __func__);
1566 return ret;
1567 }
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 {
1647 char *outstr;
1648 l_int32 nbytes, ret;
1649
1650 if (!filein)
1651 return ERROR_INT("filein not defined", __func__, 1);
1652 if (!fileout)
1653 return ERROR_INT("fileout not defined", __func__, 1);
1654 if (strcmp(operation, "w") && strcmp(operation, "a"))
1655 return ERROR_INT("operation must be \"w\" or \"a\"", __func__, 1);
1656
1657 if (convertFlateToPSString(filein, &outstr, &nbytes, x, y, res, scale,
1658 pageno, endpage))
1659 return ERROR_INT("ps string not made", __func__, 1);
1660
1661 ret = l_binaryWrite(fileout, operation, outstr, nbytes);
1662 LEPT_FREE(outstr);
1663 if (ret) L_ERROR("ps string not written to file\n", __func__);
1664 return ret;
1665 }
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 {
1712 char *outstr;
1713 l_float32 xpt, ypt, wpt, hpt;
1714 L_COMP_DATA *cid;
1715
1716 if (!poutstr)
1717 return ERROR_INT("&outstr not defined", __func__, 1);
1718 if (!pnbytes)
1719 return ERROR_INT("&nbytes not defined", __func__, 1);
1720 *pnbytes = 0;
1721 *poutstr = NULL;
1722 if (!filein)
1723 return ERROR_INT("filein not defined", __func__, 1);
1724
1725 if ((cid = l_generateFlateData(filein, 1)) == NULL)
1726 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 if (scale == 0.0)
1732 scale = 1.0;
1733 if (res <= 0) {
1734 if (cid->res > 0)
1735 res = cid->res;
1736 else
1737 res = DefaultInputRes;
1738 }
1739 xpt = scale * x * 72.f / res;
1740 ypt = scale * y * 72.f / res;
1741 wpt = scale * cid->w * 72.f / res;
1742 hpt = scale * cid->h * 72.f / res;
1743
1744 if (pageno == 0)
1745 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 outstr = generateFlatePS(NULL, cid, xpt, ypt, wpt, hpt, pageno, endpage);
1759 l_CIDataDestroy(&cid);
1760 if (!outstr)
1761 return ERROR_INT("outstr not made", __func__, 1);
1762 *poutstr = outstr;
1763 *pnbytes = strlen(outstr);
1764 return 0;
1765 }
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 {
1793 l_int32 w, h, bps, spp;
1794 char *outstr;
1795 char bigbuf[Bufsize];
1796 SARRAY *sa;
1797
1798 if (!cid)
1799 return (char *)ERROR_PTR("flate data not defined", __func__, NULL);
1800 w = cid->w;
1801 h = cid->h;
1802 bps = cid->bps;
1803 spp = cid->spp;
1804
1805 sa = sarrayCreate(50);
1806 sarrayAddString(sa, "%!PS-Adobe-3.0 EPSF-3.0", L_COPY);
1807 sarrayAddString(sa, "%%Creator: leptonica", L_COPY);
1808 if (filein)
1809 snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: %s", filein);
1810 else
1811 snprintf(bigbuf, sizeof(bigbuf), "%%%%Title: Flate compressed PS");
1812 sarrayAddString(sa, bigbuf, L_COPY);
1813 sarrayAddString(sa, "%%DocumentData: Clean7Bit", L_COPY);
1814
1815 if (var_PS_WRITE_BOUNDING_BOX == 1) {
1816 snprintf(bigbuf, sizeof(bigbuf),
1817 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f",
1818 xpt, ypt, xpt + wpt, ypt + hpt);
1819 sarrayAddString(sa, bigbuf, L_COPY);
1820 }
1821
1822 sarrayAddString(sa, "%%LanguageLevel: 3", L_COPY);
1823 sarrayAddString(sa, "%%EndComments", L_COPY);
1824 snprintf(bigbuf, sizeof(bigbuf), "%%%%Page: %d %d", pageno, pageno);
1825 sarrayAddString(sa, bigbuf, L_COPY);
1826
1827 sarrayAddString(sa, "save", L_COPY);
1828 snprintf(bigbuf, sizeof(bigbuf),
1829 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt);
1830 sarrayAddString(sa, bigbuf, L_COPY);
1831
1832 snprintf(bigbuf, sizeof(bigbuf),
1833 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt);
1834 sarrayAddString(sa, bigbuf, L_COPY);
1835
1836 /* If there is a colormap, add the data; it is now owned by sa */
1837 if (cid->cmapdata85) {
1838 snprintf(bigbuf, sizeof(bigbuf),
1839 "[ /Indexed /DeviceRGB %d %%set colormap type/size",
1840 cid->ncolors - 1);
1841 sarrayAddString(sa, bigbuf, L_COPY);
1842 sarrayAddString(sa, " <~", L_COPY);
1843 sarrayAddString(sa, cid->cmapdata85, L_INSERT);
1844 sarrayAddString(sa, " ] setcolorspace", L_COPY);
1845 } else if (spp == 1) {
1846 sarrayAddString(sa, "/DeviceGray setcolorspace", L_COPY);
1847 } else { /* spp == 3 */
1848 sarrayAddString(sa, "/DeviceRGB setcolorspace", L_COPY);
1849 }
1850
1851 sarrayAddString(sa,
1852 "/RawData currentfile /ASCII85Decode filter def", L_COPY);
1853 sarrayAddString(sa,
1854 "/Data RawData << >> /FlateDecode filter def", L_COPY);
1855
1856 sarrayAddString(sa, "{ << /ImageType 1", L_COPY);
1857 snprintf(bigbuf, sizeof(bigbuf), " /Width %d", w);
1858 sarrayAddString(sa, bigbuf, L_COPY);
1859 snprintf(bigbuf, sizeof(bigbuf), " /Height %d", h);
1860 sarrayAddString(sa, bigbuf, L_COPY);
1861 snprintf(bigbuf, sizeof(bigbuf), " /BitsPerComponent %d", bps);
1862 sarrayAddString(sa, bigbuf, L_COPY);
1863 snprintf(bigbuf, sizeof(bigbuf),
1864 " /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h);
1865 sarrayAddString(sa, bigbuf, L_COPY);
1866
1867 if (cid->cmapdata85) {
1868 sarrayAddString(sa, " /Decode [0 255]", L_COPY);
1869 } else if (spp == 1) {
1870 if (bps == 1) /* miniswhite photometry */
1871 sarrayAddString(sa, " /Decode [1 0]", L_COPY);
1872 else /* bps > 1 */
1873 sarrayAddString(sa, " /Decode [0 1]", L_COPY);
1874 } else { /* spp == 3 */
1875 sarrayAddString(sa, " /Decode [0 1 0 1 0 1]", L_COPY);
1876 }
1877
1878 sarrayAddString(sa, " /DataSource Data", L_COPY);
1879 sarrayAddString(sa, " >> image", L_COPY);
1880 sarrayAddString(sa, " Data closefile", L_COPY);
1881 sarrayAddString(sa, " RawData flushfile", L_COPY);
1882 if (endpage == TRUE)
1883 sarrayAddString(sa, " showpage", L_COPY);
1884 sarrayAddString(sa, " restore", L_COPY);
1885 sarrayAddString(sa, "} exec", L_COPY);
1886
1887 /* Insert the ascii85 gzipped data; this is now owned by sa */
1888 sarrayAddString(sa, cid->data85, L_INSERT);
1889
1890 /* Generate and return the output string */
1891 outstr = sarrayToString(sa, 1);
1892 sarrayDestroy(&sa);
1893 cid->cmapdata85 = NULL; /* it has been transferred to sa and destroyed */
1894 cid->data85 = NULL; /* it has been transferred to sa and destroyed */
1895 return outstr;
1896 }
1897
1898
1899 /*---------------------------------------------------------------------*
1900 * Write to memory *
1901 *---------------------------------------------------------------------*/
1902 /*!
1903 * \brief pixWriteMemPS()
1904 *
1905 * \param[out] pdata data of tiff compressed image
1906 * \param[out] psize size of returned data
1907 * \param[in] pix
1908 * \param[in] box [optional]
1909 * \param[in] res can use 0 for default of 300 ppi
1910 * \param[in] scale to prevent scaling, use either 1.0 or 0.0
1911 * \return 0 if OK, 1 on error
1912 *
1913 * <pre>
1914 * Notes:
1915 * (1) See pixWriteStringPS() for usage.
1916 * (2) This is just a wrapper for pixWriteStringPS(), which
1917 * writes uncompressed image data to memory.
1918 * </pre>
1919 */
1920 l_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 {
1928 if (!pdata)
1929 return ERROR_INT("&data not defined", __func__, 1 );
1930 if (!psize)
1931 return ERROR_INT("&size not defined", __func__, 1 );
1932 if (!pix)
1933 return ERROR_INT("&pix not defined", __func__, 1 );
1934
1935 *pdata = (l_uint8 *)pixWriteStringPS(pix, box, res, scale);
1936 *psize = strlen((char *)(*pdata));
1937 return 0;
1938 }
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 {
1958 l_int32 resw, resh, res;
1959
1960 if (fillfract == 0.0)
1961 fillfract = DefaultFillFraction;
1962 resw = (l_int32)((w * 72.) / (LetterWidth * fillfract));
1963 resh = (l_int32)((h * 72.) / (LetterHeight * fillfract));
1964 res = L_MAX(resw, resh);
1965 return res;
1966 }
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 {
1983 l_int32 resw, resh, res;
1984
1985 if (fillfract == 0.0)
1986 fillfract = DefaultFillFraction;
1987 resw = (l_int32)((w * 72.) / (A4Width * fillfract));
1988 resh = (l_int32)((h * 72.) / (A4Height * fillfract));
1989 res = L_MAX(resw, resh);
1990 return res;
1991 }
1992
1993
1994 /*-------------------------------------------------------------*
1995 * Setting flag for writing bounding box hint *
1996 *-------------------------------------------------------------*/
1997 void
1998 l_psWriteBoundingBox(l_int32 flag)
1999 {
2000 var_PS_WRITE_BOUNDING_BOX = flag;
2001 }
2002
2003
2004 /* --------------------------------------------*/
2005 #endif /* USE_PSIO */
2006 /* --------------------------------------------*/