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