Leptonica  1.83.1
Image processing and image analysis suite
psio2.c
Go to the documentation of this file.
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 
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.95;
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  *-------------------------------------------------------------*/
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.5 * 300. / (l_float32)w;
207  else
208  scale = 11.0 * 300. / (l_float32)h;
209 
210  if ((fp = fopenWriteStream(fileout, "wb")) == NULL)
211  return ERROR_INT("file not opened for write", __func__, 1);
212  ret = pixWriteStreamPS(fp, pix, NULL, 0, scale);
213  fclose(fp);
214 
215  pixDestroy(&pix);
216  return ret;
217 }
218 
219 
238 l_ok
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 
336 char *
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 
444 char *
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 
549 static void
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.5 - winch) / 2.;
587  yinch = (11.0 - hinch) / 2.;
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.;
594  if (bh == 0)
595  hinch = (l_float32)hpix / fres;
596  else
597  hinch = (l_float32)bh / 1000.;
598  xinch = (l_float32)bx / 1000.;
599  yinch = (l_float32)by / 1000.;
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. * winch;
612  *phpt = 72. * hinch;
613  *pxpt = 72. * xinch;
614  *pypt = 72. * yinch;
615  return;
616 }
617 
618 
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  *-------------------------------------------------------------*/
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 
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 
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. / res;
885  ypt = scale * y * 72. / res;
886  wpt = scale * cid->w * 72. / res;
887  hpt = scale * cid->h * 72. / 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 
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  *-------------------------------------------------------------*/
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 
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 
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. / res;
1266  ypt = scale * y * 72. / res;
1267  wpt = scale * cid->w * 72. / res;
1268  hpt = scale * cid->h * 72. / 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 
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  *-------------------------------------------------------------*/
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("file not found", __func__, 1);
1464  istiff = fileFormatIsTiff(fp);
1465  if (!istiff) {
1466  fclose(fp);
1467  return ERROR_INT("file not tiff format", __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("pix not made", __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  *---------------------------------------------------------------------*/
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 
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 
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. / res;
1740  ypt = scale * y * 72. / res;
1741  wpt = scale * cid->w * 72. / res;
1742  hpt = scale * cid->h * 72. / 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 
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  *---------------------------------------------------------------------*/
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  *-------------------------------------------------------------*/
1953 l_int32
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 
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 /* --------------------------------------------*/
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
L_COMP_DATA * l_generateG4Data(const char *fname, l_int32 ascii85flag)
l_generateG4Data()
Definition: pdfio2.c:1099
L_COMP_DATA * l_generateJpegData(const char *fname, l_int32 ascii85flag)
l_generateJpegData()
Definition: pdfio2.c:913
void l_CIDataDestroy(L_COMP_DATA **pcid)
l_CIDataDestroy()
Definition: pdfio2.c:1638
L_COMP_DATA * l_generateFlateData(const char *fname, l_int32 ascii85flag)
l_generateFlateData()
Definition: pdfio2.c:1290
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
@ L_COPY
Definition: pix.h:505
@ L_INSERT
Definition: pix.h:504
PIX * pixConvertForPSWrap(PIX *pixs)
pixConvertForPSWrap()
Definition: pixconv.c:3823
char * pixWriteStringPS(PIX *pixs, BOX *box, l_int32 res, l_float32 scale)
pixWriteStringPS()
Definition: psio2.c:337
static 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)
generateFlatePS()
Definition: psio2.c:1784
static l_ok 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)
convertG4ToPSString()
Definition: psio2.c:1223
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)
generateUncompressedPS()
Definition: psio2.c:445
l_ok 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)
convertFlateToPS()
Definition: psio2.c:1637
static 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)
getScaledParametersPS()
Definition: psio2.c:550
static l_ok 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)
convertFlateToPSString()
Definition: psio2.c:1702
l_ok pixWriteStreamPS(FILE *fp, PIX *pix, BOX *box, l_int32 res, l_float32 scale)
pixWriteStreamPS()
Definition: psio2.c:239
l_ok 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)
convertJpegToPS()
Definition: psio2.c:782
l_int32 getResA4Page(l_int32 w, l_int32 h, l_float32 fillfract)
getResA4Page()
Definition: psio2.c:1979
l_ok pixWritePSEmbed(const char *filein, const char *fileout)
pixWritePSEmbed()
Definition: psio2.c:188
static l_ok 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)
convertJpegToPSString()
Definition: psio2.c:842
l_ok convertTiffMultipageToPS(const char *filein, const char *fileout, l_float32 fillfract)
convertTiffMultipageToPS()
Definition: psio2.c:1447
static void convertByteToHexAscii(l_uint8 byteval, char *pnib1, char *pnib2)
convertByteToHexAscii()
Definition: psio2.c:627
l_ok convertFlateToPSEmbed(const char *filein, const char *fileout)
convertFlateToPSEmbed()
Definition: psio2.c:1525
l_ok convertG4ToPSEmbed(const char *filein, const char *fileout)
convertG4ToPSEmbed()
Definition: psio2.c:1058
l_ok pixWriteMemPS(l_uint8 **pdata, size_t *psize, PIX *pix, BOX *box, l_int32 res, l_float32 scale)
pixWriteMemPS()
Definition: psio2.c:1921
l_ok convertJpegToPSEmbed(const char *filein, const char *fileout)
convertJpegToPSEmbed()
Definition: psio2.c:668
l_ok 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)
convertG4ToPS()
Definition: psio2.c:1162
static 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)
generateJpegPS()
Definition: psio2.c:934
l_int32 getResLetterPage(l_int32 w, l_int32 h, l_float32 fillfract)
getResLetterPage()
Definition: psio2.c:1954
static 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)
generateG4PS()
Definition: psio2.c:1317
PIX * pixRead(const char *filename)
pixRead()
Definition: readfile.c:189
l_int32 fileFormatIsTiff(FILE *fp)
fileFormatIsTiff()
Definition: readfile.c:780
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:169
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:353
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:435
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:716
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
l_int32 ncolors
Definition: imageio.h:190
size_t nbytescomp
Definition: imageio.h:185
l_int32 minisblack
Definition: imageio.h:195
char * cmapdata85
Definition: imageio.h:188
size_t nbytes85
Definition: imageio.h:187
PIX * pixReadTiff(const char *filename, l_int32 n)
pixReadTiff()
Definition: tiffio.c:394
l_ok tiffGetCount(FILE *fp, l_int32 *pn)
tiffGetCount()
Definition: tiffio.c:1633
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 lept_rmfile(const char *filepath)
lept_rmfile()
Definition: utils2.c:2429
char * l_makeTempFilename(void)
l_makeTempFilename()
Definition: utils2.c:3286
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1905
l_ok l_binaryWrite(const char *filename, const char *operation, const void *data, size_t nbytes)
l_binaryWrite()
Definition: utils2.c:1519
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1864